diff --git a/src/pdm/backend/base.py b/src/pdm/backend/base.py index eb01933..28f7a2d 100644 --- a/src/pdm/backend/base.py +++ b/src/pdm/backend/base.py @@ -6,7 +6,7 @@ import sys import warnings from pathlib import Path -from typing import Any, Iterable, Mapping, TypeVar, cast +from typing import TYPE_CHECKING, Any, Iterable, Mapping, TypeVar, cast from pdm.backend.config import Config from pdm.backend.exceptions import PDMWarning, ValidationError @@ -15,6 +15,9 @@ from pdm.backend.structures import FileMap from pdm.backend.utils import cd, import_module_at_path, is_python_package +if TYPE_CHECKING: + from typing import SupportsIndex + if sys.version_info >= (3, 10): from importlib.metadata import entry_points else: @@ -102,6 +105,13 @@ def __init__( self.config_settings = dict(config_settings or {}) self._hooks = list(self.get_hooks()) + def __reduce_ex__(self, __protocol: SupportsIndex = 3) -> str | tuple[Any, ...]: + return ( + self.__class__, + (self.location, self.config_settings), + {"config": self.config}, + ) + def get_hooks(self) -> Iterable[BuildHookInterface]: """Load hooks in the following order: @@ -137,13 +147,7 @@ def build_context(self, destination: Path, **kwargs: Any) -> Context: if not destination.exists(): destination.mkdir(0o700, parents=True) return Context( - root=self.location, - config=self.config, - target=self.target, - build_dir=build_dir, - dist_dir=destination, - config_settings=self.config_settings, - kwargs=kwargs, + build_dir=build_dir, dist_dir=destination, kwargs=kwargs, builder=self ) def __enter__(self: T) -> T: diff --git a/src/pdm/backend/hooks/base.py b/src/pdm/backend/hooks/base.py index c4d7897..40dedde 100644 --- a/src/pdm/backend/hooks/base.py +++ b/src/pdm/backend/hooks/base.py @@ -8,6 +8,8 @@ if TYPE_CHECKING: from typing import Protocol + + from pdm.backend.base import Builder else: Protocol = object @@ -20,27 +22,42 @@ class Context: assign arbitrary attributes to this object. Attributes: - root: The project root directory - config: The parsed pyproject.toml as a Config object - target: The target to build, one of "sdist", "wheel", "editable" build_dir: The build directory for storing files generated during the build dist_dir: The directory to store the built artifacts - config_settings: The config settings passed to the hook kwargs: The extra args passed to the build method + builder: The builder associated with this build context """ - root: Path - config: Config - target: str build_dir: Path dist_dir: Path - config_settings: dict[str, str] kwargs: dict[str, Any] - - def ensure_build_dir(self) -> None: - """Create if the build dir doesn't exist""" + builder: Builder + + @property + def config(self) -> Config: + """The parsed pyproject.toml as a Config object""" + return self.builder.config + + @property + def root(self) -> Path: + """The project root directory""" + return self.builder.location + + @property + def target(self) -> str: + """The target to build, one of 'sdist', 'wheel', 'editable'""" + return self.builder.target + + @property + def config_settings(self) -> dict[str, str]: + """The config settings passed to the hook""" + return self.builder.config_settings + + def ensure_build_dir(self) -> Path: + """Return the build dir and create if it doesn't exist""" if not self.build_dir.exists(): self.build_dir.mkdir(mode=0o700, parents=True) + return self.build_dir class BuildHookInterface(Protocol): diff --git a/src/pdm/backend/hooks/setuptools.py b/src/pdm/backend/hooks/setuptools.py index 35ee191..164a4c2 100644 --- a/src/pdm/backend/hooks/setuptools.py +++ b/src/pdm/backend/hooks/setuptools.py @@ -74,7 +74,7 @@ def pdm_build_update_files(self, context: Context, files: dict[str, Path]) -> No self._build_lib(context) def _build_lib(self, context: Context) -> None: - context.ensure_build_dir() + build_dir = context.ensure_build_dir() setup_py = self.ensure_setup_py(context) with tempfile.TemporaryDirectory(prefix="pdm-build-") as temp_dir: build_args = [sys.executable, str(setup_py), "build", "-b", temp_dir] @@ -88,9 +88,9 @@ def _build_lib(self, context: Context) -> None: # copy the files under temp_dir/lib.* to context.build_dir for file in lib_dir.iterdir(): if file.is_dir(): - shutil.copytree(file, context.build_dir / file.name) + shutil.copytree(file, build_dir / file.name) else: - shutil.copy2(file, context.build_dir) + shutil.copy2(file, build_dir) def _build_inplace(self, context: Context) -> None: setup_py = self.ensure_setup_py(context)