-
-
Notifications
You must be signed in to change notification settings - Fork 32.7k
Open
Labels
stdlibPython modules in the Lib dirPython modules in the Lib dirtopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
This can happen internally in get_annotations
and means subsequent attempts to evaluate it will fail even if the names have since been defined.
Underlying logic:
from annotationlib import get_annotations, Format
class Demo:
x: Sequence[undefined]
annos = get_annotations(Demo, format=Format.FORWARDREF)
x_anno = annos['x']
# Try to evaluate the reference, but just give a forwardref if it fails
x_repeat_anno = x_anno.evaluate(format=Format.FORWARDREF)
# The resulting reference no longer shares the globals namespace with the annotate function
print(f"{x_anno.__globals__ is Demo.__annotate__.__globals__ = }") # True
print(f"{x_repeat_anno.__globals__ is Demo.__annotate__.__globals__ = }") # False
# Define the previously undefined attributes
from collections.abc import Sequence
undefined = str
# This means evaluation fails in the second case
print(f"{x_anno.evaluate() = }") # collections.abc.Sequence[str]
print(f"{x_repeat_anno.evaluate() = }") # NameError
This evaluate
call happens internally if get_annotations
has to rely on the fallback behaviour for an unexpected exception, such as an AttributeError
:
from annotationlib import get_annotations, Format
import typing
class Works:
a: Sequence[undefined]
b: unknowable
# Intentionally set up an annotation that will raise AttributeError on evaluation
class Fails:
a: Sequence[undefined]
b: typing.doesnotexist
a_works = get_annotations(Works, format=Format.FORWARDREF)['a']
a_fails = get_annotations(Fails, format=Format.FORWARDREF)['a']
# Realise the references
from collections.abc import Sequence
undefined = str
print(f"{a_works.evaluate() = }") # collections.abc.Sequence[str]
print(f"{a_fails.evaluate() = }") # NameError
This appears to be caused by the creation of a new globals dict here:
Lines 164 to 167 in e39255e
if type_params is not None: | |
globals = dict(globals) | |
for param in type_params: | |
globals[param.__name__] = param |
Commenting this out makes these examples succeed, but obviously breaks type parameters.
CPython versions tested on:
CPython main branch, 3.14
Operating systems tested on:
No response
Linked PRs
Metadata
Metadata
Assignees
Labels
stdlibPython modules in the Lib dirPython modules in the Lib dirtopic-typingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error