diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/ast.py | 26 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 3 | ||||
-rw-r--r-- | Lib/keyword.py | 3 | ||||
-rw-r--r-- | Lib/opcode.py | 20 | ||||
-rw-r--r-- | Lib/test/support/__init__.py | 9 | ||||
-rw-r--r-- | Lib/test/test_ast.py | 125 | ||||
-rw-r--r-- | Lib/test/test_keyword.py | 3 | ||||
-rw-r--r-- | Lib/test/test_sys.py | 2 | ||||
-rw-r--r-- | Lib/test/test_type_aliases.py | 204 | ||||
-rw-r--r-- | Lib/test/test_type_params.py | 847 | ||||
-rw-r--r-- | Lib/test/test_typing.py | 54 | ||||
-rw-r--r-- | Lib/typing.py | 591 |
12 files changed, 1380 insertions, 507 deletions
@@ -1051,6 +1051,7 @@ class _Unparser(NodeVisitor): self.fill("@") self.traverse(deco) self.fill("class " + node.name) + self._typeparams_helper(node.typeparams) with self.delimit_if("(", ")", condition = node.bases or node.keywords): comma = False for e in node.bases: @@ -1082,6 +1083,7 @@ class _Unparser(NodeVisitor): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) + self._typeparams_helper(node.typeparams) with self.delimit("(", ")"): self.traverse(node.args) if node.returns: @@ -1090,6 +1092,30 @@ class _Unparser(NodeVisitor): with self.block(extra=self.get_type_comment(node)): self._write_docstring_and_traverse_body(node) + def _typeparams_helper(self, typeparams): + if typeparams is not None and len(typeparams) > 0: + with self.delimit("[", "]"): + self.interleave(lambda: self.write(", "), self.traverse, typeparams) + + def visit_TypeVar(self, node): + self.write(node.name) + if node.bound: + self.write(": ") + self.traverse(node.bound) + + def visit_TypeVarTuple(self, node): + self.write("*" + node.name) + + def visit_ParamSpec(self, node): + self.write("**" + node.name) + + def visit_TypeAlias(self, node): + self.fill("type ") + self.traverse(node.name) + self._typeparams_helper(node.typeparams) + self.write(" = ") + self.traverse(node.value) + def visit_For(self, node): self._for_helper("for ", node) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3ca5a1a..73ac440 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -444,6 +444,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization) # Python 3.12b1 3529 (Inline list/dict/set comprehensions) # Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches) +# Python 3.12b1 3531 (Add PEP 695 changes) # Python 3.13 will start with 3550 @@ -460,7 +461,7 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3530).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3531).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/keyword.py b/Lib/keyword.py index cc2b46b..e22c837 100644 --- a/Lib/keyword.py +++ b/Lib/keyword.py @@ -56,7 +56,8 @@ kwlist = [ softkwlist = [ '_', 'case', - 'match' + 'match', + 'type' ] iskeyword = frozenset(kwlist).__contains__ diff --git a/Lib/opcode.py b/Lib/opcode.py index 155466b..97d0a65 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -131,6 +131,7 @@ def_op('RETURN_GENERATOR', 75) def_op('RETURN_VALUE', 83) def_op('SETUP_ANNOTATIONS', 85) +def_op('LOAD_LOCALS', 87) def_op('POP_EXCEPT', 89) @@ -206,7 +207,6 @@ EXTENDED_ARG = 144 def_op('LIST_APPEND', 145) def_op('SET_ADD', 146) def_op('MAP_ADD', 147) -def_op('LOAD_CLASSDEREF', 148) hasfree.append(148) def_op('COPY_FREE_VARS', 149) def_op('YIELD_VALUE', 150) @@ -228,6 +228,10 @@ hasconst.append(172) def_op('CALL_INTRINSIC_1', 173) def_op('CALL_INTRINSIC_2', 174) +name_op('LOAD_FROM_DICT_OR_GLOBALS', 175) +def_op('LOAD_FROM_DICT_OR_DEREF', 176) +hasfree.append(176) + # Instrumented instructions MIN_INSTRUMENTED_OPCODE = 238 @@ -318,12 +322,20 @@ _intrinsic_1_descs = [ "INTRINSIC_ASYNC_GEN_WRAP", "INTRINSIC_UNARY_POSITIVE", "INTRINSIC_LIST_TO_TUPLE", + "INTRINSIC_TYPEVAR", + "INTRINSIC_PARAMSPEC", + "INTRINSIC_TYPEVARTUPLE", + "INTRINSIC_SUBSCRIPT_GENERIC", + "INTRINSIC_TYPEALIAS", ] _intrinsic_2_descs = [ - 'INTRINSIC_2_INVALID', - 'INTRINSIC_PREP_RERAISE_STAR', - ] + "INTRINSIC_2_INVALID", + "INTRINSIC_PREP_RERAISE_STAR", + "INTRINSIC_TYPEVAR_WITH_BOUND", + "INTRINSIC_TYPEVAR_WITH_CONSTRAINTS", + "INTRINSIC_SET_FUNCTION_TYPE_PARAMS", +] _specializations = { "BINARY_OP": [ diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d063837..d555c53f 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -12,6 +12,7 @@ import re import stat import sys import sysconfig +import textwrap import time import types import unittest @@ -619,6 +620,14 @@ def sortdict(dict): withcommas = ", ".join(reprpairs) return "{%s}" % withcommas + +def run_code(code: str) -> dict[str, object]: + """Run a piece of code after dedenting it, and return its global namespace.""" + ns = {} + exec(textwrap.dedent(code), ns) + return ns + + def check_syntax_error(testcase, statement, errtext='', *, lineno=None, offset=None): with testcase.assertRaisesRegex(SyntaxError, errtext) as cm: compile(statement, '<test string>', 'exec') diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 34808ed..cf128e1 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -181,7 +181,22 @@ exec_tests = [ "def f(a=1, /, b=2, *, c): pass", "def f(a=1, /, b=2, *, c=4, **kwargs): pass", "def f(a=1, /, b=2, *, c, **kwargs): pass", - + # Type aliases + "type X = int", + "type X[T] = int", + "type X[T, *Ts, **P] = (T, Ts, P)", + "type X[T: int, *Ts, **P] = (T, Ts, P)", + "type X[T: (int, str), *Ts, **P] = (T, Ts, P)", + # Generic classes + "class X[T]: pass", + "class X[T, *Ts, **P]: pass", + "class X[T: int, *Ts, **P]: pass", + "class X[T: (int, str), *Ts, **P]: pass", + # Generic functions + "def f[T](): pass", + "def f[T, *Ts, **P](): pass", + "def f[T: int, *Ts, **P](): pass", + "def f[T: (int, str), *Ts, **P](): pass", ] # These are compiled through "single" @@ -262,7 +277,6 @@ eval_tests = [ "()", # Combination "a.b.c.d(a.b[1:2])", - ] # TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension @@ -1013,6 +1027,18 @@ class AST_Tests(unittest.TestCase): with self.assertRaises(SyntaxError): ast.parse(code, feature_version=(3, 10)) + def test_type_params_feature_version(self): + samples = [ + "type X = int", + "class X[T]: pass", + "def f[T](): pass", + ] + for sample in samples: + with self.subTest(sample): + ast.parse(sample) + with self.assertRaises(SyntaxError): + ast.parse(sample, feature_version=(3, 11)) + def test_invalid_major_feature_version(self): with self.assertRaises(ValueError): ast.parse('pass', feature_version=(2, 7)) @@ -1557,16 +1583,16 @@ class ASTValidatorTests(unittest.TestCase): def test_funcdef(self): a = ast.arguments([], [], None, [], [], None, []) - f = ast.FunctionDef("x", a, [], [], None) + f = ast.FunctionDef("x", [], a, [], [], None) self.stmt(f, "empty body on FunctionDef") - f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())], + f = ast.FunctionDef("x", [], a, [ast.Pass()], [ast.Name("x", ast.Store())], None) self.stmt(f, "must have Load context") - f = ast.FunctionDef("x", a, [ast.Pass()], [], + f = ast.FunctionDef("x", [], a, [ast.Pass()], [], ast.Name("x", ast.Store())) self.stmt(f, "must have Load context") def fac(args): - return ast.FunctionDef("x", args, [ast.Pass()], [], None) + return ast.FunctionDef("x", [], args, [ast.Pass()], [], None) self._check_arguments(fac, self.stmt) def test_classdef(self): @@ -1579,7 +1605,7 @@ class ASTValidatorTests(unittest.TestCase): body = [ast.Pass()] if decorator_list is None: decorator_list = [] - return ast.ClassDef("myclass", bases, keywords, + return ast.ClassDef("myclass", [], bases, keywords, body, decorator_list) self.stmt(cls(bases=[ast.Name("x", ast.Store())]), "must have Load context") @@ -2869,23 +2895,23 @@ def main(): exec_results = [ ('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), ('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), -('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 23), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 27), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 45), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 14), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 23), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 21), 'f', [], ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 71), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 27), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('FunctionDef', (1, 0, 1, 45), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [], [('Pass', (1, 8, 1, 12))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 21), 'C', [], [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), ('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), ('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), ('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), @@ -2922,28 +2948,41 @@ exec_results = [ ('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), ('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), ('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), -('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), +('Module', [('FunctionDef', (4, 0, 4, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), ('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 39), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 20), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 30), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 42), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 40), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), +('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []), +('Module', [('ClassDef', (1, 0, 1, 16), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None)], [], [], [('Pass', (1, 12, 1, 16))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 26), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')], [], [], [('Pass', (1, 22, 1, 26))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 31), 'X', [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')], [], [], [('Pass', (1, 27, 1, 31))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 38), 'X', [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')], [], [], [('Pass', (1, 34, 1, 38))], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None)], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 31), 'f', [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 38), 'f', [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None)], []), ] single_results = [ ('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), diff --git a/Lib/test/test_keyword.py b/Lib/test/test_keyword.py index f329f88..858e5de 100644 --- a/Lib/test/test_keyword.py +++ b/Lib/test/test_keyword.py @@ -39,7 +39,8 @@ class Test_iskeyword(unittest.TestCase): self.assertIn("async", keyword.kwlist) self.assertIn("await", keyword.kwlist) - def test_match_and_case_are_soft_keywords(self): + def test_soft_keywords(self): + self.assertIn("type", keyword.softkwlist) self.assertIn("match", keyword.softkwlist) self.assertIn("case", keyword.softkwlist) self.assertIn("_", keyword.softkwlist) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index e1db450..d81501f 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1449,7 +1449,7 @@ class SizeofTest(unittest.TestCase): check(x, size('3Pi3c7P2ic??2P')) # function def func(): pass - check(func, size('14Pi')) + check(func, size('15Pi')) class c(): @staticmethod def foo(): diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py new file mode 100644 index 0000000..d2abb93 --- /dev/null +++ b/Lib/test/test_type_aliases.py @@ -0,0 +1,204 @@ +import types +import unittest +from test.support import check_syntax_error, run_code + +from typing import Callable, TypeAliasType, TypeVar, get_args + + +class TypeParamsInvalidTest(unittest.TestCase): + def test_name_collision_01(self): + check_syntax_error(self, """type TA1[A, **A] = None""", "duplicate type parameter 'A'") + + def test_name_non_collision_02(self): + ns = run_code("""type TA1[A] = lambda A: A""") + self.assertIsInstance(ns["TA1"], TypeAliasType) + self.assertTrue(callable(ns["TA1"].__value__)) + self.assertEqual("arg", ns["TA1"].__value__("arg")) + + def test_name_non_collision_03(self): + ns = run_code(""" + class Outer[A]: + type TA1[A] = None + """ + ) + outer_A, = ns["Outer"].__type_params__ + inner_A, = ns["Outer"].TA1.__type_params__ + self.assertIsNot(outer_A, inner_A) + + +class TypeParamsAccessTest(unittest.TestCase): + def test_alias_access_01(self): + ns = run_code("type TA1[A, B] = dict[A, B]") + alias = ns["TA1"] + self.assertIsInstance(alias, TypeAliasType) + self.assertEqual(alias.__type_params__, get_args(alias.__value__)) + + def test_alias_access_02(self): + ns = run_code(""" + type TA1[A, B] = TA1[A, B] | int + """ + ) + alias = ns["TA1"] + self.assertIsInstance(alias, TypeAliasType) + A, B = alias.__type_params__ + self.assertEqual(alias.__value__, alias[A, B] | int) + + def test_alias_access_03(self): + ns = run_code(""" + class Outer[A]: + def inner[B](self): + type TA1[C] = TA1[A, B] | int + return TA1 + """ + ) + cls = ns["Outer"] + A, = cls.__type_params__ + B, = cls.inner.__type_params__ + alias = cls.inner(None) + self.assertIsInstance(alias, TypeAliasType) + alias2 = cls.inner(None) + self.assertIsNot(alias, alias2) + self.assertEqual(len(alias.__type_params__), 1) + + self.assertEqual(alias.__value__, alias[A, B] | int) + + +class TypeParamsAliasValueTest(unittest.TestCase): + def test_alias_value_01(self): + type TA1 = int + + self.assertIsInstance(TA1, TypeAliasType) + self.assertEqual(TA1.__value__, int) + self.assertEqual(TA1.__parameters__, ()) + self.assertEqual(TA1.__type_params__, ()) + + type TA2 = TA1 | str + + self.assertIsInstance(TA2, TypeAliasType) + a, b = TA2.__value__.__args__ + self.assertEqual(a, TA1) + self.assertEqual(b, str) + self.assertEqual(TA2.__parameters__, ()) + self.assertEqual(TA2.__type_params__, ()) + + def test_alias_value_02(self): + class Parent[A]: + type TA1[B] = dict[A, B] + + self.assertIsInstance(Parent.TA1, TypeAliasType) + self.assertEqual(len(Parent.TA1.__parameters__), 1) + self.assertEqual(len(Parent.__parameters__), 1) + a, = Parent.__parameters__ + b, = Parent.TA1.__parameters__ + self.assertEqual(Parent.__type_params__, (a,)) + self.assertEqual(Parent.TA1.__type_params__, (b,)) + self.assertEqual(Parent.TA1.__value__, dict[a, b]) + + def test_alias_value_03(self): + def outer[A](): + type TA1[B] = dict[A, B] + return TA1 + + o = outer() + self.assertIsInstance(o, TypeAliasType) + self.assertEqual(len(o.__parameters__), 1) + self.assertEqual(len(outer.__type_params__), 1) + b = o.__parameters__[0] + self.assertEqual(o.__type_params__, (b,)) + + def test_alias_value_04(self): + def more_generic[T, *Ts, **P](): + type TA[T2, *Ts2, **P2] = tuple[Callable[P, tuple[T, *Ts]], Callable[P2, tuple[T2, *Ts2]]] + return TA + + alias = more_generic() + self.assertIsInstance(alias, TypeAliasType) + T2, Ts2, P2 = alias.__type_params__ + self.assertEqual(alias.__parameters__, (T2, *Ts2, P2)) + T, Ts, P = more_generic.__type_params__ + self.assertEqual(alias.__value__, tuple[Callable[P, tuple[T, *Ts]], Callable[P2, tuple[T2, *Ts2]]]) + + def test_subscripting(self): + type NonGeneric = int + type Generic[A] = dict[A, A] + type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + + with self.assertRaises(TypeError): + NonGeneric[int] + + specialized = Generic[int] + self.assertIsInstance(specialized, types.GenericAlias) + self.assertIs(specialized.__origin__, Generic) + self.assertEqual(specialized.__args__, (int,)) + + specialized2 = VeryGeneric[int, str, float, [bool, range]] + self.assertIsInstance(specialized2, types.GenericAlias) + self.assertIs(specialized2.__origin__, VeryGeneric) + self.assertEqual(specialized2.__args__, (int, str, float, [bool, range])) + + def test_repr(self): + type Simple = int + self.assertEqual(repr(Simple), "Simple") + + def test_recursive_repr(self): + type Recursive = Recursive + self.assertEqual(repr(Recursive), "Recursive") + + type X = list[Y] + type Y = list[X] + self.assertEqual(repr(X), "X") + + +class TypeAliasConstructorTest(unittest.TestCase): + def test_basic(self): + TA = TypeAliasType("TA", int) + self.assertEqual(TA.__name__, "TA") + self.assertIs(TA.__value__, int) + self.assertEqual(TA.__type_params__, ()) + + def test_generic(self): + T = TypeVar("T") + TA = TypeAliasType("TA", list[T], type_params=(T,)) + self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__value__, list[T]) + self.assertEqual(TA.__type_params__, (T,)) + + def test_keywords(self): + TA = TypeAliasType(name="TA", value=int) + self.assertEqual(TA.__name__, "TA") + self.assertIs(TA.__value__, int) + self.assertEqual(TA.__type_params__, ()) + + def test_errors(self): + with self.assertRaises(TypeError): + TypeAliasType() + with self.assertRaises(TypeError): + TypeAliasType("TA") + with self.assertRaises(TypeError): + TypeAliasType("TA", list, ()) + with self.assertRaises(TypeError): + TypeAliasType("TA", list, type_params=42) + + +class TypeAliasTypeTest(unittest.TestCase): + def test_immutable(self): + with self.assertRaises(TypeError): + TypeAliasType.whatever = "not allowed" + + def test_no_subclassing(self): + with self.assertRaisesRegex(TypeError, "not an acceptable base type"): + class MyAlias(TypeAliasType): + pass + + def test_union(self): + type Alias1 = int + type Alias2 = str + union = Alias1 | Alias2 + self.assertIsInstance(union, types.UnionType) + self.assertEqual(get_args(union), (Alias1, Alias2)) + union2 = Alias1 | list[float] + self.assertIsInstance(union2, types.UnionType) + self.assertEqual(get_args(union2), (Alias1, list[float])) + union3 = list[range] | Alias1 + self.assertIsInstance(union3, types.UnionType) + self.assertEqual(get_args(union3), (list[range], Alias1)) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py new file mode 100644 index 0000000..3ca13c2 --- /dev/null +++ b/Lib/test/test_type_params.py @@ -0,0 +1,847 @@ +import asyncio +import textwrap +import types +import unittest +from test.support import requires_working_socket, check_syntax_error, run_code + +from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args + + +class TypeParamsInvalidTest(unittest.TestCase): + def test_name_collision_01(self): + check_syntax_error(self, """def func[**A, A](): ...""") + + def test_name_non_collision_02(self): + ns = run_code("""def func[A](A): return A""") + func = ns["func"] + self.assertEqual(func(1), 1) + A, = func.__type_params__ + self.assertEqual(A.__name__, "A") + + def test_name_non_collision_03(self): + ns = run_code("""def func[A](*A): return A""") + func = ns["func"] + self.assertEqual(func(1), (1,)) + A, = func.__type_params__ + self.assertEqual(A.__name__, "A") + + def test_name_non_collision_04(self): + # Mangled names should not cause a conflict. + ns = run_code(""" + class ClassA: + def func[__A](self, __A): return __A + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + A, = cls.func.__type_params__ + self.assertEqual(A.__name__, "__A") + + def test_name_non_collision_05(self): + ns = run_code(""" + class ClassA: + def func[_ClassA__A](self, __A): return __A + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + A, = cls.func.__type_params__ + self.assertEqual(A.__name__, "_ClassA__A") + + def test_name_non_collision_06(self): + ns = run_code(""" + class ClassA[X]: + def func(self, X): return X + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_07(self): + ns = run_code(""" + class ClassA[X]: + def func(self): + X = 1 + return X + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(), 1) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_08(self): + ns = run_code(""" + class ClassA[X]: + def func(self): + return [X for X in [1, 2]] + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(), [1, 2]) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_9(self): + ns = run_code(""" + class ClassA[X]: + def func[X](self): + ... + """ + ) + cls = ns["ClassA"] + outer_X, = cls.__type_params__ + inner_X, = cls.func.__type_params__ + self.assertEqual(outer_X.__name__, "X") + self.assertEqual(inner_X.__name__, "X") + self.assertIsNot(outer_X, inner_X) + + def test_name_non_collision_10(self): + ns = run_code(""" + class ClassA[X]: + X: int + """ + ) + cls = ns["ClassA"] + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + self.assertIs(cls.__annotations__["X"], int) + + def test_name_non_collision_13(self): + ns = run_code(""" + X = 1 + def outer(): + def inner[X](): + global X + X = 2 + return inner + """ + ) + self.assertEqual(ns["X"], 1) + outer = ns["outer"] + outer()() + self.assertEqual(ns["X"], 2) + + def test_disallowed_expressions(self): + check_syntax_error(self, "type X = (yield)") + check_syntax_error(self, "type X = (yield from x)") + check_syntax_error(self, "type X = (await 42)") + check_syntax_error(self, "async def f(): type X = (yield)") + check_syntax_error(self, "type X = (y := 3)") + check_syntax_error(self, "class X[T: (yield)]: pass") + check_syntax_error(self, "class X[T: (yield from x)]: pass") + check_syntax_error(self, "class X[T: (await 42)]: pass") + check_syntax_error(self, "class X[T: (y := 3)]: pass") + check_syntax_error(self, "class X[T](y := Sequence[T]): pass") + check_syntax_error(self, "def f[T](y: (x := Sequence[T])): pass") + + +class TypeParamsNonlocalTest(unittest.TestCase): + def test_nonlocal_disallowed_01(self): + code = """ + def outer(): + X = 1 + def inner[X](): + nonlocal X + return X + """ + check_syntax_error(self, code) + + def test_nonlocal_disallowed_02(self): + code = """ + def outer2[T](): + def inner1(): + nonlocal T + """ + check_syntax_error(self, textwrap.dedent(code)) + + def test_nonlocal_disallowed_03(self): + code = """ + class Cls[T]: + nonlocal T + """ + check_syntax_error(self, textwrap.dedent(code)) + + def test_nonlocal_allowed(self): + code = """ + def func[T](): + T = "func" + def inner(): + nonlocal T + T = "inner" + inner() + assert T == "inner" + """ + ns = run_code(code) + func = ns["func"] + T, = func.__type_params__ + self.assertEqual(T.__name__, "T") + + +class TypeParamsAccessTest(unittest.TestCase): + def test_class_access_01(self): + ns = run_code(""" + class ClassA[A, B](dict[A, B]): + ... + """ + ) + cls = ns["ClassA"] + A, B = cls.__type_params__ + self.assertEqual(types.get_original_bases(cls), (dict[A, B], Generic[A, B])) + + def test_class_access_02(self): + ns = run_code(""" + class MyMeta[A, B](type): ... + class ClassA[A, B](metaclass=MyMeta[A, B]): + ... + """ + ) + meta = ns["MyMeta"] + cls = ns["ClassA"] + A1, B1 = meta.__type_params__ + A2, B2 = cls.__type_params__ + self.assertIsNot(A1, A2) + self.assertIsNot(B1, B2) + self.assertIs(type(cls), meta) + + def test_class_access_03(self): + code = """ + def my_decorator(a): + ... + @my_decorator(A) + class ClassA[A, B](): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_function_access_01(self): + ns = run_code(""" + def func[A, B](a: dict[A, B]): + ... + """ + ) + func = ns["func"] + A, B = func.__type_params__ + self.assertEqual(func.__annotations__["a"], dict[A, B]) + + def test_function_access_02(self): + code = """ + def func[A](a = list[A]()): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_function_access_03(self): + code = """ + def my_decorator(a): + ... + @my_decorator(A) + def func[A](): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_method_access_01(self): + ns = run_code(""" + class ClassA: + x = int + def func[T](self, a: x, b: T): + ... + """ + ) + cls = ns["ClassA"] + self.assertIs(cls.func.__annotations__["a"], int) + T, = cls.func.__type_params__ + self.assertIs(cls.func.__annotations__["b"], T) + + def test_nested_access_01(self): + ns = run_code(""" + class ClassA[A]: + def funcB[B](self): + class ClassC[C]: + def funcD[D](self): + return lambda: (A, B, C, D) + return ClassC + """ + ) + cls = ns["ClassA"] + A, = cls.__type_params__ + B, = cls.funcB.__type_params__ + classC = cls().funcB() + C, = classC.__type_params__ + D, = classC.funcD.__type_params__ + self.assertEqual(classC().funcD()(), (A, B, C, D)) + + def test_out_of_scope_01(self): + code = """ + class ClassA[T]: ... + x = T + """ + + with self.assertRaisesRegex(NameError, "name 'T' is not defined"): + run_code(code) + + def test_out_of_scope_02(self): + code = """ + class ClassA[A]: + def funcB[B](self): ... + + x = B + """ + + with self.assertRaisesRegex(NameError, "name 'B' is not defined"): + run_code(code) + + def test_class_scope_interaction_01(self): + ns = run_code(""" + class C: + x = 1 + def method[T](self, arg: x): pass + """) + cls = ns["C"] + self.assertEqual(cls.method.__annotations__["arg"], 1) + + def test_class_scope_interaction_02(self): + ns = run_code(""" + class C: + class Base: pass + class Child[T](Base): pass + """) + cls = ns["C"] + self.assertEqual(cls.Child.__bases__, (cls.Base, Generic)) + T, = cls.Child.__type_params__ + self.assertEqual(types.get_original_bases(cls.Child), (cls.Base, Generic[T])) + + def test_class_deref(self): + ns = run_code(""" + class C[T]: + T = "class" + type Alias = T + """) + cls = ns["C"] + self.assertEqual(cls.Alias.__value__, "class") + + def test_shadowing_nonlocal(self): + ns = run_code(""" + def outer[T](): + T = "outer" + def inner(): + nonlocal T + T = "inner" + return T + return lambda: T, inner + """) + outer = ns["outer"] + T, = outer.__type_params__ + self.assertEqual(T.__name__, "T") + getter, inner = outer() + self.assertEqual(getter(), "outer") + self.assertEqual(inner(), "inner") + self.assertEqual(getter(), "inner") + + def test_reference_previous_typevar(self): + def func[S, T: Sequence[S]](): + pass + + S, T = func.__type_params__ + self.assertEqual(T.__bound__, Sequence[S]) + + def test_super(self): + class Base: + def meth(self): + return "base" + + class Child(Base): + # Having int in the annotation ensures the class gets cells for both + # __class__ and __classdict__ + def meth[T](self, arg: int) -> T: + return super().meth() + "child" + + c = Child() + self.assertEqual(c.meth(1), "basechild") + + def test_type_alias_containing_lambda(self): + type Alias[T] = lambda: T + T, = Alias.__type_params__ + self.assertIs(Alias.__value__(), T) + + def test_class_base_containing_lambda(self): + # Test that scopes nested inside hidden functions work correctly + outer_var = "outer" + class Base[T]: ... + class Child[T](Base[lambda: (int, outer_var, T)]): ... + base, _ = types.get_original_bases(Child) + func, = get_args(base) + T, = Child.__type_params__ + self.assertEqual(func(), (int, "outer", T)) + + def test_comprehension_01(self): + type Alias[T: ([T for T in (T, [1])[1]], T)] = [T for T in T.__name__] + self.assertEqual(Alias.__value__, ["T"]) + T, = Alias.__type_params__ + self.assertEqual(T.__constraints__, ([1], T)) + + def test_comprehension_02(self): + type Alias[T: [lambda: T for T in (T, [1])[1]]] = [lambda: T for T in T.__name__] + func, = Alias.__value__ + self.assertEqual(func(), "T") + T, = Alias.__type_params__ + func, = T.__bound__ + self.assertEqual(func(), 1) + + +def global_generic_func[T](): + pass + +class GlobalGenericClass[T]: + pass + + +class TypeParamsLazyEvaluationTest(unittest.TestCase): + def test_qualname(self): + class Foo[T]: + pass + + def func[T](): + pass + + self.assertEqual(Foo.__qualname__, "TypeParamsLazyEvaluationTest.test_qualname.<locals>.Foo") + self.assertEqual(func.__qualname__, "TypeParamsLazyEvaluationTest.test_qualname.<locals>.func") + self.assertEqual(global_generic_func.__qualname__, "global_generic_func") + self.assertEqual(GlobalGenericClass.__qualname__, "GlobalGenericClass") + + def test_recursive_class(self): + class Foo[T: Foo, U: (Foo, Foo)]: + pass + + type_params = Foo.__type_params__ + self.assertEqual(len(type_params), 2) + self.assertEqual(type_params[0].__name__, "T") + self.assertEqual(type_params[0].__bound__, Foo) + self.assertEqual(type_params[0].__constraints__, None) + + self.assertEqual(type_params[1].__name__, "U") + self.assertEqual(type_params[1].__bound__, None) + self.assertEqual(type_params[1].__constraints__, (Foo, Foo)) + + def test_evaluation_error(self): + class Foo[T: Undefined, U: (Undefined,)]: + pass + + type_params = Foo.__type_params__ + with self.assertRaises(NameError): + type_params[0].__bound__ + self.assertEqual(type_params[0].__constraints__, None) + self.assertEqual(type_params[1].__bound__, None) + with self.assertRaises(NameError): + type_params[1].__constraints__ + + Undefined = "defined" + self.assertEqual(type_params[0].__bound__, "defined") + self.assertEqual(type_params[0].__constraints__, None) + + self.assertEqual(type_params[1].__bound__, None) + self.assertEqual(type_params[1].__constraints__, ("defined",)) + + +class TypeParamsClassScopeTest(unittest.TestCase): + def test_alias(self): + class X: + T = int + type U = T + self.assertIs(X.U.__value__, int) + + ns = run_code(""" + glb = "global" + class X: + cls = "class" + type U = (glb, cls) + """) + cls = ns["X"] + self.assertEqual(cls.U.__value__, ("global", "class")) + + def test_bound(self): + class X: + T = int + def foo[U: T](self): ... + self.assertIs(X.foo.__type_params__[0].__bound__, int) + + ns = run_code(""" + glb = "global" + class X: + cls = "class" + def foo[T: glb, U: cls](self): ... + """) + cls = ns["X"] + T, U = cls.foo.__type_params__ + self.assertEqual(T.__bound__, "global") + self.assertEqual(U.__bound__, "class") + + def test_modified_later(self): + class X: + T = int + def foo[U: T](self): ... + type Alias = T + X.T = float + self.assertIs(X.foo.__type_params__[0].__bound__, float) + self.assertIs(X.Alias.__value__, float) + + def test_binding_uses_global(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + type Alias = x + val = Alias.__value__ + def meth[T: x](self, arg: x): ... + bound = meth.__type_params__[0].__bound__ + annotation = meth.__annotations__["arg"] + x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.val, "global") + self.assertEqual(cls.bound, "global") + self.assertEqual(cls.annotation, "global") + + def test_no_binding_uses_nonlocal(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + type Alias = x + val = Alias.__value__ + def meth[T: x](self, arg: x): ... + bound = meth.__type_params__[0].__bound__ + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.val, "nonlocal") + self.assertEqual(cls.bound, "nonlocal") + self.assertEqual(cls.meth.__annotations__["arg"], "nonlocal") + + def test_explicit_global(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + global x + type Alias = x + Cls.x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global") + + def test_explicit_global_with_no_static_bound(self): + ns = run_code(""" + def outer(): + class Cls: + global x + type Alias = x + Cls.x = "class" + return Cls + """) + ns["x"] = "global" + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global") + + def test_explicit_global_with_assignment(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + global x + type Alias = x + x = "global from class" + Cls.x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global from class") + + def test_explicit_nonlocal(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + nonlocal x + type Alias = x + x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "class") + + +class TypeParamsManglingTest(unittest.TestCase): + def test_mangling(self): + class Foo[__T]: + param = __T + def meth[__U](self, arg: __T, arg2: __U): + return (__T, __U) + type Alias[__V] = (__T, __V) + + T = Foo.__type_params__[0] + self.assertEqual(T.__name__, "__T") + U = Foo.meth.__type_params__[0] + self.assertEqual(U.__name__, "__U") + V = Foo.Alias.__type_params__[0] + self.assertEqual(V.__name__, "__V") + + anno = Foo.meth.__annotations__ + self.assertIs(anno["arg"], T) + self.assertIs(anno["arg2"], U) + self.assertEqual(Foo().meth(1, 2), (T, U)) + + self.assertEqual(Foo.Alias.__value__, (T, V)) + + +class TypeParamsComplexCallsTest(unittest.TestCase): + def test_defaults(self): + # Generic functions with both defaults and kwdefaults trigger a specific code path + # in the compiler. + def func[T](a: T = "a", *, b: T = "b"): + return (a, b) + + T, = func.__type_params__ + self.assertIs(func.__annotations__["a"], T) + self.assertIs(func.__annotations__["b"], T) + self.assertEqual(func(), ("a", "b")) + self.assertEqual(func(1), (1, "b")) + self.assertEqual(func(b=2), ("a", 2)) + + def test_complex_base(self): + class Base: + def __init_subclass__(cls, **kwargs) -> None: + cls.kwargs = kwargs + + kwargs = {"c": 3} + # Base classes with **kwargs trigger a different code path in the compiler. + class C[T](Base, a=1, b=2, **kwargs): + pass + + T, = C.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C.kwargs, {"a": 1, "b": 2, "c": 3}) + + bases = (Base,) + class C2[T](*bases, **kwargs): + pass + + T, = C2.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C2.kwargs, {"c": 3}) + + +class TypeParamsTraditionalTypeVarsTest(unittest.TestCase): + def test_traditional_01(self): + code = """ + from typing import Generic + class ClassA[T](Generic[T]): ... + """ + + with self.assertRaisesRegex(TypeError, r"Cannot inherit from Generic\[...\] multiple times."): + run_code(code) + + def test_traditional_02(self): + from typing import TypeVar + S = TypeVar("S") + with self.assertRaises(TypeError): + class ClassA[T](dict[T, S]): ... + + def test_traditional_03(self): + # This does not generate a runtime error, but it should be + # flagged as an error by type checkers. + from typing import TypeVar + S = TypeVar("S") + def func[T](a: T, b: S) -> T | S: + return a + + +class TypeParamsTypeVarTest(unittest.TestCase): + def test_typevar_01(self): + def func1[A: str, B: str | int, C: (int, str)](): + return (A, B, C) + + a, b, c = func1() + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__bound__, str) + self.assertTrue(a.__infer_variance__) + self.assertFalse(a.__covariant__) + self.assertFalse(a.__contravariant__) + + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__bound__, str | int) + self.assertTrue(b.__infer_variance__) + self.assertFalse(b.__covariant__) + self.assertFalse(b.__contravariant__) + + self.assertIsInstance(c, TypeVar) + self.assertEqual(c.__bound__, None) + self.assertEqual(c.__constraints__, (int, str)) + self.assertTrue(c.__infer_variance__) + self.assertFalse(c.__covariant__) + self.assertFalse(c.__contravariant__) + + def test_typevar_generator(self): + def get_generator[A](): + def generator1[C](): + yield C + + def generator2[B](): + yield A + yield B + yield from generator1() + return generator2 + + gen = get_generator() + + a, b, c = [x for x in gen()] + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__name__, "A") + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__name__, "B") + self.assertIsInstance(c, TypeVar) + self.assertEqual(c.__name__, "C") + + @requires_working_socket() + def test_typevar_coroutine(self): + def get_coroutine[A](): + async def coroutine[B](): + return (A, B) + return coroutine + + co = get_coroutine() + + self.addCleanup(asyncio.set_event_loop_policy, None) + a, b = asyncio.run(co()) + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__name__, "A") + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__name__, "B") + + +class TypeParamsTypeVarTupleTest(unittest.TestCase): + def test_typevartuple_01(self): + code = """def func1[*A: str](): pass""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """def func1[*A: (int, str)](): pass""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + code = """class X[*A: str]: pass""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """class X[*A: (int, str)]: pass""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + code = """type X[*A: str] = int""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """type X[*A: (int, str)] = int""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + + def test_typevartuple_02(self): + def func1[*A](): + return A + + a = func1() + self.assertIsInstance(a, TypeVarTuple) + + +class TypeParamsTypeVarParamSpecTest(unittest.TestCase): + def test_paramspec_01(self): + code = """def func1[**A: str](): pass""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """def func1[**A: (int, str)](): pass""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + code = """class X[**A: str]: pass""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """class X[**A: (int, str)]: pass""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + code = """type X[**A: str] = int""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """type X[**A: (int, str)] = int""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + + def test_paramspec_02(self): + def func1[**A](): + return A + + a = func1() + self.assertIsInstance(a, ParamSpec) + self.assertTrue(a.__infer_variance__) + self.assertFalse(a.__covariant__) + self.assertFalse(a.__contravariant__) + + +class TypeParamsTypeParamsDunder(unittest.TestCase): + def test_typeparams_dunder_class_01(self): + class Outer[A, B]: + class Inner[C, D]: + @staticmethod + def get_typeparams(): + return A, B, C, D + + a, b, c, d = Outer.Inner.get_typeparams() + self.assertEqual(Outer.__type_params__, (a, b)) + self.assertEqual(Outer.Inner.__type_params__, (c, d)) + + self.assertEqual(Outer.__parameters__, (a, b)) + self.assertEqual(Outer.Inner.__parameters__, (c, d)) + + def test_typeparams_dunder_class_02(self): + class ClassA: + pass + + self.assertEqual(ClassA.__type_params__, ()) + + def test_typeparams_dunder_class_03(self): + code = """ + class ClassA[A](): + pass + ClassA.__type_params__ = () + """ + + with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'type' objects is not writable"): + run_code(code) + + def test_typeparams_dunder_function_01(self): + def outer[A, B](): + def inner[C, D](): + return A, B, C, D + + return inner + + inner = outer() + a, b, c, d = inner() + self.assertEqual(outer.__type_params__, (a, b)) + self.assertEqual(inner.__type_params__, (c, d)) + + def test_typeparams_dunder_function_02(self): + def func1(): + pass + + self.assertEqual(func1.__type_params__, ()) + + def test_typeparams_dunder_function_03(self): + code = """ + def func[A](): + pass + func.__type_params__ = () + """ + + with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'function' objects is not writable"): + run_code(code) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e1c6a8a..71aff87 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -48,11 +48,8 @@ from test import mod_generics_cache from test import _typed_dict_helper -py_typing = import_helper.import_fresh_module('typing', blocked=['_typing']) -c_typing = import_helper.import_fresh_module('typing', fresh=['_typing']) - - CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' +NOT_A_BASE_TYPE = "type 'typing.%s' is not an acceptable base type" CANNOT_SUBCLASS_INSTANCE = 'Cannot subclass an instance of %s' @@ -430,7 +427,7 @@ class TypeVarTests(BaseTestCase): self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'TypeVar'): class V(TypeVar): pass T = TypeVar("T") with self.assertRaisesRegex(TypeError, @@ -446,6 +443,9 @@ class TypeVarTests(BaseTestCase): TypeVar('X', bound=Union) with self.assertRaises(TypeError): TypeVar('X', str, float, bound=Employee) + with self.assertRaisesRegex(TypeError, + r"Bound must be a type\. Got \(1, 2\)\."): + TypeVar('X', bound=(1, 2)) def test_missing__name__(self): # See bpo-39942 @@ -1161,7 +1161,7 @@ class TypeVarTupleTests(BaseTestCase): self.assertEndsWith(repr(K[float, str]), 'A[float, str, typing.Unpack[typing.Tuple[str, ...]]]') def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'TypeVarTuple'): class C(TypeVarTuple): pass Ts = TypeVarTuple('Ts') with self.assertRaisesRegex(TypeError, @@ -6444,34 +6444,27 @@ class TypeTests(BaseTestCase): class TestModules(TestCase): func_names = ['_idfunc'] - def test_py_functions(self): - for fname in self.func_names: - self.assertEqual(getattr(py_typing, fname).__module__, 'typing') - - @skipUnless(c_typing, 'requires _typing') def test_c_functions(self): for fname in self.func_names: - self.assertEqual(getattr(c_typing, fname).__module__, '_typing') + self.assertEqual(getattr(typing, fname).__module__, '_typing') -class NewTypeTests: +class NewTypeTests(BaseTestCase): def cleanup(self): - for f in self.module._cleanups: + for f in typing._cleanups: f() @classmethod def setUpClass(cls): - sys.modules['typing'] = cls.module global UserId - UserId = cls.module.NewType('UserId', int) - cls.UserName = cls.module.NewType(cls.__qualname__ + '.UserName', str) + UserId = typing.NewType('UserId', int) + cls.UserName = typing.NewType(cls.__qualname__ + '.UserName', str) @classmethod def tearDownClass(cls): global UserId del UserId del cls.UserName - sys.modules['typing'] = typing def tearDown(self): self.cleanup() @@ -6491,11 +6484,11 @@ class NewTypeTests: def test_or(self): for cls in (int, self.UserName): with self.subTest(cls=cls): - self.assertEqual(UserId | cls, self.module.Union[UserId, cls]) - self.assertEqual(cls | UserId, self.module.Union[cls, UserId]) + self.assertEqual(UserId | cls, typing.Union[UserId, cls]) + self.assertEqual(cls | UserId, typing.Union[cls, UserId]) - self.assertEqual(self.module.get_args(UserId | cls), (UserId, cls)) - self.assertEqual(self.module.get_args(cls | UserId), (cls, UserId)) + self.assertEqual(typing.get_args(UserId | cls), (UserId, cls)) + self.assertEqual(typing.get_args(cls | UserId), (cls, UserId)) def test_special_attrs(self): self.assertEqual(UserId.__name__, 'UserId') @@ -6516,7 +6509,7 @@ class NewTypeTests: f'{__name__}.{self.__class__.__qualname__}.UserName') def test_pickle(self): - UserAge = self.module.NewType('UserAge', float) + UserAge = typing.NewType('UserAge', float) for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.subTest(proto=proto): pickled = pickle.dumps(UserId, proto) @@ -6548,15 +6541,6 @@ class NewTypeTests: ... -class NewTypePythonTests(NewTypeTests, BaseTestCase): - module = py_typing - - -@skipUnless(c_typing, 'requires _typing') -class NewTypeCTests(NewTypeTests, BaseTestCase): - module = c_typing - - class NamedTupleTests(BaseTestCase): class NestedEmployee(NamedTuple): name: str @@ -8170,11 +8154,11 @@ class ParamSpecTests(BaseTestCase): self.assertEqual(C2[Concatenate[T, P2]].__parameters__, (T, P2)) def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpec'): class C(ParamSpec): pass - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecArgs'): class C(ParamSpecArgs): pass - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecKwargs'): class C(ParamSpecKwargs): pass P = ParamSpec('P') with self.assertRaisesRegex(TypeError, diff --git a/Lib/typing.py b/Lib/typing.py index 61aed09..8d132e2 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -23,6 +23,7 @@ from abc import abstractmethod, ABCMeta import collections from collections import defaultdict import collections.abc +import copyreg import contextlib import functools import operator @@ -32,12 +33,16 @@ import types import warnings from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType, GenericAlias - -try: - from _typing import _idfunc -except ImportError: - def _idfunc(_, x): - return x +from _typing import ( + _idfunc, + TypeVar, + ParamSpec, + TypeVarTuple, + ParamSpecArgs, + ParamSpecKwargs, + TypeAliasType, + Generic, +) # Please keep __all__ alphabetized within each category. __all__ = [ @@ -149,6 +154,7 @@ __all__ = [ 'TYPE_CHECKING', 'TypeAlias', 'TypeGuard', + 'TypeAliasType', 'Unpack', ] @@ -695,6 +701,15 @@ def Union(self, parameters): return _UnionGenericAlias(self, parameters, name="Optional") return _UnionGenericAlias(self, parameters) +def _make_union(left, right): + """Used from the C implementation of TypeVar. + + TypeVar.__or__ calls this instead of returning types.UnionType + because we want to allow unions between TypeVars and strings + (forward references.) + """ + return Union[left, right] + @_SpecialForm def Optional(self, parameters): """Optional type. @@ -926,333 +941,162 @@ class _PickleUsingNameMixin: return self.__name__ -class _BoundVarianceMixin: - """Mixin giving __init__ bound and variance arguments. - - This is used by TypeVar and ParamSpec, which both employ the notions of - a type 'bound' (restricting type arguments to be a subtype of some - specified type) and type 'variance' (determining subtype relations between - generic types). - """ - def __init__(self, bound, covariant, contravariant): - """Used to setup TypeVars and ParamSpec's bound, covariant and - contravariant attributes. - """ - if covariant and contravariant: - raise ValueError("Bivariant types are not supported.") - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if bound: - self.__bound__ = _type_check(bound, "Bound must be a type.") - else: - self.__bound__ = None - - def __or__(self, right): - return Union[self, right] - - def __ror__(self, left): - return Union[left, self] - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class TypeVar(_Final, _Immutable, _BoundVarianceMixin, _PickleUsingNameMixin, - _root=True): - """Type variable. - - Usage:: - - T = TypeVar('T') # Can be anything - A = TypeVar('A', str, bytes) # Must be str or bytes - - Type variables exist primarily for the benefit of static type - checkers. They serve as the parameters for generic types as well - as for generic function definitions. See class Generic for more - information on generic types. Generic functions work as follows: - - def repeat(x: T, n: int) -> List[T]: - '''Return a list containing n references to x.''' - return [x]*n - - def longest(x: A, y: A) -> A: - '''Return the longest of two strings.''' - return x if len(x) >= len(y) else y - - The latter example's signature is essentially the overloading - of (str, str) -> str and (bytes, bytes) -> bytes. Also note - that if the arguments are instances of some subclass of str, - the return type is still plain str. - - At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError. - - Type variables defined with covariant=True or contravariant=True - can be used to declare covariant or contravariant generic types. - See PEP 484 for more details. By default generic types are invariant - in all type variables. - - Type variables can be introspected. e.g.: - - T.__name__ == 'T' - T.__constraints__ == () - T.__covariant__ == False - T.__contravariant__ = False - A.__constraints__ == (str, bytes) - - Note that only type variables defined in global scope can be pickled. - """ - - def __init__(self, name, *constraints, bound=None, - covariant=False, contravariant=False): - self.__name__ = name - super().__init__(bound, covariant, contravariant) - if constraints and bound is not None: - raise TypeError("Constraints cannot be combined with bound=...") - if constraints and len(constraints) == 1: - raise TypeError("A single constraint is not allowed") - msg = "TypeVar(name, constraint, ...): constraints must be types." - self.__constraints__ = tuple(_type_check(t, msg) for t in constraints) - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod +def _typevar_subst(self, arg): + msg = "Parameters to generic types must be types." + arg = _type_check(arg, msg, is_argument=True) + if ((isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack) or + (isinstance(arg, GenericAlias) and getattr(arg, '__unpacked__', False))): + raise TypeError(f"{arg} is not valid as type argument") + return arg - def __typing_subst__(self, arg): - msg = "Parameters to generic types must be types." - arg = _type_check(arg, msg, is_argument=True) - if ((isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack) or - (isinstance(arg, GenericAlias) and getattr(arg, '__unpacked__', False))): - raise TypeError(f"{arg} is not valid as type argument") - return arg +def _typevartuple_prepare_subst(self, alias, args): + params = alias.__parameters__ + typevartuple_index = params.index(self) + for param in params[typevartuple_index + 1:]: + if isinstance(param, TypeVarTuple): + raise TypeError(f"More than one TypeVarTuple parameter in {alias}") + + alen = len(args) + plen = len(params) + left = typevartuple_index + right = plen - typevartuple_index - 1 + var_tuple_index = None + fillarg = None + for k, arg in enumerate(args): + if not isinstance(arg, type): + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs and len(subargs) == 2 and subargs[-1] is ...: + if var_tuple_index is not None: + raise TypeError("More than one unpacked arbitrary-length tuple argument") + var_tuple_index = k + fillarg = subargs[0] + if var_tuple_index is not None: + left = min(left, var_tuple_index) + right = min(right, alen - var_tuple_index - 1) + elif left + right > alen: + raise TypeError(f"Too few arguments for {alias};" + f" actual {alen}, expected at least {plen-1}") -class TypeVarTuple(_Final, _Immutable, _PickleUsingNameMixin, _root=True): - """Type variable tuple. + return ( + *args[:left], + *([fillarg]*(typevartuple_index - left)), + tuple(args[left: alen - right]), + *([fillarg]*(plen - right - left - typevartuple_index - 1)), + *args[alen - right:], + ) - Usage: - Ts = TypeVarTuple('Ts') # Can be given any name +def _paramspec_subst(self, arg): + if isinstance(arg, (list, tuple)): + arg = tuple(_type_check(a, "Expected a type.") for a in arg) + elif not _is_param_expr(arg): + raise TypeError(f"Expected a list of types, an ellipsis, " + f"ParamSpec, or Concatenate. Got {arg}") + return arg - Just as a TypeVar (type variable) is a placeholder for a single type, - a TypeVarTuple is a placeholder for an *arbitrary* number of types. For - example, if we define a generic class using a TypeVarTuple: - class C(Generic[*Ts]): ... +def _paramspec_prepare_subst(self, alias, args): + params = alias.__parameters__ + i = params.index(self) + if i >= len(args): + raise TypeError(f"Too few arguments for {alias}") + # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. + if len(params) == 1 and not _is_param_expr(args[0]): + assert i == 0 + args = (args,) + # Convert lists to tuples to help other libraries cache the results. + elif isinstance(args[i], list): + args = (*args[:i], tuple(args[i]), *args[i+1:]) + return args - Then we can parameterize that class with an arbitrary number of type - arguments: - C[int] # Fine - C[int, str] # Also fine - C[()] # Even this is fine +@_tp_cache +def _generic_class_getitem(cls, params): + """Parameterizes a generic class. - For more details, see PEP 646. + At least, parameterizing a generic class is the *main* thing this method + does. For example, for some generic class `Foo`, this is called when we + do `Foo[int]` - there, with `cls=Foo` and `params=int`. - Note that only TypeVarTuples defined in global scope can be pickled. + However, note that this method is also called when defining generic + classes in the first place with `class Foo(Generic[T]): ...`. """ + if not isinstance(params, tuple): + params = (params,) - def __init__(self, name): - self.__name__ = name - - # Used for pickling. - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod - - def __iter__(self): - yield Unpack[self] - - def __repr__(self): - return self.__name__ + params = tuple(_type_convert(p) for p in params) + is_generic_or_protocol = cls in (Generic, Protocol) - def __typing_subst__(self, arg): - raise TypeError("Substitution of bare TypeVarTuple is not supported") + if is_generic_or_protocol: + # Generic and Protocol can only be subscripted with unique type variables. + if not params: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty" + ) + if not all(_is_typevar_like(p) for p in params): + raise TypeError( + f"Parameters to {cls.__name__}[...] must all be type variables " + f"or parameter specification variables.") + if len(set(params)) != len(params): + raise TypeError( + f"Parameters to {cls.__name__}[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + for param in cls.__parameters__: + prepare = getattr(param, '__typing_prepare_subst__', None) + if prepare is not None: + params = prepare(cls, params) + _check_generic(cls, params, len(cls.__parameters__)) - def __typing_prepare_subst__(self, alias, args): - params = alias.__parameters__ - typevartuple_index = params.index(self) - for param in params[typevartuple_index + 1:]: + new_args = [] + for param, new_arg in zip(cls.__parameters__, params): if isinstance(param, TypeVarTuple): - raise TypeError(f"More than one TypeVarTuple parameter in {alias}") - - alen = len(args) - plen = len(params) - left = typevartuple_index - right = plen - typevartuple_index - 1 - var_tuple_index = None - fillarg = None - for k, arg in enumerate(args): - if not isinstance(arg, type): - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs and len(subargs) == 2 and subargs[-1] is ...: - if var_tuple_index is not None: - raise TypeError("More than one unpacked arbitrary-length tuple argument") - var_tuple_index = k - fillarg = subargs[0] - if var_tuple_index is not None: - left = min(left, var_tuple_index) - right = min(right, alen - var_tuple_index - 1) - elif left + right > alen: - raise TypeError(f"Too few arguments for {alias};" - f" actual {alen}, expected at least {plen-1}") - - return ( - *args[:left], - *([fillarg]*(typevartuple_index - left)), - tuple(args[left: alen - right]), - *([fillarg]*(plen - right - left - typevartuple_index - 1)), - *args[alen - right:], - ) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpecArgs(_Final, _Immutable, _root=True): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpecKwargs(_Final, _Immutable, _root=True): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpec(_Final, _Immutable, _BoundVarianceMixin, _PickleUsingNameMixin, - _root=True): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or as the first argument to ``Callable``, or as parameters for user-defined - Generics. See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'P' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ + new_args.extend(new_arg) + else: + new_args.append(new_arg) + params = tuple(new_args) - @property - def args(self): - return ParamSpecArgs(self) + return _GenericAlias(cls, params) - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False): - self.__name__ = name - super().__init__(bound, covariant, contravariant) - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod - def __typing_subst__(self, arg): - if isinstance(arg, (list, tuple)): - arg = tuple(_type_check(a, "Expected a type.") for a in arg) - elif not _is_param_expr(arg): - raise TypeError(f"Expected a list of types, an ellipsis, " - f"ParamSpec, or Concatenate. Got {arg}") - return arg +def _generic_init_subclass(cls, *args, **kwargs): + super(Generic, cls).__init_subclass__(*args, **kwargs) + tvars = [] + if '__orig_bases__' in cls.__dict__: + error = Generic in cls.__orig_bases__ + else: + error = (Generic in cls.__bases__ and + cls.__name__ != 'Protocol' and + type(cls) != _TypedDictMeta) + if error: + raise TypeError("Cannot inherit from plain Generic") + if '__orig_bases__' in cls.__dict__: + tvars = _collect_parameters(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, _GenericAlias) and + base.__origin__ is Generic): + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...] multiple times.") + gvars = base.__parameters__ + if gvars is not None: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in Generic[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) - def __typing_prepare_subst__(self, alias, args): - params = alias.__parameters__ - i = params.index(self) - if i >= len(args): - raise TypeError(f"Too few arguments for {alias}") - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. - if len(params) == 1 and not _is_param_expr(args[0]): - assert i == 0 - args = (args,) - # Convert lists to tuples to help other libraries cache the results. - elif isinstance(args[i], list): - args = (*args[:i], tuple(args[i]), *args[i+1:]) - return args def _is_dunder(attr): return attr.startswith('__') and attr.endswith('__') @@ -1812,113 +1656,6 @@ class _UnpackGenericAlias(_GenericAlias, _root=True): return isinstance(self.__args__[0], TypeVarTuple) -class Generic: - """Abstract base class for generic types. - - A generic type is typically declared by inheriting from - this class parameterized with one or more type variables. - For example, a generic mapping type might be defined as:: - - class Mapping(Generic[KT, VT]): - def __getitem__(self, key: KT) -> VT: - ... - # Etc. - - This class can then be used as follows:: - - def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: - try: - return mapping[key] - except KeyError: - return default - """ - __slots__ = () - _is_protocol = False - - @_tp_cache - def __class_getitem__(cls, params): - """Parameterizes a generic class. - - At least, parameterizing a generic class is the *main* thing this method - does. For example, for some generic class `Foo`, this is called when we - do `Foo[int]` - there, with `cls=Foo` and `params=int`. - - However, note that this method is also called when defining generic - classes in the first place with `class Foo(Generic[T]): ...`. - """ - if not isinstance(params, tuple): - params = (params,) - - params = tuple(_type_convert(p) for p in params) - if cls in (Generic, Protocol): - # Generic and Protocol can only be subscripted with unique type variables. - if not params: - raise TypeError( - f"Parameter list to {cls.__qualname__}[...] cannot be empty" - ) - if not all(_is_typevar_like(p) for p in params): - raise TypeError( - f"Parameters to {cls.__name__}[...] must all be type variables " - f"or parameter specification variables.") - if len(set(params)) != len(params): - raise TypeError( - f"Parameters to {cls.__name__}[...] must all be unique") - else: - # Subscripting a regular Generic subclass. - for param in cls.__parameters__: - prepare = getattr(param, '__typing_prepare_subst__', None) - if prepare is not None: - params = prepare(cls, params) - _check_generic(cls, params, len(cls.__parameters__)) - - new_args = [] - for param, new_arg in zip(cls.__parameters__, params): - if isinstance(param, TypeVarTuple): - new_args.extend(new_arg) - else: - new_args.append(new_arg) - params = tuple(new_args) - - return _GenericAlias(cls, params) - - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - tvars = [] - if '__orig_bases__' in cls.__dict__: - error = Generic in cls.__orig_bases__ - else: - error = (Generic in cls.__bases__ and - cls.__name__ != 'Protocol' and - type(cls) != _TypedDictMeta) - if error: - raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: - tvars = _collect_parameters(cls.__orig_bases__) - # Look for Generic[T1, ..., Tn]. - # If found, tvars must be a subset of it. - # If not found, tvars is it. - # Also check for and reject plain Generic, - # and reject multiple Generic[...]. - gvars = None - for base in cls.__orig_bases__: - if (isinstance(base, _GenericAlias) and - base.__origin__ is Generic): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] multiple times.") - gvars = base.__parameters__ - if gvars is not None: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in Generic[{s_args}]") - tvars = gvars - cls.__parameters__ = tuple(tvars) - - class _TypingEllipsis: """Internal placeholder for ... (ellipsis).""" @@ -2024,6 +1761,18 @@ def _lazy_load_getattr_static(): _cleanups.append(_lazy_load_getattr_static.cache_clear) +def _pickle_psargs(psargs): + return ParamSpecArgs, (psargs.__origin__,) + +copyreg.pickle(ParamSpecArgs, _pickle_psargs) + +def _pickle_pskwargs(pskwargs): + return ParamSpecKwargs, (pskwargs.__origin__,) + +copyreg.pickle(ParamSpecKwargs, _pickle_pskwargs) + +del _pickle_psargs, _pickle_pskwargs + class _ProtocolMeta(ABCMeta): # This metaclass is really unfortunate and exists only because of @@ -2943,7 +2692,7 @@ class NamedTupleMeta(type): module=ns['__module__']) nm_tpl.__bases__ = bases if Generic in bases: - class_getitem = Generic.__class_getitem__.__func__ + class_getitem = _generic_class_getitem nm_tpl.__class_getitem__ = classmethod(class_getitem) # update from user namespace without overriding special namedtuple attributes for key in ns: |