Skip to content

Commit

Permalink
Simplify content format and pyproject code
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed Jul 10, 2023
1 parent 8ff0ac8 commit dd00e6c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 44 deletions.
58 changes: 50 additions & 8 deletions src/poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

from packaging.utils import canonicalize_name

from poetry.core.pyproject.formats.content_format import ContentFormat
from poetry.core.utils.helpers import readme_content_type


Expand All @@ -22,6 +21,8 @@
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.poetry import Poetry
from poetry.core.pyproject.formats.content_format import ContentFormat
from poetry.core.pyproject.toml import PyProjectTOML

DependencyConstraint = Union[str, Dict[str, Any]]
DependencyConfig = Mapping[
Expand All @@ -37,23 +38,38 @@ class Factory:
Factory class to create various elements needed by Poetry.
"""

def __init__(self) -> None:
from poetry.core.pyproject.formats.legacy_content_format import (
LegacyContentFormat,
)
from poetry.core.pyproject.formats.standard_content_format import (
StandardContentFormat,
)

self._default_format: type[ContentFormat] = LegacyContentFormat
self._content_formats: dict[str, type[ContentFormat]] = {
"legacy": LegacyContentFormat,
"standard": StandardContentFormat,
}

def register_content_format(
self, name: str, content_format: type[ContentFormat]
) -> None:
self._content_formats[name] = content_format

def create_poetry(
self, cwd: Path | None = None, with_groups: bool = True
) -> Poetry:
from poetry.core.poetry import Poetry
from poetry.core.pyproject.toml import PyProjectTOML

poetry_file = self.locate(cwd)
pyproject = PyProjectTOML(path=poetry_file)
pyproject = self.create_pyproject(poetry_file)

if not pyproject.is_poetry_project():
raise RuntimeError(f"The project at {poetry_file} is not a Poetry project")

content_format = pyproject.content_format
assert isinstance(content_format, ContentFormat)

# Checking validity
check_result = content_format.validate(strict=False)
check_result = pyproject.content.validate(strict=False)
if check_result.errors:
message = ""
for error in check_result.errors:
Expand All @@ -62,7 +78,7 @@ def create_poetry(
raise RuntimeError("The Poetry configuration is invalid:\n" + message)

# Load package
package = content_format.to_package(
package = pyproject.content.to_package(
root=poetry_file.parent, with_groups=with_groups
)

Expand All @@ -74,6 +90,32 @@ def get_package(cls, name: str, version: str) -> ProjectPackage:

return ProjectPackage(name, version)

def create_pyproject(self, path: Path) -> PyProjectTOML:
from poetry.core.pyproject.toml import PyProjectTOML

content_format = self.guess_content_format(path)

pyproject = PyProjectTOML(path, content_format)

return pyproject

def guess_content_format(self, path: Path) -> type[ContentFormat]:
if not path.exists():
return self._default_format

from poetry.core.utils._compat import tomllib

data = tomllib.loads(path.read_text(encoding="utf-8"))

for name, fmt in self._content_formats.items():
if fmt.supports(data):
logger.debug("Using the %s format", name)
return fmt

raise RuntimeError(
"Unable to determine the content format of the pyproject.toml file"
)

@classmethod
def create_dependency(
cls,
Expand Down
6 changes: 5 additions & 1 deletion src/poetry/core/pyproject/formats/content_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def hash_content(self) -> dict[str, Any]:
@abstractmethod
def poetry_config(self) -> dict[str, Any]:
"""
The custom poetry configuration (i.e. the parts in [tool.poetry] that are not related to the package)
The custom poetry configuration (i.e. the parts in [tool.poetry]
that are not related to the package)
"""
...

def is_empty(self) -> bool:
return not self._content
53 changes: 22 additions & 31 deletions src/poetry/core/pyproject/toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,31 @@
from typing import TYPE_CHECKING
from typing import Any

from poetry.core.pyproject.formats.content_format import ContentFormat
from poetry.core.pyproject.formats.legacy_content_format import LegacyContentFormat
from poetry.core.pyproject.formats.standard_content_format import StandardContentFormat
from poetry.core.pyproject.tables import BuildSystem
from poetry.core.utils._compat import tomllib


if TYPE_CHECKING:
from pathlib import Path

from poetry.core.pyproject.formats.content_format import ContentFormat


class PyProjectTOML:
SUPPORTED_FORMATS: list[type[ContentFormat]] = [
LegacyContentFormat,
StandardContentFormat,
]
def __init__(
self, path: Path, content_format: type[ContentFormat] | None = None
) -> None:
if content_format is None:
from poetry.core.pyproject.formats.legacy_content_format import (
LegacyContentFormat,
)

content_format = LegacyContentFormat

def __init__(self, path: Path) -> None:
self._path = path
self._content_format: type[ContentFormat] = content_format
self._data: dict[str, Any] | None = None
self._content_format: ContentFormat | None = None
self._content: ContentFormat | None = None
self._build_system: BuildSystem | None = None

@property
Expand All @@ -39,16 +43,16 @@ def data(self) -> dict[str, Any]:
with self.path.open("rb") as f:
self._data = tomllib.load(f)

self._content_format = self.guess_format(self._data)

return self._data

@property
def content_format(self) -> ContentFormat | None:
if self.data:
return self._content_format
def content(self) -> ContentFormat | None:
if self._content is not None:
return self._content

self._content = self._content_format(self.data)

return None
return self._content

def is_build_system_defined(self) -> bool:
return "build-system" in self.data
Expand All @@ -59,7 +63,7 @@ def build_system(self) -> BuildSystem:
build_backend = None
requires = None

if not self.path.exists():
if not self._path.exists():
build_backend = "poetry.core.masonry.api"
requires = ["poetry-core"]

Expand All @@ -78,20 +82,7 @@ def poetry_config(self) -> dict[str, Any]:

raise PyProjectException(f"{self._path} is not a Poetry pyproject file")

assert isinstance(self._content_format, ContentFormat)

return self._content_format.poetry_config
return self.content.poetry_config

def is_poetry_project(self) -> bool:
if not self.data:
return False

return self._content_format is not None

@classmethod
def guess_format(cls, data: dict[str, Any]) -> ContentFormat | None:
for fmt in cls.SUPPORTED_FORMATS:
if fmt.supports(data):
return fmt(data)

return None
return not self.content.is_empty()
5 changes: 1 addition & 4 deletions tests/test_core_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
from pathlib import Path

from poetry.core import __version__
from poetry.core.pyproject.formats.content_format import ContentFormat
from poetry.core.pyproject.toml import PyProjectTOML


def test_version_is_synced() -> None:
pyproject = PyProjectTOML(Path(__file__).parent.parent.joinpath("pyproject.toml"))
content_format = pyproject.content_format
assert isinstance(content_format, ContentFormat)
assert __version__ == content_format.to_package(pyproject.path).version.text
assert __version__ == pyproject.content.to_package(pyproject.path).version.text

0 comments on commit dd00e6c

Please sign in to comment.