Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mypy "is not valid as a type" for types constructed with `type()`

Tags:

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.

like image 236
user3534080 Avatar asked Oct 28 '19 16:10

user3534080


People also ask

How do I ignore MYPY errors?

You can use a special comment # type: ignore[code, ...] to only ignore errors with a specific error code (or codes) on a particular line. This can be used even if you have not configured mypy to show error codes. Currently it's only possible to disable arbitrary error codes on individual lines using this comment.

What is MYPY used for?

“Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or 'duck') typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking.” A little background on the Mypy project.

Does MYPY run code?

Installing and running mypy This command makes mypy type check your program.py file and print out any errors it finds. Mypy will type check your code statically: this means that it will check for errors without ever running your code, just like a linter.


1 Answers

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.

like image 125
Alex Waygood Avatar answered Sep 20 '22 15:09

Alex Waygood