Как обеспечить типобезопасность модели Pydantic Generic с данными подклассов и избежать ошибок mypy?Python

Программы на Python
Ответить
Anonymous
 Как обеспечить типобезопасность модели Pydantic Generic с данными подклассов и избежать ошибок mypy?

Сообщение Anonymous »

У меня есть следующий абстрактный класс данных и несколько конкретных подклассов:

Код: Выделить всё

import abc
from typing import TypeVar, Generic, Union

from pydantic import BaseModel

T = TypeVar('T')

class Data(BaseModel, abc.ABC, Generic[T]):
def handle(self, data: T) -> None:
raise NotImplementedError()

class StringData(Data[str]):
name: str = "string"

def handle(self, data: str) -> None:
print("String data:", data)

class IntData(Data[int]):
name: str = "int"

def handle(self, data: int) -> None:
print("Int data:", data)
Теперь мне нужен класс DataManager, который может содержать любой подкласс Data и вызовы дескриптора делегата.
Обратите внимание, что я должен использовать Union вместо абстрактного класса, чтобы model_dump_json действительно давал правильный результат. Это не идеально, но, похоже, другого выхода нет.

Код: Выделить всё

U = TypeVar('U')

class DataManager(BaseModel, Generic[U]):
my_data: Union[StringData, IntData] # Good
my_data: Data # NOT GOOD!
Итак, предположим, что после этого шага у нас есть:

Код: Выделить всё

class DataManager(BaseModel, Generic[U]):
my_data: Union[StringData, IntData]

def handle(self, data: U) -> None:
self.my_data.handle(data)

class StringDataManager(DataManager[str]):
pass

StringDataManager(my_data=StringData()).handle(data="some-string")
Это кажется верным, поскольку каждый подкласс DataManager соответствует типу своих данных. Таким образом, при вызове дескриптора все работает во время выполнения — например, использование в качестве менеджера строк установит «U» в строку, которая будет идеально передавать «строку» в функцию дескриптора StringData. Однако mypy здесь терпит неудачу, потому что он думает, что мы передаем U, хотя на самом деле мы передаем правильный тип.

Аргумент 1 для «дескриптора» «StringData» имеет несовместимый тип «U»; ожидается "str" ​​[arg-type]


Аргумент 1 для "дескриптора" "IntData" имеет несовместимый тип "U"; ожидается "int" [тип-аргумента]


Подробнее здесь: https://stackoverflow.com/questions/798 ... avoid-mypy
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»