1import os 2from pathlib import Path 3from typing import Any, Mapping, Optional, Union 4 5from pep517.wrappers import HookMissing 6 7from pdm.builders.base import EnvBuilder 8from pdm.models.environment import Environment 9 10 11class EditableBuilder(EnvBuilder): 12 """Build egg-info in isolated env with managed Python.""" 13 14 FALLBACK_BACKEND = { 15 "build-backend": "setuptools_pep660", 16 "requires": ["setuptools_pep660"], 17 } 18 19 def __init__(self, src_dir: Union[str, Path], environment: Environment) -> None: 20 super().__init__(src_dir, environment) 21 if self._hook.build_backend.startswith( 22 "pdm.pep517" 23 ) and environment.interpreter.version_tuple < (3, 6): 24 # pdm.pep517 backend is not available on Python 2, use the fallback backend 25 self.init_build_system(self.FALLBACK_BACKEND) 26 27 def prepare_metadata( 28 self, out_dir: str, config_settings: Optional[Mapping[str, Any]] = None 29 ) -> str: 30 self.install(self._requires, shared=True) 31 try: 32 requires = self._hook.get_requires_for_build_editable(config_settings) 33 self.install(requires) 34 filename = self._hook.prepare_metadata_for_build_editable( 35 out_dir, config_settings 36 ) 37 except HookMissing: 38 self.init_build_system(self.FALLBACK_BACKEND) 39 return self.prepare_metadata(out_dir, config_settings) 40 return os.path.join(out_dir, filename) 41 42 def build( 43 self, 44 out_dir: str, 45 config_settings: Optional[Mapping[str, Any]] = None, 46 metadata_directory: Optional[str] = None, 47 ) -> str: 48 self.install(self._requires, shared=True) 49 try: 50 requires = self._hook.get_requires_for_build_editable(config_settings) 51 self.install(requires) 52 filename = self._hook.build_editable( 53 out_dir, config_settings, metadata_directory 54 ) 55 except HookMissing: 56 self.init_build_system(self.FALLBACK_BACKEND) 57 return self.build(out_dir, config_settings, metadata_directory) 58 return os.path.join(out_dir, filename) 59