https://github.com/python/cpython/commit/7f16f1bc114ea42ceb51ccb5008b74571a875f6b commit: 7f16f1bc114ea42ceb51ccb5008b74571a875f6b branch: main author: Jelle Zijlstra <jelle.zijls...@gmail.com> committer: JelleZijlstra <jelle.zijls...@gmail.com> date: 2025-04-28T08:38:11-07:00 summary:
typing, annotationlib: clean tests (#133087) - Add @cpython_only decorator to lazy import tests - Rename reference to SOURCE format - Always two newlines between test case classes - Merge two classes of ForwardRef tests - Use get_annotations instead of annotationlib.get_annotations - Format test_annotationlib with Black (not expecting that we'll keep this up but it's close to Black-formatted right now) files: M Lib/test/test_annotationlib.py M Lib/test/test_typing.py diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index 0890be529a7e52..be55f044b15ccb 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -16,12 +16,7 @@ annotations_to_string, type_repr, ) -from typing import ( - Unpack, - get_type_hints, - List, - Union, -) +from typing import Unpack, get_type_hints, List, Union from test import support from test.support import import_helper @@ -64,9 +59,9 @@ def test_closure(self): def inner(arg: x): pass - anno = annotationlib.get_annotations(inner, format=Format.FORWARDREF) + anno = get_annotations(inner, format=Format.FORWARDREF) fwdref = anno["arg"] - self.assertIsInstance(fwdref, annotationlib.ForwardRef) + self.assertIsInstance(fwdref, ForwardRef) self.assertEqual(fwdref.__forward_arg__, "x") with self.assertRaises(NameError): fwdref.evaluate() @@ -74,17 +69,17 @@ def inner(arg: x): x = 1 self.assertEqual(fwdref.evaluate(), x) - anno = annotationlib.get_annotations(inner, format=Format.FORWARDREF) + anno = get_annotations(inner, format=Format.FORWARDREF) self.assertEqual(anno["arg"], x) def test_function(self): def f(x: int, y: doesntexist): pass - anno = annotationlib.get_annotations(f, format=Format.FORWARDREF) + anno = get_annotations(f, format=Format.FORWARDREF) self.assertIs(anno["x"], int) fwdref = anno["y"] - self.assertIsInstance(fwdref, annotationlib.ForwardRef) + self.assertIsInstance(fwdref, ForwardRef) self.assertEqual(fwdref.__forward_arg__, "doesntexist") with self.assertRaises(NameError): fwdref.evaluate() @@ -101,7 +96,7 @@ def f( ): pass - anno = annotationlib.get_annotations(f, format=Format.FORWARDREF) + anno = get_annotations(f, format=Format.FORWARDREF) x_anno = anno["x"] self.assertIsInstance(x_anno, ForwardRef) self.assertEqual(x_anno, support.EqualToForwardRef("some.module", owner=f)) @@ -127,14 +122,14 @@ def f( self.assertEqual(gamma_anno, support.EqualToForwardRef("some < obj", owner=f)) -class TestSourceFormat(unittest.TestCase): +class TestStringFormat(unittest.TestCase): def test_closure(self): x = 0 def inner(arg: x): pass - anno = annotationlib.get_annotations(inner, format=Format.STRING) + anno = get_annotations(inner, format=Format.STRING) self.assertEqual(anno, {"arg": "x"}) def test_closure_undefined(self): @@ -144,14 +139,14 @@ def test_closure_undefined(self): def inner(arg: x): pass - anno = annotationlib.get_annotations(inner, format=Format.STRING) + anno = get_annotations(inner, format=Format.STRING) self.assertEqual(anno, {"arg": "x"}) def test_function(self): def f(x: int, y: doesntexist): pass - anno = annotationlib.get_annotations(f, format=Format.STRING) + anno = get_annotations(f, format=Format.STRING) self.assertEqual(anno, {"x": "int", "y": "doesntexist"}) def test_expressions(self): @@ -185,7 +180,7 @@ def f( ): pass - anno = annotationlib.get_annotations(f, format=Format.STRING) + anno = get_annotations(f, format=Format.STRING) self.assertEqual( anno, { @@ -236,7 +231,7 @@ def f( ): pass - anno = annotationlib.get_annotations(f, format=Format.STRING) + anno = get_annotations(f, format=Format.STRING) self.assertEqual( anno, { @@ -270,7 +265,7 @@ def f( ): pass - anno = annotationlib.get_annotations(f, format=Format.STRING) + anno = get_annotations(f, format=Format.STRING) self.assertEqual( anno, { @@ -293,125 +288,19 @@ def f(fstring: f"{a}"): pass with self.assertRaisesRegex(TypeError, format_msg): - annotationlib.get_annotations(f, format=Format.STRING) + get_annotations(f, format=Format.STRING) def f(fstring_format: f"{a:02d}"): pass with self.assertRaisesRegex(TypeError, format_msg): - annotationlib.get_annotations(f, format=Format.STRING) - - -class TestForwardRefClass(unittest.TestCase): - def test_special_attrs(self): - # Forward refs provide a different introspection API. __name__ and - # __qualname__ make little sense for forward refs as they can store - # complex typing expressions. - fr = annotationlib.ForwardRef("set[Any]") - self.assertFalse(hasattr(fr, "__name__")) - self.assertFalse(hasattr(fr, "__qualname__")) - self.assertEqual(fr.__module__, "annotationlib") - # Forward refs are currently unpicklable once they contain a code object. - fr.__forward_code__ # fill the cache - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises(TypeError): - pickle.dumps(fr, proto) - - def test_evaluate_with_type_params(self): - class Gen[T]: - alias = int - - with self.assertRaises(NameError): - ForwardRef("T").evaluate() - with self.assertRaises(NameError): - ForwardRef("T").evaluate(type_params=()) - with self.assertRaises(NameError): - ForwardRef("T").evaluate(owner=int) - - (T,) = Gen.__type_params__ - self.assertIs(ForwardRef("T").evaluate(type_params=Gen.__type_params__), T) - self.assertIs(ForwardRef("T").evaluate(owner=Gen), T) - - with self.assertRaises(NameError): - ForwardRef("alias").evaluate(type_params=Gen.__type_params__) - self.assertIs(ForwardRef("alias").evaluate(owner=Gen), int) - # If you pass custom locals, we don't look at the owner's locals - with self.assertRaises(NameError): - ForwardRef("alias").evaluate(owner=Gen, locals={}) - # But if the name exists in the locals, it works - self.assertIs( - ForwardRef("alias").evaluate(owner=Gen, locals={"alias": str}), str - ) - - def test_fwdref_with_module(self): - self.assertIs(ForwardRef("Format", module="annotationlib").evaluate(), Format) - self.assertIs( - ForwardRef("Counter", module="collections").evaluate(), collections.Counter - ) - self.assertEqual( - ForwardRef("Counter[int]", module="collections").evaluate(), - collections.Counter[int], - ) - - with self.assertRaises(NameError): - # If globals are passed explicitly, we don't look at the module dict - ForwardRef("Format", module="annotationlib").evaluate(globals={}) - - def test_fwdref_to_builtin(self): - self.assertIs(ForwardRef("int").evaluate(), int) - self.assertIs(ForwardRef("int", module="collections").evaluate(), int) - self.assertIs(ForwardRef("int", owner=str).evaluate(), int) - - # builtins are still searched with explicit globals - self.assertIs(ForwardRef("int").evaluate(globals={}), int) - - # explicit values in globals have precedence - obj = object() - self.assertIs(ForwardRef("int").evaluate(globals={"int": obj}), obj) - - def test_fwdref_value_is_not_cached(self): - fr = ForwardRef("hello") - with self.assertRaises(NameError): - fr.evaluate() - self.assertIs(fr.evaluate(globals={"hello": str}), str) - with self.assertRaises(NameError): - fr.evaluate() - - def test_fwdref_with_owner(self): - self.assertEqual( - ForwardRef("Counter[int]", owner=collections).evaluate(), - collections.Counter[int], - ) - - def test_name_lookup_without_eval(self): - # test the codepath where we look up simple names directly in the - # namespaces without going through eval() - self.assertIs(ForwardRef("int").evaluate(), int) - self.assertIs(ForwardRef("int").evaluate(locals={"int": str}), str) - self.assertIs( - ForwardRef("int").evaluate(locals={"int": float}, globals={"int": str}), - float, - ) - self.assertIs(ForwardRef("int").evaluate(globals={"int": str}), str) - with support.swap_attr(builtins, "int", dict): - self.assertIs(ForwardRef("int").evaluate(), dict) - - with self.assertRaises(NameError): - ForwardRef("doesntexist").evaluate() - - def test_fwdref_invalid_syntax(self): - fr = ForwardRef("if") - with self.assertRaises(SyntaxError): - fr.evaluate() - fr = ForwardRef("1+") - with self.assertRaises(SyntaxError): - fr.evaluate() + get_annotations(f, format=Format.STRING) class TestGetAnnotations(unittest.TestCase): def test_builtin_type(self): - self.assertEqual(annotationlib.get_annotations(int), {}) - self.assertEqual(annotationlib.get_annotations(object), {}) + self.assertEqual(get_annotations(int), {}) + self.assertEqual(get_annotations(object), {}) def test_custom_metaclass(self): class Meta(type): @@ -420,7 +309,7 @@ class Meta(type): class C(metaclass=Meta): x: int - self.assertEqual(annotationlib.get_annotations(C), {"x": int}) + self.assertEqual(get_annotations(C), {"x": int}) def test_missing_dunder_dict(self): class NoDict(type): @@ -433,22 +322,22 @@ def __dict__(cls): class C1(metaclass=NoDict): a: int - self.assertEqual(annotationlib.get_annotations(C1), {"a": int}) + self.assertEqual(get_annotations(C1), {"a": int}) self.assertEqual( - annotationlib.get_annotations(C1, format=Format.FORWARDREF), + get_annotations(C1, format=Format.FORWARDREF), {"a": int}, ) self.assertEqual( - annotationlib.get_annotations(C1, format=Format.STRING), + get_annotations(C1, format=Format.STRING), {"a": "int"}, ) - self.assertEqual(annotationlib.get_annotations(NoDict), {"b": str}) + self.assertEqual(get_annotations(NoDict), {"b": str}) self.assertEqual( - annotationlib.get_annotations(NoDict, format=Format.FORWARDREF), + get_annotations(NoDict, format=Format.FORWARDREF), {"b": str}, ) self.assertEqual( - annotationlib.get_annotations(NoDict, format=Format.STRING), + get_annotations(NoDict, format=Format.STRING), {"b": "str"}, ) @@ -460,53 +349,53 @@ def f2(a: undefined): pass self.assertEqual( - annotationlib.get_annotations(f1, format=Format.VALUE), + get_annotations(f1, format=Format.VALUE), {"a": int}, ) - self.assertEqual(annotationlib.get_annotations(f1, format=1), {"a": int}) + self.assertEqual(get_annotations(f1, format=1), {"a": int}) fwd = support.EqualToForwardRef("undefined", owner=f2) self.assertEqual( - annotationlib.get_annotations(f2, format=Format.FORWARDREF), + get_annotations(f2, format=Format.FORWARDREF), {"a": fwd}, ) - self.assertEqual(annotationlib.get_annotations(f2, format=3), {"a": fwd}) + self.assertEqual(get_annotations(f2, format=3), {"a": fwd}) self.assertEqual( - annotationlib.get_annotations(f1, format=Format.STRING), + get_annotations(f1, format=Format.STRING), {"a": "int"}, ) - self.assertEqual(annotationlib.get_annotations(f1, format=4), {"a": "int"}) + self.assertEqual(get_annotations(f1, format=4), {"a": "int"}) with self.assertRaises(ValueError): - annotationlib.get_annotations(f1, format=42) + get_annotations(f1, format=42) with self.assertRaisesRegex( ValueError, r"The VALUE_WITH_FAKE_GLOBALS format is for internal use only", ): - annotationlib.get_annotations(f1, format=Format.VALUE_WITH_FAKE_GLOBALS) + get_annotations(f1, format=Format.VALUE_WITH_FAKE_GLOBALS) with self.assertRaisesRegex( ValueError, r"The VALUE_WITH_FAKE_GLOBALS format is for internal use only", ): - annotationlib.get_annotations(f1, format=2) + get_annotations(f1, format=2) def test_custom_object_with_annotations(self): class C: def __init__(self): self.__annotations__ = {"x": int, "y": str} - self.assertEqual(annotationlib.get_annotations(C()), {"x": int, "y": str}) + self.assertEqual(get_annotations(C()), {"x": int, "y": str}) def test_custom_format_eval_str(self): def foo(): pass with self.assertRaises(ValueError): - annotationlib.get_annotations(foo, format=Format.FORWARDREF, eval_str=True) - annotationlib.get_annotations(foo, format=Format.STRING, eval_str=True) + get_annotations(foo, format=Format.FORWARDREF, eval_str=True) + get_annotations(foo, format=Format.STRING, eval_str=True) def test_stock_annotations(self): def foo(a: int, b: str): @@ -515,11 +404,11 @@ def foo(a: int, b: str): for format in (Format.VALUE, Format.FORWARDREF): with self.subTest(format=format): self.assertEqual( - annotationlib.get_annotations(foo, format=format), + get_annotations(foo, format=format), {"a": int, "b": str}, ) self.assertEqual( - annotationlib.get_annotations(foo, format=Format.STRING), + get_annotations(foo, format=Format.STRING), {"a": "int", "b": "str"}, ) @@ -529,16 +418,16 @@ def foo(a: int, b: str): continue with self.subTest(format=format): self.assertEqual( - annotationlib.get_annotations(foo, format=format), + get_annotations(foo, format=format), {"a": "foo", "b": "str"}, ) self.assertEqual( - annotationlib.get_annotations(foo, eval_str=True, locals=locals()), + get_annotations(foo, eval_str=True, locals=locals()), {"a": foo, "b": str}, ) self.assertEqual( - annotationlib.get_annotations(foo, eval_str=True, globals=locals()), + get_annotations(foo, eval_str=True, globals=locals()), {"a": foo, "b": str}, ) @@ -554,33 +443,29 @@ def test_stock_annotations_in_module(self): {"format": Format.FORWARDREF, "eval_str": False}, ]: with self.subTest(**kwargs): + self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) self.assertEqual( - annotationlib.get_annotations(isa, **kwargs), {"a": int, "b": str} - ) - self.assertEqual( - annotationlib.get_annotations(isa.MyClass, **kwargs), + get_annotations(isa.MyClass, **kwargs), {"a": int, "b": str}, ) self.assertEqual( - annotationlib.get_annotations(isa.function, **kwargs), + get_annotations(isa.function, **kwargs), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function2, **kwargs), + get_annotations(isa.function2, **kwargs), {"a": int, "b": "str", "c": isa.MyClass, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function3, **kwargs), + get_annotations(isa.function3, **kwargs), {"a": "int", "b": "str", "c": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(annotationlib, **kwargs), {} + get_annotations(annotationlib, **kwargs), {} ) # annotations module has no annotations + self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) self.assertEqual( - annotationlib.get_annotations(isa.UnannotatedClass, **kwargs), {} - ) - self.assertEqual( - annotationlib.get_annotations(isa.unannotated_function, **kwargs), + get_annotations(isa.unannotated_function, **kwargs), {}, ) @@ -589,68 +474,60 @@ def test_stock_annotations_in_module(self): {"format": Format.VALUE, "eval_str": True}, ]: with self.subTest(**kwargs): + self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) self.assertEqual( - annotationlib.get_annotations(isa, **kwargs), {"a": int, "b": str} - ) - self.assertEqual( - annotationlib.get_annotations(isa.MyClass, **kwargs), + get_annotations(isa.MyClass, **kwargs), {"a": int, "b": str}, ) self.assertEqual( - annotationlib.get_annotations(isa.function, **kwargs), + get_annotations(isa.function, **kwargs), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function2, **kwargs), + get_annotations(isa.function2, **kwargs), {"a": int, "b": str, "c": isa.MyClass, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function3, **kwargs), + get_annotations(isa.function3, **kwargs), {"a": int, "b": str, "c": isa.MyClass}, ) + self.assertEqual(get_annotations(annotationlib, **kwargs), {}) + self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) self.assertEqual( - annotationlib.get_annotations(annotationlib, **kwargs), {} - ) - self.assertEqual( - annotationlib.get_annotations(isa.UnannotatedClass, **kwargs), {} - ) - self.assertEqual( - annotationlib.get_annotations(isa.unannotated_function, **kwargs), + get_annotations(isa.unannotated_function, **kwargs), {}, ) self.assertEqual( - annotationlib.get_annotations(isa, format=Format.STRING), + get_annotations(isa, format=Format.STRING), {"a": "int", "b": "str"}, ) self.assertEqual( - annotationlib.get_annotations(isa.MyClass, format=Format.STRING), + get_annotations(isa.MyClass, format=Format.STRING), {"a": "int", "b": "str"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function, format=Format.STRING), + get_annotations(isa.function, format=Format.STRING), {"a": "int", "b": "str", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function2, format=Format.STRING), + get_annotations(isa.function2, format=Format.STRING), {"a": "int", "b": "str", "c": "MyClass", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function3, format=Format.STRING), + get_annotations(isa.function3, format=Format.STRING), {"a": "int", "b": "str", "c": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(annotationlib, format=Format.STRING), + get_annotations(annotationlib, format=Format.STRING), {}, ) self.assertEqual( - annotationlib.get_annotations(isa.UnannotatedClass, format=Format.STRING), + get_annotations(isa.UnannotatedClass, format=Format.STRING), {}, ) self.assertEqual( - annotationlib.get_annotations( - isa.unannotated_function, format=Format.STRING - ), + get_annotations(isa.unannotated_function, format=Format.STRING), {}, ) @@ -661,23 +538,23 @@ def test_stock_annotations_on_wrapper(self): self.assertEqual(wrapped(1, "x"), isa.MyClass(3, "xxx")) self.assertIsNot(wrapped.__globals__, isa.function.__globals__) self.assertEqual( - annotationlib.get_annotations(wrapped), + get_annotations(wrapped), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, format=Format.FORWARDREF), + get_annotations(wrapped, format=Format.FORWARDREF), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, format=Format.STRING), + get_annotations(wrapped, format=Format.STRING), {"a": "int", "b": "str", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, eval_str=True), + get_annotations(wrapped, eval_str=True), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, eval_str=False), + get_annotations(wrapped, eval_str=False), {"a": int, "b": str, "return": isa.MyClass}, ) @@ -695,30 +572,28 @@ def test_stringized_annotations_in_module(self): ]: with self.subTest(**kwargs): self.assertEqual( - annotationlib.get_annotations(isa, **kwargs), + get_annotations(isa, **kwargs), {"a": "int", "b": "str"}, ) self.assertEqual( - annotationlib.get_annotations(isa.MyClass, **kwargs), + get_annotations(isa.MyClass, **kwargs), {"a": "int", "b": "str"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function, **kwargs), + get_annotations(isa.function, **kwargs), {"a": "int", "b": "str", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function2, **kwargs), + get_annotations(isa.function2, **kwargs), {"a": "int", "b": "'str'", "c": "MyClass", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(isa.function3, **kwargs), + get_annotations(isa.function3, **kwargs), {"a": "'int'", "b": "'str'", "c": "'MyClass'"}, ) + self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) self.assertEqual( - annotationlib.get_annotations(isa.UnannotatedClass, **kwargs), {} - ) - self.assertEqual( - annotationlib.get_annotations(isa.unannotated_function, **kwargs), + get_annotations(isa.unannotated_function, **kwargs), {}, ) @@ -727,38 +602,34 @@ def test_stringized_annotations_in_module(self): {"format": Format.VALUE, "eval_str": True}, ]: with self.subTest(**kwargs): + self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) self.assertEqual( - annotationlib.get_annotations(isa, **kwargs), {"a": int, "b": str} - ) - self.assertEqual( - annotationlib.get_annotations(isa.MyClass, **kwargs), + get_annotations(isa.MyClass, **kwargs), {"a": int, "b": str}, ) self.assertEqual( - annotationlib.get_annotations(isa.function, **kwargs), + get_annotations(isa.function, **kwargs), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function2, **kwargs), + get_annotations(isa.function2, **kwargs), {"a": int, "b": "str", "c": isa.MyClass, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(isa.function3, **kwargs), + get_annotations(isa.function3, **kwargs), {"a": "int", "b": "str", "c": "MyClass"}, ) + self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) self.assertEqual( - annotationlib.get_annotations(isa.UnannotatedClass, **kwargs), {} - ) - self.assertEqual( - annotationlib.get_annotations(isa.unannotated_function, **kwargs), + get_annotations(isa.unannotated_function, **kwargs), {}, ) def test_stringized_annotations_in_empty_module(self): isa2 = inspect_stringized_annotations_2 - self.assertEqual(annotationlib.get_annotations(isa2), {}) - self.assertEqual(annotationlib.get_annotations(isa2, eval_str=True), {}) - self.assertEqual(annotationlib.get_annotations(isa2, eval_str=False), {}) + self.assertEqual(get_annotations(isa2), {}) + self.assertEqual(get_annotations(isa2, eval_str=True), {}) + self.assertEqual(get_annotations(isa2, eval_str=False), {}) def test_stringized_annotations_on_wrapper(self): isa = inspect_stringized_annotations @@ -766,15 +637,15 @@ def test_stringized_annotations_on_wrapper(self): self.assertEqual(wrapped(1, "x"), isa.MyClass(3, "xxx")) self.assertIsNot(wrapped.__globals__, isa.function.__globals__) self.assertEqual( - annotationlib.get_annotations(wrapped), + get_annotations(wrapped), {"a": "int", "b": "str", "return": "MyClass"}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, eval_str=True), + get_annotations(wrapped, eval_str=True), {"a": int, "b": str, "return": isa.MyClass}, ) self.assertEqual( - annotationlib.get_annotations(wrapped, eval_str=False), + get_annotations(wrapped, eval_str=False), {"a": "int", "b": "str", "return": "MyClass"}, ) @@ -782,13 +653,11 @@ def test_stringized_annotations_on_class(self): isa = inspect_stringized_annotations # test that local namespace lookups work self.assertEqual( - annotationlib.get_annotations(isa.MyClassWithLocalAnnotations), + get_annotations(isa.MyClassWithLocalAnnotations), {"x": "mytype"}, ) self.assertEqual( - annotationlib.get_annotations( - isa.MyClassWithLocalAnnotations, eval_str=True - ), + get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), {"x": int}, ) @@ -796,23 +665,23 @@ def test_modify_annotations(self): def f(x: int): pass - self.assertEqual(annotationlib.get_annotations(f), {"x": int}) + self.assertEqual(get_annotations(f), {"x": int}) self.assertEqual( - annotationlib.get_annotations(f, format=Format.FORWARDREF), + get_annotations(f, format=Format.FORWARDREF), {"x": int}, ) f.__annotations__["x"] = str # The modification is reflected in VALUE (the default) - self.assertEqual(annotationlib.get_annotations(f), {"x": str}) + self.assertEqual(get_annotations(f), {"x": str}) # ... and also in FORWARDREF, which tries __annotations__ if available self.assertEqual( - annotationlib.get_annotations(f, format=Format.FORWARDREF), + get_annotations(f, format=Format.FORWARDREF), {"x": str}, ) # ... but not in STRING which always uses __annotate__ self.assertEqual( - annotationlib.get_annotations(f, format=Format.STRING), + get_annotations(f, format=Format.STRING), {"x": "int"}, ) @@ -832,7 +701,7 @@ def __annotations__(self): ValueError, r".*__annotations__ is neither a dict nor None" ), ): - annotationlib.get_annotations(wa, format=format) + get_annotations(wa, format=format) def test_annotations_on_custom_object(self): class HasAnnotations: @@ -841,16 +710,10 @@ def __annotations__(self): return {"x": int} ha = HasAnnotations() - self.assertEqual( - annotationlib.get_annotations(ha, format=Format.VALUE), {"x": int} - ) - self.assertEqual( - annotationlib.get_annotations(ha, format=Format.FORWARDREF), {"x": int} - ) + self.assertEqual(get_annotations(ha, format=Format.VALUE), {"x": int}) + self.assertEqual(get_annotations(ha, format=Format.FORWARDREF), {"x": int}) - self.assertEqual( - annotationlib.get_annotations(ha, format=Format.STRING), {"x": "int"} - ) + self.assertEqual(get_annotations(ha, format=Format.STRING), {"x": "int"}) def test_raising_annotations_on_custom_object(self): class HasRaisingAnnotations: @@ -861,15 +724,13 @@ def __annotations__(self): hra = HasRaisingAnnotations() with self.assertRaises(NameError): - annotationlib.get_annotations(hra, format=Format.VALUE) + get_annotations(hra, format=Format.VALUE) with self.assertRaises(NameError): - annotationlib.get_annotations(hra, format=Format.FORWARDREF) + get_annotations(hra, format=Format.FORWARDREF) undefined = float - self.assertEqual( - annotationlib.get_annotations(hra, format=Format.VALUE), {"x": float} - ) + self.assertEqual(get_annotations(hra, format=Format.VALUE), {"x": float}) def test_forwardref_prefers_annotations(self): class HasBoth: @@ -882,15 +743,9 @@ def __annotate__(self): return lambda format: {"x": str} hb = HasBoth() - self.assertEqual( - annotationlib.get_annotations(hb, format=Format.VALUE), {"x": int} - ) - self.assertEqual( - annotationlib.get_annotations(hb, format=Format.FORWARDREF), {"x": int} - ) - self.assertEqual( - annotationlib.get_annotations(hb, format=Format.STRING), {"x": str} - ) + self.assertEqual(get_annotations(hb, format=Format.VALUE), {"x": int}) + self.assertEqual(get_annotations(hb, format=Format.FORWARDREF), {"x": int}) + self.assertEqual(get_annotations(hb, format=Format.STRING), {"x": str}) def test_only_annotate(self): def f(x: int): @@ -902,14 +757,10 @@ def __annotate__(self): return f.__annotate__ oa = OnlyAnnotate() + self.assertEqual(get_annotations(oa, format=Format.VALUE), {"x": int}) + self.assertEqual(get_annotations(oa, format=Format.FORWARDREF), {"x": int}) self.assertEqual( - annotationlib.get_annotations(oa, format=Format.VALUE), {"x": int} - ) - self.assertEqual( - annotationlib.get_annotations(oa, format=Format.FORWARDREF), {"x": int} - ) - self.assertEqual( - annotationlib.get_annotations(oa, format=Format.STRING), + get_annotations(oa, format=Format.STRING), {"x": "int"}, ) @@ -927,25 +778,23 @@ def __call__(self): for obj in (None, 1, object(), CustomClass()): with self.subTest(format=format, obj=obj): with self.assertRaises(TypeError): - annotationlib.get_annotations(obj, format=format) + get_annotations(obj, format=format) # Callables and types with no annotations return an empty dict for obj in (int, len, MyCallable()): with self.subTest(format=format, obj=obj): - self.assertEqual( - annotationlib.get_annotations(obj, format=format), {} - ) + self.assertEqual(get_annotations(obj, format=format), {}) def test_pep695_generic_class_with_future_annotations(self): ann_module695 = inspect_stringized_annotations_pep695 - A_annotations = annotationlib.get_annotations(ann_module695.A, eval_str=True) + A_annotations = get_annotations(ann_module695.A, eval_str=True) A_type_params = ann_module695.A.__type_params__ self.assertIs(A_annotations["x"], A_type_params[0]) self.assertEqual(A_annotations["y"].__args__[0], Unpack[A_type_params[1]]) self.assertIs(A_annotations["z"].__args__[0], A_type_params[2]) def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self): - B_annotations = annotationlib.get_annotations( + B_annotations = get_annotations( inspect_stringized_annotations_pep695.B, eval_str=True ) self.assertEqual(B_annotations, {"x": int, "y": str, "z": bytes}) @@ -954,14 +803,14 @@ def test_pep695_generic_class_with_future_annotations_name_clash_with_global_var self, ): ann_module695 = inspect_stringized_annotations_pep695 - C_annotations = annotationlib.get_annotations(ann_module695.C, eval_str=True) + C_annotations = get_annotations(ann_module695.C, eval_str=True) self.assertEqual( set(C_annotations.values()), set(ann_module695.C.__type_params__) ) def test_pep_695_generic_function_with_future_annotations(self): ann_module695 = inspect_stringized_annotations_pep695 - generic_func_annotations = annotationlib.get_annotations( + generic_func_annotations = get_annotations( ann_module695.generic_function, eval_str=True ) func_t_params = ann_module695.generic_function.__type_params__ @@ -978,7 +827,7 @@ def test_pep_695_generic_function_with_future_annotations_name_clash_with_global ): self.assertEqual( set( - annotationlib.get_annotations( + get_annotations( inspect_stringized_annotations_pep695.generic_function_2, eval_str=True, ).values() @@ -990,7 +839,7 @@ def test_pep_695_generic_function_with_future_annotations_name_clash_with_global def test_pep_695_generic_method_with_future_annotations(self): ann_module695 = inspect_stringized_annotations_pep695 - generic_method_annotations = annotationlib.get_annotations( + generic_method_annotations = get_annotations( ann_module695.D.generic_method, eval_str=True ) params = { @@ -1007,7 +856,7 @@ def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_v ): self.assertEqual( set( - annotationlib.get_annotations( + get_annotations( inspect_stringized_annotations_pep695.D.generic_method_2, eval_str=True, ).values() @@ -1021,9 +870,7 @@ def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_a self, ): self.assertEqual( - annotationlib.get_annotations( - inspect_stringized_annotations_pep695.E, eval_str=True - ), + get_annotations(inspect_stringized_annotations_pep695.E, eval_str=True), {"x": str}, ) @@ -1179,7 +1026,7 @@ class C: self.assertEqual(get_annotate_function(C)(Format.VALUE), {"a": int}) -class TestToSource(unittest.TestCase): +class TestTypeRepr(unittest.TestCase): def test_type_repr(self): class Nested: pass @@ -1190,9 +1037,11 @@ def nested(): self.assertEqual(type_repr(int), "int") self.assertEqual(type_repr(MyClass), f"{__name__}.MyClass") self.assertEqual( - type_repr(Nested), f"{__name__}.TestToSource.test_type_repr.<locals>.Nested") + type_repr(Nested), f"{__name__}.TestTypeRepr.test_type_repr.<locals>.Nested" + ) self.assertEqual( - type_repr(nested), f"{__name__}.TestToSource.test_type_repr.<locals>.nested") + type_repr(nested), f"{__name__}.TestTypeRepr.test_type_repr.<locals>.nested" + ) self.assertEqual(type_repr(len), "len") self.assertEqual(type_repr(type_repr), "annotationlib.type_repr") self.assertEqual(type_repr(times_three), f"{__name__}.times_three") @@ -1203,6 +1052,8 @@ def nested(): self.assertEqual(type_repr(Format.VALUE), repr(Format.VALUE)) self.assertEqual(type_repr(MyClass()), "my repr") + +class TestAnnotationsToString(unittest.TestCase): def test_annotations_to_string(self): self.assertEqual(annotations_to_string({}), {}) self.assertEqual(annotations_to_string({"x": int}), {"x": "int"}) @@ -1216,14 +1067,14 @@ class A: pass -class ForwardRefTests(unittest.TestCase): +class TestForwardRefClass(unittest.TestCase): def test_forwardref_instance_type_error(self): - fr = ForwardRef('int') + fr = ForwardRef("int") with self.assertRaises(TypeError): isinstance(42, fr) def test_forwardref_subclass_type_error(self): - fr = ForwardRef('int') + fr = ForwardRef("int") with self.assertRaises(TypeError): issubclass(int, fr) @@ -1232,26 +1083,27 @@ def test_forwardref_only_str_arg(self): ForwardRef(1) # only `str` type is allowed def test_forward_equality(self): - fr = ForwardRef('int') - self.assertEqual(fr, ForwardRef('int')) - self.assertNotEqual(List['int'], List[int]) - self.assertNotEqual(fr, ForwardRef('int', module=__name__)) - frm = ForwardRef('int', module=__name__) - self.assertEqual(frm, ForwardRef('int', module=__name__)) - self.assertNotEqual(frm, ForwardRef('int', module='__other_name__')) + fr = ForwardRef("int") + self.assertEqual(fr, ForwardRef("int")) + self.assertNotEqual(List["int"], List[int]) + self.assertNotEqual(fr, ForwardRef("int", module=__name__)) + frm = ForwardRef("int", module=__name__) + self.assertEqual(frm, ForwardRef("int", module=__name__)) + self.assertNotEqual(frm, ForwardRef("int", module="__other_name__")) def test_forward_equality_get_type_hints(self): - c1 = ForwardRef('C') - c1_gth = ForwardRef('C') - c2 = ForwardRef('C') - c2_gth = ForwardRef('C') + c1 = ForwardRef("C") + c1_gth = ForwardRef("C") + c2 = ForwardRef("C") + c2_gth = ForwardRef("C") class C: pass + def foo(a: c1_gth, b: c2_gth): pass - self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': C, 'b': C}) + self.assertEqual(get_type_hints(foo, globals(), locals()), {"a": C, "b": C}) self.assertEqual(c1, c2) self.assertEqual(c1, c1_gth) self.assertEqual(c1_gth, c2_gth) @@ -1262,40 +1114,44 @@ def foo(a: c1_gth, b: c2_gth): self.assertEqual(Union[c1, c1_gth, int], Union[c1, int]) def test_forward_equality_hash(self): - c1 = ForwardRef('int') - c1_gth = ForwardRef('int') - c2 = ForwardRef('int') - c2_gth = ForwardRef('int') + c1 = ForwardRef("int") + c1_gth = ForwardRef("int") + c2 = ForwardRef("int") + c2_gth = ForwardRef("int") def foo(a: c1_gth, b: c2_gth): pass + get_type_hints(foo, globals(), locals()) self.assertEqual(hash(c1), hash(c2)) self.assertEqual(hash(c1_gth), hash(c2_gth)) self.assertEqual(hash(c1), hash(c1_gth)) - c3 = ForwardRef('int', module=__name__) - c4 = ForwardRef('int', module='__other_name__') + c3 = ForwardRef("int", module=__name__) + c4 = ForwardRef("int", module="__other_name__") self.assertNotEqual(hash(c3), hash(c1)) self.assertNotEqual(hash(c3), hash(c1_gth)) self.assertNotEqual(hash(c3), hash(c4)) - self.assertEqual(hash(c3), hash(ForwardRef('int', module=__name__))) + self.assertEqual(hash(c3), hash(ForwardRef("int", module=__name__))) def test_forward_equality_namespace(self): def namespace1(): - a = ForwardRef('A') + a = ForwardRef("A") + def fun(x: a): pass + get_type_hints(fun, globals(), locals()) return a def namespace2(): - a = ForwardRef('A') + a = ForwardRef("A") class A: pass + def fun(x: a): pass @@ -1306,23 +1162,29 @@ def fun(x: a): self.assertEqual(namespace1(), namespace2()) def test_forward_repr(self): - self.assertEqual(repr(List['int']), "typing.List[ForwardRef('int')]") - self.assertEqual(repr(List[ForwardRef('int', module='mod')]), - "typing.List[ForwardRef('int', module='mod')]") + self.assertEqual(repr(List["int"]), "typing.List[ForwardRef('int')]") + self.assertEqual( + repr(List[ForwardRef("int", module="mod")]), + "typing.List[ForwardRef('int', module='mod')]", + ) def test_forward_recursion_actually(self): def namespace1(): - a = ForwardRef('A') + a = ForwardRef("A") A = a - def fun(x: a): pass + + def fun(x: a): + pass ret = get_type_hints(fun, globals(), locals()) return a def namespace2(): - a = ForwardRef('A') + a = ForwardRef("A") A = a - def fun(x: a): pass + + def fun(x: a): + pass ret = get_type_hints(fun, globals(), locals()) return a @@ -1335,11 +1197,11 @@ def fun(x: a): pass def test_syntax_error(self): with self.assertRaises(SyntaxError): - typing.Generic['/T'] + typing.Generic["/T"] def test_delayed_syntax_error(self): - def foo(a: 'Node[T'): + def foo(a: "Node[T"): pass with self.assertRaises(SyntaxError): @@ -1349,10 +1211,10 @@ def test_syntax_error_empty_string(self): for form in [typing.List, typing.Set, typing.Type, typing.Deque]: with self.subTest(form=form): with self.assertRaises(SyntaxError): - form[''] + form[""] def test_or(self): - X = ForwardRef('X') + X = ForwardRef("X") # __or__/__ror__ itself self.assertEqual(X | "x", Union[X, "x"]) self.assertEqual("x" | X, Union["x", X]) @@ -1364,13 +1226,121 @@ def test_multiple_ways_to_create(self): self.assertIsInstance(X2, ForwardRef) self.assertEqual(X1, X2) + def test_special_attrs(self): + # Forward refs provide a different introspection API. __name__ and + # __qualname__ make little sense for forward refs as they can store + # complex typing expressions. + fr = ForwardRef("set[Any]") + self.assertNotHasAttr(fr, "__name__") + self.assertNotHasAttr(fr, "__qualname__") + self.assertEqual(fr.__module__, "annotationlib") + # Forward refs are currently unpicklable once they contain a code object. + fr.__forward_code__ # fill the cache + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.assertRaises(TypeError): + pickle.dumps(fr, proto) + + def test_evaluate_with_type_params(self): + class Gen[T]: + alias = int + + with self.assertRaises(NameError): + ForwardRef("T").evaluate() + with self.assertRaises(NameError): + ForwardRef("T").evaluate(type_params=()) + with self.assertRaises(NameError): + ForwardRef("T").evaluate(owner=int) + + (T,) = Gen.__type_params__ + self.assertIs(ForwardRef("T").evaluate(type_params=Gen.__type_params__), T) + self.assertIs(ForwardRef("T").evaluate(owner=Gen), T) + + with self.assertRaises(NameError): + ForwardRef("alias").evaluate(type_params=Gen.__type_params__) + self.assertIs(ForwardRef("alias").evaluate(owner=Gen), int) + # If you pass custom locals, we don't look at the owner's locals + with self.assertRaises(NameError): + ForwardRef("alias").evaluate(owner=Gen, locals={}) + # But if the name exists in the locals, it works + self.assertIs( + ForwardRef("alias").evaluate(owner=Gen, locals={"alias": str}), str + ) + + def test_fwdref_with_module(self): + self.assertIs(ForwardRef("Format", module="annotationlib").evaluate(), Format) + self.assertIs( + ForwardRef("Counter", module="collections").evaluate(), collections.Counter + ) + self.assertEqual( + ForwardRef("Counter[int]", module="collections").evaluate(), + collections.Counter[int], + ) + + with self.assertRaises(NameError): + # If globals are passed explicitly, we don't look at the module dict + ForwardRef("Format", module="annotationlib").evaluate(globals={}) + + def test_fwdref_to_builtin(self): + self.assertIs(ForwardRef("int").evaluate(), int) + self.assertIs(ForwardRef("int", module="collections").evaluate(), int) + self.assertIs(ForwardRef("int", owner=str).evaluate(), int) + + # builtins are still searched with explicit globals + self.assertIs(ForwardRef("int").evaluate(globals={}), int) + + # explicit values in globals have precedence + obj = object() + self.assertIs(ForwardRef("int").evaluate(globals={"int": obj}), obj) + + def test_fwdref_value_is_not_cached(self): + fr = ForwardRef("hello") + with self.assertRaises(NameError): + fr.evaluate() + self.assertIs(fr.evaluate(globals={"hello": str}), str) + with self.assertRaises(NameError): + fr.evaluate() + + def test_fwdref_with_owner(self): + self.assertEqual( + ForwardRef("Counter[int]", owner=collections).evaluate(), + collections.Counter[int], + ) + + def test_name_lookup_without_eval(self): + # test the codepath where we look up simple names directly in the + # namespaces without going through eval() + self.assertIs(ForwardRef("int").evaluate(), int) + self.assertIs(ForwardRef("int").evaluate(locals={"int": str}), str) + self.assertIs( + ForwardRef("int").evaluate(locals={"int": float}, globals={"int": str}), + float, + ) + self.assertIs(ForwardRef("int").evaluate(globals={"int": str}), str) + with support.swap_attr(builtins, "int", dict): + self.assertIs(ForwardRef("int").evaluate(), dict) + + with self.assertRaises(NameError): + ForwardRef("doesntexist").evaluate() + + def test_fwdref_invalid_syntax(self): + fr = ForwardRef("if") + with self.assertRaises(SyntaxError): + fr.evaluate() + fr = ForwardRef("1+") + with self.assertRaises(SyntaxError): + fr.evaluate() + class TestAnnotationLib(unittest.TestCase): def test__all__(self): support.check__all__(self, annotationlib) + @support.cpython_only def test_lazy_imports(self): - import_helper.ensure_lazy_imports("annotationlib", { - "typing", - "warnings", - }) + import_helper.ensure_lazy_imports( + "annotationlib", + { + "typing", + "warnings", + }, + ) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 93cc2a8ca83b8f..8c55ba4623e719 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -53,7 +53,10 @@ captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper, run_code, EqualToForwardRef, ) -from test.typinganndata import ann_module695, mod_generics_cache, _typed_dict_helper +from test.typinganndata import ( + ann_module695, mod_generics_cache, _typed_dict_helper, + ann_module, ann_module2, ann_module3, ann_module5, ann_module6, ann_module8 +) CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' @@ -377,6 +380,7 @@ def test_alias(self): self.assertEqual(get_args(alias_2), (LiteralString,)) self.assertEqual(get_args(alias_3), (LiteralString,)) + class TypeVarTests(BaseTestCase): def test_basic_plain(self): T = TypeVar('T') @@ -629,7 +633,7 @@ class TypeParameterDefaultsTests(BaseTestCase): def test_typevar(self): T = TypeVar('T', default=int) self.assertEqual(T.__default__, int) - self.assertTrue(T.has_default()) + self.assertIs(T.has_default(), True) self.assertIsInstance(T, TypeVar) class A(Generic[T]): ... @@ -639,19 +643,19 @@ def test_typevar_none(self): U = TypeVar('U') U_None = TypeVar('U_None', default=None) self.assertIs(U.__default__, NoDefault) - self.assertFalse(U.has_default()) + self.assertIs(U.has_default(), False) self.assertIs(U_None.__default__, None) - self.assertTrue(U_None.has_default()) + self.assertIs(U_None.has_default(), True) class X[T]: ... T, = X.__type_params__ self.assertIs(T.__default__, NoDefault) - self.assertFalse(T.has_default()) + self.assertIs(T.has_default(), False) def test_paramspec(self): P = ParamSpec('P', default=(str, int)) self.assertEqual(P.__default__, (str, int)) - self.assertTrue(P.has_default()) + self.assertIs(P.has_default(), True) self.assertIsInstance(P, ParamSpec) class A(Generic[P]): ... @@ -664,19 +668,19 @@ def test_paramspec_none(self): U = ParamSpec('U') U_None = ParamSpec('U_None', default=None) self.assertIs(U.__default__, NoDefault) - self.assertFalse(U.has_default()) + self.assertIs(U.has_default(), False) self.assertIs(U_None.__default__, None) - self.assertTrue(U_None.has_default()) + self.assertIs(U_None.has_default(), True) class X[**P]: ... P, = X.__type_params__ self.assertIs(P.__default__, NoDefault) - self.assertFalse(P.has_default()) + self.assertIs(P.has_default(), False) def test_typevartuple(self): Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]]) self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]]) - self.assertTrue(Ts.has_default()) + self.assertIs(Ts.has_default(), True) self.assertIsInstance(Ts, TypeVarTuple) class A(Generic[Unpack[Ts]]): ... @@ -762,14 +766,14 @@ def test_typevartuple_none(self): U = TypeVarTuple('U') U_None = TypeVarTuple('U_None', default=None) self.assertIs(U.__default__, NoDefault) - self.assertFalse(U.has_default()) + self.assertIs(U.has_default(), False) self.assertIs(U_None.__default__, None) - self.assertTrue(U_None.has_default()) + self.assertIs(U_None.has_default(), True) class X[**Ts]: ... Ts, = X.__type_params__ self.assertIs(Ts.__default__, NoDefault) - self.assertFalse(Ts.has_default()) + self.assertIs(Ts.has_default(), False) def test_no_default_after_non_default(self): DefaultStrT = TypeVar('DefaultStrT', default=str) @@ -1170,7 +1174,6 @@ class C(Generic[*Ts]): pass ) - class UnpackTests(BaseTestCase): def test_accepts_single_type(self): @@ -2186,8 +2189,8 @@ def test_cannot_instantiate(self): type(u)() def test_union_generalization(self): - self.assertFalse(Union[str, typing.Iterable[int]] == str) - self.assertFalse(Union[str, typing.Iterable[int]] == typing.Iterable[int]) + self.assertNotEqual(Union[str, typing.Iterable[int]], str) + self.assertNotEqual(Union[str, typing.Iterable[int]], typing.Iterable[int]) self.assertIn(str, Union[str, typing.Iterable[int]].__args__) self.assertIn(typing.Iterable[int], Union[str, typing.Iterable[int]].__args__) @@ -2603,6 +2606,7 @@ def test_errors(self): with self.assertRaisesRegex(TypeError, "few arguments for"): C1[int] + class TypingCallableTests(BaseCallableTests, BaseTestCase): Callable = typing.Callable @@ -2780,6 +2784,7 @@ class Coordinate(Protocol): x: int y: int + @runtime_checkable class Point(Coordinate, Protocol): label: str @@ -4120,12 +4125,12 @@ class PG(Protocol[T]): def meth(self): pass - self.assertTrue(P._is_protocol) - self.assertTrue(PR._is_protocol) - self.assertTrue(PG._is_protocol) - self.assertFalse(P._is_runtime_protocol) - self.assertTrue(PR._is_runtime_protocol) - self.assertTrue(PG[int]._is_protocol) + self.assertIs(P._is_protocol, True) + self.assertIs(PR._is_protocol, True) + self.assertIs(PG._is_protocol, True) + self.assertIs(P._is_runtime_protocol, False) + self.assertIs(PR._is_runtime_protocol, True) + self.assertIs(PG[int]._is_protocol, True) self.assertEqual(typing._get_protocol_attrs(P), {'meth'}) self.assertEqual(typing._get_protocol_attrs(PR), {'x'}) self.assertEqual(frozenset(typing._get_protocol_attrs(PG)), @@ -5838,6 +5843,7 @@ def test_no_isinstance(self): with self.assertRaises(TypeError): issubclass(int, ClassVar) + class FinalTests(BaseTestCase): def test_basics(self): @@ -6043,7 +6049,7 @@ def wrong(self) -> int: instance = Child() self.assertEqual(instance.correct, 2) - self.assertTrue(Child.correct.fget.__override__) + self.assertIs(Child.correct.fget.__override__, True) self.assertEqual(instance.wrong, 2) self.assertNotHasAttr(Child.wrong, "__override__") self.assertNotHasAttr(Child.wrong.fset, "__override__") @@ -6084,9 +6090,9 @@ def on_bottom(self, a: int) -> int: instance = WithOverride() self.assertEqual(instance.on_top(1), 2) - self.assertTrue(instance.on_top.__override__) + self.assertIs(instance.on_top.__override__, True) self.assertEqual(instance.on_bottom(1), 3) - self.assertTrue(instance.on_bottom.__override__) + self.assertIs(instance.on_bottom.__override__, True) class CastTests(BaseTestCase): @@ -6124,8 +6130,6 @@ def test_errors(self): # We need this to make sure that `@no_type_check` respects `__module__` attr: -from test.typinganndata import ann_module8 - @no_type_check class NoTypeCheck_Outer: Inner = ann_module8.NoTypeCheck_Outer.Inner @@ -6193,7 +6197,7 @@ class D: for klass in [A, A.B, A.B.C, A.D]: with self.subTest(klass=klass): - self.assertTrue(klass.__no_type_check__) + self.assertIs(klass.__no_type_check__, True) self.assertEqual(get_type_hints(klass), {}) for not_modified in [Other, B]: @@ -6210,19 +6214,19 @@ def st(x: int) -> int: ... @classmethod def cl(cls, y: int) -> int: ... - self.assertTrue(Some.st.__no_type_check__) + self.assertIs(Some.st.__no_type_check__, True) self.assertEqual(get_type_hints(Some.st), {}) - self.assertTrue(Some.cl.__no_type_check__) + self.assertIs(Some.cl.__no_type_check__, True) self.assertEqual(get_type_hints(Some.cl), {}) def test_no_type_check_other_module(self): - self.assertTrue(NoTypeCheck_Outer.__no_type_check__) + self.assertIs(NoTypeCheck_Outer.__no_type_check__, True) with self.assertRaises(AttributeError): ann_module8.NoTypeCheck_Outer.__no_type_check__ with self.assertRaises(AttributeError): ann_module8.NoTypeCheck_Outer.Inner.__no_type_check__ - self.assertTrue(NoTypeCheck_WithFunction.__no_type_check__) + self.assertIs(NoTypeCheck_WithFunction.__no_type_check__, True) with self.assertRaises(AttributeError): ann_module8.NoTypeCheck_function.__no_type_check__ @@ -6247,7 +6251,7 @@ class A: # Corner case: `lambda` is both an assignment and a function: bar: Callable[[int], int] = lambda arg: arg - self.assertTrue(A.bar.__no_type_check__) + self.assertIs(A.bar.__no_type_check__, True) self.assertEqual(get_type_hints(A.bar), {}) def test_no_type_check_TypeError(self): @@ -6334,6 +6338,7 @@ def test_collect_parameters(self): typing._collect_parameters self.assertEqual(cm.filename, __file__) + @cpython_only def test_lazy_import(self): import_helper.ensure_lazy_imports("typing", { "warnings", @@ -6449,10 +6454,6 @@ def test_overload_registry_repeated(self): self.assertEqual(list(get_overloads(impl)), overloads) -from test.typinganndata import ( - ann_module, ann_module2, ann_module3, ann_module5, ann_module6, -) - T_a = TypeVar('T_a') class AwaitableWrapper(typing.Awaitable[T_a]): @@ -6665,8 +6666,8 @@ def test_respect_no_type_check(self): class NoTpCheck: class Inn: def __init__(self, x: 'not a type'): ... - self.assertTrue(NoTpCheck.__no_type_check__) - self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) + self.assertIs(NoTpCheck.__no_type_check__, True) + self.assertIs(NoTpCheck.Inn.__init__.__no_type_check__, True) self.assertEqual(gth(ann_module2.NTC.meth), {}) class ABase(Generic[T]): def meth(x: int): ... @@ -10196,6 +10197,7 @@ def test_var_substitution(self): self.assertEqual(C[Concatenate[str, P2]], Concatenate[int, str, P2]) self.assertEqual(C[...], Concatenate[int, ...]) + class TypeGuardTests(BaseTestCase): def test_basics(self): TypeGuard[int] # OK _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com