From aee2325335878b630bcef252e0dcf9507bc30e63 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 18 Aug 2021 11:07:59 -0700 Subject: build: Fully annotate EnvironmentVariables --- mesonbuild/build.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 0143022..62f6f6e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -427,11 +427,11 @@ class ExtractedObjects(HoldableObject): class EnvironmentVariables(HoldableObject): def __init__(self) -> None: - self.envvars = [] + self.envvars: T.List[T.Tuple[T.Callable[[T.Dict[str, str], str, T.List[str], str], str], str, T.List[str], str]] = [] # The set of all env vars we have operations for. Only used for self.has_name() - self.varnames = set() + self.varnames: T.Set[str] = set() - def __repr__(self): + def __repr__(self) -> str: repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.envvars) @@ -450,14 +450,17 @@ class EnvironmentVariables(HoldableObject): self.varnames.add(name) self.envvars.append((self._prepend, name, values, separator)) - def _set(self, env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: + @staticmethod + def _set(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: return separator.join(values) - def _append(self, env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: + @staticmethod + def _append(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: curr = env.get(name) return separator.join(values if curr is None else [curr] + values) - def _prepend(self, env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: + @staticmethod + def _prepend(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str: curr = env.get(name) return separator.join(values if curr is None else values + [curr]) -- cgit v1.1 From 8c90140f2bcc1025cc37c5489ef3f60c469009a5 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 10 Aug 2021 15:00:05 -0700 Subject: build: add ability to set initial value of EnvironmentVariables Which is useful as we move the validation out of the the EnvironmentVariablesObject --- mesonbuild/build.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 62f6f6e..bc4065b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -426,11 +426,15 @@ class ExtractedObjects(HoldableObject): ] class EnvironmentVariables(HoldableObject): - def __init__(self) -> None: + def __init__(self, values: T.Optional[T.Dict[str, str]] = None) -> None: self.envvars: T.List[T.Tuple[T.Callable[[T.Dict[str, str], str, T.List[str], str], str], str, T.List[str], str]] = [] # The set of all env vars we have operations for. Only used for self.has_name() self.varnames: T.Set[str] = set() + if values: + for name, value in values.items(): + self.set(name, [value]) + def __repr__(self) -> str: repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.envvars) -- cgit v1.1 From ec59cbdf6128fd65b46f6d1837145a124ef0bba9 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 10 Aug 2021 14:45:17 -0700 Subject: interpreter: move 'env' to type_checking --- mesonbuild/interpreter/interpreter.py | 3 ++- mesonbuild/interpreter/type_checking.py | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index d104f74..ec5c75c 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -51,6 +51,7 @@ from .interpreterobjects import ( NullSubprojectInterpreter, ) from .type_checking import ( + ENV_KW, INSTALL_MODE_KW, LANGUAGE_KW, NATIVE_KW, @@ -189,7 +190,7 @@ TEST_KWARGS: T.List[KwargInfo] = [ listify=True, default=[], since='0.46.0'), KwargInfo('priority', int, default=0, since='0.52.0'), # TODO: env needs reworks of the way the environment variable holder itself works probably - KwargInfo('env', (EnvironmentVariablesObject, list, dict, str, NoneType)), + ENV_KW, KwargInfo('suite', ContainerTypeInfo(list, str), listify=True, default=['']), # yes, a list of empty string ] diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index d4e178d..3d43b21 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -6,6 +6,7 @@ import typing as T from .. import compilers +from ..build import EnvironmentVariables from ..coredata import UserFeatureOption from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo from ..mesonlib import FileMode, MachineChoice @@ -126,3 +127,8 @@ REQUIRED_KW: KwargInfo[T.Union[bool, UserFeatureOption]] = KwargInfo( default=True, # TODO: extract_required_kwarg could be converted to a convertor ) + +ENV_KW: KwargInfo[T.Union[EnvironmentVariables, T.List, T.Dict, str, NoneType]] = KwargInfo( + 'env', + (EnvironmentVariables, list, dict, str), +) -- cgit v1.1 From 75d2ec9a40c2712d99f23a46462c0ef22246e581 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 10 Aug 2021 14:45:49 -0700 Subject: interpreter/type_checking: add a validator to env Let's start moving the validation out of the interpreter object --- mesonbuild/interpreter/type_checking.py | 36 +++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 3d43b21..0ebb8cd 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -8,8 +8,9 @@ import typing as T from .. import compilers from ..build import EnvironmentVariables from ..coredata import UserFeatureOption +from ..interpreterbase import TYPE_var from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo -from ..mesonlib import FileMode, MachineChoice +from ..mesonlib import FileMode, MachineChoice, listify # Helper definition for type checks that are `Optional[T]` NoneType: T.Type[None] = type(None) @@ -128,7 +129,38 @@ REQUIRED_KW: KwargInfo[T.Union[bool, UserFeatureOption]] = KwargInfo( # TODO: extract_required_kwarg could be converted to a convertor ) -ENV_KW: KwargInfo[T.Union[EnvironmentVariables, T.List, T.Dict, str, NoneType]] = KwargInfo( +def _env_validator(value: T.Union[EnvironmentVariables, T.List['TYPE_var'], T.Dict[str, 'TYPE_var'], str, None]) -> T.Optional[str]: + def _splitter(v: str) -> T.Optional[str]: + split = v.split('=', 1) + if len(split) == 1: + return f'"{v}" is not two string values separated by an "="' + # We have to cast here, assert isn't good enough to narrow from + # Tuple[str, ...] -> Tuple[str, str] + return None + + if isinstance(value, str): + v = _splitter(value) + if v is not None: + return v + elif isinstance(value, list): + for i in listify(value): + if not isinstance(i, str): + return f"All array elements must be a string, not {i!r}" + v = _splitter(i) + if v is not None: + return v + elif isinstance(value, dict): + # We don't need to spilt here, just do the type checking + for k, dv in value.items(): + if not isinstance(dv, str): + return f"Dictionary element {k} must be a string not {dv!r}" + # We know that otherwise we have an EnvironmentVariables object or None, and + # we're okay at this point + return None + + +ENV_KW: KwargInfo[T.Union[EnvironmentVariables, T.List, T.Dict, str, None]] = KwargInfo( 'env', (EnvironmentVariables, list, dict, str), + validator=_env_validator, ) -- cgit v1.1 From d87b3c7b3f114446792ca5fb5867f538808caeb1 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 10 Aug 2021 15:06:44 -0700 Subject: interpreter/type_checking: Add convertor to env keyword argument This does the conversion to an EnvironmentVariables, so that the receiver always gets a EnvironmentVariables object and not a list, dict, or string --- mesonbuild/interpreter/type_checking.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 0ebb8cd..4eed965 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -134,8 +134,6 @@ def _env_validator(value: T.Union[EnvironmentVariables, T.List['TYPE_var'], T.Di split = v.split('=', 1) if len(split) == 1: return f'"{v}" is not two string values separated by an "="' - # We have to cast here, assert isn't good enough to narrow from - # Tuple[str, ...] -> Tuple[str, str] return None if isinstance(value, str): @@ -159,8 +157,23 @@ def _env_validator(value: T.Union[EnvironmentVariables, T.List['TYPE_var'], T.Di return None +def _env_convertor(value: T.Union[EnvironmentVariables, T.List[str], T.Dict[str, str], str, None]) -> EnvironmentVariables: + def splitter(input: str) -> T.Tuple[str, str]: + a, b = input.split('=', 1) + return (a.strip(), b.strip()) + + if isinstance(value, (str, list)): + return EnvironmentVariables(dict(splitter(v) for v in listify(value))) + elif isinstance(value, dict): + return EnvironmentVariables(value) + elif value is None: + return EnvironmentVariables() + return value + + ENV_KW: KwargInfo[T.Union[EnvironmentVariables, T.List, T.Dict, str, None]] = KwargInfo( 'env', - (EnvironmentVariables, list, dict, str), + (EnvironmentVariables, list, dict, str, NoneType), validator=_env_validator, + convertor=_env_convertor, ) -- cgit v1.1 From 940fc372dbe8a7e28a4868be51b15c85a0630365 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 10 Aug 2021 15:18:28 -0700 Subject: interperter/kwargs: narrow type checking Since the convertor has been added env, we are now only going to be an EnvironmentVariables object, nothing else. --- mesonbuild/interpreter/kwargs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 77826cb..9eb02be 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -39,7 +39,7 @@ class BaseTest(TypedDict): workdir: T.Optional[str] depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]] priority: int - env: T.Union[EnvironmentVariablesObject, T.List[str], T.Dict[str, str], str] + env: EnvironmentVariablesObject suite: T.List[str] -- cgit v1.1 From d6a1f85248e80650d628d969212a06992d1b8f4c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 18 Aug 2021 11:14:10 -0700 Subject: Allow EnvironmentVariablesObject to be passed an EnvironmentVariables instance --- mesonbuild/interpreter/interpreterobjects.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index d524059..c614f09 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -241,7 +241,9 @@ class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObjec 'append': self.append_method, 'prepend': self.prepend_method, }) - if isinstance(initial_values, dict): + if isinstance(initial_values, build.EnvironmentVariables): + self.vars = initial_values + elif isinstance(initial_values, dict): for k, v in initial_values.items(): self.set_method([k, v], {}) elif initial_values is not None: -- cgit v1.1 From 3731e1d8f38be0ba3360d6badae789b1078e5b5a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 18 Aug 2021 14:13:17 -0700 Subject: make EnvironmentVariablesObject a proper holder Currently, EnvironmentVariablesObject is a strange holder-that's-not-a-holder. This has implicaitons for things that expect to get an EnvironmentVariables object, as we can't automatically unholder it, and instead have to to manually do so. Now we can automatically unholder it, which makes everything much nicer. --- mesonbuild/interpreter/interpreter.py | 43 ++++++++++++--------------- mesonbuild/interpreter/interpreterobjects.py | 44 +++++++++------------------- mesonbuild/interpreter/kwargs.py | 3 +- mesonbuild/interpreter/mesonmain.py | 15 +++++----- 4 files changed, 42 insertions(+), 63 deletions(-) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index ec5c75c..d640e65 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -42,7 +42,6 @@ from .mesonmain import MesonMain from .dependencyfallbacks import DependencyFallbacksHolder from .interpreterobjects import ( SubprojectHolder, - EnvironmentVariablesObject, ConfigurationDataObject, Test, RunProcess, @@ -396,6 +395,7 @@ class Interpreter(InterpreterBase, HoldableObject): build.Data: OBJ.DataHolder, build.InstallDir: OBJ.InstallDirHolder, build.IncludeDirs: OBJ.IncludeDirsHolder, + build.EnvironmentVariables: OBJ.EnvironmentVariablesObject, compilers.RunResult: compilerOBJ.TryRunResultHolder, dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder, coredata.UserFeatureOption: OBJ.FeatureOptionHolder, @@ -1723,19 +1723,14 @@ This will become a hard error in the future.''' % kwargs['input'], location=self kwargs: 'kwargs.FuncTest') -> None: self.add_test(node, args, kwargs, True) - def unpack_env_kwarg(self, kwargs: T.Union[EnvironmentVariablesObject, T.Dict[str, str], T.List[str]]) -> build.EnvironmentVariables: - envlist = kwargs.get('env', EnvironmentVariablesObject()) - if isinstance(envlist, EnvironmentVariablesObject): - env = envlist.vars - elif isinstance(envlist, dict): - FeatureNew.single_use('environment dictionary', '0.52.0', self.subproject) - env = EnvironmentVariablesObject(envlist) - env = env.vars - else: - # Convert from array to environment object - env = EnvironmentVariablesObject(envlist) - env = env.vars - return env + def unpack_env_kwarg(self, kwargs: T.Union[build.EnvironmentVariables, T.Dict[str, 'TYPE_var'], T.List['TYPE_var'], str]) -> build.EnvironmentVariables: + envlist = kwargs.get('env') + if envlist is None: + return build.EnvironmentVariables() + msg = ENV_KW.validator(envlist) + if msg: + raise InvalidArguments(f'"env": {msg}') + return ENV_KW.convertor(envlist) def make_test(self, node: mparser.BaseNode, args: T.Tuple[str, T.Union[build.Executable, build.Jar, ExternalProgram, mesonlib.File]], @@ -2361,17 +2356,17 @@ This will become a hard error in the future.''' % kwargs['input'], location=self @noKwargs @noArgsFlattening - def func_environment(self, node, args, kwargs): - if len(args) > 1: - raise InterpreterException('environment takes only one optional positional arguments') - elif len(args) == 1: + @typed_pos_args('environment', optargs=[(str, list, dict)]) + def func_environment(self, node: mparser.FunctionNode, args: T.Tuple[T.Union[None, str, T.List['TYPE_var'], T.Dict[str, 'TYPE_var']]], + kwargs: 'TYPE_kwargs') -> build.EnvironmentVariables: + init = args[0] + if init is not None: FeatureNew.single_use('environment positional arguments', '0.52.0', self.subproject) - initial_values = args[0] - if not isinstance(initial_values, dict) and not isinstance(initial_values, list): - raise InterpreterException('environment first argument must be a dictionary or a list') - else: - initial_values = {} - return EnvironmentVariablesObject(initial_values, self.subproject) + msg = ENV_KW.validator(init) + if msg: + raise InvalidArguments(f'"environment": {msg}') + return ENV_KW.convertor(init) + return build.EnvironmentVariables() @typed_pos_args('join_paths', varargs=str, min_varargs=1) @noKwargs diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index c614f09..53a0666 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -229,39 +229,19 @@ class RunProcess(MesonInterpreterObject): def stderr_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.stderr -# 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() + +class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], MutableInterpreterObject): + + def __init__(self, obj: build.EnvironmentVariables, interpreter: 'Interpreter'): + super().__init__(obj, interpreter) self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend': self.prepend_method, }) - if isinstance(initial_values, build.EnvironmentVariables): - self.vars = initial_values - elif isinstance(initial_values, dict): - for k, v in initial_values.items(): - self.set_method([k, v], {}) - elif initial_values is not None: - for e in mesonlib.listify(initial_values): - if not isinstance(e, str): - raise InterpreterException('Env var definition must be a list of strings.') - if '=' not in e: - raise InterpreterException('Env var definition must be of type key=val.') - (k, val) = e.split('=', 1) - k = k.strip() - val = val.strip() - if ' ' in k: - raise InterpreterException('Env var key must not have spaces in it.') - self.set_method([k, val], {}) def __repr__(self) -> str: repr_str = "<{0}: {1}>" - return repr_str.format(self.__class__.__name__, self.vars.envvars) + return repr_str.format(self.__class__.__name__, self.held_object.envvars) def unpack_separator(self, kwargs: T.Dict[str, T.Any]) -> str: separator = kwargs.get('separator', os.pathsep) @@ -270,9 +250,13 @@ class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObjec " argument needs to be a string.") return separator + def __deepcopy__(self, memo: T.Dict[str, object]) -> 'EnvironmentVariablesObject': + # Avoid trying to copy the intepreter + return EnvironmentVariablesObject(copy.deepcopy(self.held_object), self.interpreter) + def warn_if_has_name(self, name: str) -> None: # Multiple append/prepend operations was not supported until 0.58.0. - if self.vars.has_name(name): + if self.held_object.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) @@ -282,7 +266,7 @@ class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObjec 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.vars.set(name, values, separator) + self.held_object.set(name, values, separator) @stringArgs @permittedKwargs({'separator'}) @@ -291,7 +275,7 @@ class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObjec name, values = args separator = self.unpack_separator(kwargs) self.warn_if_has_name(name) - self.vars.append(name, values, separator) + self.held_object.append(name, values, separator) @stringArgs @permittedKwargs({'separator'}) @@ -300,7 +284,7 @@ class EnvironmentVariablesObject(MutableInterpreterObject, MesonInterpreterObjec name, values = args separator = self.unpack_separator(kwargs) self.warn_if_has_name(name) - self.vars.prepend(name, values, separator) + self.held_object.prepend(name, values, separator) class ConfigurationDataObject(MutableInterpreterObject, MesonInterpreterObject): diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 9eb02be..317f7c6 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -11,7 +11,6 @@ from typing_extensions import TypedDict, Literal from .. import build from .. import coredata from ..mesonlib import MachineChoice, File, FileMode, FileOrString -from .interpreterobjects import EnvironmentVariablesObject class FuncAddProjectArgs(TypedDict): @@ -39,7 +38,7 @@ class BaseTest(TypedDict): workdir: T.Optional[str] depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]] priority: int - env: EnvironmentVariablesObject + env: build.EnvironmentVariables suite: T.List[str] diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 5355c47..9c4f50a 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -7,13 +7,13 @@ from .. import mlog from ..mesonlib import MachineChoice, OptionKey from ..programs import OverrideProgram, ExternalProgram +from ..interpreter.type_checking import ENV_KW from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, typed_pos_args, permittedKwargs, noArgsFlattening, noPosargs, noKwargs, typed_kwargs, KwargInfo, MesonVersionString, InterpreterException) from .interpreterobjects import (ExecutableHolder, ExternalProgramHolder, - CustomTargetHolder, CustomTargetIndexHolder, - EnvironmentVariablesObject) + CustomTargetHolder, CustomTargetIndexHolder) from .type_checking import NATIVE_KW, NoneType import typing as T @@ -415,9 +415,10 @@ class MesonMain(MesonInterpreterObject): @FeatureNew('add_devenv', '0.58.0') @noKwargs - @typed_pos_args('add_devenv', (str, list, dict, EnvironmentVariablesObject)) - def add_devenv_method(self, args: T.Union[str, list, dict, EnvironmentVariablesObject], kwargs: T.Dict[str, T.Any]) -> None: + @typed_pos_args('add_devenv', (str, list, dict, build.EnvironmentVariables)) + def add_devenv_method(self, args: T.Tuple[T.Union[str, list, dict, build.EnvironmentVariables]], kwargs: T.Dict[str, T.Any]) -> None: env = args[0] - if isinstance(env, (str, list, dict)): - env = EnvironmentVariablesObject(env) - self.build.devenv.append(env.vars) + msg = ENV_KW.validator(env) + if msg: + raise build.InvalidArguments(f'"add_devenv": {msg}') + self.build.devenv.append(ENV_KW.convertor(env)) -- cgit v1.1 From 43f942be34433c0668572fa830bd56c61f612870 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 18 Aug 2021 14:17:40 -0700 Subject: interpreterobjects: Use typed_kwargs for EnvironmentVariablesObject --- mesonbuild/interpreter/interpreterobjects.py | 43 ++++++++++++---------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 53a0666..bc9d8e7 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -17,7 +17,7 @@ from ..interpreterbase import ( ContainerTypeInfo, KwargInfo, InterpreterObject, MesonInterpreterObject, ObjectHolder, MutableInterpreterObject, FeatureCheckBase, FeatureNewKwargs, FeatureNew, FeatureDeprecated, - typed_pos_args, typed_kwargs, stringArgs, permittedKwargs, + typed_pos_args, typed_kwargs, permittedKwargs, noArgsFlattening, noPosargs, noKwargs, permissive_unholder_return, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs, flatten, resolve_second_level_holders, InterpreterException, InvalidArguments, InvalidCode) from ..interpreter.type_checking import NoneType @@ -30,9 +30,14 @@ import typing as T if T.TYPE_CHECKING: from . import kwargs from .interpreter import Interpreter - from ..environment import Environment from ..envconfig import MachineInfo + from typing_extensions import TypedDict + + class EnvironmentSeparatorKW(TypedDict): + + separator: str + def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired', subproject: str, @@ -230,6 +235,9 @@ class RunProcess(MesonInterpreterObject): return self.stderr +_ENV_SEPARATOR_KW = KwargInfo('separator', str, default=os.pathsep) + + class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], MutableInterpreterObject): def __init__(self, obj: build.EnvironmentVariables, interpreter: 'Interpreter'): @@ -243,13 +251,6 @@ class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], Mutab repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.held_object.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("EnvironmentVariablesObject methods 'separator'" - " argument needs to be a string.") - return separator - def __deepcopy__(self, memo: T.Dict[str, object]) -> 'EnvironmentVariablesObject': # Avoid trying to copy the intepreter return EnvironmentVariablesObject(copy.deepcopy(self.held_object), self.interpreter) @@ -260,31 +261,25 @@ class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], Mutab m = f'Overriding previous value of environment variable {name!r} with a new one' FeatureNew('0.58.0', m).use(self.subproject) - @stringArgs - @permittedKwargs({'separator'}) @typed_pos_args('environment.set', str, varargs=str, min_varargs=1) - def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: T.Dict[str, T.Any]) -> None: + @typed_kwargs('environment.set', _ENV_SEPARATOR_KW) + def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args - separator = self.unpack_separator(kwargs) - self.held_object.set(name, values, separator) + self.held_object.set(name, values, kwargs['separator']) - @stringArgs - @permittedKwargs({'separator'}) @typed_pos_args('environment.append', str, varargs=str, min_varargs=1) - def append_method(self, args: T.Tuple[str, T.List[str]], kwargs: T.Dict[str, T.Any]) -> None: + @typed_kwargs('environment.append', _ENV_SEPARATOR_KW) + def append_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args - separator = self.unpack_separator(kwargs) self.warn_if_has_name(name) - self.held_object.append(name, values, separator) + self.held_object.append(name, values, kwargs['separator']) - @stringArgs - @permittedKwargs({'separator'}) @typed_pos_args('environment.prepend', str, varargs=str, min_varargs=1) - def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: T.Dict[str, T.Any]) -> None: + @typed_kwargs('environment.prepend', _ENV_SEPARATOR_KW) + def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args - separator = self.unpack_separator(kwargs) self.warn_if_has_name(name) - self.held_object.prepend(name, values, separator) + self.held_object.prepend(name, values, kwargs['separator']) class ConfigurationDataObject(MutableInterpreterObject, MesonInterpreterObject): -- cgit v1.1 From 81f5cee2188dcbd6b92e6b570c2c98961588a17a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 30 Aug 2021 17:58:16 -0700 Subject: interpreter: rename EnvironmentVariablesObject -> EnvironmentVariablesHolder This is more consistent with other Holder classes --- mesonbuild/interpreter/interpreter.py | 2 +- mesonbuild/interpreter/interpreterobjects.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index d640e65..c21b90e 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -395,7 +395,7 @@ class Interpreter(InterpreterBase, HoldableObject): build.Data: OBJ.DataHolder, build.InstallDir: OBJ.InstallDirHolder, build.IncludeDirs: OBJ.IncludeDirsHolder, - build.EnvironmentVariables: OBJ.EnvironmentVariablesObject, + build.EnvironmentVariables: OBJ.EnvironmentVariablesHolder, compilers.RunResult: compilerOBJ.TryRunResultHolder, dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder, coredata.UserFeatureOption: OBJ.FeatureOptionHolder, diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index bc9d8e7..262ff87 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -238,7 +238,7 @@ class RunProcess(MesonInterpreterObject): _ENV_SEPARATOR_KW = KwargInfo('separator', str, default=os.pathsep) -class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], MutableInterpreterObject): +class EnvironmentVariablesHolder(ObjectHolder[build.EnvironmentVariables], MutableInterpreterObject): def __init__(self, obj: build.EnvironmentVariables, interpreter: 'Interpreter'): super().__init__(obj, interpreter) @@ -251,9 +251,9 @@ class EnvironmentVariablesObject(ObjectHolder[build.EnvironmentVariables], Mutab repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.held_object.envvars) - def __deepcopy__(self, memo: T.Dict[str, object]) -> 'EnvironmentVariablesObject': + def __deepcopy__(self, memo: T.Dict[str, object]) -> 'EnvironmentVariablesHolder': # Avoid trying to copy the intepreter - return EnvironmentVariablesObject(copy.deepcopy(self.held_object), self.interpreter) + return EnvironmentVariablesHolder(copy.deepcopy(self.held_object), self.interpreter) def warn_if_has_name(self, name: str) -> None: # Multiple append/prepend operations was not supported until 0.58.0. -- cgit v1.1