__init_subclass__ 时支持打字和 IDE

Typing and IDE support while __init_subclass__

我的目标是简化测试。我注意到每个 api 测试都使用 TestClient class 和查询包装器。

import pytest

class UserWrapper:
    def get_user(self):
        ...

class EventWrapper:
    def get_event(self):
        ...

class Base:
    @pytest.fixture(autouse=True)
    def setup(self, client):
        self.client = client

    def __init_subclass__(cls, wrapper, **kwargs):
        cls.wrapper = wrapper

class TestUserApi(Base, wrapper=UserWrapper()):
    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_user(resp.json())

class TestEventApi(Base, wrapper=EventWrapper()):
    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_event(resp.json())

问题是我想在某个地方输入 wrapper class 以获得 IDE 支持(比如转到声明和自动完成)。我试过了

class TestEventApi(Base, wrapper: EventWrapper=EventWrapper()):

但它不解析。我试过了:

def __init_subclass__(cls, wrapper: Union[UserWrapper, EventWrapper], **kwargs):

但我的版权投诉:cannot access member get_user of type EventWrapper

如果不为每个测试文件创建额外的 class 我能做什么?

为什么还要麻烦 __init_subclass__

class Base:
    @pytest.fixture(autouse=True)
    def setup(self, client):
        self.client = client

class TestUserApi(Base):
    wrapper = UserWrapper()

    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_user(resp.json())

class TestEventApi(Base):
    wrapper = EventWrapper()

    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_event(resp.json())

虽然如果你真的坚持,你也可以这样做(根据 PEP 484):

from typing import TypeVar, Generic

T = TypeVar('T')

class Base(Generic[T]):
    def setup(self, client):
        self.client = client

    wrapper: T

    def __init_subclass__(cls, wrapper: T, **kwargs):
        cls.wrapper = wrapper

class TestUserApi(Base[UserWrapper], wrapper=UserWrapper()):
    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_user(resp.json())

class TestEventApi(Base[EventWrapper], wrapper=EventWrapper()):
    def test_create(self):
        resp = self.client.post(...)
        assert self.wrapper.get_event(resp.json())

你的工具是否支持这是另一回事;例如,当给出这段代码时,mypy 几乎放弃了类型检查 self.wrapper