mypy supports recursive types and will be enabled by default since v0.990. E.g.:
JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None]
Recursive types need to use
ForwardRefs at the right-hand side to reference the type alias before assignment. The ref
ForwardRef('JSON') is not generic parameterized.
I’m trying to annotate an arbitrarily nested container with a specific element type or parameterized by a typevar. For example:
T = TypeVar('T') PyTree = Union[ T, Tuple['PyTree[T]', ...], # Tuple, NamedTuple List['PyTree[T]'], Dict[Any, 'PyTree[T]'], # Dict, OrderedDict, DefaultDict ]
since the typevar
T is inside a string
'PyTree[T]', which will be converted to a
ForwardRef. However, it will be never evaluated because it is not assigned to a variable (
PyTree[T] is not a valid identifier either). So I get:
>>> TreeOfInts = PyTree[int] >>> TreeOfInts typing.Union[int, typing.Tuple[ForwardRef('PyTree[T]'), ...], typing.List[ForwardRef('PyTree[T]')], typing.Dict[typing.Any, ForwardRef('PyTree[T]')]]
Union only substitutes the first
int which not in
ForwardRefs, while the remaining
ForwardRefs are remained as
As an alternative, I can specify the
int type as:
>>> TreeOfInts = Union[int, Tuple['TreeOfInts', ...], List['TreeOfInts'], Dict[Any, 'TreeOfInts']] >>> TreeOfInts typing.Union[int, typing.Tuple[ForwardRef('TreeOfInts'), ...], typing.List[ForwardRef('TreeOfInts')], typing.Dict[typing.Any, ForwardRef('TreeOfInts')]]
But this approach is not considered because it is impossible to cover all element types for function annotations. E.g:
def tree_leaves( tree: PyTree[T], is_leaf: Optional[Callable[[T], bool]] = None, *, none_is_leaf: bool = False, ) -> List[T]: ...
Is it possible to make
ForwardRef generic? Or is there any other way to define a generic recursive type (for function annotations)?