diff options
author | Eli Schwartz <eschwartz@archlinux.org> | 2023-02-13 19:50:03 -0500 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2023-02-22 10:32:09 -0800 |
commit | 9fa4da3ba94cd1bd41917c93742396bd3f94330f (patch) | |
tree | 2da865455ef0f451b8955c1b7a7aa88763eec1cd /mesonbuild/modules/python.py | |
parent | 6719724c7c6ddecba60cc27f60a07862bb707615 (diff) | |
download | meson-9fa4da3ba94cd1bd41917c93742396bd3f94330f.zip meson-9fa4da3ba94cd1bd41917c93742396bd3f94330f.tar.gz meson-9fa4da3ba94cd1bd41917c93742396bd3f94330f.tar.bz2 |
python module/dependency: move the specialized external program
In preparation for handling more work inside dependencies.*, we need to
be able to run a PythonExternalProgram from the python dependency. Move
most of the definition -- but only the parts that have no interest in a
ModuleState -- and subclass a bit of sanity checking that we need to
handle specially when used in the module.
Diffstat (limited to 'mesonbuild/modules/python.py')
-rw-r--r-- | mesonbuild/modules/python.py | 88 |
1 files changed, 11 insertions, 77 deletions
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index fbc412f..effa669 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -16,7 +16,6 @@ from __future__ import annotations from pathlib import Path import copy import functools -import json import os import shutil import typing as T @@ -30,6 +29,7 @@ from ..dependencies import (DependencyMethods, PkgConfigDependency, NotFoundDepe DependencyTypeName, ExternalDependency) from ..dependencies.base import process_method_kw from ..dependencies.detect import get_dep_identifier +from ..dependencies.python import BasicPythonExternalProgram from ..environment import detect_cpu_family from ..interpreter import ExternalProgramHolder, extract_required_kwarg, permitted_dependency_kwargs from ..interpreter import primitives as P_OBJ @@ -54,19 +54,6 @@ if T.TYPE_CHECKING: from ..interpreter.kwargs import ExtractRequired from ..interpreterbase.interpreterbase import TYPE_var, TYPE_kwargs - class PythonIntrospectionDict(TypedDict): - - install_paths: T.Dict[str, str] - is_pypy: bool - is_venv: bool - link_libpython: bool - sysconfig_paths: T.Dict[str, str] - paths: T.Dict[str, str] - platform: str - suffix: str - variables: T.Dict[str, str] - version: str - class PyInstallKw(TypedDict): pure: T.Optional[bool] @@ -91,7 +78,7 @@ mod_kwargs -= {'name_prefix', 'name_suffix'} class _PythonDependencyBase(_Base): - def __init__(self, python_holder: 'PythonExternalProgram', embed: bool): + def __init__(self, python_holder: 'BasicPythonExternalProgram', embed: bool): self.embed = embed self.version: str = python_holder.info['version'] self.platform = python_holder.info['platform'] @@ -109,7 +96,7 @@ class _PythonDependencyBase(_Base): class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'PythonExternalProgram', + kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram', libpc: bool = False): if libpc: mlog.debug(f'Searching for {name!r} via pkgconfig lookup in LIBPC') @@ -137,7 +124,7 @@ class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): class PythonFrameworkDependency(ExtraFrameworkDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'PythonExternalProgram'): + kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'): ExtraFrameworkDependency.__init__(self, name, environment, kwargs) _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) @@ -145,7 +132,7 @@ class PythonFrameworkDependency(ExtraFrameworkDependency, _PythonDependencyBase) class PythonSystemDependency(SystemDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'PythonExternalProgram'): + kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'): SystemDependency.__init__(self, name, environment, kwargs) _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) @@ -283,7 +270,7 @@ class PythonSystemDependency(SystemDependency, _PythonDependencyBase): def python_factory(env: 'Environment', for_machine: 'MachineChoice', kwargs: T.Dict[str, T.Any], - installation: 'PythonExternalProgram') -> T.List['DependencyGenerator']: + installation: 'BasicPythonExternalProgram') -> T.List['DependencyGenerator']: # We can't use the factory_methods decorator here, as we need to pass the # extra installation argument methods = process_method_kw({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM}, kwargs) @@ -298,7 +285,7 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', # If python-X.Y.pc exists in LIBPC, we will try to use it def wrap_in_pythons_pc_dir(name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], - installation: 'PythonExternalProgram') -> 'ExternalDependency': + installation: 'BasicPythonExternalProgram') -> 'ExternalDependency': if not pkg_libdir: # there is no LIBPC, so we can't search in it empty = ExternalDependency(DependencyTypeName('pkgconfig'), env, {}) @@ -339,66 +326,13 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', return candidates -class PythonExternalProgram(ExternalProgram): - def __init__(self, name: str, command: T.Optional[T.List[str]] = None, - ext_prog: T.Optional[ExternalProgram] = None): - if ext_prog is None: - super().__init__(name, command=command, silent=True) - else: - self.name = name - self.command = ext_prog.command - self.path = ext_prog.path - - # We want strong key values, so we always populate this with bogus data. - # Otherwise to make the type checkers happy we'd have to do .get() for - # everycall, even though we know that the introspection data will be - # complete - self.info: 'PythonIntrospectionDict' = { - 'install_paths': {}, - 'is_pypy': False, - 'is_venv': False, - 'link_libpython': False, - 'sysconfig_paths': {}, - 'paths': {}, - 'platform': 'sentinal', - 'suffix': 'sentinel', - 'variables': {}, - 'version': '0.0', - } - self.pure: bool = True - - def _check_version(self, version: str) -> bool: - if self.name == 'python2': - return mesonlib.version_compare(version, '< 3.0') - elif self.name == 'python3': - return mesonlib.version_compare(version, '>= 3.0') - return True - +class PythonExternalProgram(BasicPythonExternalProgram): def sanity(self, state: T.Optional['ModuleState'] = None) -> bool: - # Sanity check, we expect to have something that at least quacks in tune - - import importlib.resources - - with importlib.resources.path('mesonbuild.scripts', 'python_info.py') as f: - cmd = self.get_command() + [str(f)] - p, stdout, stderr = mesonlib.Popen_safe(cmd) - try: - info = json.loads(stdout) - except json.JSONDecodeError: - info = None - mlog.debug('Could not introspect Python (%s): exit code %d' % (str(p.args), p.returncode)) - mlog.debug('Program stdout:\n') - mlog.debug(stdout) - mlog.debug('Program stderr:\n') - mlog.debug(stderr) - - if info is not None and self._check_version(info['version']): - self.info = T.cast('PythonIntrospectionDict', info) + ret = super().sanity() + if ret: self.platlib = self._get_path(state, 'platlib') self.purelib = self._get_path(state, 'purelib') - return True - else: - return False + return ret def _get_path(self, state: T.Optional['ModuleState'], key: str) -> None: rel_path = self.info['install_paths'][key][1:] |