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
typing
but that doesn't includeText
. Installingtyping
from PyPI doesn't solve that. (And there are users that run the package on that version of Python).This make my package dependent on
typing
for 2.7/3.3/3.4 installs, requiring extra downloads and installs.I have my own
Union
types 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
mypy
isMYPYPATH
and that is read by the package's code, and not set by it. AlthoughMYPYPATH
might be set (especially when generatingtypeshed
information, to provide the "other" type info), there is no guarantee that it is.You cannot comment out the
import
statement, but you can put it in a block that never executes:this has the advantage that you don't have to import
os
to get at the environment variable (and/orsys
to 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, usingStreamTypeText
in any of the type definitions, should do:The above will satisfy
mypy
, so it will not throw an error onText
not being defined. It will also work on 3.5.0/1 and obliviates the need for making your package dependent ontyping
You would probably still have to install
typing
if you were to runmypy
in a Python 2.7 environment, but your normal package's users are not affected by that.Note that I added a comment
# MYPY
after theif
of each block. Searching files forfrom typing
is easy, but the block withStreamType
would otherwise not so easily be found, in casemypy
changes its behaviour and your code needs adapting.