from keyword import iskeyword
from operator import attrgetter
from collections import namedtuple, OrderedDict
+from typing import _rewrite_star_unpack
from weakref import ref as make_weakref
# Create constants for the compiler flags in Include/code.h
if type_params := getattr(obj, "__type_params__", ()):
locals = {param.__name__: param for param in type_params} | locals
- return_value = {key:
- value if not isinstance(value, str) else eval(value, globals, locals)
+ return_value = {
+ key: value if not isinstance(value, str)
+ else eval(_rewrite_star_unpack(value), globals, locals)
for key, value in ann.items() }
return return_value
self.assertEqual(inspect.get_annotations(isa2, eval_str=True), {})
self.assertEqual(inspect.get_annotations(isa2, eval_str=False), {})
+ def f(*args: *tuple[int, ...]): ...
+ self.assertEqual(inspect.get_annotations(f, eval_str=True),
+ {'args': (*tuple[int, ...],)[0]})
+
def times_three(fn):
@functools.wraps(fn)
def wrapper(a, b):
if not isinstance(arg, str):
raise TypeError(f"Forward reference must be a string -- got {arg!r}")
- # If we do `def f(*args: *Ts)`, then we'll have `arg = '*Ts'`.
- # Unfortunately, this isn't a valid expression on its own, so we
- # do the unpacking manually.
- if arg.startswith('*'):
- arg_to_compile = f'({arg},)[0]' # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
- else:
- arg_to_compile = arg
try:
- code = compile(arg_to_compile, '<string>', 'eval')
+ code = compile(_rewrite_star_unpack(arg), '<string>', 'eval')
except SyntaxError:
raise SyntaxError(f"Forward reference must be an expression -- got {arg!r}")
return f'ForwardRef({self.__forward_arg__!r}{module_repr})'
+def _rewrite_star_unpack(arg):
+ """If the given argument annotation expression is a star unpack e.g. `'*Ts'`
+ rewrite it to a valid expression.
+ """
+ if arg.startswith("*"):
+ return f"({arg},)[0]" # E.g. (*Ts,)[0] or (*tuple[int, int],)[0]
+ else:
+ return arg
+
+
def _is_unpacked_typevartuple(x: Any) -> bool:
return ((not isinstance(x, type)) and
getattr(x, '__typing_is_unpacked_typevartuple__', False))