Description
Bug report
Bug description:
While looking into #125618 I ran into this case.
Using the union syntax gives a ForwardRef
that can't be evaluated as the class that can be evaluated gets converted into its repr
via ast.Constant
. Using the typing.Union
class however gives a proper union object where only the undefined value is a forwardref.
str | undefined
->ForwardRef("<class 'str'> | undefined")
Union[str, undefined]
->str | ForwardRef("undefined")
Example:
from annotationlib import get_annotations, Format
from typing import Union
class DifferentUnions:
attrib: str | undefined
other_attrib: Union[str, undefined]
different_unions = get_annotations(DifferentUnions, format=Format.FORWARDREF)
print(different_unions)
Formatted Output:
{
'attrib': ForwardRef("<class 'str'> | undefined", is_class=True, owner=<class '__main__.DifferentUnions'>),
'other_attrib': str | ForwardRef('undefined', is_class=True, owner=<class '__main__.DifferentUnions'>)
}
One possible solution to this is to add a create_unions
attribute to the _StringifierDict
. If this is True
then the __or__
and __ror__
methods should create types.UnionType
instances instead of calling __make_new
. This is False
for Format.STRING
in order to keep a | b
in the reproduction in that case.
I already have a branch with this approach so I can make a PR.
Doing this will break the current test_nonexistent_attribute
ForwardRef test as some | obj
would evaluate to ForwardRef('some') | ForwardRef('obj')
instead of ForwardRef('some | obj')
but I think this is probably correct and the test should be changed.
CPython versions tested on:
CPython main branch
Operating systems tested on:
No response