Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting around "typing.Union is not a generic class"

In Python's typing module, it seems that anything that is not a generic type does not support subscripting:

>>> import typing
>>> from yarl import URL

>>> StrOrURL = typing.Union[URL, str]
>>> typing.List[StrOrURL]                # OK; List is generic
typing.List[typing.Union[yarl.URL, str]]

>>> SetOrDict = typing.Union[set, dict]
>>> SetOrDict[StrOrURL]                  # Raises
TypeError: typing.Union[set, dict] is not a generic class

This will be the case whether SetOrDict is defined with typing.Union or typing.TypeVar. (In Python 3.7, at least.)

It looks like there is a way to subclass Generic, presumably like:

class SetOrDict(typing.Generic[StrOrURL]):
    # ...

But this will immediately raise TypeError: Parameters to Generic[...] must all be type variables.

Is there a way to accommodate the above? I.e., what is the recommended practice for subscripting user-defined (non-generic) typedefs?

like image 444
Brad Solomon Avatar asked Oct 17 '22 08:10

Brad Solomon


1 Answers

You can't use a Union[...], alias or otherwise, as a generic type, no. Your union contents are also not generic, you can't state what types a dict or set object can contain by using dict or set directly, you'd use Set or Dict.

You have a new union:

URLorStrSetOrDict = typing.Union[Set[StrOrUrl], Dict[StrOrUrl, Any]]

Note that a dictionary has keys and values, you need to provide information on both. If this used as the input for an API, then consider using the more generic and immutable AbstractSet and Mapping types; this makes it clear that your API only needs to read information.

Personally, I'd look hard at refactoring a codebase that is this muddy about what kinds of objects it can accept. Requiring that an API accepts only sets and existing code has to pass in set(dictionary) instead of dictionary is not an arduous requirement, or perhaps the API really would work with any iterable of StrOrUrl.

like image 115
Martijn Pieters Avatar answered Oct 23 '22 09:10

Martijn Pieters