Порядок полей множественного наследования Pydantic – деталь реализации или стабильная функция?Python

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

Сообщение Anonymous »

У меня есть несколько моделей, которые очень похожи. Поля идентификатора разные. В противном случае другие группы полей встречаются по предопределенным шаблонам. Например, в приведенном ниже примере поля Present0 и Present1 будут отображаться в некоторых моделях, но не в других.
В конечном итоге модели используются для преобразования Polars dataframes в данные json для использования Tabulator — библиотекой форматирования таблиц HTML/JS, поэтому порядок определенно имеет значение, и модели — хорошее место для хранения этой информации. Я даже встроил директивы форматирования для Tabulator с помощью Annotated.
Поэтому я хочу определить более мелкие подмодели с тем, что специфично для каждой модели, а также определение повторяющихся групп полей. Затем соберите их с помощью множественного наследования.
На их форумах был вопрос, посвященный построению моделей с помощью множественного наследования, и хотя отвечавший не решался одобрить этот подход, он все же сказал, что при условии, что функциональность была стабильной частью поведения Pydantic.
А как насчет упорядочения полей, которое, похоже, происходит в обратном порядке заказать?

Примеры данных:

Project shape: (2, 7)
┌─────────┬───────┬──────────┬──────────┬───────────┬─────────────┬─────────────┐
│ project ┆ descr ┆ present0 ┆ present1 ┆ usercount ┆ lastupdater ┆ lastupddttm │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 ┆ i64 ┆ i64 ┆ str ┆ str │
╞═════════╪═══════╪══════════╪══════════╪═══════════╪═════════════╪═════════════╡
│ project ┆ d ┆ 0 ┆ 1 ┆ 77 ┆ mcuban ┆ 2009 │
│ project ┆ d ┆ 0 ┆ 1 ┆ 77 ┆ mcuban ┆ 2009 │
└─────────┴───────┴──────────┴──────────┴───────────┴─────────────┴─────────────┘

Customer shape: (2, 7)
┌──────────┬───────┬──────────┬──────────┬───────────┬─────────────┬─────────────┐
│ customer ┆ descr ┆ present0 ┆ present1 ┆ usercount ┆ lastupdater ┆ lastupddttm │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 ┆ i64 ┆ i64 ┆ str ┆ str │
╞══════════╪═══════╪══════════╪══════════╪═══════════╪═════════════╪═════════════╡
│ proj ┆ d ┆ 0 ┆ 1 ┆ 77 ┆ jsmith ┆ 1999 │
│ proj ┆ d ┆ 0 ┆ 1 ┆ 77 ┆ jsmith ┆ 1999 │
└──────────┴───────┴──────────┴──────────┴───────────┴─────────────┴─────────────┘

Тестовый код — T2project_rev_order_columns дает правильный порядок

import sys
from rich import inspect as rin
import pydantic as pyd
import polars as pl

verbose = "-v" in sys.argv

class Project(pyd.BaseModel):
"""my reference field order"""
project : str = "project"
descr : str = "d"
present0 : int = 0
present1 : int = 1
usercount : int = 77
lastupdater : str = "mcuban"
lastupddttm : str = "2009"

class Customer(pyd.BaseModel):
customer : str = "proj"
descr : str = "d"
present0 : int = 0
present1 : int = 1
usercount : int = 77
lastupdater : str = "jsmith"
lastupddttm : str = "1999"

# assemble by components
class KProject(pyd.BaseModel):
project : str = "project"
descr : str = "d"

class Pres(pyd.BaseModel):
present0 : int = 0
present1 : int = 1

class Tag(pyd.BaseModel):
usercount : int = 77

class Upd(pyd.BaseModel):
lastupdater : str = "jsmith"
lastupddttm : str = "1999"

class T1project_order_columns(KProject, Pres, Tag, Upd):
pass

class T2project_rev_order_columns(Upd, Tag, Pres, KProject):
"""ordering works, but is that guaranteed by Pydantic?"""

def test():
def build_df(cls_):
df = pl.from_dicts([cls_().model_dump() for i in range(0,2)])
if verbose:
print("\n\n", cls_.__name__, df)
return df.columns

dataexp = [
Project,
Customer,
T1project_order_columns,
T2project_rev_order_columns,
]

for cls_ in dataexp:
got = build_df(cls_)
if cls_ is Project:
exp = got
classname = f"{cls_.__name__:30.30}"

if not classname.startswith("T"):
continue

if exp == got:
print(f"✅ {classname}\n")
else:
msg2 = f"❌ {classname}"
print(f"{msg2} exp:{','.join(exp)}\n{' ' * (len(msg2)+2)}got:{','.join(got)}\n")

test()

выход:

❌ T1project_order_columns exp:project,descr,present0,present1,usercount,lastupdater,lastupddttm
got:lastupdater,lastupddttm,usercount,present0,present1,project,descr

✅ T2project_rev_order_columns

Вопрос: это гарантия заказа или деталь реализации?

p.s. только для информации — встраивание дополнительных директив метаданных в модель

Вы не можете использовать модели pydantic в Annotated, это приведет к какой-то странной ошибке pydantic. Неpydantic типы данных, такие как классы данных, работают. Annotated — это кортеж, вам придется просмотреть его составляющие и направить конфигурацию к интересующим компонентам.
@dataclass
class TabulatorSettings:
"use on Tab Models as Annotated dont use a pydantic model in Annotated metadata"
urlField: str = ""
title: str = ""
formatter: str = ""

class CompareGeneral_TabData(pyd.BaseModel):
label: str
value: Annotated[Any, TabulatorSettings(title="Left", formatter="html", width=100)]
value_oth: Annotated[Any, TabulatorSettings(title="Right", formatter="html", width=100)]



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

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

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

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

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

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

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