Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1834453

Browse files
[3.12]gh-114053: Fix bad interaction of PEP 695, PEP 563 andinspect.get_annotations (GH-120270) (#120475)
gh-114053: Fix bad interaction of PEP 695, PEP 563 and `inspect.get_annotations` (GH-120270)(cherry picked from commit42351c3)Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parentc9fc099 commit1834453

File tree

4 files changed

+186
-1
lines changed

4 files changed

+186
-1
lines changed

‎Lib/inspect.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,13 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
280280
ifglobalsisNone:
281281
globals=obj_globals
282282
iflocalsisNone:
283-
locals=obj_locals
283+
locals=obj_localsor {}
284+
285+
# "Inject" type parameters into the local namespace
286+
# (unless they are shadowed by assignments *in* the local namespace),
287+
# as a way of emulating annotation scopes when calling `eval()`
288+
iftype_params:=getattr(obj,"__type_params__", ()):
289+
locals= {param.__name__:paramforparamintype_params}|locals
284290

285291
return_value= {key:
286292
valueifnotisinstance(value,str)elseeval(value,globals,locals)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__importannotations
2+
fromtypingimportCallable,Unpack
3+
4+
5+
classA[T,*Ts,**P]:
6+
x:T
7+
y:tuple[*Ts]
8+
z:Callable[P,str]
9+
10+
11+
classB[T,*Ts,**P]:
12+
T=int
13+
Ts=str
14+
P=bytes
15+
x:T
16+
y:Ts
17+
z:P
18+
19+
20+
Eggs=int
21+
Spam=str
22+
23+
24+
classC[Eggs,**Spam]:
25+
x:Eggs
26+
y:Spam
27+
28+
29+
defgeneric_function[T,*Ts,**P](
30+
x:T,*y:Unpack[Ts],z:P.args,zz:P.kwargs
31+
)->None: ...
32+
33+
34+
defgeneric_function_2[Eggs,**Spam](x:Eggs,y:Spam):pass
35+
36+
37+
classD:
38+
Foo=int
39+
Bar=str
40+
41+
defgeneric_method[Foo,**Bar](
42+
self,x:Foo,y:Bar
43+
)->None: ...
44+
45+
defgeneric_method_2[Eggs,**Spam](self,x:Eggs,y:Spam):pass
46+
47+
48+
defnested():
49+
fromtypesimportSimpleNamespace
50+
frominspectimportget_annotations
51+
52+
Eggs=bytes
53+
Spam=memoryview
54+
55+
56+
classE[Eggs,**Spam]:
57+
x:Eggs
58+
y:Spam
59+
60+
defgeneric_method[Eggs,**Spam](self,x:Eggs,y:Spam):pass
61+
62+
63+
defgeneric_function[Eggs,**Spam](x:Eggs,y:Spam):pass
64+
65+
66+
returnSimpleNamespace(
67+
E=E,
68+
E_annotations=get_annotations(E,eval_str=True),
69+
E_meth_annotations=get_annotations(E.generic_method,eval_str=True),
70+
generic_func=generic_function,
71+
generic_func_annotations=get_annotations(generic_function,eval_str=True)
72+
)

‎Lib/test/test_inspect/test_inspect.py‎

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
importsys
1818
importtypes
1919
importtextwrap
20+
fromtypingimportUnpack
2021
importunicodedata
2122
importunittest
2223
importunittest.mock
@@ -40,6 +41,7 @@
4041
fromtest.test_inspectimportinspect_stock_annotations
4142
fromtest.test_inspectimportinspect_stringized_annotations
4243
fromtest.test_inspectimportinspect_stringized_annotations_2
44+
fromtest.test_inspectimportinspect_stringized_annotations_pep695
4345

4446

4547
# Functions tested in this suite:
@@ -1505,6 +1507,107 @@ def wrapper(a, b):
15051507
self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations), {'x':'mytype'})
15061508
self.assertEqual(inspect.get_annotations(isa.MyClassWithLocalAnnotations,eval_str=True), {'x':int})
15071509

