Skip to content

Commit

Permalink
poetry: expose build-system dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
abn committed Jan 17, 2025
1 parent 074dbf2 commit 528e796
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 6 deletions.
48 changes: 46 additions & 2 deletions src/poetry/core/poetry.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
from __future__ import annotations

import logging

from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any

from packaging.utils import canonicalize_name

from poetry.core.packages.dependency import Dependency
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.pyproject.toml import PyProjectTOML


if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)


if TYPE_CHECKING:
from poetry.core.packages.project_package import ProjectPackage


Expand All @@ -23,6 +32,7 @@ def __init__(
self._pyproject = pyproject_type(file)
self._package = package
self._local_config = local_config
self._build_system_dependencies: list[Dependency] | None = None

@property
def pyproject(self) -> PyProjectTOML:
Expand All @@ -48,3 +58,37 @@ def local_config(self) -> dict[str, Any]:

def get_project_config(self, config: str, default: Any = None) -> Any:
return self._local_config.get("config", {}).get(config, default)

@property
def build_system_dependencies(self) -> list[Dependency]:
if self._build_system_dependencies is None:
build_system = self.pyproject.build_system
self._build_system_dependencies = []

for requirement in build_system.requires:
dependency = None
try:
dependency = Dependency.create_from_pep_508(requirement)
except ValueError:
# PEP 517 requires can be path if not PEP 508
path = Path(requirement)

if path.is_file():
dependency = FileDependency(
name=canonicalize_name(path.name), path=path
)
elif path.is_dir():
dependency = DirectoryDependency(
name=canonicalize_name(path.name), path=path
)

# skip since we could not determine requirement
if dependency:
self._build_system_dependencies.append(dependency)
else:
logger.debug(
"Skipping build system dependency - could not determine requirement type: %s",
requirement,
)

return self._build_system_dependencies
84 changes: 80 additions & 4 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@

from poetry.core.constraints.version import parse_constraint
from poetry.core.factory import Factory
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.packages.url_dependency import URLDependency
from poetry.core.packages.vcs_dependency import VCSDependency
from poetry.core.pyproject.tables import BuildSystem
from poetry.core.utils._compat import tomllib
from poetry.core.version.markers import SingleMarker


if TYPE_CHECKING:
from pytest import LogCaptureFixture

from poetry.core.packages.dependency import Dependency
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.packages.file_dependency import FileDependency


fixtures_dir = Path(__file__).parent / "fixtures"

Expand Down Expand Up @@ -976,3 +976,79 @@ def test_all_classifiers_unique_even_if_classifiers_is_duplicated() -> None:
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Build Tools",
]


@pytest.mark.parametrize(
("project", "expected"),
[
("sample_project", set(BuildSystem().dependencies)),
(
"project_with_build_system_requires",
{
Dependency.create_from_pep_508("poetry-core"),
Dependency.create_from_pep_508("Cython (>=0.29.6,<0.30.0)"),
},
),
],
)
def test_poetry_build_system_dependencies_from_fixtures(
project: str, expected: set[Dependency]
) -> None:
poetry = Factory().create_poetry(fixtures_dir / project)
assert set(poetry.build_system_dependencies) == expected


SAMPLE_PROJECT_DIRECTORY = fixtures_dir / "sample_project"
SIMPLE_PROJECT_WHEEL = (
fixtures_dir
/ "simple_project"
/ "dist"
/ "simple_project-1.2.3-py2.py3-none-any.whl"
)


@pytest.mark.parametrize(
("requires", "expected"),
[
(BuildSystem().requires, set(BuildSystem().dependencies)),
(["poetry-core>=2.0.0"], {Dependency("poetry-core", ">=2.0.0")}),
(["****invalid****"], set()),
(
["hatch", "numpy ; sys_platform == 'win32'"],
{
Dependency("hatch", "*"),
Dependency.create_from_pep_508("numpy ; sys_platform == 'win32'"),
},
),
(
[SAMPLE_PROJECT_DIRECTORY.as_posix()],
{
DirectoryDependency(
SAMPLE_PROJECT_DIRECTORY.name, SAMPLE_PROJECT_DIRECTORY
)
},
),
(
[SIMPLE_PROJECT_WHEEL.as_posix()],
{FileDependency(SIMPLE_PROJECT_WHEEL.name, SIMPLE_PROJECT_WHEEL)},
),
],
)
def test_poetry_build_system_dependencies(
requires: list[str], expected: set[Dependency], temporary_directory: Path
) -> None:
pyproject_toml = temporary_directory / "pyproject.toml"
build_system_requires = ", ".join(f'"{require}"' for require in requires)
content = f"""[project]
name = "my-package"
version = "1.2.3"
[build-system]
requires = [{build_system_requires}]
build-backend = "some.api.we.do.not.care.about"
"""
pyproject_toml.write_text(content)
poetry = Factory().create_poetry(temporary_directory)

assert set(poetry.build_system_dependencies) == expected

0 comments on commit 528e796

Please sign in to comment.