Skip to content

Commit

Permalink
pythongh-119180: annotationlib: Fix __all__, formatting (python#122365)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored and blhsing committed Aug 22, 2024
1 parent 7064e0c commit ace7ab9
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 33 deletions.
30 changes: 23 additions & 7 deletions Lib/annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
import sys
import types

__all__ = ["Format", "ForwardRef", "call_annotate_function", "get_annotations"]
__all__ = [
"Format",
"ForwardRef",
"call_annotate_function",
"call_evaluate_function",
"get_annotate_function",
"get_annotations",
]


class Format(enum.IntEnum):
Expand Down Expand Up @@ -426,8 +433,7 @@ def call_evaluate_function(evaluate, format, *, owner=None):
return call_annotate_function(evaluate, format, owner=owner, _is_evaluate=True)


def call_annotate_function(annotate, format, *, owner=None,
_is_evaluate=False):
def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
"""Call an __annotate__ function. __annotate__ functions are normally
generated by the compiler to defer the evaluation of annotations. They
can be called with any of the format arguments in the Format enum, but
Expand Down Expand Up @@ -473,8 +479,13 @@ def call_annotate_function(annotate, format, *, owner=None,
closure = tuple(new_closure)
else:
closure = None
func = types.FunctionType(annotate.__code__, globals, closure=closure,
argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
func = types.FunctionType(
annotate.__code__,
globals,
closure=closure,
argdefs=annotate.__defaults__,
kwdefaults=annotate.__kwdefaults__,
)
annos = func(Format.VALUE)
if _is_evaluate:
return annos if isinstance(annos, str) else repr(annos)
Expand Down Expand Up @@ -528,8 +539,13 @@ def call_annotate_function(annotate, format, *, owner=None,
closure = tuple(new_closure)
else:
closure = None
func = types.FunctionType(annotate.__code__, globals, closure=closure,
argdefs=annotate.__defaults__, kwdefaults=annotate.__kwdefaults__)
func = types.FunctionType(
annotate.__code__,
globals,
closure=closure,
argdefs=annotate.__defaults__,
kwdefaults=annotate.__kwdefaults__,
)
result = func(Format.VALUE)
for obj in globals.stringifiers:
obj.__class__ = ForwardRef
Expand Down
4 changes: 1 addition & 3 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
stack(), trace() - get info about frames on the stack or in a traceback
signature() - get a Signature object for the callable
get_annotations() - safely compute an object's annotations
"""

# This module is in the public domain. No warranties.
Expand Down Expand Up @@ -142,7 +140,7 @@


import abc
from annotationlib import get_annotations
from annotationlib import get_annotations # re-exported
import ast
import dis
import collections.abc
Expand Down
67 changes: 44 additions & 23 deletions Lib/test/test_annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from annotationlib import Format, ForwardRef, get_annotations, get_annotate_function
from typing import Unpack

from test import support
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
Expand Down Expand Up @@ -327,7 +328,9 @@ class C1(metaclass=NoDict):
)
self.assertEqual(annotationlib.get_annotations(NoDict), {"b": str})
self.assertEqual(
annotationlib.get_annotations(NoDict, format=annotationlib.Format.FORWARDREF),
annotationlib.get_annotations(
NoDict, format=annotationlib.Format.FORWARDREF
),
{"b": str},
)
self.assertEqual(
Expand Down Expand Up @@ -715,12 +718,13 @@ def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self):
)
self.assertEqual(B_annotations, {"x": int, "y": str, "z": bytes})

def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self):
def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(
self,
):
ann_module695 = inspect_stringized_annotations_pep695
C_annotations = annotationlib.get_annotations(ann_module695.C, eval_str=True)
self.assertEqual(
set(C_annotations.values()),
set(ann_module695.C.__type_params__)
set(C_annotations.values()), set(ann_module695.C.__type_params__)
)

