Skip to content

Commit

Permalink
wip: poc pep 735
Browse files Browse the repository at this point in the history
  • Loading branch information
finswimmer committed Jan 23, 2025
1 parent d97577e commit 6473ff4
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 20 deletions.
50 changes: 39 additions & 11 deletions src/poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -332,16 +338,38 @@ 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,
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(
Expand Down
3 changes: 0 additions & 3 deletions src/poetry/core/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,6 @@
"^[a-zA-Z-_.0-9]+$": {
"type": "object",
"description": "This represents a single dependency group",
"required": [
"dependencies"
],
"properties": {
"optional": {
"type": "boolean",
Expand Down
24 changes: 18 additions & 6 deletions src/poetry/core/packages/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,10 @@ def with_constraint(self: T, constraint: str | VersionConstraint) -> T:

@classmethod
def create_from_pep_508(
cls, name: str, relative_to: Path | None = None
cls,
name: str,
relative_to: Path | None = None,
groups: Iterable[str] | None = None,
) -> Dependency:
"""
Resolve a PEP-508 requirement string to a `Dependency` instance. If a
Expand Down Expand Up @@ -413,17 +416,23 @@ def create_from_pep_508(
rev=url.rev,
directory=url.subdirectory,
extras=req.extras,
groups=groups,
)
elif link.scheme == "git":
dep = VCSDependency(
name, "git", link.url_without_fragment, extras=req.extras
name,
"git",
link.url_without_fragment,
extras=req.extras,
groups=groups,
)
elif link.scheme in ("http", "https"):
dep = URLDependency(
name,
link.url_without_fragment,
directory=link.subdirectory_fragment,
extras=req.extras,
groups=groups,
)
elif is_file_uri:
# handle RFC 8089 references
Expand All @@ -434,6 +443,7 @@ def create_from_pep_508(
base=relative_to,
subdirectory=link.subdirectory_fragment,
extras=req.extras,
groups=groups,
)
else:
with suppress(ValueError):
Expand All @@ -443,17 +453,18 @@ def create_from_pep_508(
path=Path(req.url),
base=relative_to,
extras=req.extras,
groups=groups,
)

if dep is None:
dep = Dependency(name, version or "*", extras=req.extras)
dep = Dependency(name, version or "*", extras=req.extras, groups=groups)

if version:
dep._constraint = parse_constraint(version)
else:
constraint: VersionConstraint | str
constraint = req.constraint if req.pretty_constraint else "*"
dep = Dependency(name, constraint, extras=req.extras)
dep = Dependency(name, constraint, extras=req.extras, groups=groups)

if req.marker:
dep.marker = req.marker
Expand Down Expand Up @@ -496,6 +507,7 @@ def _make_file_or_dir_dep(
base: Path | None = None,
subdirectory: str | None = None,
extras: list[str] | None = None,
groups: Iterable[str] | None = None,
) -> FileDependency | DirectoryDependency | None:
"""
Helper function to create a file or directoru dependency with the given arguments.
Expand All @@ -520,10 +532,10 @@ def _make_file_or_dir_dep(

if is_file:
return FileDependency(
name, path, base=base, directory=subdirectory, extras=extras
name, path, base=base, directory=subdirectory, extras=extras, groups=groups
)

if subdirectory:
path = path / subdirectory

return DirectoryDependency(name, path, base=base, extras=extras)
return DirectoryDependency(name, path, base=base, extras=extras, groups=groups)
2 changes: 2 additions & 0 deletions tests/fixtures/sample_project_with_groups_new/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
My Package
==========
69 changes: 69 additions & 0 deletions tests/fixtures/sample_project_with_groups_new/pyproject.toml
Original file line number Diff line number Diff line change
@@ -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 = "[email protected]" }
]
maintainers = [
{ name = "Sébastien Eustace", email = "[email protected]" }
]

classifiers = [
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules"
]

# Requirements
dependencies = [
"cleo ~=0.6",
"pendulum @ git+https://github.com/sdispater/[email protected]",
"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 }
25 changes: 25 additions & 0 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 6473ff4

Please sign in to comment.