aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/interpreter/interpreterobjects.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/interpreter/interpreterobjects.py')
-rw-r--r--mesonbuild/interpreter/interpreterobjects.py548
1 files changed, 261 insertions, 287 deletions
diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py
index c0eecca..7c4e75e 100644
--- a/mesonbuild/interpreter/interpreterobjects.py
+++ b/mesonbuild/interpreter/interpreterobjects.py
@@ -1,8 +1,8 @@
import os
import shlex
import subprocess
-import re
import copy
+import textwrap
from pathlib import Path, PurePath
@@ -33,22 +33,22 @@ if T.TYPE_CHECKING:
from ..envconfig import MachineInfo
-def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired', subproject: str,
- feature_check: T.Optional['FeatureCheckBase'] = None,
+def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
+ subproject: str,
+ feature_check: T.Optional[FeatureCheckBase] = None,
default: bool = True) -> T.Tuple[bool, bool, T.Optional[str]]:
val = kwargs.get('required', default)
disabled = False
required = False
feature: T.Optional[str] = None
- if isinstance(val, FeatureOptionHolder):
+ if isinstance(val, coredata.UserFeatureOption):
if not feature_check:
feature_check = FeatureNew('User option "feature"', '0.47.0')
feature_check.use(subproject)
- option = val.held_object
feature = val.name
- if option.is_disabled():
+ if val.is_disabled():
disabled = True
- elif option.is_enabled():
+ elif val.is_enabled():
required = True
elif isinstance(val, bool):
required = val
@@ -62,9 +62,9 @@ def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired', subproject: str,
return disabled, required, feature
-def extract_search_dirs(kwargs):
- search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
- search_dirs = [Path(d).expanduser() for d in search_dirs]
+def extract_search_dirs(kwargs: T.Dict[str, T.Any]) -> T.List[str]:
+ search_dirs_str = mesonlib.stringlistify(kwargs.get('dirs', []))
+ search_dirs = [Path(d).expanduser() for d in search_dirs_str]
for d in search_dirs:
if mesonlib.is_windows() and d.root.startswith('\\'):
# a Unix-path starting with `/` that is not absolute on Windows.
@@ -75,12 +75,12 @@ def extract_search_dirs(kwargs):
return list(map(str, search_dirs))
class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
- def __init__(self, env: 'Environment', name: str, option: coredata.UserFeatureOption):
- super().__init__(option)
+ def __init__(self, option: coredata.UserFeatureOption, interpreter: 'Interpreter'):
+ super().__init__(option, interpreter)
if option and option.is_auto():
# TODO: we need to case here because options is not a TypedDict
- self.held_object = T.cast(coredata.UserFeatureOption, env.coredata.options[OptionKey('auto_features')])
- self.name = name
+ self.held_object = T.cast(coredata.UserFeatureOption, self.env.coredata.options[OptionKey('auto_features')])
+ self.held_object.name = option.name
self.methods.update({'enabled': self.enabled_method,
'disabled': self.disabled_method,
'allowed': self.allowed_method,
@@ -90,34 +90,36 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
})
@property
- def value(self):
+ def value(self) -> str:
return 'disabled' if not self.held_object else self.held_object.value
- def as_disabled(self):
- return FeatureOptionHolder(None, self.name, None)
+ def as_disabled(self) -> coredata.UserFeatureOption:
+ disabled = copy.deepcopy(self.held_object)
+ disabled.value = 'disabled'
+ return disabled
@noPosargs
- @permittedKwargs({})
- def enabled_method(self, args, kwargs):
+ @noKwargs
+ def enabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.value == 'enabled'
@noPosargs
- @permittedKwargs({})
- def disabled_method(self, args, kwargs):
+ @noKwargs
+ def disabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.value == 'disabled'
@noPosargs
- @permittedKwargs({})
- def allowed_method(self, args, kwargs):
+ @noKwargs
+ def allowed_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return not self.value == 'disabled'
@noPosargs
- @permittedKwargs({})
- def auto_method(self, args, kwargs):
+ @noKwargs
+ def auto_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.value == 'auto'
@permittedKwargs({'error_message'})
- def require_method(self, args, kwargs):
+ def require_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption:
if len(args) != 1:
raise InvalidArguments('Expected 1 argument, got %d.' % (len(args), ))
if not isinstance(args[0], bool):
@@ -126,38 +128,57 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
if error_message and not isinstance(error_message, str):
raise InterpreterException("Error message must be a string.")
if args[0]:
- return self
+ return copy.deepcopy(self.held_object)
+ assert isinstance(error_message, str)
if self.value == 'enabled':
- prefix = 'Feature {} cannot be enabled'.format(self.name)
+ prefix = 'Feature {} cannot be enabled'.format(self.held_object.name)
prefix = prefix + ': ' if error_message else ''
raise InterpreterException(prefix + error_message)
return self.as_disabled()
- @permittedKwargs({})
- def disable_auto_if_method(self, args, kwargs):
+ @noKwargs
+ def disable_auto_if_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption:
if len(args) != 1:
raise InvalidArguments('Expected 1 argument, got %d.' % (len(args), ))
if not isinstance(args[0], bool):
raise InvalidArguments('boolean argument expected.')
- return self if self.value != 'auto' or not args[0] else self.as_disabled()
+ return copy.deepcopy(self.held_object) if self.value != 'auto' or not args[0] else self.as_disabled()
class RunProcess(MesonInterpreterObject):
- def __init__(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
+ def __init__(self,
+ cmd: ExternalProgram,
+ args: T.List[str],
+ env: build.EnvironmentVariables,
+ source_dir: str,
+ build_dir: str,
+ subdir: str,
+ mesonintrospect: T.List[str],
+ in_builddir: bool = False,
+ check: bool = False,
+ capture: bool = True) -> None:
super().__init__()
if not isinstance(cmd, ExternalProgram):
raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
self.capture = capture
- pc, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
- self.returncode = pc.returncode
+ self.returncode, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
self.methods.update({'returncode': self.returncode_method,
'stdout': self.stdout_method,
'stderr': self.stderr_method,
})
- def run_command(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False):
+ def run_command(self,
+ cmd: ExternalProgram,
+ args: T.List[str],
+ env: build.EnvironmentVariables,
+ source_dir: str,
+ build_dir: str,
+ subdir: str,
+ mesonintrospect: T.List[str],
+ in_builddir: bool,
+ check: bool = False) -> T.Tuple[int, str, str]:
command_array = cmd.get_command() + args
menv = {'MESON_SOURCE_ROOT': source_dir,
'MESON_BUILD_ROOT': build_dir,
@@ -188,28 +209,33 @@ class RunProcess(MesonInterpreterObject):
if check and p.returncode != 0:
raise InterpreterException('Command "{}" failed with status {}.'.format(' '.join(command_array), p.returncode))
- return p, o, e
+ return p.returncode, o, e
except FileNotFoundError:
raise InterpreterException('Could not execute command "%s".' % ' '.join(command_array))
@noPosargs
- @permittedKwargs({})
- def returncode_method(self, args, kwargs):
+ @noKwargs
+ def returncode_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
return self.returncode
@noPosargs
- @permittedKwargs({})
- def stdout_method(self, args, kwargs):
+ @noKwargs
+ def stdout_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.stdout
@noPosargs
- @permittedKwargs({})
- def stderr_method(self, args, kwargs):
+ @noKwargs
+ def stderr_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.stderr
-class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.EnvironmentVariables]):
- def __init__(self, initial_values=None, subproject: str = ''):
- super().__init__(build.EnvironmentVariables(), subproject=subproject)
+# TODO: Parsing the initial values should be either done directly in the
+# `Interpreter` or in `build.EnvironmentVariables`. This way, this class
+# can be converted into a pure object holder.
+class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObject):
+ # TODO: Move the type cheking for initial_values out of this class and replace T.Any
+ def __init__(self, initial_values: T.Optional[T.Any] = None, subproject: str = ''):
+ super().__init__(subproject=subproject)
+ self.vars = build.EnvironmentVariables()
self.methods.update({'set': self.set_method,
'append': self.append_method,
'prepend': self.prepend_method,
@@ -232,18 +258,18 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
def __repr__(self) -> str:
repr_str = "<{0}: {1}>"
- return repr_str.format(self.__class__.__name__, self.held_object.envvars)
+ return repr_str.format(self.__class__.__name__, self.vars.envvars)
def unpack_separator(self, kwargs: T.Dict[str, T.Any]) -> str:
separator = kwargs.get('separator', os.pathsep)
if not isinstance(separator, str):
- raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
+ raise InterpreterException("EnvironmentVariablesObject methods 'separator'"
" argument needs to be a string.")
return separator
def warn_if_has_name(self, name: str) -> None:
# Multiple append/prepend operations was not supported until 0.58.0.
- if self.held_object.has_name(name):
+ if self.vars.has_name(name):
m = f'Overriding previous value of environment variable {name!r} with a new one'
FeatureNew('0.58.0', m).use(self.subproject)
@@ -253,7 +279,7 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: T.Dict[str, T.Any]) -> None:
name, values = args
separator = self.unpack_separator(kwargs)
- self.held_object.set(name, values, separator)
+ self.vars.set(name, values, separator)
@stringArgs
@permittedKwargs({'separator'})
@@ -262,7 +288,7 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
name, values = args
separator = self.unpack_separator(kwargs)
self.warn_if_has_name(name)
- self.held_object.append(name, values, separator)
+ self.vars.append(name, values, separator)
@stringArgs
@permittedKwargs({'separator'})
@@ -271,13 +297,14 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder[build.En
name, values = args
separator = self.unpack_separator(kwargs)
self.warn_if_has_name(name)
- self.held_object.prepend(name, values, separator)
+ self.vars.prepend(name, values, separator)
-class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder[build.ConfigurationData]):
- def __init__(self, subproject: str, initial_values=None):
+class ConfigurationDataObject(MutableInterpreterObject, MesonInterpreterObject):
+ def __init__(self, subproject: str, initial_values: T.Optional[T.Dict[str, T.Any]] = None) -> None:
self.used = False # These objects become immutable after use in configure_file.
- super().__init__(build.ConfigurationData(), subproject=subproject)
+ super().__init__(subproject=subproject)
+ self.conf_data = build.ConfigurationData()
self.methods.update({'set': self.set_method,
'set10': self.set10_method,
'set_quoted': self.set_quoted_method,
@@ -291,15 +318,15 @@ class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder[build.Confi
for k, v in initial_values.items():
self.set_method([k, v], {})
elif initial_values:
- raise AssertionError('Unsupported ConfigurationDataHolder initial_values')
+ raise AssertionError('Unsupported ConfigurationDataObject initial_values')
- def is_used(self):
+ def is_used(self) -> bool:
return self.used
- def mark_used(self):
+ def mark_used(self) -> None:
self.used = True
- def validate_args(self, args, kwargs):
+ def validate_args(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Tuple[str, T.Union[str, int, bool], T.Optional[str]]:
if len(args) == 1 and isinstance(args[0], list) and len(args[0]) == 2:
mlog.deprecation('Passing a list as the single argument to '
'configuration_data.set is deprecated. This will '
@@ -323,85 +350,101 @@ class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder[build.Confi
if desc is not None and not isinstance(desc, str):
raise InterpreterException('Description must be a string.')
- return name, val, desc
+ # TODO: Remove the cast once we get rid of the deprecation
+ return name, T.cast(T.Union[str, bool, int], val), desc
@noArgsFlattening
- def set_method(self, args, kwargs):
+ def set_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> None:
(name, val, desc) = self.validate_args(args, kwargs)
- self.held_object.values[name] = (val, desc)
+ self.conf_data.values[name] = (val, desc)
- def set_quoted_method(self, args, kwargs):
+ def set_quoted_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> None:
(name, val, desc) = self.validate_args(args, kwargs)
if not isinstance(val, str):
raise InterpreterException("Second argument to set_quoted must be a string.")
escaped_val = '\\"'.join(val.split('"'))
- self.held_object.values[name] = ('"' + escaped_val + '"', desc)
+ self.conf_data.values[name] = ('"' + escaped_val + '"', desc)
- def set10_method(self, args, kwargs):
+ def set10_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> None:
(name, val, desc) = self.validate_args(args, kwargs)
if val:
- self.held_object.values[name] = (1, desc)
+ self.conf_data.values[name] = (1, desc)
else:
- self.held_object.values[name] = (0, desc)
+ self.conf_data.values[name] = (0, desc)
- def has_method(self, args, kwargs):
- return args[0] in self.held_object.values
+ def has_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
+ return args[0] in self.conf_data.values
@FeatureNew('configuration_data.get()', '0.38.0')
@noArgsFlattening
- def get_method(self, args, kwargs):
+ def get_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int, bool]:
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Get method takes one or two arguments.')
+ if not isinstance(args[0], str):
+ raise InterpreterException('The variable name must be a string.')
name = args[0]
- if name in self.held_object:
- return self.held_object.get(name)[0]
+ if name in self.conf_data:
+ return self.conf_data.get(name)[0]
if len(args) > 1:
- return args[1]
+ # Assertion does not work because setting other values is still
+ # supported, but deprecated. Use T.cast in the meantime (even though
+ # this is a lie).
+ # TODO: Fix this once the deprecation is removed
+ # assert isinstance(args[1], (int, str, bool))
+ return T.cast(T.Union[str, int, bool], args[1])
raise InterpreterException('Entry %s not in configuration data.' % name)
@FeatureNew('configuration_data.get_unquoted()', '0.44.0')
- def get_unquoted_method(self, args, kwargs):
+ def get_unquoted_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int, bool]:
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Get method takes one or two arguments.')
+ if not isinstance(args[0], str):
+ raise InterpreterException('The variable name must be a string.')
name = args[0]
- if name in self.held_object:
- val = self.held_object.get(name)[0]
+ if name in self.conf_data:
+ val = self.conf_data.get(name)[0]
elif len(args) > 1:
+ assert isinstance(args[1], (str, int, bool))
val = args[1]
else:
raise InterpreterException('Entry %s not in configuration data.' % name)
- if val[0] == '"' and val[-1] == '"':
+ if isinstance(val, str) and val[0] == '"' and val[-1] == '"':
return val[1:-1]
return val
- def get(self, name):
- return self.held_object.values[name] # (val, desc)
+ def get(self, name: str) -> T.Tuple[T.Union[str, int, bool], T.Optional[str]]:
+ return self.conf_data.values[name]
@FeatureNew('configuration_data.keys()', '0.57.0')
@noPosargs
- def keys_method(self, args, kwargs):
+ def keys_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]:
return sorted(self.keys())
- def keys(self):
- return self.held_object.values.keys()
+ def keys(self) -> T.List[str]:
+ return list(self.conf_data.values.keys())
- def merge_from_method(self, args, kwargs):
+ def merge_from_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> None:
if len(args) != 1:
raise InterpreterException('Merge_from takes one positional argument.')
- from_object = args[0]
- if not isinstance(from_object, ConfigurationDataHolder):
+ from_object_holder = args[0]
+ if not isinstance(from_object_holder, ConfigurationDataObject):
raise InterpreterException('Merge_from argument must be a configuration data object.')
- from_object = from_object.held_object
+ from_object = from_object_holder.conf_data
for k, v in from_object.values.items():
- self.held_object.values[k] = v
+ self.conf_data.values[k] = v
+
-permitted_partial_dependency_kwargs = {
- 'compile_args', 'link_args', 'links', 'includes', 'sources'
-}
+_PARTIAL_DEP_KWARGS = [
+ KwargInfo('compile_args', bool, default=False),
+ KwargInfo('link_args', bool, default=False),
+ KwargInfo('links', bool, default=False),
+ KwargInfo('includes', bool, default=False),
+ KwargInfo('sources', bool, default=False),
+]
class DependencyHolder(ObjectHolder[Dependency]):
- def __init__(self, dep: Dependency, subproject: str):
- super().__init__(dep, subproject=subproject)
+ def __init__(self, dep: Dependency, interpreter: 'Interpreter'):
+ super().__init__(dep, interpreter)
self.methods.update({'found': self.found_method,
'type_name': self.type_name_method,
'version': self.version_method,
@@ -415,35 +458,35 @@ class DependencyHolder(ObjectHolder[Dependency]):
'as_link_whole': self.as_link_whole_method,
})
- def found(self):
+ def found(self) -> bool:
return self.found_method([], {})
@noPosargs
- @permittedKwargs({})
- def type_name_method(self, args, kwargs):
+ @noKwargs
+ def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.type_name
@noPosargs
- @permittedKwargs({})
- def found_method(self, args, kwargs):
+ @noKwargs
+ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
if self.held_object.type_name == 'internal':
return True
return self.held_object.found()
@noPosargs
- @permittedKwargs({})
- def version_method(self, args, kwargs):
+ @noKwargs
+ def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.get_version()
@noPosargs
- @permittedKwargs({})
- def name_method(self, args, kwargs):
+ @noKwargs
+ def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.get_name()
@FeatureDeprecated('Dependency.get_pkgconfig_variable', '0.56.0',
'use Dependency.get_variable(pkgconfig : ...) instead')
@permittedKwargs({'define_variable', 'default'})
- def pkgconfig_method(self, args, kwargs):
+ def pkgconfig_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
args = listify(args)
if len(args) != 1:
raise InterpreterException('get_pkgconfig_variable takes exactly one argument.')
@@ -455,8 +498,8 @@ class DependencyHolder(ObjectHolder[Dependency]):
@FeatureNew('dep.get_configtool_variable', '0.44.0')
@FeatureDeprecated('Dependency.get_configtool_variable', '0.56.0',
'use Dependency.get_variable(configtool : ...) instead')
- @permittedKwargs({})
- def configtool_method(self, args, kwargs):
+ @noKwargs
+ def configtool_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
args = listify(args)
if len(args) != 1:
raise InterpreterException('get_configtool_variable takes exactly one argument.')
@@ -467,16 +510,16 @@ class DependencyHolder(ObjectHolder[Dependency]):
@FeatureNew('dep.partial_dependency', '0.46.0')
@noPosargs
- @permittedKwargs(permitted_partial_dependency_kwargs)
- def partial_dependency_method(self, args, kwargs):
+ @typed_kwargs('dep.partial_dependency', *_PARTIAL_DEP_KWARGS)
+ def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency:
pdep = self.held_object.get_partial_dependency(**kwargs)
- return DependencyHolder(pdep, self.subproject)
+ return pdep
@FeatureNew('dep.get_variable', '0.51.0')
@typed_pos_args('dep.get_variable', optargs=[str])
@permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'internal', 'default_value', 'pkgconfig_define'})
@FeatureNewKwargs('dep.get_variable', '0.54.0', ['internal'])
- def variable_method(self, args: T.Tuple[T.Optional[str]], kwargs: T.Dict[str, T.Any]) -> str:
+ def variable_method(self, args: T.Tuple[T.Optional[str]], kwargs: T.Dict[str, T.Any]) -> T.Union[str, T.List[str]]:
default_varname = args[0]
if default_varname is not None:
FeatureNew('0.58.0', 'Positional argument to dep.get_variable()').use(self.subproject)
@@ -486,129 +529,102 @@ class DependencyHolder(ObjectHolder[Dependency]):
@FeatureNew('dep.include_type', '0.52.0')
@noPosargs
- @permittedKwargs({})
- def include_type_method(self, args, kwargs):
+ @noKwargs
+ def include_type_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.get_include_type()
@FeatureNew('dep.as_system', '0.52.0')
- @permittedKwargs({})
- def as_system_method(self, args, kwargs):
+ @noKwargs
+ def as_system_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> Dependency:
args = listify(args)
new_is_system = 'system'
if len(args) > 1:
raise InterpreterException('as_system takes only one optional value')
if len(args) == 1:
+ if not isinstance(args[0], str):
+ raise InterpreterException('as_system takes exactly one string parameter')
new_is_system = args[0]
new_dep = self.held_object.generate_system_dependency(new_is_system)
- return DependencyHolder(new_dep, self.subproject)
+ return new_dep
@FeatureNew('dep.as_link_whole', '0.56.0')
- @permittedKwargs({})
+ @noKwargs
@noPosargs
- def as_link_whole_method(self, args, kwargs):
+ def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> Dependency:
if not isinstance(self.held_object, InternalDependency):
raise InterpreterException('as_link_whole method is only supported on declare_dependency() objects')
new_dep = self.held_object.generate_link_whole_dependency()
- return DependencyHolder(new_dep, self.subproject)
+ return new_dep
class ExternalProgramHolder(ObjectHolder[ExternalProgram]):
- def __init__(self, ep: ExternalProgram, subproject: str, backend=None):
- super().__init__(ep, subproject=subproject)
- self.backend = backend
+ def __init__(self, ep: ExternalProgram, interpreter: 'Interpreter') -> None:
+ super().__init__(ep, interpreter)
self.methods.update({'found': self.found_method,
'path': self.path_method,
'full_path': self.full_path_method})
@noPosargs
- @permittedKwargs({})
- def found_method(self, args, kwargs):
+ @noKwargs
+ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.found()
@noPosargs
- @permittedKwargs({})
+ @noKwargs
@FeatureDeprecated('ExternalProgram.path', '0.55.0',
'use ExternalProgram.full_path() instead')
- def path_method(self, args, kwargs):
+ def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self._full_path()
@noPosargs
- @permittedKwargs({})
+ @noKwargs
@FeatureNew('ExternalProgram.full_path', '0.55.0')
- def full_path_method(self, args, kwargs):
+ def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self._full_path()
- def _full_path(self):
+ def _full_path(self) -> str:
exe = self.held_object
+ # TODO: How is this case even possible? Why can this hold a build.Executable?
if isinstance(exe, build.Executable):
- return self.backend.get_target_filename_abs(exe)
+ assert self.interpreter.backend is not None
+ return self.interpreter.backend.get_target_filename_abs(exe)
+ if not self.found():
+ raise InterpreterException('Unable to get the path of a not-found external program')
+ path = exe.get_path()
+ assert path is not None
return exe.get_path()
- def found(self):
+ def found(self) -> bool:
return isinstance(self.held_object, build.Executable) or self.held_object.found()
- def get_command(self):
- return self.held_object.get_command()
-
- def get_name(self):
- exe = self.held_object
- if isinstance(exe, build.Executable):
- return exe.name
- return exe.get_name()
-
class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]):
- def __init__(self, el: ExternalLibrary, subproject: str):
- super().__init__(el, subproject=subproject)
+ def __init__(self, el: ExternalLibrary, interpreter: 'Interpreter'):
+ super().__init__(el, interpreter)
self.methods.update({'found': self.found_method,
'type_name': self.type_name_method,
'partial_dependency': self.partial_dependency_method,
})
- def found(self):
- return self.held_object.found()
-
@noPosargs
- @permittedKwargs({})
- def type_name_method(self, args, kwargs):
+ @noKwargs
+ def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.type_name
@noPosargs
- @permittedKwargs({})
- def found_method(self, args, kwargs):
- return self.found()
-
- def get_name(self):
- return self.held_object.name
-
- def get_compile_args(self):
- return self.held_object.get_compile_args()
-
- def get_link_args(self):
- return self.held_object.get_link_args()
-
- def get_exe_args(self):
- return self.held_object.get_exe_args()
+ @noKwargs
+ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
+ return self.held_object.found()
@FeatureNew('dep.partial_dependency', '0.46.0')
@noPosargs
- @permittedKwargs(permitted_partial_dependency_kwargs)
- def partial_dependency_method(self, args, kwargs):
+ @typed_kwargs('dep.partial_dependency', *_PARTIAL_DEP_KWARGS)
+ def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency:
pdep = self.held_object.get_partial_dependency(**kwargs)
- return DependencyHolder(pdep, self.subproject)
-
-
-class GeneratedListHolder(ObjectHolder[build.GeneratedList]):
- def __init__(self, arg1: 'build.GeneratedList'):
- super().__init__(arg1)
-
- def __repr__(self) -> str:
- r = '<{}: {!r}>'
- return r.format(self.__class__.__name__, self.held_object.get_outputs())
-
+ return pdep
# A machine that's statically known from the cross file
class MachineHolder(ObjectHolder['MachineInfo']):
- def __init__(self, machine_info: 'MachineInfo'):
- super().__init__(machine_info)
+ def __init__(self, machine_info: 'MachineInfo', interpreter: 'Interpreter'):
+ super().__init__(machine_info, interpreter)
self.methods.update({'system': self.system_method,
'cpu': self.cpu_method,
'cpu_family': self.cpu_family_method,
@@ -616,88 +632,45 @@ class MachineHolder(ObjectHolder['MachineInfo']):
})
@noPosargs
- @permittedKwargs({})
- def cpu_family_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str:
+ @noKwargs
+ def cpu_family_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.cpu_family
@noPosargs
- @permittedKwargs({})
- def cpu_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str:
+ @noKwargs
+ def cpu_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.cpu
@noPosargs
- @permittedKwargs({})
- def system_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str:
+ @noKwargs
+ def system_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.system
@noPosargs
- @permittedKwargs({})
- def endian_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str:
+ @noKwargs
+ def endian_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.held_object.endian
class IncludeDirsHolder(ObjectHolder[build.IncludeDirs]):
- def __init__(self, idobj: build.IncludeDirs):
- super().__init__(idobj)
+ pass
class FileHolder(ObjectHolder[mesonlib.File]):
- def __init__(self, fobj: mesonlib.File):
- super().__init__(fobj)
+ pass
class HeadersHolder(ObjectHolder[build.Headers]):
- def __init__(self, obj: build.Headers):
- super().__init__(obj)
-
- def set_install_subdir(self, subdir):
- self.held_object.install_subdir = subdir
-
- def get_install_subdir(self):
- return self.held_object.install_subdir
-
- def get_sources(self):
- return self.held_object.sources
-
- def get_custom_install_dir(self):
- return self.held_object.custom_install_dir
-
- def get_custom_install_mode(self):
- return self.held_object.custom_install_mode
+ pass
class DataHolder(ObjectHolder[build.Data]):
- def __init__(self, data: build.Data):
- super().__init__(data)
-
- def get_source_subdir(self):
- return self.held_object.source_subdir
-
- def get_sources(self):
- return self.held_object.sources
-
- def get_install_dir(self):
- return self.held_object.install_dir
+ pass
-class InstallDirHolder(ObjectHolder[build.IncludeDirs]):
- def __init__(self, obj: build.InstallDir):
- super().__init__(obj)
+class InstallDirHolder(ObjectHolder[build.InstallDir]):
+ pass
class ManHolder(ObjectHolder[build.Man]):
- def __init__(self, obj: build.Man):
- super().__init__(obj)
-
- def get_custom_install_dir(self) -> T.Optional[str]:
- return self.held_object.custom_install_dir
-
- def get_custom_install_mode(self) -> T.Optional[FileMode]:
- return self.held_object.custom_install_mode
-
- def locale(self) -> T.Optional[str]:
- return self.held_object.locale
-
- def get_sources(self) -> T.List[mesonlib.File]:
- return self.held_object.sources
+ pass
class GeneratedObjectsHolder(ObjectHolder[build.ExtractedObjects]):
- def __init__(self, held_object: build.ExtractedObjects):
- super().__init__(held_object)
+ pass
class Test(MesonInterpreterObject):
def __init__(self, name: str, project: str, suite: T.List[str], exe: build.Executable,
@@ -720,17 +693,27 @@ class Test(MesonInterpreterObject):
self.protocol = TestProtocol.from_str(protocol)
self.priority = priority
- def get_exe(self):
+ def get_exe(self) -> build.Executable:
return self.exe
- def get_name(self):
+ def get_name(self) -> str:
return self.name
-class SubprojectHolder(ObjectHolder[T.Optional['Interpreter']]):
+class NullSubprojectInterpreter(HoldableObject):
+ pass
- def __init__(self, subinterpreter: T.Optional['Interpreter'], subdir: str, warnings=0, disabled_feature=None,
- exception=None):
- super().__init__(subinterpreter)
+# TODO: This should really be an `ObjectHolder`, but the additional stuff in this
+# class prevents this. Thus, this class should be split into a pure
+# `ObjectHolder` and a class specifically for stroing in `Interpreter`.
+class SubprojectHolder(MesonInterpreterObject):
+
+ def __init__(self, subinterpreter: T.Union['Interpreter', NullSubprojectInterpreter],
+ subdir: str,
+ warnings: int = 0,
+ disabled_feature: T.Optional[str] = None,
+ exception: T.Optional[MesonException] = None) -> None:
+ super().__init__()
+ self.held_object = subinterpreter
self.warnings = warnings
self.disabled_feature = disabled_feature
self.exception = exception
@@ -740,20 +723,20 @@ class SubprojectHolder(ObjectHolder[T.Optional['Interpreter']]):
})
@noPosargs
- @permittedKwargs({})
- def found_method(self, args, kwargs):
+ @noKwargs
+ def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.found()
- def found(self):
- return self.held_object is not None
+ def found(self) -> bool:
+ return not isinstance(self.held_object, NullSubprojectInterpreter)
- @permittedKwargs({})
+ @noKwargs
@noArgsFlattening
@unholder_return
def get_variable_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]:
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Get_variable takes one or two arguments.')
- if not self.found():
+ if isinstance(self.held_object, NullSubprojectInterpreter): # == not self.found()
raise InterpreterException('Subproject "%s" disabled can\'t get_variable on it.' % (self.subdir))
varname = args[0]
if not isinstance(varname, str):
@@ -768,12 +751,8 @@ class SubprojectHolder(ObjectHolder[T.Optional['Interpreter']]):
raise InvalidArguments(f'Requested variable "{varname}" not found.')
-class ModuleObjectHolder(ObjectHolder['ModuleObject']):
- def __init__(self, modobj: 'ModuleObject', interpreter: 'Interpreter'):
- super().__init__(modobj)
- self.interpreter = interpreter
-
- def method_call(self, method_name, args, kwargs):
+class ModuleObjectHolder(ObjectHolder[ModuleObject]):
+ def method_call(self, method_name: str, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> TYPE_var:
modobj = self.held_object
method = modobj.methods.get(method_name)
if not method:
@@ -791,10 +770,10 @@ class ModuleObjectHolder(ObjectHolder['ModuleObject']):
if isinstance(ret, ModuleReturnValue):
self.interpreter.process_new_values(ret.new_objects)
ret = ret.return_value
- return self.interpreter.holderify(ret)
+ return ret
class MutableModuleObjectHolder(ModuleObjectHolder, MutableInterpreterObject):
- def __deepcopy__(self, memo):
+ def __deepcopy__(self, memo: T.Dict[int, T.Any]) -> 'MutableModuleObjectHolder':
# Deepcopy only held object, not interpreter
modobj = copy.deepcopy(self.held_object, memo)
return MutableModuleObjectHolder(modobj, self.interpreter)
@@ -916,7 +895,7 @@ class SharedModuleHolder(BuildTargetHolder[build.SharedModule]):
class JarHolder(BuildTargetHolder[build.Jar]):
pass
-class CustomTargetIndexHolder(TargetHolder[build.CustomTargetIndex]):
+class CustomTargetIndexHolder(ObjectHolder[build.CustomTargetIndex]):
def __init__(self, target: build.CustomTargetIndex, interp: 'Interpreter'):
super().__init__(target, interp)
self.methods.update({'full_path': self.full_path_method,
@@ -924,74 +903,69 @@ class CustomTargetIndexHolder(TargetHolder[build.CustomTargetIndex]):
@FeatureNew('custom_target[i].full_path', '0.54.0')
@noPosargs
- @permittedKwargs({})
- def full_path_method(self, args, kwargs):
+ @noKwargs
+ def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
+ assert self.interpreter.backend is not None
return self.interpreter.backend.get_target_filename_abs(self.held_object)
-class CustomTargetHolder(TargetHolder[build.CustomTarget]):
+class CustomTargetHolder(ObjectHolder[build.CustomTarget]):
def __init__(self, target: 'build.CustomTarget', interp: 'Interpreter'):
super().__init__(target, interp)
self.methods.update({'full_path': self.full_path_method,
'to_list': self.to_list_method,
})
- def __repr__(self):
+ def __repr__(self) -> str:
r = '<{} {}: {}>'
h = self.held_object
return r.format(self.__class__.__name__, h.get_id(), h.command)
@noPosargs
- @permittedKwargs({})
- def full_path_method(self, args, kwargs):
+ @noKwargs
+ def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str:
return self.interpreter.backend.get_target_filename_abs(self.held_object)
@FeatureNew('custom_target.to_list', '0.54.0')
@noPosargs
- @permittedKwargs({})
- def to_list_method(self, args, kwargs):
+ @noKwargs
+ def to_list_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[build.CustomTargetIndex]:
result = []
for i in self.held_object:
- result.append(CustomTargetIndexHolder(i, self.interpreter))
+ result.append(i)
return result
- def __getitem__(self, index):
- return CustomTargetIndexHolder(self.held_object[index], self.interpreter)
+ def __getitem__(self, index: int) -> build.CustomTargetIndex:
+ return self.held_object[index]
- def __setitem__(self, index, value): # lgtm[py/unexpected-raise-in-special-method]
+ def __setitem__(self, index: int, value: T.Any) -> None: # lgtm[py/unexpected-raise-in-special-method]
raise InterpreterException('Cannot set a member of a CustomTarget')
- def __delitem__(self, index): # lgtm[py/unexpected-raise-in-special-method]
+ def __delitem__(self, index: int) -> None: # lgtm[py/unexpected-raise-in-special-method]
raise InterpreterException('Cannot delete a member of a CustomTarget')
- def outdir_include(self):
- return IncludeDirsHolder(build.IncludeDirs('', [], False,
- [os.path.join('@BUILD_ROOT@', self.interpreter.backend.get_target_dir(self.held_object))]))
-
-class RunTargetHolder(TargetHolder):
- def __init__(self, target, interp):
- super().__init__(target, interp)
+class RunTargetHolder(ObjectHolder[build.RunTarget]):
+ pass
- def __repr__(self):
- r = '<{} {}: {}>'
- h = self.held_object
- return r.format(self.__class__.__name__, h.get_id(), h.command)
+class AliasTargetHolder(ObjectHolder[build.AliasTarget]):
+ pass
+class GeneratedListHolder(ObjectHolder[build.GeneratedList]):
+ pass
class GeneratorHolder(ObjectHolder[build.Generator]):
-
- def __init__(self, gen: 'build.Generator', interpreter: 'Interpreter'):
- self().__init__(self, gen, interpreter.subproject)
- self.interpreter = interpreter
+ def __init__(self, gen: build.Generator, interpreter: 'Interpreter'):
+ super().__init__(gen, interpreter)
self.methods.update({'process': self.process_method})
- @typed_pos_args('generator.process', min_varargs=1, varargs=(str, mesonlib.File, CustomTargetHolder, CustomTargetIndexHolder, GeneratedListHolder))
+ @typed_pos_args('generator.process', min_varargs=1, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList))
@typed_kwargs(
'generator.process',
KwargInfo('preserve_path_from', str, since='0.45.0'),
KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]),
)
- def process_method(self, args: T.Tuple[T.List[T.Union[str, mesonlib.File, CustomTargetHolder, CustomTargetIndexHolder, GeneratedListHolder]]],
- kwargs: 'kwargs.GeneratorProcess') -> GeneratedListHolder:
+ def process_method(self,
+ args: T.Tuple[T.List[T.Union[str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList]]],
+ kwargs: 'kwargs.GeneratorProcess') -> build.GeneratedList:
preserve_path_from = kwargs['preserve_path_from']
if preserve_path_from is not None:
preserve_path_from = os.path.normpath(preserve_path_from)
@@ -999,12 +973,12 @@ class GeneratorHolder(ObjectHolder[build.Generator]):
# This is a bit of a hack. Fix properly before merging.
raise InvalidArguments('Preserve_path_from must be an absolute path for now. Sorry.')
- if any(isinstance(a, (CustomTargetHolder, CustomTargetIndexHolder, GeneratedListHolder)) for a in args[0]):
+ if any(isinstance(a, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) for a in args[0]):
FeatureNew.single_use(
f'Calling generator.process with CustomTaget or Index of CustomTarget.',
'0.57.0', self.interpreter.subproject)
- gl = self.held_object.process_files(mesonlib.unholder(args[0]), self.interpreter,
+ gl = self.held_object.process_files(args[0], self.interpreter,
preserve_path_from, extra_args=kwargs['extra_args'])
- return GeneratedListHolder(gl)
+ return gl