Reputation: 1455
mypy complains error: Variable "packagename.Foo" is not valid as a type
Foo = type('Foo', (), {})
Bar = Optional[Foo]
This error can be fixed by defining the type as a class:
class Foo:
pass
Bar = Optional[Foo]
Is there any other way around this? I need to keep the type definition dynamic.
Upvotes: 37
Views: 14621
Reputation: 9120
Here is a related mypy issue 8897. In my case given this example:
Bla = type("Bla", (), {}) # type: ignore[valid-type, misc]
class Foo(Bla):
pass
I could convince mypy to accept Bla
by explicitly typing the LHS of the assignment:
Bla: type = type("Bla", (), {})
Tested only with mypy 1.3.0 (compiled: yes)
.
Upvotes: 1
Reputation: 7499
How about this, as a workaround?
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
class Foo: pass
else:
Foo = type('Foo', (), {})
Bar = Optional[Foo]
typing.TYPE_CHECKING
is a constant that will always be True
at compile-time, and will always be False
at runtime. In this way, we can keep MyPy happy by only telling it about the static definition, but at runtime we can be as dynamic as we like.
You should be aware, though, that this is very much a workaround rather than a solution. By doing it this way, we are essentially lying to the type-checker about the true definition of Foo
. This means that MyPy may fail to spot errors in some places, and may raise errors where none exist in other places. Dynamically constructing types at runtime is very useful in some situations, but goes against some fundamental principles of type-checking in Python, so you'll have trouble getting a type-checker to approve what you're doing without some kind of a hack.
Upvotes: 9