Определение сигнатур базового класса для подклассов Pydantic BaseModelPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Определение сигнатур базового класса для подклассов Pydantic BaseModel

Сообщение Anonymous »

TL;DR: Есть ли способ:
  • иметь собственный инициализатор в подподклассе pydantic .BaseModel,
  • которая показывает полную и завершенную подпись в Pylance,
  • без копирования всех вручную имена полей в каждом конструкторе подкласса?
Упрощенно
Предположим, у меня есть такая настройка:
from pydantic import BaseModel

class NumberWithMetadata(BaseModel):
value: float | int
source: str

class FloatWM(NumberWithMetadata):
value: float

Пока хорошо. В VS Code, когда я набираю FloatWM(, Pylance через IntelliSense показывает мне полную и правильную подпись, ограниченную только плавающими числами:

(*, value: float, source: str) -> FloatWM
Однако я хочу, чтобы мой подкласс выполнял пользовательскую логику во время инициализации, поэтому мне нужен инициализатор. Я не хочу, чтобы дочерний класс знал подробности полей базового класса, поэтому я **kwargs:
class FloatWM(NumberWithMetadata):
value: float

def __init__(self, value: float, **kwargs):
super().__init__(value = value * 1.618, **kwargs)

Во время выполнения это работает по желанию… но теперь, когда я набираю FloatWM( Pylance показывает только:

(*, value: float, **kwargs: Unknown) -> FloatWM
Есть ли синтаксис или шаблон, который я могу использовать, чтобы получить чистый IntelliSense в VS Code для подкласса?
Реальная установка< /h3>
Чтобы избежать проблемы XY с моим упрощенным кодом, приведенным выше:
Основной вариант использования — иметь много разных полей во многих разных классах, некоторые из которых оберните пинту.Количество. В каждом поле указывается требуемая размерность и базовая единица измерения для этого поля. Размерность применяется при создании значения для поля, а единицы измерения по умолчанию применяются, если они не указаны.
class ValueWithAttribution(BaseModel):
value: Any
source: str
# more fields here

class NumberWithAttribution(ValueWithAttribution):
value: float | int

type QuantityOrLiteral = float | int | str | PydanticPintQuantity

class QuantityWithAttribution(ValueWithAttribution):
value: Quantity

def __init__(self, value: QuantityOrLiteral, **kwargs):
units = self.__class__.__annotations__.get("value").__metadata__[0].units
if isinstance(value, (float, int)):
super().__init__(value=Quantity(value, units), **kwargs)
else:
if isinstance(value, str):
value = Quantity(value)
if value.units.is_compatible_with(units):
super().__init__(value=value, **kwargs)
else:
# raise hell

class Length(QuantityWithAttribution):
value: Annotated[Quantity, PydanticPintQuantity("meters")]

class Weight(QuantityWithAttribution):
value: Annotated[Quantity, PydanticPintQuantity("kg")]

class Person(MyBase):
height: Length
weight: Weight

me = Person(
height = Length('70 inches', source='I said so'),
weight = Weight(84, source='my treacherous scale')
)


Выходит за рамки этого вопроса, но связанная тема: хочу ли я, чтобы Pylance принимал позиционный аргумент при построении длины() и веса (), я считаю, что мне также придется добавить это к каждому такому конечному классу (несмотря на то, что их родительский класс уже имеет эту подпись):
class Length(QuantityWithAttribution):
value: Annotated[Quantity, PydanticPintQuantity("meters")]

# This is not functionally needed, by is required for
# Pylance to accept that there's a positional argument :'(
def __init__(self, value: QuantityOrLiteral, **kwargs):
super().__init__(value=value, **kwargs)


Подробнее здесь: https://stackoverflow.com/questions/792 ... -basemodel
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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