For use with pydantic, I want to create recursive type aliases at runtime. "Normal" type aliases are possible like this:
from typing import TypeAliasType
alias = TypeAliasType("alias", str)
foo: alias = "bar"
But now I want to create a recursive type alias like this one:
from collections.abc import Sequence
type recursive = int | Sequence[recursive]
This includes a forward reference, which I found impossible to emulate at runtime. There is ForwardRef, but besides being discouraged it did not work for me:
from typing import ForwardRef, TypeAliasType
from collections.abc import Sequence
# This is what I want to emulate at runtime
type recursive = int | Sequence[recursive]
print(recursive.__value__) # int | collections.abc.Sequence[recursive]
# This is my (failing) attempt to emulate it at runtime
dynamic_list_of_types = float | int
ref = ForwardRef("recursive")
recursive = TypeAliasType("recursive", dynamic_list_of_types | Sequence[ref])
print(recursive.__value__) # float | int | collections.abc.Sequence[ForwardRef('recursive')]
How can I declare such a recursive type alias during runtime?
I am aware of how to do it statically as in this question. Because the list of allowed types (the dynamic_list_of_types in my example above) is not fixed, but can be expanded dynamically, this is not possible here.
More context: I have a pydantic model inside some package that offers support for plugins. This model has some fields like mylist: Sequence[MyTypeAlias], where MyTypeAlias describes a union of allowed types. The plugins are now supposed to expand this list of allowed types with their own models. The solution I am aiming for is to collect this list and replace all occurences of MyTypeAlias with the updated union. This works well, except for the recursive types mentioned here. Other options to manually mark all such occurences (which are many) would decrease readability in the models of the main package, so I chose this approach.
type recursive = Union[int | Iterable['recursive']]- also, that's not really a type alias but just a type, but I don't think that matters for the answer. If you really need it to be an alias, than analogousrecursive: TypeAlias = Union[int | Iterable['recursive']]>>> print(recursive.__value__)already printsint | collections.abc.Sequence[recursive]in a Python 3.13 REPL, indicating thattype recursive = int | Sequence[recursive]already works at runtime for defining recursive type aliases. Are you trying to ask instead: "How do I create recursive type aliases without the PEP 695typestatement?"dynamic_list_of_types. Maybe this helps:type recursive = produce_types() | Sequence[recursive]does work if you defineproduce_typesasdef produce_types(): return int | str. Would this be dynamic enough for your purposes?