添加类型信息而不依赖于键入模块

时间:2017-04-20 10:21:49

标签: python typing mypy typeshed

我一直在向我的软件包的.py文件添加类型信息,以支持针对软件包运行mypy。除此之外,还可以为此第三方软件包生成typeshed信息。

由于我的包必须与Python 2.7兼容,我使用注释来获取类型信息:

def __init__(self, s):
    # type: (Text) -> None

但是为了运行mypy,这需要我导入输入:

from typing import Text, IO, BinaryIO, Union

这会导致两个问题:

  1. 这不适用于Python 3.5.0和3.5.1,因为它有一个模块typing但不包含Text。从PyPI安装typing并没有解决这个问题。 (并且有些用户在该版本的Python上运行该软件包。)

  2. 这使得我的软件包依赖typing进行2.7 / 3.3 / 3.4安装,需要额外的下载和安装。

  3. 我定义了自己的Union类型:

    StreamType = Union[BinaryIO, IO[str], StringIO]
    StreamTextType = Union[Text, StreamType]
    

    根据可用或不可用的类型,必须有条件地执行此代码。

  4. 对于第一个问题,由于我没有在Python 3.5.0 / 1下运行mypy,我可以做类似的事情:

    import sys
    if sys.version_info < (3, 5, 0) and sys.version_info >= (3, 5, 2):
        from typing import Text, IO, BinaryIO, Union
    

    但这并不能解决第二个问题。

    评论import,与评论中的类型信息一样,

    # from typing import Text, IO, BinaryIO, Union
    

    会导致mypy抛出错误Name 'Text' is not defined

    第三个问题可以通过使用try - except(丑陋,也可能效率低下)或通过测试环境变量(也可用于解决第一个问题)。

    运行mypy时是否设置了环境变量,我可以对其进行测试,以便只在运行mypy时执行import语句? 针对环境变量进行测试还可以让我将自己类型的定义放在#34; guarded&#34;。

    中。

    或其他一些解决方案?

1 个答案:

答案 0 :(得分:5)

mypy关联的唯一环境变量是MYPYPATH,它由包的代码读取,而不是由它设置。虽然可能会设置MYPYPATH(特别是在生成typeshed信息时,要提供&#34;其他&#34;类型信息),但不能保证它是。

您无法注释掉import语句,但可以将其放在一个永不执行的块中:

if False:  # MYPY
    from typing import Text, IO, BinaryIO, Union

这样做的好处是,您不必导入os来获取环境变量(和/或sys以获取version_info)在您的特定Python文件中没有其他需要。

您的类型定义也应该像这样指定,并且可以在导入或定义所有使用的类型后的任何地方出现:

# import or define StringIO

if False:  # MYPY
    StreamType = Union[BinaryIO, IO[str], StringIO]
    StreamTextType = Union[Text, StreamType]

如果以上内容位于mytypes.py中,则您的包中的任何其他源文件(在任何类型定义中使用StreamTypeText)都应执行以下操作:

if False:  # MYPY
    from typing import Text, IO, BinaryIO, Union
    from .mytypes StreamType

上述内容将满足mypy,因此不会在Text未定义时抛出错误。它也适用于3.5.0 / 1,并且无需使您的包依赖于typing

如果您要在Python 2.7环境中运行typing,您可能仍需要安装mypy,但普通软件包的用户不会受此影响。

请注意,我在每个块的# MYPY之后添加了评论if。搜索from typing的文件很简单,但如果StreamType更改其行为并且您的代码需要进行调整,那么mypy的块就不会那么容易找到。