Commit 402ca3b9 by Arun Babu Neelicattu Committed by Randy Döring

factory: cleanup creation from package

This change ensures that generated toml file from packages contain all
relevant metadata and handles groups correct.
parent f645ab96
...@@ -116,14 +116,16 @@ You can specify a package in the following forms: ...@@ -116,14 +116,16 @@ You can specify a package in the following forms:
break break
root_package.python_versions = ".".join( # type: ignore[union-attr] assert root_package is not None
root_package.python_versions = ".".join(
str(v) for v in system_env.version_info[:3] str(v) for v in system_env.version_info[:3]
) )
# We create a `pyproject.toml` file based on all the information # We create a `pyproject.toml` file based on all the information
# we have about the current environment. # we have about the current environment.
if not env_dir.joinpath("pyproject.toml").exists(): if not env_dir.joinpath("pyproject.toml").exists():
Factory.create_pyproject_from_package( Factory.create_pyproject_from_package(
root_package, # type: ignore[arg-type] root_package,
env_dir, env_dir,
) )
......
from __future__ import annotations from __future__ import annotations
import contextlib
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
...@@ -22,10 +23,17 @@ from poetry.plugins.plugin_manager import PluginManager ...@@ -22,10 +23,17 @@ from poetry.plugins.plugin_manager import PluginManager
from poetry.poetry import Poetry from poetry.poetry import Poetry
try:
from poetry.core.packages.dependency_group import MAIN_GROUP
except ImportError:
MAIN_GROUP = "default"
if TYPE_CHECKING: if TYPE_CHECKING:
from pathlib import Path from pathlib import Path
from cleo.io.io import IO from cleo.io.io import IO
from poetry.core.packages.package import Package
from poetry.repositories.legacy_repository import LegacyRepository from poetry.repositories.legacy_repository import LegacyRepository
...@@ -206,23 +214,73 @@ class Factory(BaseFactory): ...@@ -206,23 +214,73 @@ class Factory(BaseFactory):
) )
@classmethod @classmethod
def create_pyproject_from_package(cls, package: ProjectPackage, path: Path) -> None: def create_pyproject_from_package(
cls, package: Package, path: Path | None = None
) -> TOMLDocument:
import tomlkit import tomlkit
from poetry.layouts.layout import POETRY_DEFAULT pyproject: dict[str, Any] = tomlkit.document()
tool_table = tomlkit.table()
tool_table._is_super_table = True
pyproject["tool"] = tool_table
pyproject: dict[str, Any] = tomlkit.loads(POETRY_DEFAULT) content: dict[str, Any] = tomlkit.table()
content = pyproject["tool"]["poetry"] pyproject["tool"]["poetry"] = content
content["name"] = package.name content["name"] = package.name
content["version"] = package.version.text content["version"] = package.version.text
content["description"] = package.description content["description"] = package.description
content["authors"] = package.authors content["authors"] = package.authors
content["license"] = package.license.id if package.license else ""
if package.classifiers:
content["classifiers"] = package.classifiers
for key, attr in {
("documentation", "documentation_url"),
("repository", "repository_url"),
("homepage", "homepage"),
("maintainers", "maintainers"),
("keywords", "keywords"),
}:
value = getattr(package, attr, None)
if value:
content[key] = value
readmes = []
for readme in package.readmes:
readme_posix_path = readme.as_posix()
with contextlib.suppress(ValueError):
if package.root_dir:
readme_posix_path = readme.relative_to(package.root_dir).as_posix()
readmes.append(readme_posix_path)
if readmes:
content["readme"] = readmes
optional_dependencies = set()
extras_section = None
if package.extras:
extras_section = tomlkit.table()
dependency_section = content["dependencies"] for extra in package.extras:
_dependencies = []
for dependency in package.extras[extra]:
_dependencies.append(dependency.name)
optional_dependencies.add(dependency.name)
extras_section[extra] = _dependencies
optional_dependencies = set(optional_dependencies)
dependency_section = content["dependencies"] = tomlkit.table()
dependency_section["python"] = package.python_versions dependency_section["python"] = package.python_versions
for dep in package.requires: for dep in package.all_requires:
constraint: dict[str, Any] = tomlkit.inline_table() constraint: dict[str, Any] = tomlkit.inline_table()
if dep.is_vcs(): if dep.is_vcs():
dep = cast(VCSDependency, dep) dep = cast(VCSDependency, dep)
...@@ -241,12 +299,39 @@ class Factory(BaseFactory): ...@@ -241,12 +299,39 @@ class Factory(BaseFactory):
if dep.extras: if dep.extras:
constraint["extras"] = sorted(dep.extras) constraint["extras"] = sorted(dep.extras)
if dep.name in optional_dependencies:
constraint["optional"] = True
if len(constraint) == 1 and "version" in constraint: if len(constraint) == 1 and "version" in constraint:
constraint = constraint["version"] constraint = constraint["version"]
dependency_section[dep.name] = constraint for group in dep.groups:
if group == MAIN_GROUP:
dependency_section[dep.name] = constraint
else:
if "group" not in content:
_table = tomlkit.table()
_table._is_super_table = True
content["group"] = _table
assert isinstance(pyproject, TOMLDocument) if group not in content["group"]:
path.joinpath("pyproject.toml").write_text( _table = tomlkit.table()
pyproject.as_string(), encoding="utf-8" _table._is_super_table = True
) content["group"][group] = _table
if "dependencies" not in content["group"][group]:
content["group"][group]["dependencies"] = tomlkit.table()
content["group"][group]["dependencies"][dep.name] = constraint
if extras_section:
content["extras"] = extras_section
pyproject.add(tomlkit.nl()) # type: ignore[attr-defined]
if path:
path.joinpath("pyproject.toml").write_text(
pyproject.as_string(), encoding="utf-8" # type: ignore[attr-defined]
)
return cast(TOMLDocument, pyproject)
...@@ -7,7 +7,7 @@ authors = [ ...@@ -7,7 +7,7 @@ authors = [
] ]
license = "MIT" license = "MIT"
readme = "README.rst" readme = ["README.rst"]
homepage = "https://python-poetry.org" homepage = "https://python-poetry.org"
repository = "https://github.com/python-poetry/poetry" repository = "https://github.com/python-poetry/poetry"
...@@ -31,5 +31,5 @@ fox = "fuz.foo:bar.baz" ...@@ -31,5 +31,5 @@ fox = "fuz.foo:bar.baz"
[build-system] [build-system]
requires = ["poetry-core>=1.0.2"] requires = ["poetry-core>=1.1.0a7"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
...@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING ...@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING
import pytest import pytest
from deepdiff import DeepDiff
from entrypoints import EntryPoint from entrypoints import EntryPoint
from poetry.core.semver.helpers import parse_constraint from poetry.core.semver.helpers import parse_constraint
from poetry.core.toml.file import TOMLFile from poetry.core.toml.file import TOMLFile
...@@ -41,10 +42,12 @@ def test_create_poetry(): ...@@ -41,10 +42,12 @@ def test_create_poetry():
assert package.description == "Some description." assert package.description == "Some description."
assert package.authors == ["Sébastien Eustace <sebastien@eustace.io>"] assert package.authors == ["Sébastien Eustace <sebastien@eustace.io>"]
assert package.license.id == "MIT" assert package.license.id == "MIT"
assert (
package.readme.relative_to(fixtures_dir).as_posix() for readme in package.readmes:
== "sample_project/README.rst" assert (
) readme.relative_to(fixtures_dir).as_posix() == "sample_project/README.rst"
)
assert package.homepage == "https://python-poetry.org" assert package.homepage == "https://python-poetry.org"
assert package.repository_url == "https://github.com/python-poetry/poetry" assert package.repository_url == "https://github.com/python-poetry/poetry"
assert package.keywords == ["packaging", "dependency", "poetry"] assert package.keywords == ["packaging", "dependency", "poetry"]
...@@ -133,6 +136,34 @@ def test_create_poetry(): ...@@ -133,6 +136,34 @@ def test_create_poetry():
] ]
@pytest.mark.parametrize(
("project",),
[
("simple_project",),
("project_with_extras",),
],
)
def test_create_pyproject_from_package(project: str):
poetry = Factory().create_poetry(fixtures_dir / project)
package = poetry.package
pyproject = Factory.create_pyproject_from_package(package)
result = pyproject["tool"]["poetry"]
expected = poetry.pyproject.poetry_config
# packages do not support this at present
expected.pop("scripts", None)
# remove any empty sections
sections = list(expected.keys())
for section in sections:
if not expected[section]:
expected.pop(section)
assert not DeepDiff(expected, result)
def test_create_poetry_with_packages_and_includes(): def test_create_poetry_with_packages_and_includes():
poetry = Factory().create_poetry(fixtures_dir / "with-include") poetry = Factory().create_poetry(fixtures_dir / "with-include")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment