Jeppe
Jeppe

Reputation: 2276

Python: Dynamically get type with generic type parameters from string

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

Answers (1)

Jeppe
Jeppe

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

Related Questions