Reputation: 2276
Given a type string with generic type parameters, how do I get the type?
E.g. The following works for Optional
, but not Optional[str]
.
import sys
from typing import Optional
this = sys.modules[__name__]
print(getattr(this, "Optional")) # typing.Optional
print(getattr(this, "Optional[str]")) # AttributeError: module '__main__' has no attribute 'Optional[str]'
In practice, this
will be another module and the type-string will be a variable only known at runtime.
Edit:
It seems that eval("Optional[str]")
returns typing.Union[str, NoneType]
. I thought this was good enough (since Optional[str] == Union[str, None] = True
), but it only works if Optional[str]
is imported in the module executing this code (which fails for types used in other modules).
Edit2: Solved by passing globals of module to eval
: eval(type_string, vars(module))
Upvotes: 2
Views: 893
Reputation: 2276
In lack of responses, I'm going to answer this myself and ask for comments.
The solution I ended up using was this:
eval("Optional[str]", vars(MODULE))
The eval function takes a source-string and optionally a dictionary of globals. The globals are important if the source string is extracted from a different module. Without it, it would only work for types imported in the module executing eval(..)
.
A full example could be this:
# other.py
from typing import Optional
a: Optional[str] = None
...
# eval_type.py
import other
print(eval("Optional[str]", vars(other)))
And if the module was dynamically loaded:
import importlib
other = importlib.import_module('other')
print(eval("Optional[str]", vars(other)))
I use this exact method for extracting types from Python-docstrings, and evaluating if they match the function-signature. The project is called pydoctest and the above solution is used here: https://github.com/jepperaskdk/pydoctest/blob/main/pydoctest/utilities.py#L48
I'm not sure how many other use-cases there really are.
Upvotes: 1