Commit c89e994e by David Hotham Committed by GitHub

update poetry to work with poetry-core after tomlkit is removed from there (#6616)

Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com>
parent c8e963e6
......@@ -11,12 +11,12 @@ from typing import TYPE_CHECKING
from typing import Any
from packaging.utils import canonicalize_name
from poetry.core.toml import TOMLFile
from poetry.config.dict_config_source import DictConfigSource
from poetry.config.file_config_source import FileConfigSource
from poetry.locations import CONFIG_DIR
from poetry.locations import DEFAULT_CACHE_DIR
from poetry.toml import TOMLFile
if TYPE_CHECKING:
......
......@@ -13,9 +13,10 @@ from poetry.config.config_source import ConfigSource
if TYPE_CHECKING:
from collections.abc import Iterator
from poetry.core.toml.file import TOMLFile
from tomlkit.toml_document import TOMLDocument
from poetry.toml.file import TOMLFile
class FileConfigSource(ConfigSource):
def __init__(self, file: TOMLFile, auth_config: bool = False) -> None:
......
......@@ -58,9 +58,8 @@ class CheckCommand(Command):
return errors, warnings
def handle(self) -> int:
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.factory import Factory
from poetry.pyproject.toml import PyProjectTOML
# Load poetry config and display errors, if any
poetry_file = self.poetry.file.path
......
......@@ -86,11 +86,11 @@ To remove a repository (repo is a short alias for repositories):
from pathlib import Path
from poetry.core.pyproject.exceptions import PyProjectException
from poetry.core.toml.file import TOMLFile
from poetry.config.config import Config
from poetry.config.file_config_source import FileConfigSource
from poetry.locations import CONFIG_DIR
from poetry.toml.file import TOMLFile
config = Config.create()
config_file = TOMLFile(CONFIG_DIR / "config.toml")
......
......@@ -73,11 +73,11 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
def handle(self) -> int:
from pathlib import Path
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.vcs.git import GitConfig
from poetry.config.config import Config
from poetry.layouts import layout
from poetry.pyproject.toml import PyProjectTOML
from poetry.utils.env import EnvManager
project_path = Path.cwd()
......
......@@ -5,11 +5,11 @@ from typing import TYPE_CHECKING
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.__version__ import __version__
from poetry.console.commands.installer_command import InstallerCommand
from poetry.factory import Factory
from poetry.pyproject.toml import PyProjectTOML
from poetry.utils.env import EnvManager
from poetry.utils.env import SystemEnv
from poetry.utils.helpers import directory
......
......@@ -12,7 +12,6 @@ from cleo.io.null_io import NullIO
from poetry.core.factory import Factory as BaseFactory
from poetry.core.packages.dependency_group import MAIN_GROUP
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.toml.file import TOMLFile
from poetry.config.config import Config
from poetry.json import validate_object
......@@ -20,6 +19,7 @@ from poetry.packages.locker import Locker
from poetry.plugins.plugin import Plugin
from poetry.plugins.plugin_manager import PluginManager
from poetry.poetry import Poetry
from poetry.toml.file import TOMLFile
if TYPE_CHECKING:
......@@ -55,15 +55,19 @@ class Factory(BaseFactory):
base_poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)
locker = Locker(
base_poetry.file.parent / "poetry.lock", base_poetry.local_config
# TODO: backward compatibility, can be simplified if poetry-core with
# https://github.com/python-poetry/poetry-core/pull/483 is available
poetry_file: Path = (
getattr(base_poetry, "pyproject_path", None) or base_poetry.file.path
)
locker = Locker(poetry_file.parent / "poetry.lock", base_poetry.local_config)
# Loading global configuration
config = Config.create()
# Loading local configuration
local_config_file = TOMLFile(base_poetry.file.parent / "poetry.toml")
local_config_file = TOMLFile(poetry_file.parent / "poetry.toml")
if local_config_file.exists():
if io.is_debug():
io.write_line(f"Loading configuration file {local_config_file.path}")
......@@ -82,7 +86,7 @@ class Factory(BaseFactory):
config.merge({"repositories": repositories})
poetry = Poetry(
base_poetry.file.path,
poetry_file,
base_poetry.local_config,
base_poetry.package,
locker,
......
......@@ -17,12 +17,12 @@ import pkginfo
from poetry.core.factory import Factory
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.utils.helpers import parse_requires
from poetry.core.utils.helpers import temporary_directory
from poetry.core.version.markers import InvalidMarker
from poetry.core.version.requirements import InvalidRequirement
from poetry.pyproject.toml import PyProjectTOML
from poetry.utils.env import EnvCommandError
from poetry.utils.env import ephemeral_environment
from poetry.utils.setup_reader import SetupReader
......
......@@ -636,9 +636,8 @@ class Executor:
def _install_directory_without_wheel_installer(
self, operation: Install | Update
) -> int:
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.factory import Factory
from poetry.pyproject.toml import PyProjectTOML
package = operation.package
operation_message = self.get_operation_message(operation)
......
......@@ -11,9 +11,9 @@ from typing import TYPE_CHECKING
from typing import Any
from poetry.core.constraints.version import Version
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.installation.base_installer import BaseInstaller
from poetry.pyproject.toml import PyProjectTOML
from poetry.repositories.http_repository import HTTPRepository
from poetry.utils._compat import encode
from poetry.utils.helpers import remove_directory
......
......@@ -5,13 +5,14 @@ from typing import TYPE_CHECKING
from typing import Any
from packaging.utils import canonicalize_name
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.utils.helpers import module_name
from tomlkit import inline_table
from tomlkit import loads
from tomlkit import table
from tomlkit.toml_document import TOMLDocument
from poetry.pyproject.toml import PyProjectTOML
if TYPE_CHECKING:
from typing import Mapping
......
......@@ -4,7 +4,6 @@ import csv
import hashlib
import json
import os
import shutil
from base64 import urlsafe_b64encode
from pathlib import Path
......@@ -44,6 +43,7 @@ WINDOWS_CMD_TEMPLATE = """\
class EditableBuilder(Builder):
def __init__(self, poetry: Poetry, env: Env, io: IO) -> None:
self._poetry: Poetry
super().__init__(poetry)
self._env = env
......@@ -105,19 +105,15 @@ class EditableBuilder(Builder):
pip_install(self._path, self._env, upgrade=True, editable=True)
else:
# Temporarily rename pyproject.toml
shutil.move(
str(self._poetry.file), str(self._poetry.file.with_suffix(".tmp"))
)
renamed_pyproject = self._poetry.file.with_suffix(".tmp")
self._poetry.file.path.rename(renamed_pyproject)
try:
pip_install(self._path, self._env, upgrade=True, editable=True)
finally:
shutil.move(
str(self._poetry.file.with_suffix(".tmp")),
str(self._poetry.file),
)
renamed_pyproject.rename(self._poetry.file.path)
finally:
if not has_setup:
os.remove(str(setup))
os.remove(setup)
def _add_pth(self) -> list[Path]:
paths = {
......
......@@ -16,7 +16,6 @@ from poetry.core.constraints.version import Version
from poetry.core.constraints.version import parse_constraint
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.toml.file import TOMLFile
from poetry.core.version.markers import parse_marker
from poetry.core.version.requirements import InvalidRequirement
from tomlkit import array
......@@ -26,6 +25,7 @@ from tomlkit import inline_table
from tomlkit import table
from poetry.__version__ import __version__
from poetry.toml.file import TOMLFile
from poetry.utils._compat import tomllib
......
......@@ -2,11 +2,13 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Any
from typing import cast
from poetry.core.poetry import Poetry as BasePoetry
from poetry.__version__ import __version__
from poetry.config.source import Source
from poetry.pyproject.toml import PyProjectTOML
if TYPE_CHECKING:
......@@ -18,6 +20,7 @@ if TYPE_CHECKING:
from poetry.packages.locker import Locker
from poetry.plugins.plugin_manager import PluginManager
from poetry.repositories.repository_pool import RepositoryPool
from poetry.toml import TOMLFile
class Poetry(BasePoetry):
......@@ -34,7 +37,15 @@ class Poetry(BasePoetry):
) -> None:
from poetry.repositories.repository_pool import RepositoryPool
try:
super().__init__( # type: ignore[call-arg]
file, local_config, package, pyproject_type=PyProjectTOML
)
except TypeError:
# TODO: backward compatibility, can be simplified if poetry-core with
# https://github.com/python-poetry/poetry-core/pull/483 is available
super().__init__(file, local_config, package)
self._pyproject = PyProjectTOML(file)
self._locker = locker
self._config = config
......@@ -43,6 +54,15 @@ class Poetry(BasePoetry):
self._disable_cache = disable_cache
@property
def pyproject(self) -> PyProjectTOML:
pyproject = super().pyproject
return cast("PyProjectTOML", pyproject)
@property
def file(self) -> TOMLFile: # type: ignore[override]
return self.pyproject.file
@property
def locker(self) -> Locker:
return self._locker
......
from __future__ import annotations
from typing import TYPE_CHECKING
from poetry.core.pyproject.toml import PyProjectTOML as BasePyProjectTOML
from tomlkit.api import table
from tomlkit.items import Table
from tomlkit.toml_document import TOMLDocument
from poetry.toml import TOMLFile
if TYPE_CHECKING:
from pathlib import Path
class PyProjectTOML(BasePyProjectTOML):
"""
Enhanced version of poetry-core's PyProjectTOML
which is capable of writing pyproject.toml
The poetry-core class uses tomli to read the file,
here we use tomlkit to preserve comments and formatting when writing.
"""
def __init__(self, path: Path) -> None:
super().__init__(path)
self._toml_file = TOMLFile(path=path)
self._toml_document: TOMLDocument | None = None
@property
def file(self) -> TOMLFile: # type: ignore[override]
return self._toml_file
@property
def data(self) -> TOMLDocument:
if self._toml_document is None:
if not self.file.exists():
self._toml_document = TOMLDocument()
else:
self._toml_document = self.file.read()
return self._toml_document
def save(self) -> None:
data = self.data
if self._build_system is not None:
if "build-system" not in data:
data["build-system"] = table()
build_system = data["build-system"]
assert isinstance(build_system, Table)
build_system["requires"] = self._build_system.requires
build_system["build-backend"] = self._build_system.build_backend
self.file.write(data=data)
def reload(self) -> None:
self._toml_document = None
self._build_system = None
from __future__ import annotations
from poetry.toml.exceptions import TOMLError
from poetry.toml.file import TOMLFile
__all__ = ["TOMLError", "TOMLFile"]
from __future__ import annotations
from poetry.core.exceptions import PoetryCoreException
from tomlkit.exceptions import TOMLKitError
class TOMLError(TOMLKitError, PoetryCoreException):
pass
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Any
from tomlkit.toml_file import TOMLFile as BaseTOMLFile
if TYPE_CHECKING:
from pathlib import Path
from tomlkit.toml_document import TOMLDocument
class TOMLFile(BaseTOMLFile):
def __init__(self, path: Path) -> None:
super().__init__(path)
self.__path = path
@property
def path(self) -> Path:
return self.__path
def exists(self) -> bool:
return self.__path.exists()
def read(self) -> TOMLDocument:
from tomlkit.exceptions import TOMLKitError
from poetry.toml import TOMLError
try:
return super().read()
except (ValueError, TOMLKitError) as e:
raise TOMLError(f"Invalid TOML file {self.path.as_posix()}: {e}")
def __getattr__(self, item: str) -> Any:
return getattr(self.__path, item)
def __str__(self) -> str:
return self.__path.as_posix()
......@@ -33,10 +33,10 @@ from packaging.tags import interpreter_version
from packaging.tags import sys_tags
from poetry.core.constraints.version import Version
from poetry.core.constraints.version import parse_constraint
from poetry.core.toml.file import TOMLFile
from poetry.core.utils.helpers import temporary_directory
from virtualenv.seed.wheels.embed import get_embed_wheel
from poetry.toml.file import TOMLFile
from poetry.utils._compat import WINDOWS
from poetry.utils._compat import decode
from poetry.utils._compat import encode
......
......@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
import pytest
import tomlkit
from poetry.core.toml.file import TOMLFile
from poetry.toml.file import TOMLFile
if TYPE_CHECKING:
......
......@@ -9,8 +9,8 @@ import pytest
import tomlkit
from poetry.core.constraints.version import Version
from poetry.core.toml.file import TOMLFile
from poetry.toml.file import TOMLFile
from poetry.utils.env import MockEnv
from tests.console.commands.env.helpers import build_venv
from tests.console.commands.env.helpers import check_output_wrapper
......
......@@ -190,7 +190,9 @@ def test_add_existing_plugin_warns_about_no_operation(
repo: TestRepository,
installed: TestRepository,
):
SelfCommand.get_default_system_pyproject_file().write_text(
pyproject = SelfCommand.get_default_system_pyproject_file()
with open(pyproject, "w", encoding="utf-8", newline="") as f:
f.write(
f"""\
[tool.poetry]
name = "poetry-instance"
......@@ -203,8 +205,7 @@ python = "^3.6"
[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies]
poetry-plugin = "^1.2.3"
""",
encoding="utf-8",
"""
)
installed.add_package(Package("poetry-plugin", "1.2.3"))
......@@ -230,7 +231,9 @@ def test_add_existing_plugin_updates_if_requested(
repo: TestRepository,
installed: TestRepository,
):
SelfCommand.get_default_system_pyproject_file().write_text(
pyproject = SelfCommand.get_default_system_pyproject_file()
with open(pyproject, "w", encoding="utf-8", newline="") as f:
f.write(
f"""\
[tool.poetry]
name = "poetry-instance"
......@@ -243,8 +246,7 @@ python = "^3.6"
[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies]
poetry-plugin = "^1.2.3"
""",
encoding="utf-8",
"""
)
installed.add_package(Package("poetry-plugin", "1.2.3"))
......
......@@ -37,7 +37,8 @@ def install_plugin(installed: Repository) -> None:
)
content = Factory.create_pyproject_from_package(package)
system_pyproject_file = SelfCommand.get_default_system_pyproject_file()
system_pyproject_file.write_text(content.as_string(), encoding="utf-8")
with open(system_pyproject_file, "w", encoding="utf-8", newline="") as f:
f.write(content.as_string())
lock_content = {
"package": [
......
......@@ -29,7 +29,7 @@ All set!
def test_check_invalid(mocker: MockerFixture, tester: CommandTester):
from poetry.core.toml import TOMLFile
from poetry.toml import TOMLFile
mocker.patch(
"poetry.poetry.Poetry.file",
......
......@@ -12,7 +12,6 @@ from typing import TYPE_CHECKING
from poetry.core.packages.package import Package
from poetry.core.packages.utils.link import Link
from poetry.core.toml.file import TOMLFile
from poetry.core.vcs.git import ParsedUrl
from poetry.config.config import Config
......@@ -187,8 +186,8 @@ class PoetryTestApplication(Application):
class TestLocker(Locker):
def __init__(self, lock: str | Path, local_config: dict) -> None:
self._lock = TOMLFile(lock)
def __init__(self, lock: Path, local_config: dict) -> None:
self._lock = lock
self._local_config = local_config
self._lock_data = None
self._content_hash = self._get_content_hash()
......
......@@ -18,7 +18,6 @@ from poetry.core.packages.dependency_group import MAIN_GROUP
from poetry.core.packages.dependency_group import DependencyGroup
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.toml.file import TOMLFile
from poetry.factory import Factory
from poetry.installation import Installer as BaseInstaller
......@@ -28,6 +27,7 @@ from poetry.packages import Locker as BaseLocker
from poetry.repositories import Repository
from poetry.repositories import RepositoryPool
from poetry.repositories.installed_repository import InstalledRepository
from poetry.toml.file import TOMLFile
from poetry.utils.env import MockEnv
from poetry.utils.env import NullEnv
from tests.helpers import MOCK_DEFAULT_GIT_REVISION
......@@ -101,8 +101,8 @@ class CustomInstalledRepository(InstalledRepository):
class Locker(BaseLocker):
def __init__(self, lock_path: str | Path) -> None:
self._lock = TOMLFile(Path(lock_path).joinpath("poetry.lock"))
def __init__(self, lock_path: Path) -> None:
self._lock = lock_path / "poetry.lock"
self._written_data = None
self._locked = False
self._content_hash = self._get_content_hash()
......@@ -111,8 +111,8 @@ class Locker(BaseLocker):
def written_data(self) -> dict | None:
return self._written_data
def set_lock_path(self, lock: str | Path) -> Locker:
self._lock = TOMLFile(Path(lock).joinpath("poetry.lock"))
def set_lock_path(self, lock: Path) -> Locker:
self._lock = lock / "poetry.lock"
return self
......
......@@ -10,7 +10,6 @@ import pytest
from cleo.io.null_io import NullIO
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.toml.file import TOMLFile
from poetry.factory import Factory
from poetry.installation import Installer as BaseInstaller
......@@ -19,6 +18,7 @@ from poetry.packages import Locker as BaseLocker
from poetry.repositories import Repository
from poetry.repositories import RepositoryPool
from poetry.repositories.installed_repository import InstalledRepository
from poetry.toml.file import TOMLFile
from poetry.utils.env import MockEnv
from poetry.utils.env import NullEnv
from tests.helpers import get_dependency
......@@ -58,8 +58,8 @@ class CustomInstalledRepository(InstalledRepository):
class Locker(BaseLocker):
def __init__(self, lock_path: str | Path) -> None:
self._lock = TOMLFile(Path(lock_path).joinpath("poetry.lock"))
def __init__(self, lock_path: Path) -> None:
self._lock = lock_path / "poetry.lock"
self._written_data = None
self._locked = False
self._content_hash = self._get_content_hash()
......@@ -68,8 +68,8 @@ class Locker(BaseLocker):
def written_data(self) -> dict | None:
return self._written_data
def set_lock_path(self, lock: str | Path) -> Locker:
self._lock = TOMLFile(Path(lock).joinpath("poetry.lock"))
def set_lock_path(self, lock: Path) -> Locker:
self._lock = lock / "poetry.lock"
return self
......
......@@ -14,9 +14,9 @@ from dulwich.client import HTTPUnauthorized
from dulwich.client import get_transport_and_path
from dulwich.config import ConfigFile
from dulwich.repo import Repo
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.console.exceptions import PoetryConsoleError
from poetry.pyproject.toml import PyProjectTOML
from poetry.utils.authenticator import Authenticator
from poetry.vcs.git import Git
from poetry.vcs.git.backend import GitRefSpec
......
......@@ -2,9 +2,8 @@ from __future__ import annotations
from pathlib import Path
from poetry.core.toml import TOMLFile
from poetry.factory import Factory
from poetry.toml import TOMLFile
FIXTURE_DIR = Path(__file__).parent / "fixtures" / "source"
......
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture
def pyproject_toml(tmp_path: Path) -> Path:
path = tmp_path / "pyproject.toml"
with path.open(mode="w"):
pass
return path
@pytest.fixture
def build_system_section(pyproject_toml: Path) -> str:
content = """
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
"""
with pyproject_toml.open(mode="a") as f:
f.write(content)
return content
@pytest.fixture
def poetry_section(pyproject_toml: Path) -> str:
content = """
[tool.poetry]
name = "poetry"
[tool.poetry.dependencies]
python = "^3.5"
"""
with pyproject_toml.open(mode="a") as f:
f.write(content)
return content
from __future__ import annotations
import uuid
from typing import TYPE_CHECKING
from poetry.pyproject.toml import PyProjectTOML
if TYPE_CHECKING:
from pathlib import Path
def test_pyproject_toml_reload(pyproject_toml: Path, poetry_section: str) -> None:
pyproject = PyProjectTOML(pyproject_toml)
name_original = pyproject.poetry_config["name"]
name_new = str(uuid.uuid4())
pyproject.poetry_config["name"] = name_new
assert isinstance(pyproject.poetry_config["name"], str)
assert pyproject.poetry_config["name"] == name_new
pyproject.reload()
assert pyproject.poetry_config["name"] == name_original
def test_pyproject_toml_save(
pyproject_toml: Path, poetry_section: str, build_system_section: str
) -> None:
pyproject = PyProjectTOML(pyproject_toml)
name = str(uuid.uuid4())
build_backend = str(uuid.uuid4())
build_requires = str(uuid.uuid4())
pyproject.poetry_config["name"] = name
pyproject.build_system.build_backend = build_backend
pyproject.build_system.requires.append(build_requires)
pyproject.save()
pyproject = PyProjectTOML(pyproject_toml)
assert isinstance(pyproject.poetry_config["name"], str)
assert pyproject.poetry_config["name"] == name
assert pyproject.build_system.build_backend == build_backend
assert build_requires in pyproject.build_system.requires
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.core.exceptions import PoetryCoreException
from poetry.toml import TOMLFile
if TYPE_CHECKING:
from pathlib import Path
def test_pyproject_toml_file_invalid(pyproject_toml: Path) -> None:
with pyproject_toml.open(mode="a") as f:
f.write("<<<<<<<<<<<")
with pytest.raises(PoetryCoreException) as excval:
_ = TOMLFile(pyproject_toml).read()
assert f"Invalid TOML file {pyproject_toml.as_posix()}" in str(excval.value)
def test_pyproject_toml_file_getattr(tmp_path: Path, pyproject_toml: Path) -> None:
file = TOMLFile(pyproject_toml)
assert file.parent == tmp_path
......@@ -8,12 +8,12 @@ import pytest
from deepdiff import DeepDiff
from packaging.utils import canonicalize_name
from poetry.core.constraints.version import parse_constraint
from poetry.core.toml.file import TOMLFile
from poetry.factory import Factory
from poetry.plugins.plugin import Plugin
from poetry.repositories.legacy_repository import LegacyRepository
from poetry.repositories.pypi_repository import PyPiRepository
from poetry.toml.file import TOMLFile
from tests.helpers import mock_metadata_entry_points
......
......@@ -13,10 +13,10 @@ import pytest
import tomlkit
from poetry.core.constraints.version import Version
from poetry.core.toml.file import TOMLFile
from poetry.factory import Factory
from poetry.repositories.installed_repository import InstalledRepository
from poetry.toml.file import TOMLFile
from poetry.utils._compat import WINDOWS
from poetry.utils.env import GET_BASE_PREFIX
from poetry.utils.env import GET_PYTHON_VERSION_ONELINER
......
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