From 7fb746e6e5c56b82e6d39523521238a7f2f81b82 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Sun, 18 Apr 2021 04:09:43 -0400 Subject: [PATCH] [commands] Refactor evaluation functions to allow passing in localns --- discord/ext/commands/core.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py index acd7898fd..22f1b234e 100644 --- a/discord/ext/commands/core.py +++ b/discord/ext/commands/core.py @@ -28,6 +28,7 @@ from typing import ( ForwardRef, Iterable, Literal, + Optional, Tuple, Union, ) @@ -89,7 +90,14 @@ def normalise_optional_params(parameters: Iterable[Any]) -> Tuple[Any, ...]: none_cls = type(None) return tuple(p for p in parameters if p is not none_cls) + (none_cls,) -def _evaluate_annotation(tp: Any, globals: Dict[str, Any], cache: Dict[str, Any] = {}, *, implicit_str=True): +def _evaluate_annotation( + tp: Any, + globals: Dict[str, Any], + locals: Dict[str, Any], + cache: Dict[str, Any], + *, + implicit_str: bool = True, +): if isinstance(tp, ForwardRef): tp = tp.__forward_arg__ # ForwardRefs always evaluate their internals @@ -98,9 +106,9 @@ def _evaluate_annotation(tp: Any, globals: Dict[str, Any], cache: Dict[str, Any] if implicit_str and isinstance(tp, str): if tp in cache: return cache[tp] - evaluated = eval(tp, globals) + evaluated = eval(tp, globals, locals) cache[tp] = evaluated - return _evaluate_annotation(evaluated, globals, cache) + return _evaluate_annotation(evaluated, globals, locals, cache) if hasattr(tp, '__args__'): implicit_str = True @@ -108,7 +116,7 @@ def _evaluate_annotation(tp: Any, globals: Dict[str, Any], cache: Dict[str, Any] if not hasattr(tp, '__origin__'): if PY_310 and tp.__class__ is types.Union: converted = Union[args] # type: ignore - return _evaluate_annotation(converted, globals, cache) + return _evaluate_annotation(converted, globals, locals, cache) return tp if tp.__origin__ is Union: @@ -123,7 +131,7 @@ def _evaluate_annotation(tp: Any, globals: Dict[str, Any], cache: Dict[str, Any] implicit_str = False evaluated_args = tuple( - _evaluate_annotation(arg, globals, cache, implicit_str=implicit_str) for arg in args + _evaluate_annotation(arg, globals, locals, cache, implicit_str=implicit_str) for arg in args ) if evaluated_args == args: @@ -136,12 +144,21 @@ def _evaluate_annotation(tp: Any, globals: Dict[str, Any], cache: Dict[str, Any] return tp -def resolve_annotation(annotation: Any, globalns: Dict[str, Any], cache: Dict[str, Any] = {}) -> Any: +def resolve_annotation( + annotation: Any, + globalns: Dict[str, Any], + localns: Optional[Dict[str, Any]], + cache: Optional[Dict[str, Any]], +) -> Any: if annotation is None: return type(None) if isinstance(annotation, str): annotation = ForwardRef(annotation) - return _evaluate_annotation(annotation, globalns, cache) + + locals = globalns if localns is None else localns + if cache is None: + cache = {} + return _evaluate_annotation(annotation, globalns, locals, cache) def get_signature_parameters(function: types.FunctionType) -> Dict[str, inspect.Parameter]: globalns = function.__globals__ @@ -157,7 +174,7 @@ def get_signature_parameters(function: types.FunctionType) -> Dict[str, inspect. params[name] = parameter.replace(annotation=type(None)) continue - annotation = _evaluate_annotation(annotation, globalns, cache) + annotation = _evaluate_annotation(annotation, globalns, globalns, cache) if annotation is converters.Greedy: raise TypeError('Unparameterized Greedy[...] is disallowed in signature.')