Skip to content

Commit 0328ac1

Browse files
committed
Add _get_annotate_attr() to access attrs on non-func annotates, and implement in fwdref format
1 parent 9e7340c commit 0328ac1

File tree

1 file changed

+39
-14
lines changed

1 file changed

+39
-14
lines changed

Lib/annotationlib.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -759,11 +759,18 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
759759
# reconstruct the source. But in the dictionary that we eventually return, we
760760
# want to return objects with more user-friendly behavior, such as an __eq__
761761
# that returns a bool and an defined set of attributes.
762-
namespace = {**annotate.__builtins__, **annotate.__globals__}
762+
annotate_globals = _get_annotate_attr(annotate, "__globals__", {})
763+
annotate_code = _get_annotate_attr(annotate, "__code__", None)
764+
annotate_defaults = _get_annotate_attr(annotate, "__defaults__", None)
765+
annotate_kwdefaults = _get_annotate_attr(annotate, "__kwdefaults__", None)
766+
namespace = {
767+
**_get_annotate_attr(annotate, "__builtins__", {}),
768+
**annotate_globals
769+
}
763770
is_class = isinstance(owner, type)
764771
globals = _StringifierDict(
765772
namespace,
766-
globals=annotate.__globals__,
773+
globals=annotate_globals,
767774
owner=owner,
768775
is_class=is_class,
769776
format=format,
@@ -772,14 +779,17 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
772779
annotate, owner, is_class, globals, allow_evaluation=True
773780
)
774781
func = types.FunctionType(
775-
annotate.__code__,
782+
annotate_code,
776783
globals,
777784
closure=closure,
778-
argdefs=annotate.__defaults__,
779-
kwdefaults=annotate.__kwdefaults__,
785+
argdefs=annotate_defaults,
786+
kwdefaults=annotate_kwdefaults,
780787
)
781788
try:
782-
result = func(Format.VALUE_WITH_FAKE_GLOBALS)
789+
if isinstance(annotate.__call__, types.MethodType):
790+
result = func(annotate.__call__.__self__, Format.VALUE_WITH_FAKE_GLOBALS)
791+
else:
792+
result = func(Format.VALUE_WITH_FAKE_GLOBALS)
783793
except NotImplementedError:
784794
# FORWARDREF and VALUE_WITH_FAKE_GLOBALS not supported, fall back to VALUE
785795
return annotate(Format.VALUE)
@@ -793,7 +803,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
793803
# a value in certain cases where an exception gets raised during evaluation.
794804
globals = _StringifierDict(
795805
{},
796-
globals=annotate.__globals__,
806+
globals=annotate_globals,
797807
owner=owner,
798808
is_class=is_class,
799809
format=format,
@@ -802,13 +812,16 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
802812
annotate, owner, is_class, globals, allow_evaluation=False
803813
)
804814
func = types.FunctionType(
805-
annotate.__code__,
815+
annotate_code,
806816
globals,
807817
closure=closure,
808-
argdefs=annotate.__defaults__,
809-
kwdefaults=annotate.__kwdefaults__,
818+
argdefs=annotate_defaults,
819+
kwdefaults=annotate_kwdefaults,
810820
)
811-
result = func(Format.VALUE_WITH_FAKE_GLOBALS)
821+
if isinstance(annotate.__call__, types.MethodType):
822+
result = func(annotate.__call__.__self__, Format.VALUE_WITH_FAKE_GLOBALS)
823+
else:
824+
result = func(Format.VALUE_WITH_FAKE_GLOBALS)
812825
globals.transmogrify(cell_dict)
813826
if _is_evaluate:
814827
if isinstance(result, ForwardRef):
@@ -833,12 +846,13 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
833846

834847

835848
def _build_closure(annotate, owner, is_class, stringifier_dict, *, allow_evaluation):
836-
if not annotate.__closure__:
849+
closure = _get_annotate_attr(annotate, "__closure__", None)
850+
if not closure:
837851
return None, None
838852
freevars = annotate.__code__.co_freevars
839853
new_closure = []
840854
cell_dict = {}
841-
for i, cell in enumerate(annotate.__closure__):
855+
for i, cell in enumerate(closure):
842856
if i < len(freevars):
843857
name = freevars[i]
844858
else:
@@ -857,7 +871,7 @@ def _build_closure(annotate, owner, is_class, stringifier_dict, *, allow_evaluat
857871
name,
858872
cell=cell,
859873
owner=owner,
860-
globals=annotate.__globals__,
874+
globals=_get_annotate_attr(annotate, "__globals__", {}),
861875
is_class=is_class,
862876
stringifier_dict=stringifier_dict,
863877
)
@@ -879,6 +893,17 @@ def _stringify_single(anno):
879893
return repr(anno)
880894

881895

896+
def _get_annotate_attr(annotate, attr, default):
897+
if (value := getattr(annotate, attr, None)) is not None:
898+
return value
899+
900+
if call_method := getattr(annotate, "__call__", None):
901+
if call_func := getattr(call_method, "__func__", None):
902+
return getattr(call_func, attr, default)
903+
904+
return default
905+
906+
882907
def get_annotate_from_class_namespace(obj):
883908
"""Retrieve the annotate function from a class namespace dictionary.
884909

0 commit comments

Comments
 (0)