我正在尝试将我们在代码库中使用的模式提取为更通用的可重用构造.但是,我似乎无法使用通用类型注释来使用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: …我想在我的 Python 包中的所有地方强制执行类型提示,并配置 CI 以在不是 100% 的情况下使构建失败。
有没有办法让我使用mypy或 Python 中的任何其他包来报告类型提示覆盖率,类似于我如何使用例如coverage.py检查代码覆盖率?
要求严格的 100% 类型提示覆盖率是否也明智?
我写了以下函数:
def _clean_dict(d):
    return {k: v for k, v in d.items() if v is not None}
我想为函数添加类型注释:
def _clean_dict(d: Dict[Any, Any]) -> Dict[Any, Any]:                           
    return {k: v for k, v in d.items() if v is not None}
但是,我想明确定义返回的字典中的值不能为 None。
有没有办法说“Any类型,除了NoneType”或“每个可能的值但是None”?
我正在使用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]
但mypy不喜欢这个,因为它抱怨:
$ mypy urltest.py
"URL" has no attribute "_val"
那么,在我自己的项目中,我如何“附加”(或扩展)实例属性注释,以便URL它可以在我的项目的其余部分中使用?IE
from yarl import URL
URL._val: SplitResult
# ...
(mypy 也不喜欢这样;“不能在对非 self 属性的赋值中声明类型。”)
我尝试在以下位置创建一个新的存根文件stubs/yarl/__init__.pyi:
from urllib.parse import SplitResult
class …我想编写在多个平台上mypy使用和工作的类型化代码asyncio。具体来说,我经常有显式绑定到事件循环的类和方法。我想为事件循环提供类型注释。
asyncio当我检查Linux 上的事件循环类型时,我得到:
>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
这种类型显然与 Unix/Linux 平台相关。
现在,我可以编写使用以下类型显式键入事件循环的代码:
>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
但您会注意到,我必须# 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())
这成功地通过了 mypy 类型检查。我犹豫是否用作AbstractEventLoop我的类型,因为它是一个抽象类型。
是否存在跨平台工作、不需要使用抽象类定义并通过 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
然而,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 …我正在将 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)
结果:
$ mypy
error: Unsupported left operand type for | ("Type[IsAuthenticatedOrReadOnly]")
使用的插件:
$ pip list | grep stubs
django-stubs                    1.2.0
djangorestframework-stubs       1.0.0
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
使用 mypy(0.720 和 0.740)进行检查。
这里可能有什么问题?由于操作'|' mypy 无法识别,我怀疑在 mypy 评估期间未添加元类 BasePermissionMetaclass (包含操作) BasePermission。我认为只需安装 djangorestframework-stubs …
举个简单的例子:
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))
所有类型检查均通过。
现在我们可以说这MyType实际上是一个具有许多属性的 ORM 类,它是协议和字典类型的真实来源。每次将属性添加到类中时,都必须在 Protocol 类主体和 TypedDict 类主体中维护相同的注释,这感觉有点多余。
我想知道是否有一种方法可以集中定义类型注释并告诉 mypy 这些是协议和 dict 类的类型定义。
我试过这个:
class TypeMixin:
    s: str
    i: int
class MyProto(TypeMixin, t.Protocol):
    pass
class MyDict(TypeMixin, t.TypedDict): …注意:由于这个答案不断获得好评 - 虽然仍然有 的用例TypedDict,但我今天会考虑使用 adataclass代替。
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
即我有一个TypedDict带有可选键的并且想要一个 …
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)
以下是错误:
a.py:16: 错误:“MyTable”的“col”类型不兼容(得到“MyEnum”,预期“str”)
如何在不添加“type:ignore”的情况下消除此错误?我还可以将 MyEnum.A 替换为 MyEnum.A.name 以使错误消失。但这看起来并不干净,并且 sqlalchemy 文档中也没有建议。
mypy ×10
python ×8
python-3.x ×4
type-hinting ×3
django ×1
django-stubs ×1
generics ×1
sqlalchemy ×1
types ×1
typeshed ×1
typing ×1