-
Notifications
You must be signed in to change notification settings - Fork 293
Expand file tree
/
Copy pathannotations_forward_refs.py
More file actions
104 lines (72 loc) · 2.48 KB
/
annotations_forward_refs.py
File metadata and controls
104 lines (72 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
Tests the handling of forward references in type annotations.
"""
# > When a type hint contains names that have not been defined yet, that
# > definition may be expressed as a string literal, to be resolved later.
import types
from typing import assert_type, Any
def func1(
p1: "ClassA", p2: "list[ClassA]", p3: list["ClassA"], p4: list["int | ClassA"]
) -> None:
assert_type(p1, ClassA)
assert_type(p2, list[ClassA])
assert_type(p3, list[ClassA])
assert_type(p4, list[ClassA | int])
bad1: ClassA # E?: Runtime error prior to 3.14: requires quotes
bad2: list[ClassA] # E?: Runtime error prior to 3.14: requires quotes
bad3: "ClassA" | int # E: Runtime error
bad4: int | "ClassA" # E: Runtime error
class ClassA:
...
# > The string literal should contain a valid Python expression
# > should be a valid code object).
var1 = 1
# The following should all generate errors because they are not legal type
# expressions, despite being enclosed in quotes.
def invalid_annotations(
p1: "eval(''.join(map(chr, [105, 110, 116])))", # E
p2: "[int, str]", # E
p3: "(int, str)", # E
p4: "[int for i in range(1)]", # E
p5: "{}", # E
p6: "(lambda : int)()", # E
p7: "[int][0]", # E
p8: "int if 1 < 3 else str", # E
p9: "var1", # E
p10: "True", # E
p11: "1", # E
p12: "-1", # E
p13: "int or str", # E
p14: 'f"int"', # E
p15: "types", # E
):
pass
# > Names within the expression are looked up in the same way as they would be
# > looked up at runtime in Python 3.14 and higher if the annotation was not
# > enclosed in a string literal.
class ClassB:
def method1(self) -> ClassB: # E?: Runtime error prior to 3.14
return ClassB()
def method2(self) -> "ClassB": # OK
return ClassB()
class ClassC:
...
class ClassD:
ClassC: "ClassC" # OK
ClassF: "ClassF" # E: circular reference
str: "str" = "" # E: circular reference
z: "int" = 0 # E: Refers to the local int function
def int(self) -> None: # OK
...
y: int = 0 # E: Refers to the local int function, which isn't a legal type expression
x: "int" = 0 # E: Refers to a local int function
def __init__(self) -> None:
self.ClassC = ClassC()
# > If a triple quote is used, the string should be parsed as though it is implicitly
# > surrounded by parentheses. This allows newline characters to be
# > used within the string literal.
value: """
int |
str |
list[int]
"""