mirror of
https://github.com/mesonbuild/meson.git
synced 2026-11-06 05:16:42 +00:00
modules/python: rework extension_module method for typing
This cleans up the typing by creating a new dictionary instead of mutating the one passed in. This gives better typing controls. I've also adding some missing keyword argument annotations, and done some casting because lists are invariant.
This commit is contained in:
1 parent
866d042b59
commit
b5f61587c3
1 file changed
+26
-24
@@ -9,7 +9,7 @@ import typing as T
|
||||
from . import ExtensionModule, ModuleInfo
|
||||
from .. import mesonlib
|
||||
from .. import mlog
|
||||
from ..build import known_shmod_kwargs, CustomTarget, CustomTargetIndex, BuildTarget, GeneratedList, StructuredSources, ExtractedObjects, SharedModule
|
||||
from ..build import CustomTarget, CustomTargetIndex, BuildTarget, GeneratedList, StructuredSources, ExtractedObjects, SharedModule
|
||||
from ..dependencies import NotFoundDependency
|
||||
from ..dependencies.detect import get_dep_identifier, find_external_dependency
|
||||
from ..dependencies.python import BasicPythonExternalProgram, python_factory, _PythonDependencyBase
|
||||
@@ -17,7 +17,7 @@ from ..interpreter import extract_required_kwarg, primitives as P_OBJ
|
||||
from ..interpreter.interpreterobjects import ProgramHolder
|
||||
from ..interpreter.type_checking import NoneType, DEPENDENCY_KWS, PRESERVE_PATH_KW, REQUIRED_KW, SHARED_MOD_KWS
|
||||
from ..interpreterbase import (
|
||||
noPosargs, noKwargs, permittedKwargs, ContainerTypeInfo,
|
||||
noPosargs, noKwargs, ContainerTypeInfo,
|
||||
InvalidArguments, typed_pos_args, typed_kwargs, KwargInfo,
|
||||
FeatureNew, disablerIfNotFound, InterpreterObject
|
||||
)
|
||||
@@ -34,6 +34,7 @@ if T.TYPE_CHECKING:
|
||||
from ..interpreter import Interpreter
|
||||
from ..interpreter.interpreter import BuildTargetSource
|
||||
from ..interpreter.kwargs import ExtractRequired, SharedModule as SharedModuleKw, FuncDependency
|
||||
from ..interpreter.type_checking import SourcesVarargsType
|
||||
from ..interpreterbase.baseobjects import TYPE_var, TYPE_kwargs
|
||||
|
||||
class PyInstallKw(TypedDict):
|
||||
@@ -52,15 +53,12 @@ if T.TYPE_CHECKING:
|
||||
|
||||
# Yes, these are different between SharedModule and ExtensionModule
|
||||
install_dir: T.Union[str, bool, None] # type: ignore[misc]
|
||||
limited_api: str
|
||||
subdir: NotRequired[T.Optional[str]]
|
||||
|
||||
MaybePythonProg = T.Union[NonExistingExternalProgram, 'PythonExternalProgram']
|
||||
|
||||
|
||||
mod_kwargs = {'subdir', 'limited_api'}
|
||||
mod_kwargs.update(known_shmod_kwargs)
|
||||
mod_kwargs -= {'name_prefix', 'name_suffix'}
|
||||
|
||||
_MOD_KWARGS = [k for k in SHARED_MOD_KWS if
|
||||
k.name not in {'name_prefix', 'name_suffix', 'install_dir'}]
|
||||
|
||||
@@ -139,7 +137,6 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
self.platlib_install_path = os.path.join(prefix, python.platlib)
|
||||
self.purelib_install_path = os.path.join(prefix, python.purelib)
|
||||
|
||||
@permittedKwargs(mod_kwargs)
|
||||
@typed_pos_args('python.extension_module', str, varargs=(str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget))
|
||||
@typed_kwargs(
|
||||
'python.extension_module',
|
||||
@@ -150,22 +147,24 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
)
|
||||
@InterpreterObject.method('extension_module')
|
||||
def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs: ExtensionModuleKw) -> 'SharedModule':
|
||||
target_kwargs = T.cast('SharedModuleKw', {k: v for k, v in kwargs.items() if k not in {'install_dir', 'subdir', 'limited_api'}})
|
||||
|
||||
if kwargs['install_dir'] is not None:
|
||||
if kwargs['subdir'] is not None:
|
||||
raise InvalidArguments('"subdir" and "install_dir" are mutually exclusive')
|
||||
# the build_target() method now expects this to be correct.
|
||||
kwargs['install_dir'] = [kwargs['install_dir']]
|
||||
target_kwargs['install_dir'] = [kwargs['install_dir']]
|
||||
else:
|
||||
# We want to remove 'subdir', but it may be None and we want to replace it with ''
|
||||
# It must be done this way since we don't allow both `install_dir`
|
||||
# and `subdir` to be set at the same time
|
||||
subdir = kwargs.pop('subdir') or ''
|
||||
subdir = kwargs.get('subdir') or ''
|
||||
|
||||
kwargs['install_dir'] = [self._get_install_dir_impl(False, subdir)]
|
||||
target_kwargs['install_dir'] = [self._get_install_dir_impl(False, subdir)]
|
||||
|
||||
target_suffix = self.suffix
|
||||
|
||||
new_deps = mesonlib.extract_as_list(kwargs, 'dependencies')
|
||||
new_deps = kwargs['dependencies'].copy()
|
||||
pydep = next((dep for dep in new_deps if isinstance(dep, _PythonDependencyBase)), None)
|
||||
if pydep is None:
|
||||
pydep = self._dependency_method_impl({'native': kwargs['native']})
|
||||
@@ -176,7 +175,7 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
'0.63.0', self.subproject, 'use python_installation.dependency()',
|
||||
self.current_node)
|
||||
|
||||
limited_api_version = kwargs.pop('limited_api')
|
||||
limited_api_version = kwargs.get('limited_api')
|
||||
allow_limited_api = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.allow_limited_api'))
|
||||
if limited_api_version != '' and allow_limited_api:
|
||||
|
||||
@@ -185,19 +184,20 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
limited_api_version_hex = self._convert_api_version_to_py_version_hex(limited_api_version, pydep.version)
|
||||
limited_api_definition = f'-DPy_LIMITED_API={limited_api_version_hex}'
|
||||
|
||||
new_c_args = mesonlib.extract_as_list(kwargs, 'c_args')
|
||||
new_c_args = kwargs['c_args'].copy()
|
||||
new_c_args.append(limited_api_definition)
|
||||
kwargs['c_args'] = new_c_args
|
||||
target_kwargs['c_args'] = new_c_args
|
||||
|
||||
new_cpp_args = mesonlib.extract_as_list(kwargs, 'cpp_args')
|
||||
new_cpp_args = kwargs['cpp_args'].copy()
|
||||
new_cpp_args.append(limited_api_definition)
|
||||
kwargs['cpp_args'] = new_cpp_args
|
||||
target_kwargs['cpp_args'] = new_cpp_args
|
||||
|
||||
# On Windows, the limited API DLL is python3.dll, not python3X.dll.
|
||||
for_machine = kwargs['native']
|
||||
if self.interpreter.environment.machines[for_machine].is_windows():
|
||||
pydep_copy = copy.copy(pydep)
|
||||
pydep_copy.find_libpy_windows(self.env, limited_api=True)
|
||||
if isinstance(pydep_copy, _PythonDependencyBase):
|
||||
pydep_copy.find_libpy_windows(self.env, limited_api=True)
|
||||
if not pydep_copy.found():
|
||||
raise mesonlib.MesonException('Python dependency supporting limited API not found')
|
||||
|
||||
@@ -214,7 +214,7 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
python_windows_debug_link_exception = f'/NODEFAULTLIB:python{pyver}_d.lib'
|
||||
python_windows_release_link_exception = f'/NODEFAULTLIB:python{pyver}.lib'
|
||||
|
||||
new_link_args = mesonlib.extract_as_list(kwargs, 'link_args')
|
||||
new_link_args = kwargs['link_args'].copy()
|
||||
|
||||
is_debug = self.interpreter.environment.coredata.optstore.get_value_for('debug')
|
||||
if is_debug:
|
||||
@@ -222,24 +222,26 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']):
|
||||
else:
|
||||
new_link_args.append(python_windows_release_link_exception)
|
||||
|
||||
kwargs['link_args'] = new_link_args
|
||||
target_kwargs['link_args'] = new_link_args
|
||||
|
||||
kwargs['dependencies'] = new_deps
|
||||
target_kwargs['dependencies'] = new_deps
|
||||
|
||||
# msys2's python3 has "-cpython-36m.dll", we have to be clever
|
||||
# FIXME: explain what the specific cleverness is here
|
||||
split, target_suffix = target_suffix.rsplit('.', 1)
|
||||
args = (args[0] + split, args[1])
|
||||
|
||||
kwargs['name_prefix'] = ''
|
||||
kwargs['name_suffix'] = target_suffix
|
||||
target_kwargs['name_prefix'] = ''
|
||||
target_kwargs['name_suffix'] = target_suffix
|
||||
|
||||
if kwargs['gnu_symbol_visibility'] == '' and \
|
||||
(self.is_pypy or mesonlib.version_compare(self.version, '>=3.9')):
|
||||
kwargs['gnu_symbol_visibility'] = 'inlineshidden'
|
||||
target_kwargs['gnu_symbol_visibility'] = 'inlineshidden'
|
||||
|
||||
kwargs.setdefault('rust_abi', 'c')
|
||||
return self.interpreter.build_target(self.current_node, args, kwargs, SharedModule)
|
||||
return self.interpreter.build_target(
|
||||
self.current_node, T.cast('T.Tuple[str, SourcesVarargsType]', args),
|
||||
target_kwargs, SharedModule)
|
||||
|
||||
def _convert_api_version_to_py_version_hex(self, api_version: str, detected_version: str) -> str:
|
||||
python_api_version_format = re.compile(r'[0-9]\.[0-9]{1,2}')
|
||||
|
||||
Reference in new issue
Block a user