标签: mypy

获取mypy以接受泛型类型的子类型作为方法参数

我正在尝试将我们在代码库中使用的模式提取为更通用的可重用构造.但是,我似乎无法使用通用类型注释来使用mypy.

这是我得到的:

from abc import (
    ABC,
    abstractmethod
)
import asyncio
import contextlib
from typing import (
    Any,
    Iterator,
    Generic,
    TypeVar
)

_TMsg = TypeVar('_TMsg')

class MsgQueueExposer(ABC, Generic[_TMsg]):

    @abstractmethod
    def subscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
        raise NotImplementedError("Must be implemented by subclasses")

    @abstractmethod
    def unsubscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
        raise NotImplementedError("Must be implemented by subclasses")


class MsgQueueSubscriber(Generic[_TMsg]):

    @contextlib.contextmanager
    def subscribe(
            self,
            msg_queue_exposer: MsgQueueExposer[_TMsg]) -> Iterator[None]:
        msg_queue_exposer.subscribe(self)
        try:
            yield
        finally:
            msg_queue_exposer.unsubscribe(self)


class DemoMsgQueSubscriber(MsgQueueSubscriber[int]):
    pass

class DemoMsgQueueExposer(MsgQueueExposer[int]):

    # The following works for mypy: …
Run Code Online (Sandbox Code Playgroud)

python generics mypy

11
推荐指数
1
解决办法
357
查看次数

检查 Python 中的类型提示覆盖率

我想在我的 Python 包中的所有地方强制执行类型提示,并配置 CI 以在不是 100% 的情况下使构建失败。

有没有办法让我使用mypy或 Python 中的任何其他包来报告类型提示覆盖率,类似于我如何使用例如coverage.py检查代码覆盖率?

要求严格的 100% 类型提示覆盖率是否也明智?

python-3.x mypy

11
推荐指数
1
解决办法
2879
查看次数

在 Python 类型注释中排除类型

我写了以下函数:

def _clean_dict(d):
    return {k: v for k, v in d.items() if v is not None}
Run Code Online (Sandbox Code Playgroud)

我想为函数添加类型注释:

def _clean_dict(d: Dict[Any, Any]) -> Dict[Any, Any]:                           
    return {k: v for k, v in d.items() if v is not None}
Run Code Online (Sandbox Code Playgroud)

但是,我想明确定义返回的字典中的值不能为 None。

有没有办法说“Any类型,除了NoneType”或“每个可能的值但是None”?

python type-hinting python-3.x mypy python-typing

11
推荐指数
2
解决办法
1683
查看次数

扩展第三方库/模块的存根文件

我正在使用yarl图书馆的URL对象。

它有一个准私有属性 ,._val它是一个urllib.parse.SplitResult对象,但在 中没有类型注释yarl/__init__.pyi。(如果开发人员不想正式将其纳入公共 API,这是可以理解的。)

但是,我选择使用URL._val,风险自负。一个虚拟示例:

# urltest.py
from urllib.parse import SplitResult
from typing import Tuple

from yarl import URL


def foo(u: URL) -> Tuple[str, str, str]:
    sr: SplitResult = u._val
    return sr[:3]
Run Code Online (Sandbox Code Playgroud)

mypy不喜欢这个,因为它抱怨:

$ mypy urltest.py
"URL" has no attribute "_val"
Run Code Online (Sandbox Code Playgroud)

那么,在我自己的项目中,我如何“附加”(或扩展)实例属性注释,以便URL它可以在我的项目的其余部分中使用?IE

from yarl import URL

URL._val: SplitResult
# ...
Run Code Online (Sandbox Code Playgroud)

(mypy 也不喜欢这样;“不能在对非 self 属性的赋值中声明类型。”)


更新

我尝试在以下位置创建一个新的存根文件stubs/yarl/__init__.pyi

from urllib.parse import SplitResult

class …
Run Code Online (Sandbox Code Playgroud)

python python-3.x mypy

11
推荐指数
1
解决办法
5722
查看次数

asyncio 事件循环的平台无关的 mypy 类型注释是什么?

我想编写在多个平台上mypy使用和工作的类型化代码asyncio。具体来说,我经常有显式绑定到事件循环的类和方法。我想为事件循环提供类型注释。

asyncio当我检查Linux 上的事件循环类型时,我得到:

>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
Run Code Online (Sandbox Code Playgroud)

这种类型显然与 Unix/Linux 平台相关。

现在,我可以编写使用以下类型显式键入事件循环的代码:

>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
Run Code Online (Sandbox Code Playgroud)

但您会注意到,我必须# type: ignore在导入中包含一个标签_UnixSelectorEventLoop,因为asyncio.unix_events没有类型存根。我还犹豫是否要导入一个私有方法,如类名开头的下划线所示。

作为替代方案,我可以使用AbstractEventLoop以下类型:

import asyncio
from asyncio.unix_events import _UnixSelectorEventLoop  # type: ignore
def func(loop: _UnixSelectorEventLoop) -> None:
    print(loop)
func(asyncio.get_event_loop())
Run Code Online (Sandbox Code Playgroud)

这成功地通过了 mypy 类型检查。我犹豫是否用作AbstractEventLoop我的类型,因为它是一个抽象类型。

是否存在跨平台工作、不需要使用抽象类定义并通过 mypy 类型检查的替代类型签名?

python type-hinting python-asyncio mypy

11
推荐指数
1
解决办法
2346
查看次数

Mypy 子类中更具体的参数

我想声明一个带有抽象方法的基类,该方法具有类型化参数,以便实现类可以为该参数指定更具体的类型,例如:

from abc import ABC, abstractmethod

class Job(ABC):
    pass

class EasyJob(Job):
    pass