def test_pep_695_generic_function_with_future_annotations(self):
Expand All @@ -737,17 +741,19 @@ def test_pep_695_generic_function_with_future_annotations(self):
self.assertIs(generic_func_annotations["z"].__origin__, func_t_params[2])
self.assertIs(generic_func_annotations["zz"].__origin__, func_t_params[2])

def test_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars(self):
def test_pep_695_generic_function_with_future_annotations_name_clash_with_global_vars(
self,
):
self.assertEqual(
set(
annotationlib.get_annotations(
inspect_stringized_annotations_pep695.generic_function_2,
eval_str=True
eval_str=True,
).values()
),
set(
inspect_stringized_annotations_pep695.generic_function_2.__type_params__
)
),
)

def test_pep_695_generic_method_with_future_annotations(self):
Expand All @@ -761,23 +767,27 @@ def test_pep_695_generic_method_with_future_annotations(self):
}
self.assertEqual(
generic_method_annotations,
{"x": params["Foo"], "y": params["Bar"], "return": None}
{"x": params["Foo"], "y": params["Bar"], "return": None},
)

def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars(self):
def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_vars(
self,
):
self.assertEqual(
set(
annotationlib.get_annotations(
inspect_stringized_annotations_pep695.D.generic_method_2,
eval_str=True
eval_str=True,
).values()
),
set(
inspect_stringized_annotations_pep695.D.generic_method_2.__type_params__
)
),
)

def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_and_local_vars(self):
def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_and_local_vars(
self,
):
self.assertEqual(
annotationlib.get_annotations(
inspect_stringized_annotations_pep695.E, eval_str=True
Expand All @@ -789,20 +799,20 @@ def test_pep_695_generics_with_future_annotations_nested_in_function(self):
results = inspect_stringized_annotations_pep695.nested()

self.assertEqual(
set(results.F_annotations.values()),
set(results.F.__type_params__)
set(results.F_annotations.values()), set(results.F.__type_params__)
)
self.assertEqual(
set(results.F_meth_annotations.values()),
set(results.F.generic_method.__type_params__)
set(results.F.generic_method.__type_params__),
)
self.assertNotEqual(
set(results.F_meth_annotations.values()),
set(results.F.__type_params__)
set(results.F_meth_annotations.values()), set(results.F.__type_params__)
)
self.assertEqual(
set(results.F_meth_annotations.values()).intersection(results.F.__type_params__),
set()
set(results.F_meth_annotations.values()).intersection(
results.F.__type_params__
),
set(),
)

self.assertEqual(results.G_annotations, {"x": str})
Expand All @@ -823,7 +833,9 @@ def evaluate(format, exc=NotImplementedError):
with self.assertRaises(NameError):
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.VALUE)
self.assertEqual(
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.FORWARDREF),
annotationlib.call_evaluate_function(
evaluate, annotationlib.Format.FORWARDREF
),
annotationlib.ForwardRef("undefined"),
)
self.assertEqual(
Expand Down Expand Up @@ -853,12 +865,14 @@ class Y(metaclass=Meta):
self.assertEqual(get_annotate_function(Y)(Format.VALUE), {"b": float})

def test_unannotated_meta(self):
class Meta(type): pass
class Meta(type):
pass

class X(metaclass=Meta):
a: str

class Y(X): pass
class Y(X):
pass

self.assertEqual(get_annotations(Meta), {})
self.assertIs(get_annotate_function(Meta), None)
Expand Down Expand Up @@ -907,6 +921,13 @@ class D(metaclass=Meta):
self.assertEqual(get_annotations(c), c.expected_annotations)
annotate_func = get_annotate_function(c)
if c.expected_annotations:
self.assertEqual(annotate_func(Format.VALUE), c.expected_annotations)
self.assertEqual(
annotate_func(Format.VALUE), c.expected_annotations
)
else:
self.assertIs(annotate_func, None)


class TestAnnotationLib(unittest.TestCase):
def test__all__(self):
support.check__all__(self, annotationlib)

0 comments on commit ace7ab9

Please sign in to comment.