1510+
deftest_pep695_generic_class_with_future_annotations(self):
1511+
ann_module695=inspect_stringized_annotations_pep695
1512+
A_annotations=inspect.get_annotations(ann_module695.A,eval_str=True)
1513+
A_type_params=ann_module695.A.__type_params__
1514+
self.assertIs(A_annotations["x"],A_type_params[0])
1515+
self.assertEqual(A_annotations["y"].__args__[0],Unpack[A_type_params[1]])
1516+
self.assertIs(A_annotations["z"].__args__[0],A_type_params[2])
1517+
1518+
deftest_pep695_generic_class_with_future_annotations_and_local_shadowing(self):
1519+
B_annotations=inspect.get_annotations(
1520+
inspect_stringized_annotations_pep695.B,eval_str=True
1521+
)
1522+
self.assertEqual(B_annotations, {"x":int,"y":str,"z":bytes})
1523+
1524+
deftest_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self):
1525+
ann_module695=inspect_stringized_annotations_pep695
1526+
C_annotations=inspect.get_annotations(ann_module695.C,eval_str=True)
1527+
self.assertEqual(
1528+
set(C_annotations.values()),
1529+
set(ann_module695.C.__type_params__)
1530+
)
1531+
1532+
deftest_pep_695_generic_function_with_future_annotations(self):
1533+
ann_module695=inspect_stringized_annotations_pep695
1534+
generic_func_annotations=inspect.get_annotations(
1535+
ann_module695.generic_function,eval_str=True
1536+
)
1537+
func_t_params=ann_module695.generic_function.__type_params__
1538+
self.assertEqual(
1539+
generic_func_annotations.keys(), {"x","y","z","zz","return"}
1540+
)
1541+
self.assertIs(generic_func_annotations["x"],func_t_params[0])
1542+
self.assertEqual(generic_func_annotations["y"],Unpack[func_t_params[1]])
1543+
self.assertIs(generic_func_annotations["z"].__origin__,func_t_params[2])
1544+
self.assertIs(generic_func_annotations["zz"].__origin__,func_t_params[2])
1545+
1546+
deftest_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars(self):
1547+
self.assertEqual(
1548+
set(
1549+
inspect.get_annotations(
1550+
inspect_stringized_annotations_pep695.generic_function_2,
1551+
eval_str=True
1552+
).values()
1553+
),
1554+
set(
1555+
inspect_stringized_annotations_pep695.generic_function_2.__type_params__
1556+
)
1557+
)
1558+
1559+
deftest_pep_695_generic_method_with_future_annotations(self):
1560+
ann_module695=inspect_stringized_annotations_pep695
1561+
generic_method_annotations=inspect.get_annotations(
1562+
ann_module695.D.generic_method,eval_str=True
1563+
)
1564+
params= {
1565+
param.__name__:param
1566+
forparaminann_module695.D.generic_method.__type_params__
1567+
}
1568+
self.assertEqual(
1569+
generic_method_annotations,
1570+
{"x":params["Foo"],"y":params["Bar"],"return":None}
1571+
)
1572+
1573+
deftest_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars(self):
1574+
self.assertEqual(
1575+
set(
1576+
inspect.get_annotations(
1577+
inspect_stringized_annotations_pep695.D.generic_method_2,
1578+
eval_str=True
1579+
).values()
1580+
),
1581+
set(
1582+
inspect_stringized_annotations_pep695.D.generic_method_2.__type_params__
1583+
)
1584+
)
1585+
1586+
deftest_pep_695_generics_with_future_annotations_nested_in_function(self):
1587+
results=inspect_stringized_annotations_pep695.nested()
1588+
1589+
self.assertEqual(
1590+
set(results.E_annotations.values()),
1591+
set(results.E.__type_params__)
1592+
)
1593+
self.assertEqual(
1594+
set(results.E_meth_annotations.values()),
1595+
set(results.E.generic_method.__type_params__)
1596+
)
1597+
self.assertNotEqual(
1598+
set(results.E_meth_annotations.values()),
1599+
set(results.E.__type_params__)
1600+
)
1601+
self.assertEqual(
1602+
set(results.E_meth_annotations.values()).intersection(results.E.__type_params__),
1603+
set()
1604+
)
1605+
1606+
self.assertEqual(
1607+
set(results.generic_func_annotations.values()),
1608+
set(results.generic_func.__type_params__)
1609+
)
1610+
15081611

15091612
classTestFormatAnnotation(unittest.TestCase):
15101613
deftest_typing_replacement(self):
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix erroneous:exc:`NameError` when calling:func:`inspect.get_annotations`
2+
with ``eval_str=True``` on a class that made use of:pep:`695` type
3+
parameters in a module that had ``from __future__ import annotations`` at
4+
the top of the file. Patch by Alex Waygood.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp