def build_wheel(): """ Build the wheel package """ log.info("Building the wheel package") # ────── Retrieve build system info. ───── # with open(str(SRC_PATH / "pyproject.toml")) as fhandle: data = toml.load(fhandle) build_sys = data['build-system'] print(build_sys['requires']) # ─────────── Init build hooks ─────────── # hooks = Pep517HookCaller(SRC_PATH, build_backend=build_sys['build-backend'], backend_path=build_sys.get('backend-path')) config_options = {} print(hooks.get_requires_for_build_wheel(config_options)) # ───────────── Launch build! ──────────── # whl_filename = hooks.build_wheel(str(BUILD_PATH), config_options) assert os.path.isfile(str(BUILD_PATH / whl_filename))
def __init__(self, src_dir: os.PathLike, environment: Environment) -> None: self._env = environment self._path: Optional[str] = None self._saved_env = None self.executable = self._env.python_executable self.src_dir = src_dir try: with open(os.path.join(src_dir, "pyproject.toml"), encoding="utf8") as f: spec = toml.load(f) except FileNotFoundError: spec = {} except Exception as e: raise BuildError(e) from e self._build_system = spec.get("build-system", self.DEFAULT_BACKEND) if "build-backend" not in self._build_system: self._build_system["build-backend"] = self.DEFAULT_BACKEND[ "build-backend"] if "requires" not in self._build_system: raise BuildError( "Missing 'build-system.requires' in pyproject.toml") self._backend = self._build_system["build-backend"] self._hook = Pep517HookCaller( src_dir, self._backend, backend_path=self._build_system.get("backend-path"), runner=self.subprocess_runner, python_executable=self.executable, )
def __init__(self, src_dir: str | Path, environment: Environment) -> None: self._env = environment self._path = self.get_env_path(src_dir) self.executable = self._env.interpreter.executable self.src_dir = src_dir self._prefix = _Prefix(self.executable, self._path) logger.debug("Preparing isolated env for PEP 517 build...") try: with open(os.path.join(src_dir, "pyproject.toml"), encoding="utf8") as f: spec = toml.load(f) except FileNotFoundError: spec = {} except Exception as e: raise BuildError(e) from e self._build_system = spec.get("build-system", self.DEFAULT_BACKEND) if "build-backend" not in self._build_system: self._build_system["build-backend"] = self.DEFAULT_BACKEND[ "build-backend"] if "requires" not in self._build_system: raise BuildError( "Missing 'build-system.requires' in pyproject.toml") self._backend = self._build_system["build-backend"] self._hook = Pep517HookCaller( src_dir, self._backend, backend_path=self._build_system.get("backend-path"), runner=self.subprocess_runner, python_executable=self.executable, )
def get_hooks(pkg, **kwargs): source_dir = pjoin(SAMPLES_DIR, pkg) with open(pjoin(source_dir, 'pyproject.toml')) as f: data = toml.load(f) return Pep517HookCaller( source_dir, data['build-system']['build-backend'], **kwargs )
def get_hooks(pkg, backend=None, path=None): source_dir = pjoin(SAMPLES_DIR, pkg) with open(pjoin(source_dir, 'pyproject.toml')) as f: data = toml.load(f) if backend is None: backend = data['build-system']['build-backend'] if path is None: path = data['build-system']['backend-path'] return Pep517HookCaller(source_dir, backend, path)
def init_build_system(self, build_system: dict[str, Any]) -> None: """Initialize the build system and requires list from the PEP 517 spec""" self._hook = Pep517HookCaller( self.src_dir, build_system["build-backend"], backend_path=build_system.get("backend-path"), runner=self.subprocess_runner, python_executable=self.executable, ) self._requires = build_system["requires"]
def get_metadata(path: Path) -> Message: with volatile.dir() as d: build_sys = compat_system(path) hooks = Pep517HookCaller( path, build_backend=build_sys["build-backend"], backend_path=build_sys.get("backend-path"), ) if build_sys.get("requires"): subprocess.run([sys.executable, "-m", "pip", "install"] + build_sys["requires"]) dist_info = hooks.prepare_metadata_for_build_wheel(d) metadata_path = Path(d, dist_info, "METADATA") with open(metadata_path) as fp: return Parser().parse(fp)
def test_backend_path_within_tree(): source_dir = pjoin(SAMPLES_DIR, 'pkg1') assert Pep517HookCaller(source_dir, 'dummy', ['.', 'subdir']) assert Pep517HookCaller(source_dir, 'dummy', ['../pkg1', 'subdir/..']) # TODO: Do we want to insist on ValueError, or invent another exception? with pytest.raises(Exception): assert Pep517HookCaller(source_dir, 'dummy', [source_dir]) with pytest.raises(Exception): Pep517HookCaller(source_dir, 'dummy', ['.', '..']) with pytest.raises(Exception): Pep517HookCaller(source_dir, 'dummy', ['subdir/../..']) with pytest.raises(Exception): Pep517HookCaller(source_dir, 'dummy', ['/'])
def init_build_system(self, build_system: dict[str, Any]) -> None: """Initialize the build system and requires list from the PEP 517 spec""" self._hook = Pep517HookCaller( self.src_dir, build_system["build-backend"], backend_path=build_system.get("backend-path"), runner=self.subprocess_runner, python_executable=self.executable, ) self._requires = build_system["requires"] self._prefix = _Prefix( self.executable, # Build backends with the same requires list share the cached base env. shared=self.get_shared_env(hash(frozenset(self._requires))), # Overlay envs are unique for each source to be built. overlay=self.get_overlay_env( os.path.normcase(self.src_dir).rstrip("\\/")), ) if build_system["build-backend"].startswith("setuptools"): self.ensure_setup_py()
def test_backend_out_of_tree(backend_path): # TODO: Do we want to insist on ValueError, or invent another exception? with pytest.raises(Exception): Pep517HookCaller(SOURCE_DIR, 'dummy', backend_path)
def test_backend_path_within_tree(backend_path): Pep517HookCaller(SOURCE_DIR, 'dummy', backend_path)
def _extract_metainfo_files_from_package_unsafe(package, output_path): # This is the unwrapped function that will # 1. make lots of stdout/stderr noise # 2. possibly modify files (if the package source is a local folder) # Use extract_metainfo_files_from_package_folder instead which avoids # these issues. clean_up_path = False path_type = "source" path = parse_as_folder_reference(package) if path is None: # This is not a path. Download it: (path_type, path) = get_package_as_folder(package) if path_type is None: # Download failed. raise ValueError( "cannot get info for this package, " + "pip says it has no downloads (conditional dependency?)") clean_up_path = True try: build_requires = [] metadata_path = None if path_type != "wheel": # We need to process this first to get the metadata. # Ensure pyproject.toml is available (pep517 expects it) if not os.path.exists(os.path.join(path, "pyproject.toml")): with open(os.path.join(path, "pyproject.toml"), "w") as f: f.write( textwrap.dedent(u"""\ [build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" """)) # Copy the pyproject.toml: shutil.copyfile(os.path.join(path, 'pyproject.toml'), os.path.join(output_path, 'pyproject.toml')) # Get build backend and requirements from pyproject.toml: with open(os.path.join(path, 'pyproject.toml')) as f: build_sys = pytoml.load(f)['build-system'] backend = build_sys["build-backend"] build_requires.extend(build_sys["requires"]) # Get a virtualenv with build requirements and get all metadata: env = BuildEnvironment() metadata = None with env: hooks = Pep517HookCaller(path, backend) env.pip_install( [transform_dep_for_pip(req) for req in build_requires]) reqs = hooks.get_requires_for_build_wheel({}) env.pip_install([transform_dep_for_pip(req) for req in reqs]) try: metadata = hooks.prepare_metadata_for_build_wheel(path) except Exception: # sadly, pep517 has no good error here pass if metadata is not None: metadata_path = os.path.join(path, metadata, "METADATA") else: # This is a wheel, so metadata should be in *.dist-info folder: metadata_path = os.path.join(path, [ f for f in os.listdir(path) if f.endswith(".dist-info") ][0], "METADATA") # Copy the metadata file: shutil.copyfile(metadata_path, os.path.join(output_path, "METADATA")) finally: if clean_up_path: shutil.rmtree(path)