class HardJob(Job):
    pass

class Worker(ABC):
    @abstractmethod
    def run(self, job: Job) -> None:
        raise NotImplementedError()

class EasyWorker(Worker):
    def run(self, job: EasyJob) -> None:
        pass

class HardWorker(Worker):
    def run(self, job: HardJob) -> None:
        pass
Run Code Online (Sandbox Code Playgroud)

然而,mypy 对此抱怨是可以理解的:

line 14: error: Argument 1 of "run" is incompatible with supertype "Worker"; supertype defines the argument type as "Job"
line 18: error: Argument 1 of "run" is incompatible with supertype "Worker"; supertype defines the …
Run Code Online (Sandbox Code Playgroud)

python type-hinting mypy python-typing

11
推荐指数
1
解决办法
763
查看次数

mypy django Rest Framework - 使用多个权限类时不支持左操作数类型

我正在将 mypy 集成到现有的代码库上(使用 django、drf 框架)。

view.py 中的示例代码:

from rest_framework.permissions import IsAdminUser, IsAuthenticatedOrReadOnly

@api_view()
@permission_classes([IsAuthenticatedOrReadOnly | IsAdminUser])
def listAbc(request):
    queryset = ...
    serializer = ...
    return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

结果:

$ mypy
error: Unsupported left operand type for | ("Type[IsAuthenticatedOrReadOnly]")
Run Code Online (Sandbox Code Playgroud)

使用的插件:

$ pip list | grep stubs
django-stubs                    1.2.0
djangorestframework-stubs       1.0.0
Run Code Online (Sandbox Code Playgroud)

mypy 配置文件(mypy.ini):

[mypy]

plugins =
    mypy_django_plugin.main, mypy_drf_plugin.main

;ignore_missing_imports = True
files=**/*.py

[mypy-*.migrations.*]
ignore_errors = True

[mypy.plugins.django-stubs]
django_settings_module = project.settings
Run Code Online (Sandbox Code Playgroud)

使用 mypy(0.720 和 0.740)进行检查。

这里可能有什么问题?由于操作'|' mypy 无法识别,我怀疑在 mypy 评估期间未添加元类 BasePermissionMetaclass (包含操作) BasePermission。我认为只需安装 djangorestframework-stubs …

python django mypy typeshed django-stubs

11
推荐指数
1
解决办法
963
查看次数

Python:在 Protocol 和 TypedDict 之间共享类型注释

举个简单的例子:

from __future__ import annotations
import typing as t


class MyType:
    def __init__(self, s: str, i: int) -> None:
        self.s = s
        self.i = i


class MyProto(t.Protocol):
    s: str
    i: int


class MyDict(t.TypedDict):
    s: str
    i: int


def my_serializer(inst: MyProto) -> MyDict:
    return {"s": inst.s, "i": inst.i}


d = my_serializer(MyType("a", 1))
Run Code Online (Sandbox Code Playgroud)

所有类型检查均通过。

现在我们可以说这MyType实际上是一个具有许多属性的 ORM 类,它是协议和字典类型的真实来源。每次将属性添加到类中时,都必须在 Protocol 类主体和 TypedDict 类主体中维护相同的注释,这感觉有点多余。

我想知道是否有一种方法可以集中定义类型注释并告诉 mypy 这些是协议和 dict 类的类型定义。

我试过这个:

class TypeMixin:
    s: str
    i: int


class MyProto(TypeMixin, t.Protocol):
    pass


class MyDict(TypeMixin, t.TypedDict): …
Run Code Online (Sandbox Code Playgroud)

python typing mypy

11
推荐指数
0
解决办法
1665
查看次数

将 dict 转换为 TypedDict 的好方法吗?

注意:由于这个答案不断获得好评 - 虽然仍然有 的用例TypedDict,但我今天会考虑使用 adataclass代替。


我想要一种很好的(`mypy --strict` 和 pythonic)方法将非类型化的 `dict` (来自 `json.loads()`)转换为 `TypedDict`。我当前的方法如下所示:
class BackupData(TypedDict, total=False):
    archive_name: str
    archive_size: int
    transfer_size: int
    transfer_time: float
    error: str


def to_backup_data(data: Mapping[str, Any]) -> BackupData:
    result = BackupData()
    if 'archive_name' in data:
        result['archive_name'] = str(data['archive_name'])
    if 'archive_size' in data:
        result['archive_size'] = int(data['archive_size'])
    if 'transfer_size' in data:
        result['transfer_size'] = int(data['transfer_size'])
    if 'transfer_time' in data:
        result['transfer_time'] = int(data['transfer_time'])
    if 'error' in data:
        result['error'] = str(data['error'])
    return result
Run Code Online (Sandbox Code Playgroud)

即我有一个TypedDict带有可选键的并且想要一个 …

types python-3.x mypy

11
推荐指数
1
解决办法
6039
查看次数

如何使用 sqlalchemy 枚举解决 mypy 错误?

mypy 报告以下代码中的错误:

import enum
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Enum

Base = declarative_base()

class MyEnum(enum.Enum):
    A = 1
    B = 2

class MyTable(Base):
    __tablename__ = 'my_table'

    col = Column(Enum(MyEnum), nullable=False)

c = MyTable(col=MyEnum.A)
Run Code Online (Sandbox Code Playgroud)

以下是错误:

a.py:16: 错误:“MyTable”的“col”类型不兼容(得到“MyEnum”,预期“str”)

如何在不添加“type:ignore”的情况下消除此错误?我还可以将 MyEnum.A 替换为 MyEnum.A.name 以使错误消失。但这看起来并不干净,并且 sqlalchemy 文档中也没有建议。

python sqlalchemy mypy

11
推荐指数
2
解决办法
5750
查看次数