Skip to content

Commit

Permalink
pythongh-119180: annotationlib: Fix __all__, reformat, other minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed Jul 27, 2024
1 parent 04eb5c8 commit e7bda02
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 36 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ repos:
rev: 24.4.2
hooks:
- id: black
name: Run Black on Tools/jit/
files: ^Tools/jit/
name: Run Black on Tools/jit/ and annotationlib
files: ^(Tools/jit/|Lib/annotationlib\.py|Lib/test/test_annotationlib\.py)
language_version: python3.12

- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
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 @@ -421,8 +428,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 @@ -468,8 +474,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 @@ -523,8 +534,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, 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 @@ -287,7 +288,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 @@ -675,12 +678,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 @@ -697,17 +701,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 @@ -721,23 +727,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 @@ -749,20 +759,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 @@ -783,7 +793,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 @@ -813,12 +825,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 @@ -867,6 +881,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)
2 changes: 1 addition & 1 deletion Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ def evaluate_forward_ref(
evaluating the forward reference. This parameter must be provided (though
it may be an empty tuple) if *owner* is not given and the forward reference
does not already have an owner set. *format* specifies the format of the
annotation and is a member of the annoations.Format enum.
annotation and is a member of the annotationlib.Format enum.
"""
if type_params is _sentinel:
Expand Down

0 comments on commit e7bda02

Please sign in to comment.