From 83710ebb47e2ca0f758cab98166059bcc10742c1 Mon Sep 17 00:00:00 2001 From: finswimmer Date: Mon, 13 Jan 2025 21:05:19 +0100 Subject: [PATCH] wip: poc pep 735 --- src/poetry/core/factory.py | 49 ++++++++++--- .../core/json/schemas/poetry-schema.json | 3 - src/poetry/core/packages/dependency.py | 6 +- .../sample_project_with_groups_new/README.rst | 2 + .../pyproject.toml | 69 +++++++++++++++++++ tests/test_factory.py | 25 +++++++ 6 files changed, 135 insertions(+), 19 deletions(-) create mode 100644 tests/fixtures/sample_project_with_groups_new/README.rst create mode 100644 tests/fixtures/sample_project_with_groups_new/pyproject.toml diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index aeb0bb114..ed612ff2a 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -133,13 +133,18 @@ def configure_package( ) -> None: project = pyproject.data.get("project", {}) tool_poetry = pyproject.poetry_config + dependency_groups = pyproject.data.get("dependency-groups", {}) package.root_dir = root cls._configure_package_metadata(package, project, tool_poetry, root) cls._configure_entry_points(package, project, tool_poetry) cls._configure_package_dependencies( - package, project, tool_poetry, with_groups=with_groups + package, + project, + tool_poetry, + dependency_groups=dependency_groups, + with_groups=with_groups, ) cls._configure_package_poetry_specifics(package, tool_poetry) @@ -282,6 +287,7 @@ def _configure_package_dependencies( package: ProjectPackage, project: dict[str, Any], tool_poetry: dict[str, Any], + dependency_groups: dict[str, list[str]], with_groups: bool = True, ) -> None: from poetry.core.packages.dependency import Dependency @@ -332,16 +338,37 @@ def _configure_package_dependencies( dependencies=tool_poetry["dependencies"], ) - if with_groups and "group" in tool_poetry: - for group_name, group_config in tool_poetry["group"].items(): - group = DependencyGroup( - group_name, optional=group_config.get("optional", False) - ) - cls._add_package_group_dependencies( - package=package, - group=group, - dependencies=group_config["dependencies"], - ) + if with_groups: + if "group" in tool_poetry: + for group_name, group_config in tool_poetry["group"].items(): + group = DependencyGroup( + group_name, optional=group_config.get("optional", False) + ) + package.add_dependency_group(group) + + if dependency_groups: + for group_name, dependencies in dependency_groups.items(): + if package.has_dependency_group(group_name): + group = package.dependency_group(group_name) + else: + group = DependencyGroup(group_name) + package.add_dependency_group(group) + + for constraint in dependencies: + dep = Dependency.create_from_pep_508( + constraint, relative_to=package.root_dir + ) + dep.groups = {group_name} + group.add_dependency(dep) + + if "group" in tool_poetry: + for group_name, group_config in tool_poetry["group"].items(): + if "dependencies" in group_config: + cls._add_package_group_dependencies( + package=package, + group=group_name, + dependencies=group_config["dependencies"], + ) if with_groups and "dev-dependencies" in tool_poetry: cls._add_package_group_dependencies( diff --git a/src/poetry/core/json/schemas/poetry-schema.json b/src/poetry/core/json/schemas/poetry-schema.json index a746328a1..b61f55845 100644 --- a/src/poetry/core/json/schemas/poetry-schema.json +++ b/src/poetry/core/json/schemas/poetry-schema.json @@ -171,9 +171,6 @@ "^[a-zA-Z-_.0-9]+$": { "type": "object", "description": "This represents a single dependency group", - "required": [ - "dependencies" - ], "properties": { "optional": { "type": "boolean", diff --git a/src/poetry/core/packages/dependency.py b/src/poetry/core/packages/dependency.py index c07c969db..289acc814 100644 --- a/src/poetry/core/packages/dependency.py +++ b/src/poetry/core/packages/dependency.py @@ -73,7 +73,7 @@ def __init__( if not groups: groups = [MAIN_GROUP] - self._groups = frozenset(groups) + self.groups = set(groups) self._allows_prereleases = allows_prereleases # "_develop" is only required for enriching [project] dependencies self._develop = False @@ -115,10 +115,6 @@ def pretty_constraint(self) -> str: def pretty_name(self) -> str: return self._pretty_name - @property - def groups(self) -> frozenset[str]: - return self._groups - @property def python_versions(self) -> str: return self._python_versions diff --git a/tests/fixtures/sample_project_with_groups_new/README.rst b/tests/fixtures/sample_project_with_groups_new/README.rst new file mode 100644 index 000000000..f7fe15470 --- /dev/null +++ b/tests/fixtures/sample_project_with_groups_new/README.rst @@ -0,0 +1,2 @@ +My Package +========== diff --git a/tests/fixtures/sample_project_with_groups_new/pyproject.toml b/tests/fixtures/sample_project_with_groups_new/pyproject.toml new file mode 100644 index 000000000..355491ea1 --- /dev/null +++ b/tests/fixtures/sample_project_with_groups_new/pyproject.toml @@ -0,0 +1,69 @@ +[project] +name = "my-package" +version = "1.2.3" +description = "Some description." +readme = "README.rst" +requires-python = ">=3.6" +license = { text = "MIT" } +keywords = ["packaging", "dependency", "poetry"] +authors = [ + { name = "Sébastien Eustace", email = "sebastien@eustace.io" } +] +maintainers = [ + { name = "Sébastien Eustace", email = "sebastien@eustace.io" } +] + +classifiers = [ + "Topic :: Software Development :: Build Tools", + "Topic :: Software Development :: Libraries :: Python Modules" +] + +# Requirements +dependencies = [ + "cleo ~=0.6", + "pendulum @ git+https://github.com/sdispater/pendulum.git@2.0", + "tomlkit @ git+https://github.com/sdispater/tomlkit.git@3bff550", + "pathlib2 ~=2.2 ; python_version == '2.7'", + # File dependency + "demo @ ../distributions/demo-0.1.0-py2.py3-none-any.whl", + # Dir dependency with setup.py + "my-package @ ../project_with_setup/", + # Dir dependency with pyproject.toml + "simple-project @ ../simple_project/", + # Dependency with markers + "functools32 ~=3.2.3 ; python_version ~= '2.7' and sys_platform == 'win32' or python_version in '3.4 3.5'", + # Dependency with python constraint + "dataclasses ~=0.7 ; python_full_version >= '3.6.1' and python_version < '3.7'" +] + +[project.optional-dependencies] +db = [ + "orator ~=0.9" +] +network = [ + "requests[security] ~=2.18" +] + +[project.urls] +homepage = "https://python-poetry.org" +repository = "https://github.com/python-poetry/poetry" +documentation = "https://python-poetry.org/docs" + +[project.scripts] +my-script = "my_package:main" + +[project.entry-points."blogtool.parsers"] +".rst" = "some_module::SomeClass" + +[tool.poetry.dependencies] +tomlkit = { develop = true } + +[dependency-groups] +test = ["pytest>7", "coverage"] +docs = ["mkdocs @ git+https://github.com/mkdocs/mkdocs.git"] + +[tool.poetry.group.docs] +optional = true + +[tool.poetry.group.docs.dependencies] +mkdocs = { develop = true } diff --git a/tests/test_factory.py b/tests/test_factory.py index 0272e3964..6337e017d 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -303,6 +303,31 @@ def test_create_poetry(project: str) -> None: ] +def test_create_poetry_with_groups() -> None: + poetry = Factory().create_poetry(fixtures_dir / "sample_project_with_groups_new") + + assert "docs" in poetry.package._dependency_groups + assert "test" in poetry.package._dependency_groups + assert poetry.package._dependency_groups["docs"].is_optional() + assert not poetry.package._dependency_groups["test"].is_optional() + + package = poetry.package + dependencies = {str(dep.name): dep for dep in package.all_requires} + + assert dependencies["mkdocs"].name == "mkdocs" + assert isinstance(dependencies["mkdocs"], VCSDependency) + assert dependencies["mkdocs"].develop is True + assert dependencies["mkdocs"].source_type == "git" + assert dependencies["mkdocs"].source == "https://github.com/mkdocs/mkdocs.git" + assert dependencies["mkdocs"].groups == frozenset({"docs"}) + + assert dependencies["pytest"].name == "pytest" + assert dependencies["pytest"].groups == frozenset({"test"}) + + assert dependencies["coverage"].name == "coverage" + assert dependencies["coverage"].groups == frozenset({"test"}) + + def test_create_poetry_with_dependencies_with_subdirectory() -> None: poetry = Factory().create_poetry( fixtures_dir / "project_with_dependencies_with_subdirectory"