diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index 4c31ca595..6952454f4 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -5,6 +5,7 @@ from typing import Any from typing import Dict from typing import List +from typing import Mapping from typing import Optional from typing import Set from typing import Union @@ -15,12 +16,19 @@ if TYPE_CHECKING: + from poetry.core.packages.dependency_group import DependencyGroup from poetry.core.packages.project_package import ProjectPackage from poetry.core.packages.types import DependencyTypes from poetry.core.poetry import Poetry from poetry.core.spdx.license import License from poetry.core.version.markers import BaseMarker + DependencyConstraint = Union[str, Dict[str, Any]] + DependencyConfig = Mapping[ + str, Union[List[DependencyConstraint], DependencyConstraint] + ] + + logger = logging.getLogger(__name__) @@ -63,6 +71,42 @@ def get_package(cls, name: str, version: str) -> "ProjectPackage": return ProjectPackage(name, version, version) + @classmethod + def _add_package_group_dependencies( + cls, + package: "ProjectPackage", + group: Union[str, "DependencyGroup"], + dependencies: "DependencyConfig", + ) -> None: + if isinstance(group, str): + if package.has_dependency_group(group): + group = package.dependency_group(group) + else: + from poetry.core.packages.dependency_group import DependencyGroup + + group = DependencyGroup(group) + + for name, constraints in dependencies.items(): + _constraints = ( + constraints if isinstance(constraints, list) else [constraints] + ) + for _constraint in _constraints: + if name.lower() == "python": + if group.name == "default" and isinstance(_constraint, str): + package.python_versions = _constraint + continue + + group.add_dependency( + cls.create_dependency( + name, + _constraint, + groups=[group.name], + root_dir=package.root_dir, + ) + ) + + package.add_dependency_group(group) + @classmethod def configure_package( cls, @@ -106,81 +150,25 @@ def configure_package( package.platform = config["platform"] if "dependencies" in config: - group = DependencyGroup("default") - for name, constraint in config["dependencies"].items(): - if name.lower() == "python": - package.python_versions = constraint - continue - - if isinstance(constraint, list): - for _constraint in constraint: - group.add_dependency( - cls.create_dependency( - name, _constraint, root_dir=package.root_dir - ) - ) - - continue - - group.add_dependency( - cls.create_dependency(name, constraint, root_dir=package.root_dir) - ) - - package.add_dependency_group(group) + cls._add_package_group_dependencies( + package=package, group="default", dependencies=config["dependencies"] + ) if with_groups and "group" in config: for group_name, group_config in config["group"].items(): group = DependencyGroup( group_name, optional=group_config.get("optional", False) ) - for name, constraint in group_config["dependencies"].items(): - if isinstance(constraint, list): - for _constraint in constraint: - group.add_dependency( - cls.create_dependency( - name, - _constraint, - groups=[group_name], - root_dir=package.root_dir, - ) - ) - - continue - - group.add_dependency( - cls.create_dependency( - name, - constraint, - groups=[group_name], - root_dir=package.root_dir, - ) - ) - - package.add_dependency_group(group) - - if with_groups and "dev-dependencies" in config: - group = DependencyGroup("dev") - for name, constraint in config["dev-dependencies"].items(): - if isinstance(constraint, list): - for _constraint in constraint: - group.add_dependency( - cls.create_dependency( - name, - _constraint, - groups=["dev"], - root_dir=package.root_dir, - ) - ) - - continue - - group.add_dependency( - cls.create_dependency( - name, constraint, groups=["dev"], root_dir=package.root_dir - ) + cls._add_package_group_dependencies( + package=package, + group=group, + dependencies=group_config["dependencies"], ) - package.add_dependency_group(group) + if with_groups and "dev-dependencies" in config: + cls._add_package_group_dependencies( + package=package, group="dev", dependencies=config["dev-dependencies"] + ) extras = config.get("extras", {}) for extra_name, requirements in extras.items(): @@ -254,7 +242,7 @@ def configure_package( def create_dependency( cls, name: str, - constraint: Union[str, Dict[str, Any]], + constraint: "DependencyConstraint", groups: Optional[List[str]] = None, root_dir: Optional[Path] = None, ) -> "DependencyTypes": diff --git a/src/poetry/core/packages/package.py b/src/poetry/core/packages/package.py index 46f49e371..459e1231b 100644 --- a/src/poetry/core/packages/package.py +++ b/src/poetry/core/packages/package.py @@ -200,11 +200,10 @@ def all_requires( """ Returns the default dependencies and group dependencies. """ - return self.requires + [ + return [ dependency for group in self._dependency_groups.values() for dependency in group.dependencies - if group.name != "default" ] def _get_author(self) -> Dict[str, Optional[str]]: @@ -373,8 +372,11 @@ def is_root(self) -> bool: def add_dependency_group(self, group: "DependencyGroup") -> None: self._dependency_groups[group.name] = group + def has_dependency_group(self, name: str) -> bool: + return name in self._dependency_groups + def dependency_group(self, name: str) -> "DependencyGroup": - if name not in self._dependency_groups: + if not self.has_dependency_group(name): raise ValueError(f'The dependency group "{name}" does not exist.') return self._dependency_groups[name] diff --git a/src/poetry/core/packages/project_package.py b/src/poetry/core/packages/project_package.py index ad5dfe592..93956ed39 100644 --- a/src/poetry/core/packages/project_package.py +++ b/src/poetry/core/packages/project_package.py @@ -54,16 +54,14 @@ def to_dependency(self) -> Union["DependencyTypes"]: return dependency @property - def python_versions(self) -> Union[str, "VersionConstraint"]: + def python_versions(self) -> str: return self._python_versions @python_versions.setter - def python_versions(self, value: Union[str, "VersionConstraint"]) -> None: - from poetry.core.semver.version_range import VersionRange - + def python_versions(self, value: str) -> None: self._python_versions = value - if value == "*" or value == VersionRange(): + if value == "*": value = "~2.7 || >=3.4" self._python_constraint = parse_constraint(value) diff --git a/tests/fixtures/project_with_groups_and_explicit_default/README.rst b/tests/fixtures/project_with_groups_and_explicit_default/README.rst new file mode 100644 index 000000000..f7fe15470 --- /dev/null +++ b/tests/fixtures/project_with_groups_and_explicit_default/README.rst @@ -0,0 +1,2 @@ +My Package +========== diff --git a/tests/fixtures/project_with_groups_and_explicit_default/pyproject.toml b/tests/fixtures/project_with_groups_and_explicit_default/pyproject.toml new file mode 100644 index 000000000..b7c02d70f --- /dev/null +++ b/tests/fixtures/project_with_groups_and_explicit_default/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "simple-project" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.7" + +[tool.poetry.group.default.dependencies] +aiohttp = "^2.17.0" + +[tools.poetry] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/fixtures/project_with_groups_and_explicit_default/simple_project/__init__.py b/tests/fixtures/project_with_groups_and_explicit_default/simple_project/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fixtures/project_with_groups_and_legacy_dev/README.rst b/tests/fixtures/project_with_groups_and_legacy_dev/README.rst new file mode 100644 index 000000000..f7fe15470 --- /dev/null +++ b/tests/fixtures/project_with_groups_and_legacy_dev/README.rst @@ -0,0 +1,2 @@ +My Package +========== diff --git a/tests/fixtures/project_with_groups_and_legacy_dev/pyproject.toml b/tests/fixtures/project_with_groups_and_legacy_dev/pyproject.toml new file mode 100644 index 000000000..6e239c72e --- /dev/null +++ b/tests/fixtures/project_with_groups_and_legacy_dev/pyproject.toml @@ -0,0 +1,20 @@ +[tool.poetry] +name = "simple-project" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.7" + +[tool.poetry.group.dev.dependencies] +pre-commit = "^2.17.0" + +[tool.poetry.dev-dependencies] +pytest = "^5.2" + +[tools.poetry] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tests/fixtures/project_with_groups_and_legacy_dev/simple_project/__init__.py b/tests/fixtures/project_with_groups_and_legacy_dev/simple_project/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_factory.py b/tests/test_factory.py index 04dddb687..79f0b0190 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -233,3 +233,29 @@ def test_create_poetry_fails_with_invalid_dev_dependencies_iff_with_dev_is_true( Factory().create_poetry( fixtures_dir / "project_with_invalid_dev_deps", with_groups=False ) + + +def test_create_poetry_with_groups_and_legacy_dev(): + poetry = Factory().create_poetry( + fixtures_dir / "project_with_groups_and_legacy_dev" + ) + + package = poetry.package + dependencies = package.all_requires + + assert len(dependencies) == 2 + assert {dependency.name for dependency in dependencies} == {"pytest", "pre-commit"} + + +def test_create_poetry_with_groups_and_explicit_default(): + poetry = Factory().create_poetry( + fixtures_dir / "project_with_groups_and_explicit_default" + ) + + package = poetry.package + dependencies = package.requires + + assert len(dependencies) == 1 + assert {dependency.name for dependency in dependencies} == { + "aiohttp", + }