From 8b1c5c9944ba0b28524d11a8d274f81733e4149b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 6 Dec 2024 12:38:28 -0800 Subject: interpreter: port dependency include_type to typed_kargs The cleanup this allows lower down points out that we don't properly validate the value passed to `as_system()`. I have no idea what happens if you pass a non-valid value, but it's a bug and I've simply made it a hard error. We can re-assess if necessary. --- mesonbuild/dependencies/base.py | 21 +++++++-------------- mesonbuild/interpreter/interpreter.py | 5 +---- mesonbuild/interpreter/interpreterobjects.py | 12 +++++++++++- mesonbuild/interpreter/kwargs.py | 3 ++- mesonbuild/interpreter/type_checking.py | 8 ++++++++ mesonbuild/modules/cmake.py | 20 ++++++++------------ 6 files changed, 37 insertions(+), 32 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 765c4782c..96ec78159 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -21,7 +21,7 @@ from ..options import OptionKey #from ..interpreterbase import FeatureDeprecated, FeatureNew if T.TYPE_CHECKING: - from typing_extensions import TypedDict + from typing_extensions import Literal, TypedDict, TypeAlias from ..compilers.compilers import Compiler from ..environment import Environment @@ -32,6 +32,8 @@ if T.TYPE_CHECKING: ) from ..interpreter.type_checking import PkgConfigDefineType + IncludeType: TypeAlias = Literal['system', 'non-system', 'preserve'] + class DependencyObjectKWs(TypedDict, total=False): """Keyword arguments that the Dependency IR object accepts. @@ -44,6 +46,7 @@ if T.TYPE_CHECKING: cmake_module_path: T.List[str] cmake_package_version: str components: T.List[str] + include_type: IncludeType _MissingCompilerBase = Compiler else: @@ -112,16 +115,6 @@ DependencyTypeName = T.NewType('DependencyTypeName', str) class Dependency(HoldableObject): - @classmethod - def _process_include_type_kw(cls, kwargs: DependencyObjectKWs) -> str: - if 'include_type' not in kwargs: - return 'preserve' - if not isinstance(kwargs['include_type'], str): # type: ignore[typeddict-item] - raise DependencyException('The include_type kwarg must be a string type') - if kwargs['include_type'] not in ['preserve', 'system', 'non-system']: # type: ignore[typeddict-item] - raise DependencyException("include_type may only be one of ['preserve', 'system', 'non-system']") - return kwargs['include_type'] # type: ignore[typeddict-item] - def __init__(self, type_name: DependencyTypeName, kwargs: DependencyObjectKWs) -> 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 @@ -138,7 +131,7 @@ class Dependency(HoldableObject): self.raw_link_args: T.Optional[T.List[str]] = None self.sources: T.List[T.Union[mesonlib.File, GeneratedTypes, 'StructuredSources']] = [] self.extra_files: T.List[mesonlib.File] = [] - self.include_type = self._process_include_type_kw(kwargs) + self.include_type = kwargs.get('include_type', 'preserve') self.ext_deps: T.List[Dependency] = [] self.d_features: T.DefaultDict[str, T.List[T.Any]] = collections.defaultdict(list) self.featurechecks: T.List['FeatureCheckBase'] = [] @@ -277,9 +270,9 @@ class Dependency(HoldableObject): return default_value raise DependencyException(f'No default provided for dependency {self!r}, which is not pkg-config, cmake, or config-tool based.') - def generate_system_dependency(self, include_type: str) -> 'Dependency': + def generate_system_dependency(self, include_type: IncludeType) -> 'Dependency': new_dep = copy.deepcopy(self) - new_dep.include_type = self._process_include_type_kw({'include_type': include_type}) # type: ignore[typeddict-unknown-key] + new_dep.include_type = include_type return new_dep def get_as_static(self, recursive: bool) -> Dependency: diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 648278426..c58824206 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1788,7 +1788,6 @@ class Interpreter(InterpreterBase, HoldableObject): search_dirs=search_dirs) # When adding kwargs, please check if they make sense in dependencies.get_dep_identifier() - @FeatureNewKwargs('dependency', '0.52.0', ['include_type']) @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message']) @FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.40.0', ['method']) @@ -1817,10 +1816,8 @@ class Interpreter(InterpreterBase, HoldableObject): if not d.found() and not_found_message: self.message_impl([not_found_message]) # Ensure the correct include type - if 'include_type' in kwargs: + if kwargs['include_type'] != 'preserve': wanted = kwargs['include_type'] - if not isinstance(wanted, str): - raise InvalidArguments('The `include_type` kwarg must be a string') actual = d.get_include_type() if wanted != actual: mlog.debug(f'Current include type of {args[0]} is {actual}. Converting to requested {wanted}') diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 4ff7e903e..b6137d175 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -31,6 +31,7 @@ import typing as T if T.TYPE_CHECKING: from . import kwargs from ..cmake.interpreter import CMakeInterpreter + from ..dependencies.base import IncludeType from ..envconfig import MachineInfo from ..interpreterbase import FeatureCheckBase, SubProject, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs from .interpreter import Interpreter @@ -569,7 +570,16 @@ class DependencyHolder(ObjectHolder[Dependency]): @typed_pos_args('dependency.as_system', optargs=[str]) @InterpreterObject.method('as_system') def as_system_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> Dependency: - return self.held_object.generate_system_dependency(args[0] or 'system') + include_type: IncludeType + if args[0] is None: + include_type = 'system' + elif args[0] not in {'preserve', 'system', 'non-system'}: + raise InvalidArguments( + 'Dependency.as_system: if an argument is given it must be one ' + f'of: "preserve", "system", "non-system", not: "{args[0]}"') + else: + include_type = T.cast('IncludeType', args[0]) + return self.held_object.generate_system_dependency(include_type) @FeatureNew('dependency.as_link_whole', '0.56.0') @noKwargs diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 6b4ca2d3a..6e524885d 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -12,7 +12,7 @@ from typing_extensions import TypedDict, Literal, Protocol, NotRequired from .. import build from .. import options from ..compilers import Compiler -from ..dependencies.base import Dependency +from ..dependencies.base import Dependency, IncludeType from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString from ..options import OptionKey from ..modules.cmake import CMakeSubprojectOptions @@ -500,3 +500,4 @@ class FuncDependency(TypedDict): components: T.List[str] default_options: T.Dict[OptionKey, options.ElementaryOptionValues] fallback: T.Union[str, T.List[str], None] + include_type: IncludeType diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 9e61a9698..20fa7c04d 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -895,9 +895,17 @@ PKGCONFIG_DEFINE_KW: KwargInfo = KwargInfo( convertor=_pkgconfig_define_convertor, ) +INCLUDE_TYPE = KwargInfo( + 'include_type', + str, + default='preserve', + since='0.52.0', + validator=in_set_validator({'system', 'non-system', 'preserve'}) +) DEPENDENCY_KWS: T.List[KwargInfo] = [ DEFAULT_OPTIONS.evolve(since='0.38.0'), + INCLUDE_TYPE, KwargInfo('allow_fallback', (bool, NoneType), since='0.56.0'), KwargInfo('cmake_args', ContainerTypeInfo(list, str), listify=True, default=[], since='0.50.0'), KwargInfo('cmake_module_path', ContainerTypeInfo(list, str), listify=True, default=[], since='0.50.0'), diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index fc300fab2..2e2abb889 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -13,7 +13,7 @@ from .. import build, mesonlib, mlog, dependencies from ..options import OptionKey from ..cmake import TargetOptions, cmake_defines_to_args from ..interpreter import SubprojectHolder -from ..interpreter.type_checking import REQUIRED_KW, INSTALL_DIR_KW, NoneType, in_set_validator +from ..interpreter.type_checking import REQUIRED_KW, INSTALL_DIR_KW, INCLUDE_TYPE, NoneType, in_set_validator from ..interpreterbase import ( FeatureNew, @@ -34,6 +34,7 @@ if T.TYPE_CHECKING: from . import ModuleState from ..cmake.common import SingleTargetOptions + from ..dependencies.base import IncludeType from ..environment import Environment from ..interpreter import Interpreter, kwargs from ..interpreterbase import TYPE_kwargs, TYPE_var, InterpreterObject @@ -62,6 +63,10 @@ if T.TYPE_CHECKING: target: T.Optional[str] + class DependencyKW(TypedDict): + + include_type: IncludeType + _TARGET_KW = KwargInfo('target', (str, NoneType)) @@ -129,17 +134,8 @@ class CMakeSubproject(ModuleObject): return self.subp.get_variable(args, kwargs) @typed_pos_args('cmake.subproject.dependency', str) - @typed_kwargs( - 'cmake.subproject.dependency', - KwargInfo( - 'include_type', - str, - default='preserve', - since='0.56.0', - validator=in_set_validator({'preserve', 'system', 'non-system'}) - ), - ) - def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: T.Dict[str, str]) -> dependencies.Dependency: + @typed_kwargs('cmake.subproject.dependency', INCLUDE_TYPE.evolve(since='0.56.0')) + def dependency(self, state: ModuleState, args: T.Tuple[str], kwargs: DependencyKW) -> dependencies.Dependency: info = self._args_to_info(args[0]) if info['func'] == 'executable': raise InvalidArguments(f'{args[0]} is an executable and does not support the dependency() method. Use target() instead.') -- cgit v1.2.3