From 0ec8cea8c6ba7b8a2677cafb608d75d861d02e30 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 13 Dec 2024 11:52:31 -0800 Subject: [PATCH] dependencies: Use a TypedDict for Dependency keyword arguments There are a couple of annoyances around the way Python's TypedDicts work that we should get out of the way: 1) A TypedDict keeps it's `total` status, so you can't do something like: ```python from interpreter.type_checking import FuncDependency class DependencyKWs(FuncDependency, total=False): pass ``` All of the arguments from FuncDependency remain required. 2) The "functional" form of `TypedDict` requires a literal for it's arguments, so you can't do something like: ```python _VALUES = {...} FuncDependency = TypedDict('FuncDependency', _VALUES) DependencyKWs = TypedDict('DependencyKWs', _VALUES, total=False) And, there are some arguments `dependency()` that are not passed to the lower levels, but are interpreter constructs. Likewise, some of the Dependency classes take additional kwargs that are not part of the dependency() DSL API. So we have to have two different TypedDicts, which is unfortunate. Additionally, TypedDicts must define all allowed keys, there is no way to define "extra keys". This means that implementing this change as a series of small commits would would require hundreds of `# type: ignore` comments to be introduced and removed across the range. That kind of noise seems counterproductive to the purpose of having small commits, since there will end up being loads of churn introduced by such a series of commits. --- mesonbuild/dependencies/__init__.py | 2 +- mesonbuild/dependencies/base.py | 60 +++++++++++++++++++++------ mesonbuild/dependencies/boost.py | 3 +- mesonbuild/dependencies/cmake.py | 19 +++++---- mesonbuild/dependencies/coarrays.py | 5 ++- mesonbuild/dependencies/configtool.py | 3 +- mesonbuild/dependencies/cuda.py | 7 ++-- mesonbuild/dependencies/detect.py | 9 ++-- mesonbuild/dependencies/dev.py | 44 +++++++++----------- mesonbuild/dependencies/dub.py | 11 +++-- mesonbuild/dependencies/factory.py | 20 ++++----- mesonbuild/dependencies/framework.py | 3 +- mesonbuild/dependencies/hdf5.py | 7 ++-- mesonbuild/dependencies/misc.py | 49 +++++++++++----------- mesonbuild/dependencies/mpi.py | 7 ++-- mesonbuild/dependencies/pkgconfig.py | 3 +- mesonbuild/dependencies/platform.py | 3 +- mesonbuild/dependencies/python.py | 15 +++---- mesonbuild/dependencies/qt.py | 19 +++++---- mesonbuild/dependencies/scalapack.py | 5 ++- mesonbuild/dependencies/ui.py | 15 +++---- mesonbuild/interpreter/kwargs.py | 5 ++- mesonbuild/interpreter/mesonmain.py | 9 ++-- mesonbuild/modules/_qt.py | 3 +- 24 files changed, 188 insertions(+), 138 deletions(-) diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 7f03eec79d99..56f1229b9c72 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -105,7 +105,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. ```python class FooSystemDependency(ExternalDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: Environment, kwargs: DependencyKWs): super().__init__(name, environment, kwargs) root = environment.properties[self.for_machine].foo_root if root is None: diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index d3c18cec22d2..e3e7942a6f90 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -21,7 +21,7 @@ #from ..interpreterbase import FeatureDeprecated, FeatureNew if T.TYPE_CHECKING: - from typing_extensions import Literal + from typing_extensions import Literal, TypedDict from ..compilers.compilers import Compiler from ..environment import Environment @@ -32,6 +32,44 @@ ) from ..interpreter.type_checking import PkgConfigDefineType + # This must be kept in sync with the FuncDependency class in + # interpreter.type_checking + # They cannot share in anyway due to the way total works + class DependencyKWs(TypedDict, total=False): + + # The following arguments to `dependency()` are used in the interpreter, + # and are not needed here: + # - allow_fallback + # - default_options + # - fallback + # - not_found_message + + cmake_args: T.List[str] + cmake_module_path: T.List[str] + cmake_package_version: str + components: T.List[str] + embed: bool + include_type: Literal['system', 'non-system', 'preserve'] + language: T.Optional[str] # TODO: use a shared literal? + main: bool + method: str + modules: T.List[str] + native: MachineChoice + optional_modules: T.List[str] + private_headers: bool + required: bool + static: T.Optional[bool] + version: T.List[str] + + # These options only exist as implementation details to Dependency + # classes, and are not available to the DSL + silent: bool + tools: T.List[str] + returncode_value: int + paths: T.List[str] + version_arg: str + skip_version: str + _MissingCompilerBase = Compiler else: _MissingCompilerBase = object @@ -99,7 +137,7 @@ class DependencyMethods(Enum): class Dependency(HoldableObject): - def __init__(self, type_name: DependencyTypeName, kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, type_name: DependencyTypeName, kwargs: DependencyKWs) -> None: # This allows two Dependencies to be compared even after being copied. # The purpose is to allow the name to be changed, but still have a proper comparison self._id = uuid.uuid4().int @@ -373,25 +411,23 @@ def get_as_shared(self, recursive: bool) -> InternalDependency: return new_dep class ExternalDependency(Dependency): - def __init__(self, type_name: DependencyTypeName, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None): + def __init__(self, type_name: DependencyTypeName, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None): Dependency.__init__(self, type_name, kwargs) self.env = environment self.name = type_name # default self.is_found = False self.language = language version_reqs = kwargs.get('version', None) - if isinstance(version_reqs, str): - version_reqs = [version_reqs] - self.version_reqs: T.Optional[T.List[str]] = version_reqs + self.version_reqs = version_reqs self.required = kwargs.get('required', True) self.silent = kwargs.get('silent', False) static = kwargs.get('static') if static is None: - static = self.env.coredata.get_option(OptionKey('prefer_static')) - self.static = T.cast('bool', static) + static = T.cast('bool', self.env.coredata.get_option(OptionKey('prefer_static'))) + self.static = static self.libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED # Is this dependency to be run on the build platform? - self.for_machine = T.cast('MachineChoice', kwargs.get('native', MachineChoice.HOST)) + self.for_machine = kwargs.get('native', MachineChoice.HOST) self.clib_compiler = detect_compiler(self.name, environment, self.for_machine, self.language) def get_compiler(self) -> T.Union['MissingCompiler', 'Compiler']: @@ -580,7 +616,7 @@ def strip_system_includedirs(environment: 'Environment', for_machine: MachineCho exclude = {f'-I{p}' for p in environment.get_compiler_system_include_dirs(for_machine)} return [i for i in include_args if i not in exclude] -def process_method_kw(possible: T.Iterable[DependencyMethods], kwargs: T.Dict[str, T.Any]) -> T.List[DependencyMethods]: +def process_method_kw(possible: T.Iterable[DependencyMethods], kwargs: DependencyKWs) -> T.List[DependencyMethods]: method: T.Union[DependencyMethods, str] = kwargs.get('method', 'auto') if isinstance(method, DependencyMethods): return [method] @@ -646,7 +682,7 @@ class SystemDependency(ExternalDependency): """Dependency base for System type dependencies.""" - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: super().__init__(DependencyTypeName('system'), env, kwargs, language=language) self.name = name @@ -660,7 +696,7 @@ class BuiltinDependency(ExternalDependency): """Dependency base for Builtin type dependencies.""" - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: super().__init__(DependencyTypeName('builtin'), env, kwargs, language=language) self.name = name diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 1aac2ce24313..53c82f6615fe 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -19,6 +19,7 @@ from .misc import threads_factory if T.TYPE_CHECKING: + from .base import DependencyKWs from ..envconfig import Properties from ..environment import Environment @@ -339,7 +340,7 @@ def get_link_args(self) -> T.List[str]: return [self.path.as_posix()] class BoostDependency(SystemDependency): - def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: Environment, kwargs: DependencyKWs) -> None: super().__init__('boost', environment, kwargs, language='cpp') buildtype = environment.coredata.get_option(OptionKey('buildtype')) assert isinstance(buildtype, str) diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 96f723e26331..6c5cb2c42d86 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -17,6 +17,7 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from ..cmake import CMakeTarget from ..environment import Environment from ..envconfig import MachineInfo @@ -69,11 +70,11 @@ def _original_module_name(self, module: str) -> str: # one module return module - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> None: # Gather a list of all languages to support self.language_list: T.List[str] = [] if language is None or force_use_global_compilers: - for_machine = T.cast('MachineChoice', kwargs.get('native', MachineChoice.HOST)) + for_machine = kwargs.get('native', MachineChoice.HOST) compilers = environment.coredata.compilers[for_machine] candidates = ['c', 'cpp', 'fortran', 'objc', 'objcxx'] self.language_list += [x for x in candidates if x in compilers] @@ -112,7 +113,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. # Setup the trace parser self.traceparser = CMakeTraceParser(self.cmakebin.version(), self._get_build_dir(), self.env) - cm_args = T.cast('T.List[str]', kwargs.get('cmake_args', [])) + cm_args = kwargs.get('cmake_args', []) cm_args = check_cmake_args(cm_args) if CMakeDependency.class_cmakeinfo[self.for_machine] is None: CMakeDependency.class_cmakeinfo[self.for_machine] = self._get_cmake_info(cm_args) @@ -121,11 +122,11 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. raise self._gen_exception('Unable to obtain CMake system information') self.cmakeinfo = cmakeinfo - package_version = T.cast('str', kwargs.get('cmake_package_version', '')) - components = [(x, True) for x in T.cast('T.List[str]', kwargs.get('components', []))] - modules = [(x, True) for x in T.cast('T.List[str]', kwargs.get('modules', []))] - modules += [(x, False) for x in T.cast('T.List[str]', kwargs.get('optional_modules', []))] - cm_path = T.cast('T.List[str]', kwargs.get('cmake_module_path', [])) + package_version = kwargs.get('cmake_package_version', '') + components = [(x, True) for x in kwargs.get('components', [])] + modules = [(x, True) for x in kwargs.get('modules', [])] + modules += [(x, False) for x in kwargs.get('optional_modules', [])] + cm_path = kwargs.get('cmake_module_path', []) cm_path = [x if os.path.isabs(x) else os.path.join(environment.get_source_dir(), x) for x in cm_path] if cm_path: cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path)) @@ -640,7 +641,7 @@ def __init__(self, name: T.Optional[str] = None, modules: T.Optional[T.List[str] self.name = name self.modules = modules - def __call__(self, name: str, env: Environment, kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> CMakeDependency: + def __call__(self, name: str, env: Environment, kwargs: DependencyKWs, language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> CMakeDependency: if self.modules: kwargs['modules'] = self.modules return CMakeDependency(self.name or name, env, kwargs, language, force_use_global_compilers) diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index 01213d1fb0f0..be8c2e3d2afb 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -13,6 +13,7 @@ from .factory import factory_methods if T.TYPE_CHECKING: + from .base import DependencyKWs from . factory import DependencyGenerator from ..environment import Environment from ..mesonlib import MachineChoice @@ -21,7 +22,7 @@ @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM}) def coarray_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id() candidates: T.List['DependencyGenerator'] = [] @@ -55,7 +56,7 @@ class CoarrayDependency(SystemDependency): Coarrays may be thought of as a high-level language abstraction of low-level MPI calls. """ - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__('coarray', environment, kwargs, language='fortran') kwargs['required'] = False kwargs['silent'] = True diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index 7d632a00cd59..4caa4e366c55 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -11,6 +11,7 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment from ..interpreter.type_checking import PkgConfigDefineType @@ -35,7 +36,7 @@ class ConfigToolDependency(ExternalDependency): allow_default_for_cross = False __strip_version = re.compile(r'^[0-9][0-9.]+') - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None, exclude_paths: T.Optional[T.List[str]] = None): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None, exclude_paths: T.Optional[T.List[str]] = None): super().__init__(DependencyTypeName('config-tool'), environment, kwargs, language=language) self.name = name # You may want to overwrite the class version in some cases diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index 096a4d834bf9..fa3535d54c61 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -17,6 +17,7 @@ if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment from ..compilers import Compiler @@ -26,7 +27,7 @@ class CudaDependency(SystemDependency): supported_languages = ['cpp', 'c', 'cuda'] # see also _default_language - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: compilers = environment.coredata.compilers[kwargs.get('native', mesonlib.MachineChoice.HOST)] language = self._detect_language(compilers) if language not in self.supported_languages: @@ -276,8 +277,8 @@ def log_details(self) -> str: def log_info(self) -> str: return self.cuda_path if self.cuda_path else '' - def get_requested(self, kwargs: T.Dict[str, T.Any]) -> T.List[str]: - candidates = T.cast('T.List[str]', kwargs.get('modules', [])) + def get_requested(self, kwargs: DependencyKWs) -> T.List[str]: + candidates = kwargs.get('modules', []) for c in candidates: if not isinstance(c, str): raise DependencyException('CUDA module argument is not a string.') diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index 1886ba1e9441..99e993d86b40 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -12,6 +12,7 @@ from .. import mlog if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment from .factory import DependencyFactory, WrappedFactoryFunc, DependencyGenerator @@ -38,7 +39,7 @@ def __contains__(self, key: object) -> bool: packages = DependencyPackages() _packages_accept_language: T.Set[str] = set() -def get_dep_identifier(name: str, kwargs: T.Dict[str, T.Any]) -> 'TV_DepID': +def get_dep_identifier(name: str, kwargs: DependencyKWs) -> 'TV_DepID': identifier: 'TV_DepID' = (('name', name), ) from ..interpreter.type_checking import DEPENDENCY_KWS @@ -85,7 +86,7 @@ def get_dep_identifier(name: str, kwargs: T.Dict[str, T.Any]) -> 'TV_DepID': 'wxwidgets': 'WxWidgets', } -def find_external_dependency(name: str, env: 'Environment', kwargs: T.Dict[str, object], candidates: T.Optional[T.List['DependencyGenerator']] = None) -> T.Union['ExternalDependency', NotFoundDependency]: +def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyKWs, candidates: T.Optional[T.List['DependencyGenerator']] = None) -> T.Union['ExternalDependency', NotFoundDependency]: assert name required = kwargs.get('required', True) lname = name.lower() @@ -95,7 +96,7 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: T.Dict[str, # display the dependency name with correct casing display_name = display_name_map.get(lname, lname) - for_machine = T.cast('MachineChoice', kwargs.get('native', MachineChoice.HOST)) + for_machine = kwargs.get('native', MachineChoice.HOST) type_text = PerMachine('Build-time', 'Run-time')[for_machine] + ' dependency' # build a list of dependency methods to try @@ -167,7 +168,7 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: T.Dict[str, def _build_external_dependency_list(name: str, env: 'Environment', for_machine: MachineChoice, - kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']: + kwargs: DependencyKWs) -> T.List['DependencyGenerator']: # Is there a specific dependency detector for this dependency? lname = name.lower() if lname in packages: diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 269de3454544..9744c6912260 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -26,19 +26,13 @@ from .pkgconfig import PkgConfigDependency if T.TYPE_CHECKING: + from .base import DependencyKWs from ..envconfig import MachineInfo from ..environment import Environment from ..compilers import Compiler from ..mesonlib import MachineChoice - from typing_extensions import TypedDict from ..interpreter.type_checking import PkgConfigDefineType - class JNISystemDependencyKW(TypedDict): - modules: T.List[str] - # FIXME: When dependency() moves to typed Kwargs, this should inherit - # from its TypedDict type. - version: T.Optional[str] - def get_shared_library_suffix(environment: 'Environment', for_machine: MachineChoice) -> str: """This is only guaranteed to work for languages that compile to machine @@ -53,7 +47,7 @@ def get_shared_library_suffix(environment: 'Environment', for_machine: MachineCh class GTestDependencySystem(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__(name, environment, kwargs, language='cpp') self.main = kwargs.get('main', False) self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src'] @@ -108,7 +102,7 @@ def log_info(self) -> str: class GTestDependencyPC(PkgConfigDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): assert name == 'gtest' if kwargs.get('main'): name = 'gtest_main' @@ -116,7 +110,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. class GMockDependencySystem(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__(name, environment, kwargs, language='cpp') self.main = kwargs.get('main', False) if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): @@ -176,7 +170,7 @@ def log_info(self) -> str: class GMockDependencyPC(PkgConfigDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): assert name == 'gmock' if kwargs.get('main'): name = 'gmock_main' @@ -191,7 +185,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): tool_name = 'llvm-config' __cpp_blacklist = {'-DNDEBUG'} - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): self.tools = get_llvm_tool_names('llvm-config') # Fedora starting with Fedora 30 adds a suffix of the number @@ -213,9 +207,9 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. return self.provided_modules = self.get_config_value(['--components'], 'modules') - modules = T.cast('T.List[str]', kwargs.get('modules', [])) + modules = kwargs.get('modules', []) self.check_components(modules) - opt_modules = T.cast('T.List[str]', kwargs.get('optional_modules', [])) + opt_modules = kwargs.get('optional_modules', []) self.check_components(opt_modules, required=False) cargs = mesonlib.OrderedSet(self.get_config_value(['--cppflags'], 'compile_args')) @@ -386,11 +380,11 @@ def log_details(self) -> str: return '' class LLVMDependencyCMake(CMakeDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: - self.llvm_modules = T.cast('T.List[str]', kwargs.get('modules', [])) - self.llvm_opt_modules = T.cast('T.List[str]', kwargs.get('optional_modules', [])) + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs) -> None: + self.llvm_modules = kwargs.get('modules', []) + self.llvm_opt_modules = kwargs.get('optional_modules', []) - for_machine = T.cast('MachineChoice', kwargs.get('native', mesonlib.MachineChoice.HOST)) + for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) compilers = env.coredata.compilers[for_machine] if not compilers or not {'c', 'cpp'}.issubset(compilers): # Initialize basic variables @@ -510,7 +504,7 @@ class ValgrindDependency(PkgConfigDependency): Consumers of Valgrind usually only need the compile args and do not want to link to its (static) libraries. ''' - def __init__(self, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, env: 'Environment', kwargs: DependencyKWs): super().__init__('valgrind', env, kwargs) def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> T.List[str]: @@ -521,7 +515,7 @@ def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> class ZlibSystemDependency(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) from ..compilers.c import AppleClangCCompiler from ..compilers.cpp import AppleClangCPPCompiler @@ -558,8 +552,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. class JNISystemDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW): - super().__init__('jni', environment, T.cast('T.Dict[str, T.Any]', kwargs)) + def __init__(self, environment: 'Environment', kwargs: DependencyKWs): + super().__init__('jni', environment, kwargs) self.feature_since = ('0.62.0', '') @@ -570,7 +564,7 @@ def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW): self.javac = environment.coredata.compilers[self.for_machine]['java'] self.version = self.javac.version - modules = T.cast('T.List[str]', kwargs.get('modules', [])) + modules = kwargs.get('modules', []) for module in modules: if module not in {'jvm', 'awt'}: msg = f'Unknown JNI module ({module})' @@ -686,7 +680,7 @@ def __machine_info_to_platform_include_dir(m: 'MachineInfo') -> T.Optional[str]: class JDKSystemDependency(JNISystemDependency): - def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW): + def __init__(self, environment: 'Environment', kwargs: DependencyKWs): super().__init__(environment, kwargs) self.feature_since = ('0.59.0', '') @@ -752,7 +746,7 @@ def _has_define(compiler: 'Compiler', dname: str, env: 'Environment') -> bool: defval, _ = compiler.get_define(dname, '', env, [], []) return defval is not None - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__('diasdk', environment, kwargs) self.is_found = False diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index cf59d78abe7a..42d9bb769b7d 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -17,6 +17,7 @@ if T.TYPE_CHECKING: from typing_extensions import TypedDict + from .base import DependencyKWs from ..environment import Environment # Definition of what `dub describe` returns (only the fields used by Meson) @@ -69,7 +70,7 @@ class DubDependency(ExternalDependency): 'llvm': 'ldc', } - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(DependencyTypeName('dub'), environment, kwargs, language='d') self.name = name from ..compilers.d import DCompiler, d_feature_args @@ -79,7 +80,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. self.compiler = _temp_comp if kwargs.get('required') is not None: - self.required = T.cast('bool', kwargs['required']) + self.required = kwargs['required'] if DubDependency.class_dubbin is None and not DubDependency.class_dubbin_searched: DubDependency.class_dubbin = self._check_dub() @@ -117,9 +118,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. # if an explicit version spec was stated, use this when querying Dub main_pack_spec = name if kwargs.get('version'): - version_spec = kwargs['version'] - if isinstance(version_spec, list): - version_spec = " ".join(version_spec) + version_spec = ' '.join(kwargs['version']) main_pack_spec = f'{name}@{version_spec}' # we need to know the target architecture @@ -328,7 +327,7 @@ def find_package_target(pkg: DubPackDesc) -> bool: for lib in bs['libs']: if os.name != 'nt': # trying to add system libraries by pkg-config - pkgdep = PkgConfigDependency(lib, environment, {'required': 'true', 'silent': True}) + pkgdep = PkgConfigDependency(lib, environment, {'required': True, 'silent': True}) if pkgdep.is_found: for arg in pkgdep.get_compile_args(): self.compile_args.append(arg) diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py index aac09cafa616..729d71dc5bd7 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2013-2021 The Meson development team -# Copyright © 2021-2023 Intel Corporation +# Copyright © 2021-2024 Intel Corporation from __future__ import annotations @@ -15,7 +15,7 @@ from .pkgconfig import PkgConfigDependency if T.TYPE_CHECKING: - from .base import ExternalDependency + from .base import DependencyKWs, ExternalDependency from .configtool import ConfigToolDependency from ..environment import Environment from ..mesonlib import MachineChoice @@ -25,7 +25,7 @@ [ 'Environment', MachineChoice, - T.Dict[str, T.Any], + DependencyKWs, T.List[DependencyMethods] ], T.List[DependencyGenerator] @@ -35,12 +35,12 @@ [ 'Environment', MachineChoice, - T.Dict[str, T.Any] + DependencyKWs ], T.List[DependencyGenerator] ] - # This should be str, Environment, T.Dict[str, T.Any], T.Optional[str] + # This should be str, Environment, DependencyKWs, T.Optional[str] # But if you try that, you get error: Cannot infer type of lambda CmakeDependencyFunc = T.Callable[..., CMakeDependency] @@ -68,7 +68,7 @@ class DependencyFactory: """ def __init__(self, name: str, methods: T.List[DependencyMethods], *, - extra_kwargs: T.Optional[T.Dict[str, T.Any]] = None, + extra_kwargs: T.Optional[DependencyKWs] = None, pkgconfig_name: T.Optional[str] = None, pkgconfig_class: 'T.Type[PkgConfigDependency]' = PkgConfigDependency, cmake_name: T.Optional[str] = None, @@ -86,7 +86,7 @@ def __init__(self, name: str, methods: T.List[DependencyMethods], *, self.methods = methods self.classes: T.Dict[ DependencyMethods, - T.Callable[['Environment', T.Dict[str, T.Any]], ExternalDependency] + T.Callable[['Environment', DependencyKWs], ExternalDependency] ] = { # Just attach the correct name right now, either the generic name # or the method specific name. @@ -116,7 +116,7 @@ def _process_method(method: DependencyMethods, env: 'Environment', for_machine: return True def __call__(self, env: 'Environment', for_machine: MachineChoice, - kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']: + kwargs: DependencyKWs) -> T.List['DependencyGenerator']: """Return a list of Dependencies with the arguments already attached.""" methods = process_method_kw(self.methods, kwargs) nwargs = self.extra_kwargs.copy() @@ -131,14 +131,14 @@ def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryFu This helps to make factory functions self documenting >>> @factory_methods([DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE]) - >>> def factory(env: Environment, for_machine: MachineChoice, kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: + >>> def factory(env: Environment, for_machine: MachineChoice, kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: >>> pass """ def inner(func: 'FactoryFunc') -> 'WrappedFactoryFunc': @functools.wraps(func) - def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']: + def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: DependencyKWs) -> T.List['DependencyGenerator']: return func(env, for_machine, kwargs, process_method_kw(methods, kwargs)) return wrapped diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index 1fbd628235ba..56fdec24f6b4 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -10,12 +10,13 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment class ExtraFrameworkDependency(ExternalDependency): system_framework_paths: T.Optional[T.List[str]] = None - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: paths = stringlistify(kwargs.get('paths', [])) super().__init__(DependencyTypeName('extraframeworks'), env, kwargs, language=language) self.name = name diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index 743f98ac5754..a1a2bdde4e2f 100644 --- a/mesonbuild/dependencies/hdf5.py +++ b/mesonbuild/dependencies/hdf5.py @@ -18,6 +18,7 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from .factory import DependencyGenerator from ..environment import Environment from ..mesonlib import MachineChoice @@ -27,7 +28,7 @@ class HDF5PkgConfigDependency(PkgConfigDependency): """Handle brokenness in the HDF5 pkg-config files.""" - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: language = language or 'c' if language not in {'c', 'cpp', 'fortran'}: raise DependencyException(f'Language {language} is not supported with HDF5.') @@ -78,7 +79,7 @@ class HDF5ConfigToolDependency(ConfigToolDependency): version_arg = '-showconfig' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: language = language or 'c' if language not in {'c', 'cpp', 'fortran'}: raise DependencyException(f'Language {language} is not supported with HDF5.') @@ -144,7 +145,7 @@ def _sanitize_version(self, ver: str) -> str: @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL}) def hdf5_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: language = kwargs.get('language') candidates: T.List['DependencyGenerator'] = [] diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 46c70a9c7c76..75653c4420e0 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -20,6 +20,7 @@ from ..options import OptionKey if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment from .factory import DependencyGenerator @@ -27,7 +28,7 @@ @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE}) def netcdf_factory(env: 'Environment', for_machine: 'mesonlib.MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: language = kwargs.get('language') if language not in (None, 'c', 'cpp', 'fortran'): @@ -52,7 +53,7 @@ def netcdf_factory(env: 'Environment', class DlBuiltinDependency(BuiltinDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`") @@ -61,7 +62,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class DlSystemDependency(SystemDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`") @@ -88,7 +89,7 @@ class OpenMPDependency(SystemDependency): '199810': '1.0', } - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: language = kwargs.get('language') super().__init__('openmp', environment, kwargs, language=language) self.is_found = False @@ -142,7 +143,7 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> No class ThreadDependency(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__(name, environment, kwargs) self.is_found = True # Happens if you are using a language with threads @@ -156,7 +157,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. class BlocksDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__('blocks', environment, kwargs) self.name = 'blocks' self.is_found = False @@ -199,7 +200,7 @@ class PcapDependencyConfigTool(ConfigToolDependency): # version 1.10.3 will hopefully add actual support for --version skip_version = '--help' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -228,7 +229,7 @@ class CupsDependencyConfigTool(ConfigToolDependency): tools = ['cups-config'] tool_name = 'cups-config' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -241,7 +242,7 @@ class LibWmfDependencyConfigTool(ConfigToolDependency): tools = ['libwmf-config'] tool_name = 'libwmf-config' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -254,7 +255,7 @@ class LibGCryptDependencyConfigTool(ConfigToolDependency): tools = ['libgcrypt-config'] tool_name = 'libgcrypt-config' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -268,7 +269,7 @@ class GpgmeDependencyConfigTool(ConfigToolDependency): tools = ['gpgme-config'] tool_name = 'gpg-config' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -279,7 +280,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. class ShadercDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, environment: 'Environment', kwargs: DependencyKWs): super().__init__('shaderc', environment, kwargs) static_lib = 'shaderc_combined' @@ -311,7 +312,7 @@ class CursesConfigToolDependency(ConfigToolDependency): # ncurses5.4-config is for macOS Catalina tools = ['ncursesw6-config', 'ncursesw5-config', 'ncurses6-config', 'ncurses5-config', 'ncurses5.4-config'] - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None): exclude_paths = None # macOS mistakenly ships /usr/bin/ncurses5.4-config and a man page for # it, but none of the headers or libraries. Ignore /usr/bin because it @@ -335,7 +336,7 @@ class CursesSystemDependency(SystemDependency): implementations, and the differences between them can be very annoying. """ - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) candidates = [ @@ -382,7 +383,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class IconvBuiltinDependency(BuiltinDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without `find_library('iconv')`") code = '''#include \n\nint main() {\n iconv_open("","");\n}''' # [ignore encoding] this is C, not python, Mr. Lint @@ -392,7 +393,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class IconvSystemDependency(SystemDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without find_library('iconv')") @@ -404,7 +405,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class IntlBuiltinDependency(BuiltinDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`") code = '''#include \n\nint main() {\n gettext("Hello world");\n}''' @@ -414,7 +415,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class IntlSystemDependency(SystemDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`") @@ -430,10 +431,10 @@ def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): class OpensslSystemDependency(SystemDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) - dependency_kwargs = { + dependency_kwargs: DependencyKWs = { 'method': 'system', 'static': self.static, } @@ -483,7 +484,7 @@ class ObjFWDependency(ConfigToolDependency): tools = ['objfw-config'] tool_name = 'objfw-config' - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, environment: 'Environment', kwargs: DependencyKWs): super().__init__('objfw', environment, kwargs) self.feature_since = ('1.5.0', '') if not self.is_found: @@ -493,7 +494,7 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): # TODO: Expose --framework-libs extra_flags = [] - for module in T.cast('T.List[str]', kwargs.get('modules', [])): + for module in kwargs.get('modules', []): extra_flags.append('--package') extra_flags.append(module) @@ -505,7 +506,7 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) def curses_factory(env: 'Environment', for_machine: 'mesonlib.MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] @@ -531,7 +532,7 @@ def curses_factory(env: 'Environment', @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM}) def shaderc_factory(env: 'Environment', for_machine: 'mesonlib.MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: """Custom DependencyFactory for ShaderC. diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index a259972b0586..ef36a5f6ad44 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -17,6 +17,7 @@ from .pkgconfig import PkgConfigDependency if T.TYPE_CHECKING: + from .base import DependencyKWs from .factory import DependencyGenerator from ..environment import Environment from ..mesonlib import MachineChoice @@ -25,7 +26,7 @@ @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) def mpi_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: language = kwargs.get('language') if language is None: @@ -104,7 +105,7 @@ def mpi_factory(env: 'Environment', class MPIConfigToolDependency(ConfigToolDependency): """Wrapper around mpicc, Intel's mpiicc and friends.""" - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None): super().__init__(name, env, kwargs, language=language) if not self.is_found: @@ -214,7 +215,7 @@ class MSMPIDependency(SystemDependency): """The Microsoft MPI.""" - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None): super().__init__(name, env, kwargs, language=language) # MSMPI only supports the C API diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index c6e6a5e4f2ca..44f355dfc813 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -19,6 +19,7 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from typing_extensions import Literal from .._typing import ImmutableListProtocol @@ -291,7 +292,7 @@ def _call_pkgbin(self, args: T.List[str], env: T.Optional[EnvironOrDict] = None) class PkgConfigDependency(ExternalDependency): - def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, environment: Environment, kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language) self.name = name diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py index 335faed2cdbb..9efafa8544ad 100644 --- a/mesonbuild/dependencies/platform.py +++ b/mesonbuild/dependencies/platform.py @@ -11,10 +11,11 @@ import typing as T if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment class AppleFrameworks(ExternalDependency): - def __init__(self, env: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, env: 'Environment', kwargs: DependencyKWs) -> None: super().__init__(DependencyTypeName('appleframeworks'), env, kwargs) modules = kwargs.get('modules', []) if isinstance(modules, str): diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index c978ad62e82e..465bcbd5fd4d 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -21,6 +21,7 @@ if T.TYPE_CHECKING: from typing_extensions import TypedDict + from .base import DependencyKWs from .factory import DependencyGenerator from ..environment import Environment from ..mesonlib import MachineChoice @@ -56,7 +57,7 @@ class Pybind11ConfigToolDependency(ConfigToolDependency): # in the meantime skip_version = '--pkgconfigdir' - def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: Environment, kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -67,7 +68,7 @@ class NumPyConfigToolDependency(ConfigToolDependency): tools = ['numpy-config'] - def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: Environment, kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -310,7 +311,7 @@ def find_libpy_windows(self, env: 'Environment', limited_api: bool = False) -> N class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram', + kwargs: DependencyKWs, installation: 'BasicPythonExternalProgram', libpc: bool = False): if libpc: mlog.debug(f'Searching for {name!r} via pkgconfig lookup in LIBPC') @@ -331,7 +332,7 @@ def __init__(self, name: str, environment: 'Environment', class PythonFrameworkDependency(ExtraFrameworkDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'): + kwargs: DependencyKWs, installation: 'BasicPythonExternalProgram'): ExtraFrameworkDependency.__init__(self, name, environment, kwargs) _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) @@ -339,7 +340,7 @@ def __init__(self, name: str, environment: 'Environment', class PythonSystemDependency(SystemDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: T.Dict[str, T.Any], installation: 'BasicPythonExternalProgram'): + kwargs: DependencyKWs, installation: 'BasicPythonExternalProgram'): SystemDependency.__init__(self, name, environment, kwargs) _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) @@ -374,7 +375,7 @@ def log_tried() -> str: return 'sysconfig' def python_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, installation: T.Optional['BasicPythonExternalProgram'] = None) -> T.List['DependencyGenerator']: # We can't use the factory_methods decorator here, as we need to pass the # extra installation argument @@ -395,7 +396,7 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', pkg_name = f'python-{pkg_version}{pkg_embed}' # 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], + def wrap_in_pythons_pc_dir(name: str, env: 'Environment', kwargs: DependencyKWs, installation: 'BasicPythonExternalProgram') -> 'ExternalDependency': if not pkg_libdir: # there is no LIBPC, so we can't search in it diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index 3fe9b15fbd6a..e8e248022259 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -22,6 +22,7 @@ from ..options import OptionKey if T.TYPE_CHECKING: + from .base import DependencyKWs from ..compilers import Compiler from ..envconfig import MachineInfo from ..environment import Environment @@ -96,7 +97,7 @@ def _get_modules_lib_suffix(version: str, info: 'MachineInfo', is_debug: bool) - class QtExtraFrameworkDependency(ExtraFrameworkDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], qvars: T.Dict[str, str], language: T.Optional[str] = None): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, qvars: T.Dict[str, str], language: T.Optional[str] = None): super().__init__(name, env, kwargs, language=language) self.mod_name = name[2:] self.qt_extra_include_directory = qvars['QT_INSTALL_HEADERS'] @@ -123,7 +124,7 @@ class _QtBase: libexecdir: T.Optional[str] = None version: str - def __init__(self, name: str, kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, kwargs: DependencyKWs): self.name = name self.qtname = name.capitalize() self.qtver = name[-1] @@ -132,13 +133,13 @@ def __init__(self, name: str, kwargs: T.Dict[str, T.Any]): else: self.qtpkgname = self.qtname - self.private_headers = T.cast('bool', kwargs.get('private_headers', False)) + self.private_headers = kwargs.get('private_headers', False) - self.requested_modules = T.cast('T.List[str]', kwargs.get('modules', [])) + self.requested_modules = kwargs.get('modules', []) if not self.requested_modules: raise DependencyException('No ' + self.qtname + ' modules specified.') - self.qtmain = T.cast('bool', kwargs.get('main', False)) + self.qtmain = kwargs.get('main', False) if not isinstance(self.qtmain, bool): raise DependencyException('"main" argument must be a boolean') @@ -171,7 +172,7 @@ class QtPkgConfigDependency(_QtBase, PkgConfigDependency, metaclass=abc.ABCMeta) """Specialization of the PkgConfigDependency for Qt.""" - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): _QtBase.__init__(self, name, kwargs) # Always use QtCore as the "main" dependency, since it has the extra @@ -250,7 +251,7 @@ class QmakeQtDependency(_QtBase, ConfigToolDependency, metaclass=abc.ABCMeta): version: str version_arg = '-v' - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): _QtBase.__init__(self, name, kwargs) self.tool_name = f'qmake{self.qtver}' self.tools = [f'qmake{self.qtver}', f'qmake-{self.name}', 'qmake'] @@ -349,7 +350,7 @@ def get_variable_args(self, variable_name: str) -> T.List[str]: def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]: pass - def _framework_detect(self, qvars: T.Dict[str, str], modules: T.List[str], kwargs: T.Dict[str, T.Any]) -> None: + def _framework_detect(self, qvars: T.Dict[str, str], modules: T.List[str], kwargs: DependencyKWs) -> None: libdir = qvars['QT_INSTALL_LIBS'] # ExtraFrameworkDependency doesn't support any methods @@ -443,7 +444,7 @@ def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]: class Qt6PkgConfigDependency(Qt6WinMainMixin, QtPkgConfigDependency): - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs): super().__init__(name, env, kwargs) if not self.libexecdir: mlog.debug(f'detected Qt6 {self.version} pkg-config dependency does not ' diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index b3fae60aeab9..3982e426dc54 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -16,6 +16,7 @@ from .factory import factory_methods if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment from ..mesonlib import MachineChoice from .factory import DependencyGenerator @@ -23,7 +24,7 @@ @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE}) def scalapack_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: T.Dict[str, T.Any], + kwargs: DependencyKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] @@ -54,7 +55,7 @@ class MKLPkgConfigDependency(PkgConfigDependency): bunch of fixups to make it work correctly. """ - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + def __init__(self, name: str, env: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None): _m = os.environ.get('MKLROOT') self.__mklroot = Path(_m).resolve() if _m else None diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index f3263645a4e3..559f605db17b 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -24,11 +24,12 @@ from .factory import DependencyFactory if T.TYPE_CHECKING: + from .base import DependencyKWs from ..environment import Environment class GLDependencySystem(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__(name, environment, kwargs) if self.env.machines[self.for_machine].is_darwin(): @@ -57,7 +58,7 @@ class GnuStepDependency(ConfigToolDependency): tools = ['gnustep-config'] tool_name = 'gnustep-config' - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + def __init__(self, environment: 'Environment', kwargs: DependencyKWs) -> None: super().__init__('gnustep', environment, kwargs, language='objc') if not self.is_found: return @@ -136,7 +137,7 @@ class SDL2DependencyConfigTool(ConfigToolDependency): tools = ['sdl2-config'] tool_name = 'sdl2-config' - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs): super().__init__(name, environment, kwargs) if not self.is_found: return @@ -149,7 +150,7 @@ class WxDependency(ConfigToolDependency): tools = ['wx-config-3.0', 'wx-config-3.1', 'wx-config', 'wx-config-gtk3'] tool_name = 'wx-config' - def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + def __init__(self, environment: 'Environment', kwargs: DependencyKWs): super().__init__('WxWidgets', environment, kwargs, language='cpp') if not self.is_found: return @@ -172,14 +173,14 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): self.link_args = self.get_config_value(['--libs'] + extra_args + self.requested_modules, 'link_args') @staticmethod - def get_requested(kwargs: T.Dict[str, T.Any]) -> T.List[str]: - return T.cast('T.List[str]', kwargs.get('modules', [])) + def get_requested(kwargs: DependencyKWs) -> T.List[str]: + return kwargs.get('modules', []) packages['wxwidgets'] = WxDependency class VulkanDependencySystem(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyKWs, language: T.Optional[str] = None) -> None: super().__init__(name, environment, kwargs, language=language) try: diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 45ba798f79fa..8edf713fa947 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright © 2021 The Meson Developers +# Copyright © 2021-2024 Intel Corporation # Copyright © 2021-2024 Intel Corporation from __future__ import annotations @@ -484,6 +484,9 @@ class FuncDeclareDependency(TypedDict): version: T.Optional[str] +# This must be kept in sync with the DependencyKws class in +# dependencies.base +# They cannot share in anyway due to the way total works class FuncDependency(ExtractRequired): allow_fallback: T.Optional[bool] diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 289c8913e74c..272a69180365 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -25,6 +25,7 @@ if T.TYPE_CHECKING: from typing_extensions import Literal, TypedDict + from ..dependencies.base import DependencyKWs from ..compilers import Compiler from ..interpreterbase import TYPE_kwargs, TYPE_var from ..mesonlib import ExecutableSerialisation @@ -388,10 +389,10 @@ def override_dependency_method(self, args: T.Tuple[str, dependencies.Dependency] def _override_dependency_impl(self, name: str, dep: dependencies.Dependency, kwargs: 'FuncOverrideDependency', static: T.Optional[bool], permissive: bool = False) -> None: - # We need the cast here as get_dep_identifier works on such a dict, - # which FuncOverrideDependency is, but mypy can't figure that out - nkwargs = T.cast('T.Dict[str, T.Any]', kwargs.copy()) - nkwargs['static'] = T.cast('T.Optional[bool]', static) + # Neither mypy nor pyright can figure out that FuncOverrideDependency is + # a subset of DependencyKWs, so we have to cast to help it out. + nkwargs = T.cast('DependencyKWs', kwargs.copy()) + nkwargs['static'] = static identifier = dependencies.get_dep_identifier(name, nkwargs) for_machine = kwargs['native'] override = self.build.dependency_overrides[for_machine].get(identifier) diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py index 1f17a004b36f..1b75ec5c0c26 100644 --- a/mesonbuild/modules/_qt.py +++ b/mesonbuild/modules/_qt.py @@ -22,6 +22,7 @@ if T.TYPE_CHECKING: from . import ModuleState + from ..dependencies.base import DependencyKWs from ..dependencies.qt import QtPkgConfigDependency, QmakeQtDependency from ..interpreter import Interpreter from ..interpreter import kwargs @@ -174,7 +175,7 @@ def _detect_tools(self, state: 'ModuleState', method: str, required: bool = True return self._tools_detected = True mlog.log(f'Detecting Qt{self.qt_version} tools') - kwargs = {'required': required, 'modules': ['Core'], 'method': method} + kwargs: DependencyKWs = {'required': required, 'modules': ['Core'], 'method': method} # Just pick one to make mypy happy qt = T.cast('QtPkgConfigDependency', find_external_dependency(f'qt{self.qt_version}', state.environment, kwargs)) if qt.found():