Skip to content

Commit

Permalink
add support for PEP 621: we must not enrich static classifiers (pytho…
Browse files Browse the repository at this point in the history
…n-poetry#708)

- if classifiers are declared in the [project] section they are static
- if classifiers are declared as dynamic in the [project] section, they can be declared in the [tool.poetry] section and enriched by license and requires-python information
  • Loading branch information
radoering committed May 19, 2024
1 parent b9be4b0 commit d11ba27
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 16 deletions.
7 changes: 4 additions & 3 deletions src/poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,10 @@ def _configure_package_metadata(

package.requires_python = project.get("requires-python", "*")
package.keywords = project.get("keywords") or tool_poetry.get("keywords", [])
package.classifiers = project.get("classifiers") or tool_poetry.get(
"classifiers", []
)
package.classifiers = (
static_classifiers := project.get("classifiers")
) or tool_poetry.get("classifiers", [])
package.dynamic_classifiers = not static_classifiers

if urls := project.get("urls"):
package.homepage = urls.get("homepage") or urls.get("Homepage")
Expand Down
8 changes: 8 additions & 0 deletions src/poetry/core/packages/project_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def __init__(
self.exclude: Sequence[Mapping[str, Any]] = []
self.custom_urls: Mapping[str, str] = {}
self._requires_python: str = "*"
self.dynamic_classifiers = True

if self._python_versions == "*":
self._python_constraint = parse_constraint("~2.7 || >=3.4")
Expand Down Expand Up @@ -111,6 +112,13 @@ def version(self) -> Version:
def version(self, value: str | Version) -> None:
self._set_version(value)

@property
def all_classifiers(self) -> list[str]:
if self.dynamic_classifiers:
return super().all_classifiers

return list(self.classifiers)

@property
def urls(self) -> dict[str, str]:
urls = super().urls
Expand Down
86 changes: 73 additions & 13 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,22 @@ def test_create_poetry(new_format: str) -> None:
"Topic :: Software Development :: Libraries :: Python Modules",
]

assert package.all_classifiers == [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
]
if new_format:
assert package.all_classifiers == package.classifiers
else:
assert package.all_classifiers == [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
]


def test_create_poetry_with_dependencies_with_subdirectory() -> None:
Expand Down Expand Up @@ -429,6 +432,63 @@ def test_create_poetry_python_version_not_compatible(tmp_path: Path) -> None:
assert "not a subset" in str(e.value)


@pytest.mark.parametrize(
("content", "expected"),
[
( # static
"""\
[project]
name = "foo"
version = "1"
requires-python = "3.10"
classifiers = ["License :: OSI Approved :: MIT License"]
""",
["License :: OSI Approved :: MIT License"],
),
( # dynamic
"""\
[project]
name = "foo"
version = "1"
requires-python = "3.10"
dynamic = [ "classifiers" ]
[tool.poetry]
classifiers = ["License :: OSI Approved :: MIT License"]
""",
[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
],
),
( # legacy
"""\
[tool.poetry]
name = "foo"
version = "1"
classifiers = ["License :: OSI Approved :: MIT License"]
[tool.poetry.dependencies]
python = "~3.10"
""",
[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
],
),
],
)
def test_create_poetry_classifiers(
content: str, expected: list[str], tmp_path: Path
) -> None:
(tmp_path / "pyproject.toml").write_text(content)
poetry = Factory().create_poetry(tmp_path)

assert poetry.package.all_classifiers == expected


def test_validate() -> None:
complete = fixtures_dir / "complete.toml"
with complete.open("rb") as f:
Expand Down

0 comments on commit d11ba27

Please sign in to comment.