I have been adding type information to my package's .py files in order to support running mypy against the package. Among other things allows to generate typeshed information for this, third party, package.
Since my package has to be Python 2.7 compatible, I use comments for the type information:
def __init__(self, s):
# type: (Text) -> None
but in order to run mypy this requires me to import typing:
from typing import Text, IO, BinaryIO, Union
this causes two problems:
This will not work on Python 3.5.0 and 3.5.1 as it has a module
typingbut that doesn't includeText. Installingtypingfrom PyPI doesn't solve that. (And there are users that run the package on that version of Python).This make my package dependent on
typingfor 2.7/3.3/3.4 installs, requiring extra downloads and installs.I have my own
Uniontypes defined:StreamType = Union[BinaryIO, IO[str], StringIO] StreamTextType = Union[Text, StreamType]the code for this would have to be conditionally executed depending on typing being available or not.
For the first problem, since I do not run mypy under Python 3.5.0/1, I can do something like:
import sys
if sys.version_info < (3, 5, 0) and sys.version_info >= (3, 5, 2):
from typing import Text, IO, BinaryIO, Union
but that doesn't solve the second issue.
Commenting out the import, like the type information that is in comments,
# from typing import Text, IO, BinaryIO, Union
will cause mypy to throw an error Name 'Text' is not defined.
The third issue can be solve by using a try-except (ugly, and maybe also inefficient) or e.g. by testing against an environment variable (which could also be used to solve the first problem).
Is there an environment variable set when running mypy, that I can test against, so that the import statement is only executed when running mypy?
Testing against an environment variable would also allow me to put the definition of my own types within that "guarded".
Or some other solution?
The only environment variable associated with
mypyisMYPYPATHand that is read by the package's code, and not set by it. AlthoughMYPYPATHmight be set (especially when generatingtypeshedinformation, to provide the "other" type info), there is no guarantee that it is.You cannot comment out the
importstatement, but you can put it in a block that never executes:this has the advantage that you don't have to import
osto get at the environment variable (and/orsysto get at theversion_info) if you have no other need for that in your specific Python file.Your type definitions should be specified like that as well, and can occur anywhere after all of the used types have been imported or defined:
If the above is in
mytypes.py, any other source file in your package, usingStreamTypeTextin any of the type definitions, should do:The above will satisfy
mypy, so it will not throw an error onTextnot being defined. It will also work on 3.5.0/1 and obliviates the need for making your package dependent ontypingYou would probably still have to install
typingif you were to runmypyin a Python 2.7 environment, but your normal package's users are not affected by that.Note that I added a comment
# MYPYafter theifof each block. Searching files forfrom typingis easy, but the block withStreamTypewould otherwise not so easily be found, in casemypychanges its behaviour and your code needs adapting.