1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
from __future__ import annotations
import shutil
import subprocess
import tarfile
import tempfile
import zipfile
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
import tomli_w
from poetry.core.utils._compat import tomllib
if TYPE_CHECKING:
from collections.abc import Generator
__toml_build_backend_patch__ = {
"build-system": {
"requires": [str(Path(__file__).parent.parent)],
"build-backend": "poetry.core.masonry.api",
}
}
@contextmanager
def temporary_project_directory(
path: Path, toml_patch: dict[str, Any] | None = None
) -> Generator[str, None, None]:
"""
Context manager that takes a project source directory, copies content to a temporary
directory, patches the `pyproject.toml` using the provided patch, or using the
default patch if one is not given. The default path replaces `build-system` section
in order to use the working copy of poetry-core as the backend.
Once the context, exists, the temporary directory is cleaned up.
:param path: Source project root directory to copy from.
:param toml_patch: Patch to use for the pyproject.toml,
defaults to build system patching.
:return: A temporary copy
"""
assert (path / "pyproject.toml").exists()
with tempfile.TemporaryDirectory(
prefix="poetry-core-pep517", ignore_cleanup_errors=True
) as tmp:
dst = Path(tmp) / path.name
shutil.copytree(str(path), dst)
toml = dst / "pyproject.toml"
with toml.open("rb") as f:
data = tomllib.load(f)
data.update(toml_patch or __toml_build_backend_patch__)
with toml.open("wb") as f:
tomli_w.dump(data, f)
yield str(dst)
def subprocess_run(*args: str, **kwargs: Any) -> subprocess.CompletedProcess[str]:
"""
Helper method to run a subprocess. Asserts for success.
"""
result = subprocess.run(
args, text=True, encoding="locale", capture_output=True, **kwargs
)
assert result.returncode == 0
return result
def validate_wheel_contents(
name: str, version: str, path: Path, files: list[str] | None = None
) -> None:
dist_info = f"{name}-{version}.dist-info"
files = files or []
with zipfile.ZipFile(path) as z:
namelist = z.namelist()
for filename in ["WHEEL", "METADATA", "RECORD", *files]:
assert f"{dist_info}/{filename}" in namelist
def validate_sdist_contents(
name: str, version: str, path: Path, files: list[str]
) -> None:
escaped_name = name.replace("-", "_")
with tarfile.open(path) as tar:
namelist = tar.getnames()
for filename in files:
assert f"{escaped_name}-{version}/{filename}" in namelist
|