Simplify get_callee_args

pull/9196/head
Xavier Claessens 3 years ago committed by Xavier Claessens
parent ab773ff9e8
commit f8cfd91d71
  1. 2
      mesonbuild/interpreterbase/__init__.py
  2. 52
      mesonbuild/interpreterbase/decorators.py
  3. 55
      mesonbuild/interpreterbase/helpers.py
  4. 12
      mesonbuild/interpreterbase/interpreterbase.py

@ -36,7 +36,6 @@ __all__ = [
'resolve_second_level_holders',
'noPosargs',
'builtinMethodNoKwargs',
'noKwargs',
'stringArgs',
'noArgsFlattening',
@ -89,7 +88,6 @@ from .baseobjects import (
from .decorators import (
noPosargs,
builtinMethodNoKwargs,
noKwargs,
stringArgs,
noArgsFlattening,

@ -13,43 +13,47 @@
# limitations under the License.
from .. import mesonlib, mlog
from .baseobjects import TV_func, TYPE_var
from .baseobjects import TV_func, TYPE_var, TYPE_kwargs
from .disabler import Disabler
from .exceptions import InterpreterException, InvalidArguments
from .helpers import check_stringlist, get_callee_args
from .helpers import check_stringlist
from ._unholder import _unholder
from functools import wraps
import abc
import itertools
import typing as T
if T.TYPE_CHECKING:
from .. import mparser
def get_callee_args(wrapped_args: T.Sequence[T.Any]) -> T.Tuple['mparser.BaseNode', T.List['TYPE_var'], 'TYPE_kwargs', str]:
# First argument could be InterpreterBase, InterpreterObject or ModuleObject.
# In the case of a ModuleObject it is the 2nd argument (ModuleState) that
# contains the needed information.
s = wrapped_args[0]
if not hasattr(s, 'current_node'):
s = wrapped_args[1]
node = s.current_node
subproject = s.subproject
args = kwargs = None
if len(wrapped_args) >= 3:
args = wrapped_args[-2]
kwargs = wrapped_args[-1]
return node, args, kwargs, subproject
def noPosargs(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
args = get_callee_args(wrapped_args)[2]
args = get_callee_args(wrapped_args)[1]
if args:
raise InvalidArguments('Function does not take positional arguments.')
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
def builtinMethodNoKwargs(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
node = wrapped_args[0].current_node
method_name = wrapped_args[2]
kwargs = wrapped_args[4]
if kwargs:
mlog.warning(f'Method {method_name!r} does not take keyword arguments.',
'This will become a hard error in the future',
location=node)
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
def noKwargs(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
kwargs = get_callee_args(wrapped_args)[3]
kwargs = get_callee_args(wrapped_args)[2]
if kwargs:
raise InvalidArguments('Function does not take keyword arguments.')
return f(*wrapped_args, **wrapped_kwargs)
@ -58,7 +62,7 @@ def noKwargs(f: TV_func) -> TV_func:
def stringArgs(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
args = get_callee_args(wrapped_args)[2]
args = get_callee_args(wrapped_args)[1]
assert(isinstance(args, list))
check_stringlist(args)
return f(*wrapped_args, **wrapped_kwargs)
@ -82,7 +86,7 @@ def permissive_unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
def disablerIfNotFound(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
kwargs = get_callee_args(wrapped_args)[3]
kwargs = get_callee_args(wrapped_args)[2]
disabler = kwargs.pop('disabler', False)
ret = f(*wrapped_args, **wrapped_kwargs)
if disabler and not ret.found():
@ -98,7 +102,7 @@ class permittedKwargs:
def __call__(self, f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
s, node, args, kwargs, _ = get_callee_args(wrapped_args)
node, args, kwargs, _ = get_callee_args(wrapped_args)
for k in kwargs:
if k not in self.permitted:
mlog.warning(f'''Passed invalid keyword argument "{k}".''', location=node)
@ -159,7 +163,7 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
@wraps(f)
def wrapper(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
args = get_callee_args(wrapped_args)[2]
args = get_callee_args(wrapped_args)[1]
# These are implementation programming errors, end users should never see them.
assert isinstance(args, list), args
@ -395,7 +399,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
@wraps(f)
def wrapper(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
_kwargs, subproject = get_callee_args(wrapped_args, want_subproject=True)[3:5]
_kwargs, subproject = get_callee_args(wrapped_args)[2:4]
# Cast here, as the convertor function may place something other than a TYPE_var in the kwargs
kwargs = T.cast(T.Dict[str, object], _kwargs)
@ -551,7 +555,7 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
def __call__(self, f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
subproject = get_callee_args(wrapped_args, want_subproject=True)[4]
subproject = get_callee_args(wrapped_args)[3]
if subproject is None:
raise AssertionError(f'{wrapped_args!r}')
self.use(subproject)
@ -638,7 +642,7 @@ class FeatureCheckKwargsBase(metaclass=abc.ABCMeta):
def __call__(self, f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
kwargs, subproject = get_callee_args(wrapped_args, want_subproject=True)[3:5]
kwargs, subproject = get_callee_args(wrapped_args)[2:4]
if subproject is None:
raise AssertionError(f'{wrapped_args!r}')
for arg in self.kwargs:

@ -61,58 +61,3 @@ def default_resolve_key(key: mparser.BaseNode) -> str:
if not isinstance(key, mparser.IdNode):
raise InterpreterException('Invalid kwargs format.')
return key.value
def get_callee_args(wrapped_args: T.Sequence[T.Any], want_subproject: bool = False) -> T.Tuple[T.Any, mparser.BaseNode, T.List['TYPE_var'], 'TYPE_kwargs', T.Optional[str]]:
s = wrapped_args[0]
n = len(wrapped_args)
# Raise an error if the codepaths are not there
subproject = None # type: T.Optional[str]
if want_subproject and n == 2:
if hasattr(s, 'subproject'):
# Interpreter base types have 2 args: self, node
node = wrapped_args[1]
# args and kwargs are inside the node
args = None
kwargs = None
subproject = s.subproject
elif hasattr(wrapped_args[1], 'subproject'):
# Module objects have 2 args: self, interpreter
node = wrapped_args[1].current_node
# args and kwargs are inside the node
args = None
kwargs = None
subproject = wrapped_args[1].subproject
else:
raise AssertionError(f'Unknown args: {wrapped_args!r}')
elif n == 3:
# Methods on objects (*Holder, MesonMain, etc) have 3 args: self, args, kwargs
node = s.current_node
args = wrapped_args[1]
kwargs = wrapped_args[2]
if want_subproject:
if hasattr(s, 'subproject'):
subproject = s.subproject
elif hasattr(s, 'interpreter'):
subproject = s.interpreter.subproject
elif n == 4:
# Meson functions have 4 args: self, node, args, kwargs
# Module functions have 4 args: self, state, args, kwargs
from .interpreterbase import InterpreterBase # TODO: refactor to avoid this import
if isinstance(s, InterpreterBase):
node = wrapped_args[1]
else:
node = wrapped_args[1].current_node
args = wrapped_args[2]
kwargs = wrapped_args[3]
if want_subproject:
if isinstance(s, InterpreterBase):
subproject = s.subproject
else:
subproject = wrapped_args[1].subproject
else:
raise AssertionError(f'Unknown args: {wrapped_args!r}')
# Sometimes interpreter methods are called internally with None instead of
# empty list/dict
args = args if args is not None else []
kwargs = kwargs if kwargs is not None else {}
return s, node, args, kwargs, subproject

@ -40,7 +40,7 @@ from .exceptions import (
BreakRequest
)
from .decorators import FeatureNew, builtinMethodNoKwargs
from .decorators import FeatureNew, noKwargs
from .disabler import Disabler, is_disabled
from .helpers import check_stringlist, default_resolve_key, flatten, resolve_second_level_holders
from ._unholder import _unholder
@ -644,7 +644,7 @@ The result of this is undefined and will become a hard error in a future Meson r
kwargs: T.Dict[str, T.Union[TYPE_var, InterpreterObject]]) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]:
return [_unholder(x) for x in args], {k: _unholder(v) for k, v in kwargs.items()}
@builtinMethodNoKwargs
@noKwargs
def bool_method_call(self, obj: bool, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int]:
if method_name == 'to_string':
if not posargs:
@ -667,7 +667,7 @@ The result of this is undefined and will become a hard error in a future Meson r
else:
raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)
@builtinMethodNoKwargs
@noKwargs
def int_method_call(self, obj: int, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, bool]:
if method_name == 'is_even':
if not posargs:
@ -698,7 +698,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return s
return None
@builtinMethodNoKwargs
@noKwargs
def string_method_call(self, obj: str, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int, bool, T.List[str]]:
if method_name == 'strip':
s1 = self._get_one_string_posarg(posargs, 'strip')
@ -791,7 +791,7 @@ The result of this is undefined and will become a hard error in a future Meson r
def unknown_function_called(self, func_name: str) -> None:
raise InvalidCode('Unknown function "%s".' % func_name)
@builtinMethodNoKwargs
@noKwargs
def array_method_call(self,
obj: T.List[T.Union[TYPE_elementary, InterpreterObject]],
method_name: str,
@ -835,7 +835,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return obj[index]
raise InterpreterException(f'Arrays do not have a method called {method_name!r}.')
@builtinMethodNoKwargs
@noKwargs
def dict_method_call(self,
obj: T.Dict[str, T.Union[TYPE_elementary, InterpreterObject]],
method_name: str,

Loading…
Cancel
Save