| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | """Tests for the annotations module.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  | import textwrap | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | import annotationlib | 
					
						
							| 
									
										
										
										
											2024-09-25 14:14:03 -07:00
										 |  |  | import builtins | 
					
						
							| 
									
										
										
										
											2024-09-23 12:06:19 -07:00
										 |  |  | import collections | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | import functools | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | import pickle | 
					
						
							| 
									
										
										
										
											2025-05-25 18:05:19 +02:00
										 |  |  | from string.templatelib import Template | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2024-09-25 17:01:09 -07:00
										 |  |  | from annotationlib import ( | 
					
						
							|  |  |  |     Format, | 
					
						
							|  |  |  |     ForwardRef, | 
					
						
							|  |  |  |     get_annotations, | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |     annotations_to_string, | 
					
						
							| 
									
										
										
										
											2025-04-15 13:10:53 -07:00
										 |  |  |     type_repr, | 
					
						
							| 
									
										
										
										
											2024-09-25 17:01:09 -07:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | from typing import Unpack, get_type_hints, List, Union | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2025-04-16 20:46:36 -07:00
										 |  |  | from test.support import import_helper | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | from test.test_inspect import inspect_stock_annotations | 
					
						
							|  |  |  | from test.test_inspect import inspect_stringized_annotations | 
					
						
							|  |  |  | from test.test_inspect import inspect_stringized_annotations_2 | 
					
						
							|  |  |  | from test.test_inspect import inspect_stringized_annotations_pep695 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def times_three(fn): | 
					
						
							|  |  |  |     @functools.wraps(fn) | 
					
						
							|  |  |  |     def wrapper(a, b): | 
					
						
							|  |  |  |         return fn(a * 3, b * 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return wrapper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-25 17:01:09 -07:00
										 |  |  | class MyClass: | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "my repr" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | class TestFormat(unittest.TestCase): | 
					
						
							|  |  |  |     def test_enum(self): | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |         self.assertEqual(Format.VALUE.value, 1) | 
					
						
							|  |  |  |         self.assertEqual(Format.VALUE, 1) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |         self.assertEqual(Format.VALUE_WITH_FAKE_GLOBALS.value, 2) | 
					
						
							|  |  |  |         self.assertEqual(Format.VALUE_WITH_FAKE_GLOBALS, 2) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |         self.assertEqual(Format.FORWARDREF.value, 3) | 
					
						
							|  |  |  |         self.assertEqual(Format.FORWARDREF, 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(Format.STRING.value, 4) | 
					
						
							|  |  |  |         self.assertEqual(Format.STRING, 4) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestForwardRefFormat(unittest.TestCase): | 
					
						
							|  |  |  |     def test_closure(self): | 
					
						
							|  |  |  |         def inner(arg: x): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(inner, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         fwdref = anno["arg"] | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertIsInstance(fwdref, ForwardRef) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual(fwdref.__forward_arg__, "x") | 
					
						
							|  |  |  |         with self.assertRaises(NameError): | 
					
						
							|  |  |  |             fwdref.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         x = 1 | 
					
						
							|  |  |  |         self.assertEqual(fwdref.evaluate(), x) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(inner, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual(anno["arg"], x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_function(self): | 
					
						
							|  |  |  |         def f(x: int, y: doesntexist): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertIs(anno["x"], int) | 
					
						
							|  |  |  |         fwdref = anno["y"] | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertIsInstance(fwdref, ForwardRef) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual(fwdref.__forward_arg__, "doesntexist") | 
					
						
							|  |  |  |         with self.assertRaises(NameError): | 
					
						
							|  |  |  |             fwdref.evaluate() | 
					
						
							|  |  |  |         self.assertEqual(fwdref.evaluate(globals={"doesntexist": 1}), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  |     def test_nonexistent_attribute(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             x: some.module, | 
					
						
							|  |  |  |             y: some[module], | 
					
						
							|  |  |  |             z: some(module), | 
					
						
							|  |  |  |             alpha: some | obj, | 
					
						
							|  |  |  |             beta: +some, | 
					
						
							|  |  |  |             gamma: some < obj, | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  |         x_anno = anno["x"] | 
					
						
							|  |  |  |         self.assertIsInstance(x_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(x_anno, support.EqualToForwardRef("some.module", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         y_anno = anno["y"] | 
					
						
							|  |  |  |         self.assertIsInstance(y_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(y_anno, support.EqualToForwardRef("some[module]", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         z_anno = anno["z"] | 
					
						
							|  |  |  |         self.assertIsInstance(z_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(z_anno, support.EqualToForwardRef("some(module)", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         alpha_anno = anno["alpha"] | 
					
						
							|  |  |  |         self.assertIsInstance(alpha_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(alpha_anno, support.EqualToForwardRef("some | obj", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         beta_anno = anno["beta"] | 
					
						
							|  |  |  |         self.assertIsInstance(beta_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(beta_anno, support.EqualToForwardRef("+some", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         gamma_anno = anno["gamma"] | 
					
						
							|  |  |  |         self.assertIsInstance(gamma_anno, ForwardRef) | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         self.assertEqual(gamma_anno, support.EqualToForwardRef("some < obj", owner=f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |     def test_partially_nonexistent_union(self): | 
					
						
							|  |  |  |         # Test unions with '|' syntax equal unions with typing.Union[] with some forwardrefs | 
					
						
							|  |  |  |         class UnionForwardrefs: | 
					
						
							|  |  |  |             pipe: str | undefined | 
					
						
							|  |  |  |             union: Union[str, undefined] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         annos = get_annotations(UnionForwardrefs, format=Format.FORWARDREF) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pipe = annos["pipe"] | 
					
						
							|  |  |  |         self.assertIsInstance(pipe, ForwardRef) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             pipe.evaluate(globals={"undefined": int}), | 
					
						
							|  |  |  |             str | int, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         union = annos["union"] | 
					
						
							|  |  |  |         self.assertIsInstance(union, Union) | 
					
						
							|  |  |  |         arg1, arg2 = typing.get_args(union) | 
					
						
							|  |  |  |         self.assertIs(arg1, str) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             arg2, support.EqualToForwardRef("undefined", is_class=True, owner=UnionForwardrefs) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | class TestStringFormat(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |     def test_closure(self): | 
					
						
							|  |  |  |         x = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def inner(arg: x): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(inner, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual(anno, {"arg": "x"}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  |     def test_closure_undefined(self): | 
					
						
							|  |  |  |         if False: | 
					
						
							|  |  |  |             x = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def inner(arg: x): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(inner, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-10-23 16:27:55 -07:00
										 |  |  |         self.assertEqual(anno, {"arg": "x"}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |     def test_function(self): | 
					
						
							|  |  |  |         def f(x: int, y: doesntexist): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "int", "y": "doesntexist"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_expressions(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             add: a + b, | 
					
						
							|  |  |  |             sub: a - b, | 
					
						
							|  |  |  |             mul: a * b, | 
					
						
							|  |  |  |             matmul: a @ b, | 
					
						
							|  |  |  |             truediv: a / b, | 
					
						
							|  |  |  |             mod: a % b, | 
					
						
							|  |  |  |             lshift: a << b, | 
					
						
							|  |  |  |             rshift: a >> b, | 
					
						
							|  |  |  |             or_: a | b, | 
					
						
							|  |  |  |             xor: a ^ b, | 
					
						
							|  |  |  |             and_: a & b, | 
					
						
							|  |  |  |             floordiv: a // b, | 
					
						
							|  |  |  |             pow_: a**b, | 
					
						
							|  |  |  |             lt: a < b, | 
					
						
							|  |  |  |             le: a <= b, | 
					
						
							|  |  |  |             eq: a == b, | 
					
						
							|  |  |  |             ne: a != b, | 
					
						
							|  |  |  |             gt: a > b, | 
					
						
							|  |  |  |             ge: a >= b, | 
					
						
							|  |  |  |             invert: ~a, | 
					
						
							|  |  |  |             neg: -a, | 
					
						
							|  |  |  |             pos: +a, | 
					
						
							|  |  |  |             getitem: a[b], | 
					
						
							|  |  |  |             getattr: a.b, | 
					
						
							|  |  |  |             call: a(b, *c, d=e),  # **kwargs are not supported | 
					
						
							|  |  |  |             *args: *a, | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "add": "a + b", | 
					
						
							|  |  |  |                 "sub": "a - b", | 
					
						
							|  |  |  |                 "mul": "a * b", | 
					
						
							|  |  |  |                 "matmul": "a @ b", | 
					
						
							|  |  |  |                 "truediv": "a / b", | 
					
						
							|  |  |  |                 "mod": "a % b", | 
					
						
							|  |  |  |                 "lshift": "a << b", | 
					
						
							|  |  |  |                 "rshift": "a >> b", | 
					
						
							|  |  |  |                 "or_": "a | b", | 
					
						
							|  |  |  |                 "xor": "a ^ b", | 
					
						
							|  |  |  |                 "and_": "a & b", | 
					
						
							|  |  |  |                 "floordiv": "a // b", | 
					
						
							|  |  |  |                 "pow_": "a ** b", | 
					
						
							|  |  |  |                 "lt": "a < b", | 
					
						
							|  |  |  |                 "le": "a <= b", | 
					
						
							|  |  |  |                 "eq": "a == b", | 
					
						
							|  |  |  |                 "ne": "a != b", | 
					
						
							|  |  |  |                 "gt": "a > b", | 
					
						
							|  |  |  |                 "ge": "a >= b", | 
					
						
							|  |  |  |                 "invert": "~a", | 
					
						
							|  |  |  |                 "neg": "-a", | 
					
						
							|  |  |  |                 "pos": "+a", | 
					
						
							|  |  |  |                 "getitem": "a[b]", | 
					
						
							|  |  |  |                 "getattr": "a.b", | 
					
						
							|  |  |  |                 "call": "a(b, *c, d=e)", | 
					
						
							|  |  |  |                 "args": "*a", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_reverse_ops(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             radd: 1 + a, | 
					
						
							|  |  |  |             rsub: 1 - a, | 
					
						
							|  |  |  |             rmul: 1 * a, | 
					
						
							|  |  |  |             rmatmul: 1 @ a, | 
					
						
							|  |  |  |             rtruediv: 1 / a, | 
					
						
							|  |  |  |             rmod: 1 % a, | 
					
						
							|  |  |  |             rlshift: 1 << a, | 
					
						
							|  |  |  |             rrshift: 1 >> a, | 
					
						
							|  |  |  |             ror: 1 | a, | 
					
						
							|  |  |  |             rxor: 1 ^ a, | 
					
						
							|  |  |  |             rand: 1 & a, | 
					
						
							|  |  |  |             rfloordiv: 1 // a, | 
					
						
							|  |  |  |             rpow: 1**a, | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "radd": "1 + a", | 
					
						
							|  |  |  |                 "rsub": "1 - a", | 
					
						
							|  |  |  |                 "rmul": "1 * a", | 
					
						
							|  |  |  |                 "rmatmul": "1 @ a", | 
					
						
							|  |  |  |                 "rtruediv": "1 / a", | 
					
						
							|  |  |  |                 "rmod": "1 % a", | 
					
						
							|  |  |  |                 "rlshift": "1 << a", | 
					
						
							|  |  |  |                 "rrshift": "1 >> a", | 
					
						
							|  |  |  |                 "ror": "1 | a", | 
					
						
							|  |  |  |                 "rxor": "1 ^ a", | 
					
						
							|  |  |  |                 "rand": "1 & a", | 
					
						
							|  |  |  |                 "rfloordiv": "1 // a", | 
					
						
							|  |  |  |                 "rpow": "1 ** a", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-08 03:37:03 +02:00
										 |  |  |     def test_template_str(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             x: t"{a}", | 
					
						
							|  |  |  |             y: list[t"{a}"], | 
					
						
							|  |  |  |             z: t"{a:b} {c!r} {d!s:t}", | 
					
						
							|  |  |  |             a: t"a{b}c{d}e{f}g", | 
					
						
							|  |  |  |             b: t"{a:{1}}", | 
					
						
							|  |  |  |             c: t"{a | b * c}", | 
					
						
							|  |  |  |         ): pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         annos = get_annotations(f, format=Format.STRING) | 
					
						
							|  |  |  |         self.assertEqual(annos, { | 
					
						
							|  |  |  |             "x": "t'{a}'", | 
					
						
							|  |  |  |             "y": "list[t'{a}']", | 
					
						
							|  |  |  |             "z": "t'{a:b} {c!r} {d!s:t}'", | 
					
						
							|  |  |  |             "a": "t'a{b}c{d}e{f}g'", | 
					
						
							|  |  |  |             # interpolations in the format spec are eagerly evaluated so we can't recover the source | 
					
						
							|  |  |  |             "b": "t'{a:1}'", | 
					
						
							|  |  |  |             "c": "t'{a | b * c}'", | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def g( | 
					
						
							|  |  |  |             x: t"{a}", | 
					
						
							|  |  |  |         ): ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         annos = get_annotations(g, format=Format.FORWARDREF) | 
					
						
							|  |  |  |         templ = annos["x"] | 
					
						
							|  |  |  |         # Template and Interpolation don't have __eq__ so we have to compare manually | 
					
						
							|  |  |  |         self.assertIsInstance(templ, Template) | 
					
						
							|  |  |  |         self.assertEqual(templ.strings, ("", "")) | 
					
						
							|  |  |  |         self.assertEqual(len(templ.interpolations), 1) | 
					
						
							|  |  |  |         interp = templ.interpolations[0] | 
					
						
							|  |  |  |         self.assertEqual(interp.value, support.EqualToForwardRef("a", owner=g)) | 
					
						
							|  |  |  |         self.assertEqual(interp.expression, "a") | 
					
						
							|  |  |  |         self.assertIsNone(interp.conversion) | 
					
						
							|  |  |  |         self.assertEqual(interp.format_spec, "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |     def test_getitem(self): | 
					
						
							|  |  |  |         def f(x: undef1[str, undef2]): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "undef1[str, undef2]"}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         fwdref = anno["x"] | 
					
						
							|  |  |  |         self.assertIsInstance(fwdref, ForwardRef) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             fwdref.evaluate(globals={"undef1": dict, "undef2": float}), dict[str, float] | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_slice(self): | 
					
						
							|  |  |  |         def f(x: a[b:c]): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "a[b:c]"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(x: a[b:c, d:e]): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "a[b:c, d:e]"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         obj = slice(1, 1, 1) | 
					
						
							|  |  |  |         def f(x: obj): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "obj"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_literals(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             a: 1, | 
					
						
							|  |  |  |             b: 1.0, | 
					
						
							|  |  |  |             c: "hello", | 
					
						
							|  |  |  |             d: b"hello", | 
					
						
							|  |  |  |             e: True, | 
					
						
							|  |  |  |             f: None, | 
					
						
							|  |  |  |             g: ..., | 
					
						
							|  |  |  |             h: 1j, | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "a": "1", | 
					
						
							|  |  |  |                 "b": "1.0", | 
					
						
							|  |  |  |                 "c": 'hello', | 
					
						
							|  |  |  |                 "d": "b'hello'", | 
					
						
							|  |  |  |                 "e": "True", | 
					
						
							|  |  |  |                 "f": "None", | 
					
						
							|  |  |  |                 "g": "...", | 
					
						
							|  |  |  |                 "h": "1j", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_displays(self): | 
					
						
							|  |  |  |         # Simple case first | 
					
						
							|  |  |  |         def f(x: a[[int, str], float]): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual(anno, {"x": "a[[int, str], float]"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def g( | 
					
						
							|  |  |  |             w: a[[int, str], float], | 
					
						
							| 
									
										
										
										
											2025-05-09 16:27:13 +02:00
										 |  |  |             x: a[{int}, 3], | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |             y: a[{int: str}, 4], | 
					
						
							|  |  |  |             z: a[(int, str), 5], | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |         anno = get_annotations(g, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "w": "a[[int, str], float]", | 
					
						
							| 
									
										
										
										
											2025-05-09 16:27:13 +02:00
										 |  |  |                 "x": "a[{int}, 3]", | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |                 "y": "a[{int: str}, 4]", | 
					
						
							|  |  |  |                 "z": "a[(int, str), 5]", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |     def test_nested_expressions(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             nested: list[Annotated[set[int], "set of ints", 4j]], | 
					
						
							|  |  |  |             set: {a + b},  # single element because order is not guaranteed | 
					
						
							|  |  |  |             dict: {a + b: c + d, "key": e + g}, | 
					
						
							|  |  |  |             list: [a, b, c], | 
					
						
							|  |  |  |             tuple: (a, b, c), | 
					
						
							|  |  |  |             slice: (a[b:c], a[b:c:d], a[:c], a[b:], a[:], a[::d], a[b::d]), | 
					
						
							|  |  |  |             extended_slice: a[:, :, c:d], | 
					
						
							|  |  |  |             unpack1: [*a], | 
					
						
							|  |  |  |             unpack2: [*a, b, c], | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         anno = get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "nested": "list[Annotated[set[int], 'set of ints', 4j]]", | 
					
						
							|  |  |  |                 "set": "{a + b}", | 
					
						
							|  |  |  |                 "dict": "{a + b: c + d, 'key': e + g}", | 
					
						
							|  |  |  |                 "list": "[a, b, c]", | 
					
						
							|  |  |  |                 "tuple": "(a, b, c)", | 
					
						
							|  |  |  |                 "slice": "(a[b:c], a[b:c:d], a[:c], a[b:], a[:], a[::d], a[b::d])", | 
					
						
							|  |  |  |                 "extended_slice": "a[:, :, c:d]", | 
					
						
							|  |  |  |                 "unpack1": "[*a]", | 
					
						
							|  |  |  |                 "unpack2": "[*a, b, c]", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_unsupported_operations(self): | 
					
						
							|  |  |  |         format_msg = "Cannot stringify annotation containing string formatting" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(fstring: f"{a}"): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, format_msg): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def f(fstring_format: f"{a:02d}"): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, format_msg): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f, format=Format.STRING) | 
					
						
							| 
									
										
										
										
											2024-09-25 14:14:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 08:49:13 -07:00
										 |  |  |     def test_shenanigans(self): | 
					
						
							|  |  |  |         # In cases like this we can't reconstruct the source; test that we do something | 
					
						
							|  |  |  |         # halfway reasonable. | 
					
						
							|  |  |  |         def f(x: x | (1).__class__, y: (1).__class__): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             get_annotations(f, format=Format.STRING), | 
					
						
							|  |  |  |             {"x": "x | <class 'int'>", "y": "<class 'int'>"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestGetAnnotations(unittest.TestCase): | 
					
						
							|  |  |  |     def test_builtin_type(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(int), {}) | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(object), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_custom_metaclass(self): | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class C(metaclass=Meta): | 
					
						
							|  |  |  |             x: int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(C), {"x": int}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_missing_dunder_dict(self): | 
					
						
							|  |  |  |         class NoDict(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __dict__(cls): | 
					
						
							|  |  |  |                 raise AttributeError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             b: str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class C1(metaclass=NoDict): | 
					
						
							|  |  |  |             a: int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(C1), {"a": int}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(C1, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(C1, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int"}, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(NoDict), {"b": str}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(NoDict, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"b": str}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(NoDict, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"b": "str"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_format(self): | 
					
						
							|  |  |  |         def f1(a: int): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f2(a: undefined): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f1, format=Format.VALUE), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int}, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(f1, format=1), {"a": int}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |         fwd = support.EqualToForwardRef("undefined", owner=f2) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f2, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": fwd}, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(f2, format=3), {"a": fwd}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f1, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int"}, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(f1, format=4), {"a": "int"}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f1, format=42) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |             ValueError, | 
					
						
							|  |  |  |             r"The VALUE_WITH_FAKE_GLOBALS format is for internal use only", | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f1, format=Format.VALUE_WITH_FAKE_GLOBALS) | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |             ValueError, | 
					
						
							|  |  |  |             r"The VALUE_WITH_FAKE_GLOBALS format is for internal use only", | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f1, format=2) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_custom_object_with_annotations(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __init__(self): | 
					
						
							|  |  |  |                 self.__annotations__ = {"x": int, "y": str} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(C()), {"x": int, "y": str}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_custom_format_eval_str(self): | 
					
						
							|  |  |  |         def foo(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(ValueError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(foo, format=Format.FORWARDREF, eval_str=True) | 
					
						
							|  |  |  |             get_annotations(foo, format=Format.STRING, eval_str=True) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_stock_annotations(self): | 
					
						
							|  |  |  |         def foo(a: int, b: str): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |         for format in (Format.VALUE, Format.FORWARDREF): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             with self.subTest(format=format): | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(foo, format=format), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(foo, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foo.__annotations__ = {"a": "foo", "b": "str"} | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |         for format in Format: | 
					
						
							| 
									
										
										
										
											2025-03-28 05:56:09 +01:00
										 |  |  |             if format == Format.VALUE_WITH_FAKE_GLOBALS: | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             with self.subTest(format=format): | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(foo, format=format), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "foo", "b": "str"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(foo, eval_str=True, locals=locals()), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": foo, "b": str}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(foo, eval_str=True, globals=locals()), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": foo, "b": str}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_stock_annotations_in_module(self): | 
					
						
							|  |  |  |         isa = inspect_stock_annotations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for kwargs in [ | 
					
						
							|  |  |  |             {}, | 
					
						
							|  |  |  |             {"eval_str": False}, | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             {"format": Format.VALUE}, | 
					
						
							|  |  |  |             {"format": Format.FORWARDREF}, | 
					
						
							|  |  |  |             {"format": Format.VALUE, "eval_str": False}, | 
					
						
							|  |  |  |             {"format": Format.FORWARDREF, "eval_str": False}, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(**kwargs): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.MyClass, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function2, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": "str", "c": isa.MyClass, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function3, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "str", "c": "MyClass"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(annotationlib, **kwargs), {} | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 )  # annotations module has no annotations | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.unannotated_function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for kwargs in [ | 
					
						
							|  |  |  |             {"eval_str": True}, | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             {"format": Format.VALUE, "eval_str": True}, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(**kwargs): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.MyClass, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function2, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str, "c": isa.MyClass, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function3, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str, "c": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(annotationlib, **kwargs), {}) | 
					
						
							|  |  |  |                 self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.unannotated_function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.MyClass, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.function, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "return": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.function2, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "c": "MyClass", "return": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.function3, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "c": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(annotationlib, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.UnannotatedClass, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.unannotated_function, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_stock_annotations_on_wrapper(self): | 
					
						
							|  |  |  |         isa = inspect_stock_annotations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         wrapped = times_three(isa.function) | 
					
						
							|  |  |  |         self.assertEqual(wrapped(1, "x"), isa.MyClass(3, "xxx")) | 
					
						
							|  |  |  |         self.assertIsNot(wrapped.__globals__, isa.function.__globals__) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "return": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, eval_str=True), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, eval_str=False), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_stringized_annotations_in_module(self): | 
					
						
							|  |  |  |         isa = inspect_stringized_annotations | 
					
						
							|  |  |  |         for kwargs in [ | 
					
						
							|  |  |  |             {}, | 
					
						
							|  |  |  |             {"eval_str": False}, | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             {"format": Format.VALUE}, | 
					
						
							|  |  |  |             {"format": Format.FORWARDREF}, | 
					
						
							|  |  |  |             {"format": Format.STRING}, | 
					
						
							|  |  |  |             {"format": Format.VALUE, "eval_str": False}, | 
					
						
							|  |  |  |             {"format": Format.FORWARDREF, "eval_str": False}, | 
					
						
							|  |  |  |             {"format": Format.STRING, "eval_str": False}, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(**kwargs): | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "str"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.MyClass, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "str"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "str", "return": "MyClass"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function2, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "'str'", "c": "MyClass", "return": "MyClass"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function3, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "'int'", "b": "'str'", "c": "'MyClass'"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.unannotated_function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for kwargs in [ | 
					
						
							|  |  |  |             {"eval_str": True}, | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             {"format": Format.VALUE, "eval_str": True}, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ]: | 
					
						
							|  |  |  |             with self.subTest(**kwargs): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa, **kwargs), {"a": int, "b": str}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.MyClass, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function2, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": int, "b": "str", "c": isa.MyClass, "return": isa.MyClass}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.function3, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {"a": "int", "b": "str", "c": "MyClass"}, | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 self.assertEqual(get_annotations(isa.UnannotatedClass, **kwargs), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     get_annotations(isa.unannotated_function, **kwargs), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     {}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_stringized_annotations_in_empty_module(self): | 
					
						
							|  |  |  |         isa2 = inspect_stringized_annotations_2 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(isa2), {}) | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(isa2, eval_str=True), {}) | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(isa2, eval_str=False), {}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_stringized_annotations_on_wrapper(self): | 
					
						
							|  |  |  |         isa = inspect_stringized_annotations | 
					
						
							|  |  |  |         wrapped = times_three(isa.function) | 
					
						
							|  |  |  |         self.assertEqual(wrapped(1, "x"), isa.MyClass(3, "xxx")) | 
					
						
							|  |  |  |         self.assertIsNot(wrapped.__globals__, isa.function.__globals__) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "return": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, eval_str=True), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": int, "b": str, "return": isa.MyClass}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(wrapped, eval_str=False), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"a": "int", "b": "str", "return": "MyClass"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_stringized_annotations_on_class(self): | 
					
						
							|  |  |  |         isa = inspect_stringized_annotations | 
					
						
							|  |  |  |         # test that local namespace lookups work | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.MyClassWithLocalAnnotations), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"x": "mytype"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(isa.MyClassWithLocalAnnotations, eval_str=True), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"x": int}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-25 18:05:19 +02:00
										 |  |  |     def test_stringized_annotation_permutations(self): | 
					
						
							|  |  |  |         def define_class(name, has_future, has_annos, base_text, extra_names=None): | 
					
						
							|  |  |  |             lines = [] | 
					
						
							|  |  |  |             if has_future: | 
					
						
							|  |  |  |                 lines.append("from __future__ import annotations") | 
					
						
							|  |  |  |             lines.append(f"class {name}({base_text}):") | 
					
						
							|  |  |  |             if has_annos: | 
					
						
							|  |  |  |                 lines.append(f"    {name}_attr: int") | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 lines.append("    pass") | 
					
						
							|  |  |  |             code = "\n".join(lines) | 
					
						
							|  |  |  |             ns = support.run_code(code, extra_names=extra_names) | 
					
						
							|  |  |  |             return ns[name] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def check_annotations(cls, has_future, has_annos): | 
					
						
							|  |  |  |             if has_annos: | 
					
						
							|  |  |  |                 if has_future: | 
					
						
							|  |  |  |                     anno = "int" | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     anno = int | 
					
						
							|  |  |  |                 self.assertEqual(get_annotations(cls), {f"{cls.__name__}_attr": anno}) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.assertEqual(get_annotations(cls), {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for meta_future, base_future, child_future, meta_has_annos, base_has_annos, child_has_annos in itertools.product( | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |             (False, True), | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             with self.subTest( | 
					
						
							|  |  |  |                 meta_future=meta_future, | 
					
						
							|  |  |  |                 base_future=base_future, | 
					
						
							|  |  |  |                 child_future=child_future, | 
					
						
							|  |  |  |                 meta_has_annos=meta_has_annos, | 
					
						
							|  |  |  |                 base_has_annos=base_has_annos, | 
					
						
							|  |  |  |                 child_has_annos=child_has_annos, | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 meta = define_class( | 
					
						
							|  |  |  |                     "Meta", | 
					
						
							|  |  |  |                     has_future=meta_future, | 
					
						
							|  |  |  |                     has_annos=meta_has_annos, | 
					
						
							|  |  |  |                     base_text="type", | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 base = define_class( | 
					
						
							|  |  |  |                     "Base", | 
					
						
							|  |  |  |                     has_future=base_future, | 
					
						
							|  |  |  |                     has_annos=base_has_annos, | 
					
						
							|  |  |  |                     base_text="metaclass=Meta", | 
					
						
							|  |  |  |                     extra_names={"Meta": meta}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 child = define_class( | 
					
						
							|  |  |  |                     "Child", | 
					
						
							|  |  |  |                     has_future=child_future, | 
					
						
							|  |  |  |                     has_annos=child_has_annos, | 
					
						
							|  |  |  |                     base_text="Base", | 
					
						
							|  |  |  |                     extra_names={"Base": base}, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 check_annotations(meta, meta_future, meta_has_annos) | 
					
						
							|  |  |  |                 check_annotations(base, base_future, base_has_annos) | 
					
						
							|  |  |  |                 check_annotations(child, child_future, child_has_annos) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |     def test_modify_annotations(self): | 
					
						
							|  |  |  |         def f(x: int): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(f), {"x": int}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"x": int}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f.__annotations__["x"] = str | 
					
						
							|  |  |  |         # The modification is reflected in VALUE (the default) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(f), {"x": str}) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  |         # ... and also in FORWARDREF, which tries __annotations__ if available | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f, format=Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  |             {"x": str}, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |         # ... but not in STRING which always uses __annotate__ | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(f, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  |             {"x": "int"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_non_dict_annotations(self): | 
					
						
							|  |  |  |         class WeirdAnnotations: | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotations__(self): | 
					
						
							|  |  |  |                 return "not a dict" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         wa = WeirdAnnotations() | 
					
						
							|  |  |  |         for format in Format: | 
					
						
							| 
									
										
										
										
											2025-03-28 05:56:09 +01:00
										 |  |  |             if format == Format.VALUE_WITH_FAKE_GLOBALS: | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  |             with ( | 
					
						
							|  |  |  |                 self.subTest(format=format), | 
					
						
							|  |  |  |                 self.assertRaisesRegex( | 
					
						
							|  |  |  |                     ValueError, r".*__annotations__ is neither a dict nor None" | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             ): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 get_annotations(wa, format=format) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_annotations_on_custom_object(self): | 
					
						
							|  |  |  |         class HasAnnotations: | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotations__(self): | 
					
						
							|  |  |  |                 return {"x": int} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ha = HasAnnotations() | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(ha, format=Format.VALUE), {"x": int}) | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(ha, format=Format.FORWARDREF), {"x": int}) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(ha, format=Format.STRING), {"x": "int"}) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_raising_annotations_on_custom_object(self): | 
					
						
							|  |  |  |         class HasRaisingAnnotations: | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotations__(self): | 
					
						
							|  |  |  |                 return {"x": undefined} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hra = HasRaisingAnnotations() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(NameError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(hra, format=Format.VALUE) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(NameError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(hra, format=Format.FORWARDREF) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         undefined = float | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(hra, format=Format.VALUE), {"x": float}) | 
					
						
							| 
									
										
										
										
											2024-09-25 15:32:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_forwardref_prefers_annotations(self): | 
					
						
							|  |  |  |         class HasBoth: | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotations__(self): | 
					
						
							|  |  |  |                 return {"x": int} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotate__(self): | 
					
						
							|  |  |  |                 return lambda format: {"x": str} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hb = HasBoth() | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         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}) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-13 16:32:44 -07:00
										 |  |  |     def test_only_annotate(self): | 
					
						
							|  |  |  |         def f(x: int): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class OnlyAnnotate: | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def __annotate__(self): | 
					
						
							|  |  |  |                 return f.__annotate__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         oa = OnlyAnnotate() | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_annotations(oa, format=Format.VALUE), {"x": int}) | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(oa, format=Format.FORWARDREF), {"x": int}) | 
					
						
							| 
									
										
										
										
											2025-04-13 16:32:44 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(oa, format=Format.STRING), | 
					
						
							| 
									
										
										
										
											2025-04-13 16:32:44 -07:00
										 |  |  |             {"x": "int"}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_no_annotations(self): | 
					
						
							|  |  |  |         class CustomClass: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class MyCallable: | 
					
						
							|  |  |  |             def __call__(self): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for format in Format: | 
					
						
							|  |  |  |             if format == Format.VALUE_WITH_FAKE_GLOBALS: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             for obj in (None, 1, object(), CustomClass()): | 
					
						
							|  |  |  |                 with self.subTest(format=format, obj=obj): | 
					
						
							|  |  |  |                     with self.assertRaises(TypeError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                         get_annotations(obj, format=format) | 
					
						
							| 
									
										
										
										
											2025-04-13 16:32:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Callables and types with no annotations return an empty dict | 
					
						
							|  |  |  |             for obj in (int, len, MyCallable()): | 
					
						
							|  |  |  |                 with self.subTest(format=format, obj=obj): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     self.assertEqual(get_annotations(obj, format=format), {}) | 
					
						
							| 
									
										
										
										
											2025-04-13 16:32:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |     def test_pep695_generic_class_with_future_annotations(self): | 
					
						
							|  |  |  |         ann_module695 = inspect_stringized_annotations_pep695 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         A_annotations = get_annotations(ann_module695.A, eval_str=True) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         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): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         B_annotations = get_annotations( | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             inspect_stringized_annotations_pep695.B, eval_str=True | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual(B_annotations, {"x": int, "y": str, "z": bytes}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |     def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars( | 
					
						
							|  |  |  |         self, | 
					
						
							|  |  |  |     ): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ann_module695 = inspect_stringized_annotations_pep695 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         C_annotations = get_annotations(ann_module695.C, eval_str=True) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             set(C_annotations.values()), set(ann_module695.C.__type_params__) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pep_695_generic_function_with_future_annotations(self): | 
					
						
							|  |  |  |         ann_module695 = inspect_stringized_annotations_pep695 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         generic_func_annotations = get_annotations( | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             ann_module695.generic_function, eval_str=True | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         func_t_params = ann_module695.generic_function.__type_params__ | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             generic_func_annotations.keys(), {"x", "y", "z", "zz", "return"} | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIs(generic_func_annotations["x"], func_t_params[0]) | 
					
						
							|  |  |  |         self.assertEqual(generic_func_annotations["y"], Unpack[func_t_params[1]]) | 
					
						
							|  |  |  |         self.assertIs(generic_func_annotations["z"].__origin__, func_t_params[2]) | 
					
						
							|  |  |  |         self.assertIs(generic_func_annotations["zz"].__origin__, func_t_params[2]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |     def test_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars( | 
					
						
							|  |  |  |         self, | 
					
						
							|  |  |  |     ): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             set( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 get_annotations( | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     inspect_stringized_annotations_pep695.generic_function_2, | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |                     eval_str=True, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 ).values() | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             set( | 
					
						
							|  |  |  |                 inspect_stringized_annotations_pep695.generic_function_2.__type_params__ | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pep_695_generic_method_with_future_annotations(self): | 
					
						
							|  |  |  |         ann_module695 = inspect_stringized_annotations_pep695 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         generic_method_annotations = get_annotations( | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             ann_module695.D.generic_method, eval_str=True | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         params = { | 
					
						
							|  |  |  |             param.__name__: param | 
					
						
							|  |  |  |             for param in ann_module695.D.generic_method.__type_params__ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             generic_method_annotations, | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             {"x": params["Foo"], "y": params["Bar"], "return": None}, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |     def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars( | 
					
						
							|  |  |  |         self, | 
					
						
							|  |  |  |     ): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             set( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                 get_annotations( | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                     inspect_stringized_annotations_pep695.D.generic_method_2, | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |                     eval_str=True, | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |                 ).values() | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             set( | 
					
						
							|  |  |  |                 inspect_stringized_annotations_pep695.D.generic_method_2.__type_params__ | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |     def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_and_local_vars( | 
					
						
							|  |  |  |         self, | 
					
						
							|  |  |  |     ): | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             get_annotations(inspect_stringized_annotations_pep695.E, eval_str=True), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |             {"x": str}, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pep_695_generics_with_future_annotations_nested_in_function(self): | 
					
						
							|  |  |  |         results = inspect_stringized_annotations_pep695.nested() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             set(results.F_annotations.values()), set(results.F.__type_params__) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             set(results.F_meth_annotations.values()), | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             set(results.F.generic_method.__type_params__), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  |         self.assertNotEqual( | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             set(results.F_meth_annotations.values()), set(results.F.__type_params__) | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |             set(results.F_meth_annotations.values()).intersection( | 
					
						
							|  |  |  |                 results.F.__type_params__ | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             set(), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(results.G_annotations, {"x": str}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             set(results.generic_func_annotations.values()), | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  |             set(results.generic_func.__type_params__), | 
					
						
							| 
									
										
										
										
											2024-07-23 14:16:50 -07:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |     def test_partial_evaluation(self): | 
					
						
							|  |  |  |         def f( | 
					
						
							|  |  |  |             x: builtins.undef, | 
					
						
							|  |  |  |             y: list[int], | 
					
						
							|  |  |  |             z: 1 + int, | 
					
						
							|  |  |  |             a: builtins.int, | 
					
						
							|  |  |  |             b: [builtins.undef, builtins.int], | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             get_annotations(f, format=Format.FORWARDREF), | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "x": support.EqualToForwardRef("builtins.undef", owner=f), | 
					
						
							|  |  |  |                 "y": list[int], | 
					
						
							|  |  |  |                 "z": support.EqualToForwardRef("1 + int", owner=f), | 
					
						
							|  |  |  |                 "a": int, | 
					
						
							|  |  |  |                 "b": [ | 
					
						
							|  |  |  |                     support.EqualToForwardRef("builtins.undef", owner=f), | 
					
						
							|  |  |  |                     # We can't resolve this because we have to evaluate the whole annotation | 
					
						
							|  |  |  |                     support.EqualToForwardRef("builtins.int", owner=f), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             get_annotations(f, format=Format.STRING), | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "x": "builtins.undef", | 
					
						
							|  |  |  |                 "y": "list[int]", | 
					
						
							|  |  |  |                 "z": "1 + int", | 
					
						
							|  |  |  |                 "a": "builtins.int", | 
					
						
							|  |  |  |                 "b": "[builtins.undef, builtins.int]", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-05 08:21:11 -07:00
										 |  |  |     def test_partial_evaluation_error(self): | 
					
						
							|  |  |  |         def f(x: range[1]): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         with self.assertRaisesRegex( | 
					
						
							|  |  |  |             TypeError, "type 'range' is not subscriptable" | 
					
						
							|  |  |  |         ): | 
					
						
							|  |  |  |             f.__annotations__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             get_annotations(f, format=Format.FORWARDREF), | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "x": support.EqualToForwardRef("range[1]", owner=f), | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |     def test_partial_evaluation_cell(self): | 
					
						
							|  |  |  |         obj = object() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class RaisesAttributeError: | 
					
						
							|  |  |  |             attriberr: obj.missing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         anno = get_annotations(RaisesAttributeError, format=Format.FORWARDREF) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             anno, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "attriberr": support.EqualToForwardRef( | 
					
						
							|  |  |  |                     "obj.missing", is_class=True, owner=RaisesAttributeError | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-27 10:24:10 -07:00
										 |  |  | class TestCallEvaluateFunction(unittest.TestCase): | 
					
						
							|  |  |  |     def test_evaluation(self): | 
					
						
							|  |  |  |         def evaluate(format, exc=NotImplementedError): | 
					
						
							| 
									
										
										
										
											2024-11-26 07:40:13 -08:00
										 |  |  |             if format > 2: | 
					
						
							| 
									
										
										
										
											2024-07-27 10:24:10 -07:00
										 |  |  |                 raise exc | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(NameError): | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             annotationlib.call_evaluate_function(evaluate, Format.VALUE) | 
					
						
							| 
									
										
										
										
											2024-07-27 10:24:10 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             annotationlib.call_evaluate_function(evaluate, Format.FORWARDREF), | 
					
						
							| 
									
										
										
										
											2025-04-04 21:36:34 -07:00
										 |  |  |             support.EqualToForwardRef("undefined"), | 
					
						
							| 
									
										
										
										
											2024-07-27 10:24:10 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             annotationlib.call_evaluate_function(evaluate, Format.STRING), | 
					
						
							| 
									
										
										
										
											2024-07-27 10:24:10 -07:00
										 |  |  |             "undefined", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | class MetaclassTests(unittest.TestCase): | 
					
						
							|  |  |  |     def test_annotated_meta(self): | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             a: int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class X(metaclass=Meta): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Y(metaclass=Meta): | 
					
						
							|  |  |  |             b: float | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(Meta), {"a": int}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertEqual(Meta.__annotate__(Format.VALUE), {"a": int}) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(X), {}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertIs(X.__annotate__, None) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(Y), {"b": float}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertEqual(Y.__annotate__(Format.VALUE), {"b": float}) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_unannotated_meta(self): | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |         class Meta(type): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class X(metaclass=Meta): | 
					
						
							|  |  |  |             a: str | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |         class Y(X): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(Meta), {}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertIs(Meta.__annotate__, None) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(Y), {}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertIs(Y.__annotate__, None) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(get_annotations(X), {"a": str}) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         self.assertEqual(X.__annotate__(Format.VALUE), {"a": str}) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_ordering(self): | 
					
						
							|  |  |  |         # Based on a sample by David Ellis | 
					
						
							|  |  |  |         # https://discuss.python.org/t/pep-749-implementing-pep-649/54974/38 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def make_classes(): | 
					
						
							|  |  |  |             class Meta(type): | 
					
						
							|  |  |  |                 a: int | 
					
						
							|  |  |  |                 expected_annotations = {"a": int} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             class A(type, metaclass=Meta): | 
					
						
							|  |  |  |                 b: float | 
					
						
							|  |  |  |                 expected_annotations = {"b": float} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             class B(metaclass=A): | 
					
						
							|  |  |  |                 c: str | 
					
						
							|  |  |  |                 expected_annotations = {"c": str} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             class C(B): | 
					
						
							|  |  |  |                 expected_annotations = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             class D(metaclass=Meta): | 
					
						
							|  |  |  |                 expected_annotations = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return Meta, A, B, C, D | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         classes = make_classes() | 
					
						
							|  |  |  |         class_count = len(classes) | 
					
						
							|  |  |  |         for order in itertools.permutations(range(class_count), class_count): | 
					
						
							|  |  |  |             names = ", ".join(classes[i].__name__ for i in order) | 
					
						
							|  |  |  |             with self.subTest(names=names): | 
					
						
							|  |  |  |                 classes = make_classes()  # Regenerate classes | 
					
						
							|  |  |  |                 for i in order: | 
					
						
							|  |  |  |                     get_annotations(classes[i]) | 
					
						
							|  |  |  |                 for c in classes: | 
					
						
							|  |  |  |                     with self.subTest(c=c): | 
					
						
							|  |  |  |                         self.assertEqual(get_annotations(c), c.expected_annotations) | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |                         annotate_func = getattr(c, "__annotate__", None) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  |                         if c.expected_annotations: | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  |                             self.assertEqual( | 
					
						
							|  |  |  |                                 annotate_func(Format.VALUE), c.expected_annotations | 
					
						
							|  |  |  |                             ) | 
					
						
							| 
									
										
										
										
											2024-07-27 09:36:06 -07:00
										 |  |  |                         else: | 
					
						
							|  |  |  |                             self.assertIs(annotate_func, None) | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  | class TestGetAnnotateFromClassNamespace(unittest.TestCase): | 
					
						
							|  |  |  |     def test_with_metaclass(self): | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             def __new__(mcls, name, bases, ns): | 
					
						
							|  |  |  |                 annotate = annotationlib.get_annotate_from_class_namespace(ns) | 
					
						
							|  |  |  |                 expected = ns["expected_annotate"] | 
					
						
							|  |  |  |                 with self.subTest(name=name): | 
					
						
							|  |  |  |                     if expected: | 
					
						
							|  |  |  |                         self.assertIsNotNone(annotate) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         self.assertIsNone(annotate) | 
					
						
							|  |  |  |                 return super().__new__(mcls, name, bases, ns) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class HasAnnotations(metaclass=Meta): | 
					
						
							|  |  |  |             expected_annotate = True | 
					
						
							|  |  |  |             a: int | 
					
						
							| 
									
										
										
										
											2024-09-18 08:39:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         class NoAnnotations(metaclass=Meta): | 
					
						
							|  |  |  |             expected_annotate = False | 
					
						
							| 
									
										
										
										
											2024-09-18 08:39:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         class CustomAnnotate(metaclass=Meta): | 
					
						
							|  |  |  |             expected_annotate = True | 
					
						
							|  |  |  |             def __annotate__(format): | 
					
						
							|  |  |  |                 return {} | 
					
						
							| 
									
										
										
										
											2024-09-18 08:39:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |         code = """
 | 
					
						
							|  |  |  |             from __future__ import annotations | 
					
						
							| 
									
										
										
										
											2024-09-18 08:39:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 07:26:42 -07:00
										 |  |  |             class HasFutureAnnotations(metaclass=Meta): | 
					
						
							|  |  |  |                 expected_annotate = False | 
					
						
							|  |  |  |                 a: int | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         exec(textwrap.dedent(code), {"Meta": Meta}) | 
					
						
							| 
									
										
										
										
											2024-09-18 08:39:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | class TestTypeRepr(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2025-04-15 13:10:53 -07:00
										 |  |  |     def test_type_repr(self): | 
					
						
							|  |  |  |         class Nested: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def nested(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(type_repr(int), "int") | 
					
						
							|  |  |  |         self.assertEqual(type_repr(MyClass), f"{__name__}.MyClass") | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             type_repr(Nested), f"{__name__}.TestTypeRepr.test_type_repr.<locals>.Nested" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-15 13:10:53 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             type_repr(nested), f"{__name__}.TestTypeRepr.test_type_repr.<locals>.nested" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-15 13:10:53 -07:00
										 |  |  |         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") | 
					
						
							|  |  |  |         self.assertEqual(type_repr(...), "...") | 
					
						
							|  |  |  |         self.assertEqual(type_repr(None), "None") | 
					
						
							|  |  |  |         self.assertEqual(type_repr(1), "1") | 
					
						
							|  |  |  |         self.assertEqual(type_repr("1"), "'1'") | 
					
						
							|  |  |  |         self.assertEqual(type_repr(Format.VALUE), repr(Format.VALUE)) | 
					
						
							|  |  |  |         self.assertEqual(type_repr(MyClass()), "my repr") | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestAnnotationsToString(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |     def test_annotations_to_string(self): | 
					
						
							|  |  |  |         self.assertEqual(annotations_to_string({}), {}) | 
					
						
							|  |  |  |         self.assertEqual(annotations_to_string({"x": int}), {"x": "int"}) | 
					
						
							|  |  |  |         self.assertEqual(annotations_to_string({"x": "int"}), {"x": "int"}) | 
					
						
							| 
									
										
										
										
											2024-09-25 17:01:09 -07:00
										 |  |  |         self.assertEqual( | 
					
						
							| 
									
										
										
										
											2024-09-26 13:49:48 -07:00
										 |  |  |             annotations_to_string({"x": int, "y": str}), {"x": "int", "y": "str"} | 
					
						
							| 
									
										
										
										
											2024-09-25 17:01:09 -07:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | class A: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | class TestForwardRefClass(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |     def test_forwardref_instance_type_error(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         fr = ForwardRef("int") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             isinstance(42, fr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forwardref_subclass_type_error(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         fr = ForwardRef("int") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             issubclass(int, fr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forwardref_only_str_arg(self): | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             ForwardRef(1)  # only `str` type is allowed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_equality(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         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__")) | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_equality_get_type_hints(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         c1 = ForwardRef("C") | 
					
						
							|  |  |  |         c1_gth = ForwardRef("C") | 
					
						
							|  |  |  |         c2 = ForwardRef("C") | 
					
						
							|  |  |  |         c2_gth = ForwardRef("C") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         def foo(a: c1_gth, b: c2_gth): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(get_type_hints(foo, globals(), locals()), {"a": C, "b": C}) | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         self.assertEqual(c1, c2) | 
					
						
							|  |  |  |         self.assertEqual(c1, c1_gth) | 
					
						
							|  |  |  |         self.assertEqual(c1_gth, c2_gth) | 
					
						
							|  |  |  |         self.assertEqual(List[c1], List[c1_gth]) | 
					
						
							|  |  |  |         self.assertNotEqual(List[c1], List[C]) | 
					
						
							|  |  |  |         self.assertNotEqual(List[c1_gth], List[C]) | 
					
						
							|  |  |  |         self.assertEqual(Union[c1, c1_gth], Union[c1]) | 
					
						
							|  |  |  |         self.assertEqual(Union[c1, c1_gth, int], Union[c1, int]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_equality_hash(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         c1 = ForwardRef("int") | 
					
						
							|  |  |  |         c1_gth = ForwardRef("int") | 
					
						
							|  |  |  |         c2 = ForwardRef("int") | 
					
						
							|  |  |  |         c2_gth = ForwardRef("int") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def foo(a: c1_gth, b: c2_gth): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         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)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         c3 = ForwardRef("int", module=__name__) | 
					
						
							|  |  |  |         c4 = ForwardRef("int", module="__other_name__") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertNotEqual(hash(c3), hash(c1)) | 
					
						
							|  |  |  |         self.assertNotEqual(hash(c3), hash(c1_gth)) | 
					
						
							|  |  |  |         self.assertNotEqual(hash(c3), hash(c4)) | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(hash(c3), hash(ForwardRef("int", module=__name__))) | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_equality_namespace(self): | 
					
						
							|  |  |  |         def namespace1(): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             a = ForwardRef("A") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             def fun(x: a): | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             get_type_hints(fun, globals(), locals()) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def namespace2(): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             a = ForwardRef("A") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             class A: | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             def fun(x: a): | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             get_type_hints(fun, globals(), locals()) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(namespace1(), namespace1()) | 
					
						
							|  |  |  |         self.assertEqual(namespace1(), namespace2()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_repr(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         self.assertEqual(repr(List["int"]), "typing.List[ForwardRef('int')]") | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             repr(List[ForwardRef("int", module="mod")]), | 
					
						
							|  |  |  |             "typing.List[ForwardRef('int', module='mod')]", | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_forward_recursion_actually(self): | 
					
						
							|  |  |  |         def namespace1(): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             a = ForwardRef("A") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             A = a | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def fun(x: a): | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             ret = get_type_hints(fun, globals(), locals()) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def namespace2(): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             a = ForwardRef("A") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             A = a | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             def fun(x: a): | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             ret = get_type_hints(fun, globals(), locals()) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         r1 = namespace1() | 
					
						
							|  |  |  |         r2 = namespace2() | 
					
						
							|  |  |  |         self.assertIsNot(r1, r2) | 
					
						
							|  |  |  |         self.assertEqual(r1, r2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_syntax_error(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             typing.Generic["/T"] | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_delayed_syntax_error(self): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         def foo(a: "Node[T"): | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError): | 
					
						
							|  |  |  |             get_type_hints(foo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |                     form[""] | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_or(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         X = ForwardRef("X") | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  |         # __or__/__ror__ itself | 
					
						
							|  |  |  |         self.assertEqual(X | "x", Union[X, "x"]) | 
					
						
							|  |  |  |         self.assertEqual("x" | X, Union["x", X]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_multiple_ways_to_create(self): | 
					
						
							|  |  |  |         X1 = Union["X"] | 
					
						
							|  |  |  |         self.assertIsInstance(X1, ForwardRef) | 
					
						
							|  |  |  |         X2 = ForwardRef("X") | 
					
						
							|  |  |  |         self.assertIsInstance(X2, ForwardRef) | 
					
						
							|  |  |  |         self.assertEqual(X1, X2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-04 15:21:56 -07:00
										 |  |  |     def test_evaluate_string_format(self): | 
					
						
							|  |  |  |         fr = ForwardRef("set[Any]") | 
					
						
							|  |  |  |         self.assertEqual(fr.evaluate(format=Format.STRING), "set[Any]") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_evaluate_forwardref_format(self): | 
					
						
							|  |  |  |         fr = ForwardRef("undef") | 
					
						
							|  |  |  |         evaluated = fr.evaluate(format=Format.FORWARDREF) | 
					
						
							|  |  |  |         self.assertIs(fr, evaluated) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fr = ForwardRef("set[undefined]") | 
					
						
							|  |  |  |         evaluated = fr.evaluate(format=Format.FORWARDREF) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             evaluated, | 
					
						
							|  |  |  |             set[support.EqualToForwardRef("undefined")], | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fr = ForwardRef("a + b") | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             fr.evaluate(format=Format.FORWARDREF), | 
					
						
							|  |  |  |             support.EqualToForwardRef("a + b"), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             fr.evaluate(format=Format.FORWARDREF, locals={"a": 1, "b": 2}), | 
					
						
							|  |  |  |             3, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fr = ForwardRef('"a" + 1') | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             fr.evaluate(format=Format.FORWARDREF), | 
					
						
							|  |  |  |             support.EqualToForwardRef('"a" + 1'), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 15:26:58 +02:00
										 |  |  |         with self.assertRaises(NameError, msg="name 'doesntexist' is not defined") as exc: | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |             ForwardRef("doesntexist").evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 15:26:58 +02:00
										 |  |  |         self.assertEqual(exc.exception.name, "doesntexist") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |     def test_fwdref_invalid_syntax(self): | 
					
						
							|  |  |  |         fr = ForwardRef("if") | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError): | 
					
						
							|  |  |  |             fr.evaluate() | 
					
						
							|  |  |  |         fr = ForwardRef("1+") | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError): | 
					
						
							|  |  |  |             fr.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 06:40:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 16:44:51 -07:00
										 |  |  | class TestAnnotationLib(unittest.TestCase): | 
					
						
							|  |  |  |     def test__all__(self): | 
					
						
							|  |  |  |         support.check__all__(self, annotationlib) | 
					
						
							| 
									
										
										
										
											2025-04-16 20:46:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |     @support.cpython_only | 
					
						
							| 
									
										
										
										
											2025-04-16 20:46:36 -07:00
										 |  |  |     def test_lazy_imports(self): | 
					
						
							| 
									
										
										
										
											2025-04-28 08:38:11 -07:00
										 |  |  |         import_helper.ensure_lazy_imports( | 
					
						
							|  |  |  |             "annotationlib", | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "typing", | 
					
						
							|  |  |  |                 "warnings", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) |