diff options
| author | Bernát Gábor <bgabor8@bloomberg.net> | 2021-09-26 09:39:34 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-26 09:39:34 +0100 |
| commit | cc04fe987ff006f54b3d15ae0227d233816e7e4f (patch) | |
| tree | 000ae4bc9e0c539af342810fcfd7fb09cde6f462 /src/tox/tox_env/python/package.py | |
| parent | d448d824f3d8514b560dfebc6819b5ddb09876ad (diff) | |
| download | tox-git-cc04fe987ff006f54b3d15ae0227d233816e7e4f.tar.gz | |
Support for external packages and builders (#2235)
Diffstat (limited to 'src/tox/tox_env/python/package.py')
| -rw-r--r-- | src/tox/tox_env/python/package.py | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/src/tox/tox_env/python/package.py b/src/tox/tox_env/python/package.py index 5964bcaf..2d43a96f 100644 --- a/src/tox/tox_env/python/package.py +++ b/src/tox/tox_env/python/package.py @@ -3,12 +3,19 @@ A tox build environment that handles Python packages. """ from abc import ABC, abstractmethod from pathlib import Path -from typing import Any, Sequence, Tuple +from typing import TYPE_CHECKING, Any, Dict, Generator, Iterator, Optional, Sequence, Tuple, Union, cast from packaging.requirements import Requirement +from ...config.sets import EnvConfigSet +from ..api import ToxEnvCreateArgs from ..package import Package, PackageToxEnv, PathPackage +from ..runner import RunToxEnv from .api import Python +from .pip.req_file import PythonDeps + +if TYPE_CHECKING: + from tox.config.main import Config class PythonPackage(Package): @@ -34,6 +41,10 @@ class DevLegacyPackage(PythonPathPackageWithDeps): class PythonPackageToxEnv(Python, PackageToxEnv, ABC): + def __init__(self, create_args: ToxEnvCreateArgs) -> None: + self._wheel_build_envs: Dict[str, PythonPackageToxEnv] = {} + super().__init__(create_args) + def register_config(self) -> None: super().register_config() @@ -43,5 +54,47 @@ class PythonPackageToxEnv(Python, PackageToxEnv, ABC): self.installer.install(self.requires(), PythonPackageToxEnv.__name__, "requires") @abstractmethod - def requires(self) -> Tuple[Requirement, ...]: + def requires(self) -> Union[Tuple[Requirement, ...], PythonDeps]: raise NotImplementedError + + def register_run_env(self, run_env: RunToxEnv) -> Generator[Tuple[str, str], PackageToxEnv, None]: + yield from super().register_run_env(run_env) + if not isinstance(run_env, Python) or run_env.conf["package"] != "wheel" or "wheel_build_env" in run_env.conf: + return + + def default_wheel_tag(conf: "Config", env_name: Optional[str]) -> str: + # https://www.python.org/dev/peps/pep-0427/#file-name-convention + # when building wheels we need to ensure that the built package is compatible with the target env + # compatibility is documented within https://www.python.org/dev/peps/pep-0427/#file-name-convention + # a wheel tag example: {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl + # python only code are often compatible at major level (unless universal wheel in which case both 2/3) + # c-extension codes are trickier, but as of today both poetry/setuptools uses pypa/wheels logic + # https://github.com/pypa/wheel/blob/master/src/wheel/bdist_wheel.py#L234-L280 + run_py = cast(Python, run_env).base_python + if run_py is None: + raise ValueError(f"could not resolve base python for {self.conf.name}") + + default_pkg_py = self.base_python + if ( + default_pkg_py.version_no_dot == run_py.version_no_dot + and default_pkg_py.impl_lower == run_py.impl_lower + ): + return self.conf.name + + return f"{self.conf.name}-{run_py.impl_lower}{run_py.version_no_dot}" + + run_env.conf.add_config( + keys=["wheel_build_env"], + of_type=str, + default=default_wheel_tag, + desc="wheel tag to use for building applications", + ) + pkg_env = run_env.conf["wheel_build_env"] + result = yield pkg_env, run_env.conf["package_tox_env_type"] + self._wheel_build_envs[pkg_env] = cast(PythonPackageToxEnv, result) + + def child_pkg_envs(self, run_conf: EnvConfigSet) -> Iterator[PackageToxEnv]: + if run_conf["package"] == "wheel": + env = self._wheel_build_envs.get(run_conf["wheel_build_env"]) + if env is not None and env.name != self.name: + yield env |
