Bug report
Bug description:
I ran into this while writing tests for #135228 with additional ways to unintentionally make the old class stick around.
MRE:
fromtypingimportAnnotatedfromannotationlibimportget_annotations, Formatdeff(x: Annotated[undefined, '']): passannos=get_annotations(f, format=Format.FORWARDREF)
print(annos['x'])
Expected: typing.Annotated[ForwardRef('undefined', owner=...), '']
Actual: ForwardRef("Annotated[undefined, '']", owner=...)
The cause is this:
_Stringifier has a __getattr__ that will return a new _Stringifier- Annotated checks
_is_unpacked_typevartuple to determine if it should fail _is_unpacked_typevartuple checks getattr(x, "__typing_is_unpacked_typevartuple__", False)- This returns a new
_Stringifier which is truthy - Annotated raises a TypeError as it thinks the
_Stringifier is an unpacked typevartuple call_annotate_function falls back to the all-stringifiers backup mode which makes the whole thing a ForwardRef
I think the solution for Annotated not partially evaluating is probably to make typing._is_unpacked_typevartuple check that the value is True rather than truthy.
One reason why this might matter - the exception that occurs internally can also prevent other annotations from partially evaluating:
fromtypingimportAnnotatedfromdataclassesimportInitVar, dataclass, fieldsfrompprintimportpp@dataclassclassPartiallyEvaluates:
x: InitVar[undefined]
@dataclassclassNoLongerEvaluates:
x: InitVar[undefined]
y: Annotated[undefined, '']
The addition of the Annotated field makes it so x is no longer correctly identified as an InitVar here.
CPython versions tested on:
3.14, CPython main branch
Operating systems tested on:
No response
Linked PRs
Bug report
Bug description:
I ran into this while writing tests for #135228 with additional ways to unintentionally make the old class stick around.
MRE:
Expected:
typing.Annotated[ForwardRef('undefined', owner=...), '']Actual:
ForwardRef("Annotated[undefined, '']", owner=...)The cause is this:
_Stringifierhas a__getattr__that will return a new_Stringifier_is_unpacked_typevartupleto determine if it should fail_is_unpacked_typevartuplechecksgetattr(x, "__typing_is_unpacked_typevartuple__", False)_Stringifierwhich is truthy_Stringifieris an unpacked typevartuplecall_annotate_functionfalls back to the all-stringifiers backup mode which makes the whole thing aForwardRefI think the solution for
Annotatednot partially evaluating is probably to maketyping._is_unpacked_typevartuplecheck that the value isTruerather than truthy.One reason why this might matter - the exception that occurs internally can also prevent other annotations from partially evaluating:
The addition of the
Annotatedfield makes it soxis no longer correctly identified as an InitVar here.CPython versions tested on:
3.14, CPython main branch
Operating systems tested on:
No response
Linked PRs
Trueinstead of truthy #137712Trueinstead of truthy (GH-137712) #138574