From 9f7c4e2385d0e09b7158f6aa6618538db0ae06c4 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 18 Sep 2024 16:07:06 +0200 Subject: [PATCH] Draft: Build wheels for different Python interpreter Fromager now support building wheels for a different Python interpreter: ```shell fromager --python-interpreter=/path/to/python ... ``` Fixes: #431 Signed-off-by: Christian Heimes --- src/fromager/__main__.py | 10 ++++++++++ src/fromager/build_environment.py | 8 +++----- src/fromager/context.py | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/fromager/__main__.py b/src/fromager/__main__.py index 5e4c1bcf..6713b440 100644 --- a/src/fromager/__main__.py +++ b/src/fromager/__main__.py @@ -2,6 +2,7 @@ import logging import pathlib +import sys import click @@ -127,6 +128,13 @@ help="Build sdist and wheen with network isolation (unshare -cn)", show_default=True, ) +@click.option( + "--python-interpreter", + type=clickext.ClickPath(), + default=pathlib.Path(sys.executable), + help="Python interpreter to build wheels for", + show_default=True, +) @click.pass_context def main( ctx: click.Context, @@ -145,6 +153,7 @@ def main( variant: str, jobs: int | None, network_isolation: bool, + python_interpreter: pathlib.Path, ) -> None: # Set the overall logger level to debug and allow the handlers to filter # messages at their own level. @@ -211,6 +220,7 @@ def main( network_isolation=network_isolation, max_jobs=jobs, settings_dir=settings_dir, + python_interpreter=python_interpreter, ) wkctx.setup() ctx.obj = wkctx diff --git a/src/fromager/build_environment.py b/src/fromager/build_environment.py index 747c5af2..2c5de0c8 100644 --- a/src/fromager/build_environment.py +++ b/src/fromager/build_environment.py @@ -1,10 +1,8 @@ import importlib.metadata import logging import pathlib -import platform import re import subprocess -import sys import typing from packaging.requirements import Requirement @@ -75,7 +73,7 @@ def __init__( build_requirements: typing.Iterable[Requirement] | None, ): self._ctx = ctx - self.path = parent_dir / f"build-{platform.python_version()}" + self.path = parent_dir / f"build-{ctx.python_version}" self._build_requirements = build_requirements self._createenv() @@ -90,7 +88,7 @@ def _createenv(self) -> None: logger.debug("creating build environment in %s", self.path) external_commands.run( - [sys.executable, "-m", "virtualenv", str(self.path)], + [str(self._ctx.python_interpreter), "-m", "virtualenv", str(self.path)], network_isolation=False, ) logger.info("created build environment in %s", self.path) @@ -258,7 +256,7 @@ def _safe_install( logger.debug("installing %s %s", req_type, req) external_commands.run( [ - sys.executable, + str(ctx.python_interpreter), "-m", "pip", "-vvv", diff --git a/src/fromager/context.py b/src/fromager/context.py index 4a790bfd..4ab527f9 100644 --- a/src/fromager/context.py +++ b/src/fromager/context.py @@ -3,6 +3,7 @@ import logging import os import pathlib +import sys import typing from urllib.parse import urlparse @@ -13,6 +14,7 @@ from . import ( constraints, dependency_graph, + external_commands, packagesettings, ) @@ -38,6 +40,7 @@ def __init__( network_isolation: bool = False, max_jobs: int | None = None, settings_dir: pathlib.Path | None = None, + python_interpreter: pathlib.Path = pathlib.Path(sys.executable), ): if active_settings is None: active_settings = packagesettings.Settings( @@ -69,6 +72,8 @@ def __init__( self.variant = variant self.network_isolation = network_isolation self.settings_dir = settings_dir + self.python_interpreter = python_interpreter.absolute() + self._python_version: str | None = None self._build_order_filename = self.work_dir / "build-order.json" self._constraints_filename = self.work_dir / "constraints.txt" @@ -165,6 +170,19 @@ def package_build_info( name = package return self.settings.package_build_info(name) + def python_version(self) -> str: + if self._python_version is None: + out = external_commands.run( + [ + str(self.python_interpreter), + "-c", + "import platform; print(platform.python_version())", + ], + network_isolation=False, + ) + self._python_version = out.split("\n", 1)[0].strip() + return self._python_version + def setup(self) -> None: # The work dir must already exist, so don't try to create it. # Use os.makedirs() to create the others in case the paths