2025-10-17 00:26:10 +03:00
2025-10-16 22:19:42 +03:00
2025-10-17 00:26:10 +03:00
2025-07-14 17:04:31 +03:00
2025-07-11 22:23:21 +03:00
2025-10-16 22:19:42 +03:00
2025-08-29 01:29:04 +03:00

megasniff

Автоматическая валидация данных по схеме, сборка и разборка объекта в одном флаконе

Как применять:

# 1. Объявляем схемы
from __future__ import annotations
import dataclasses
import typing


@dataclasses.dataclass
class SomeSchema1:
    a: int
    b: float | str
    c: SomeSchema2 | str | None


@dataclasses.dataclass
class SomeSchema2:
    field1: dict
    field2: float
    field3: typing.Optional[SomeSchema1]


# 2. Генерируем метод для валидации и сборки
import megasniff

infl = megasniff.SchemaInflatorGenerator()
defl = megasniff.SchemaDeflatorGenerator()
fn_in = infl.schema_to_inflator(SomeSchema1)
fn_out = defl.schema_to_deflator(SomeSchema1)

# 3. Проверяем что всё работает

data = fn_in({'a': 1, 'b': 2, 'c': {'field1': {}, 'field2': '1.1', 'field3': None}})
# SomeSchema1(a=1, b=2.0, c={'field1': {}, 'field2': 1.1, 'field3': None})
fn_out(data)
# {'a': 1, 'b': 2.0, 'c': {'field1': {}, 'field2': 1.1, 'field3': None}}

Особенности работы:

  • поддерживает циклические зависимости
  • проверяет Union-типы через ретрай на выбросе исключения
  • по умолчанию использует готовый щаблон для кодогенерации и исполняет его по запросу, требуется особое внимание к сохранности данного шаблона
  • проверяет типы списков, может приводить списки к множествам
  • не проверяет типы generic-словарей, кортежей (реализация ожидается)
  • пользовательские проверки типов должны быть реализованы через наследование и проверки в конструкторе
  • опциональный strict-mode: выключение приведения базовых типов
  • для inflation может генерировать кортежи верхнеуровневых объектов при наличии описания схемы (полезно при развертывании аргументов)
  • TypedDict поддерживается только для inflation из-за сложностей выбора варианта при сборке Union-полей
  • для deflation поддерживается включение режима explicit_casts, приводящего типы к тем, которые указаны в аннотациях (не распространяется на Union-типы, т.к. невозможно определить какой из них должен быть выбран)

Как установить:

uv:

uv add megasniff --index sniff_index=https://git.nikto-b.ru/api/packages/nikto_b/pypi/simple

poetry:

  1. Добавить репозиторий в pyproject.toml
poetry source add --priority=supplemental sniff_index https://git.nikto-b.ru/api/packages/nikto_b/pypi/simple
  1. Поставить пакет
poetry add --source sniff_index megasniff

Strict-mode:

Strict-mode off:

@dataclass
class A:
    a: list[int]
>>> {"a": [1, 1.1, "321"]}
<<< A(a=[1, 1, 321])
>>> A(a=[1, 1.1, "321"])
<<< {"a": [1, 1.1, "321"]}  # explicit_casts=False
<<< {"a": [1, 1, 321]}  # explicit_casts=True

Strict-mode on:

@dataclass
class A:
    a: list[int]
>>> {"a": [1, 1.1, "321"]}
<<< FieldValidationException, т.к. 1.1 не является int
>>> A(a=[1, 1.1, "321"])
<<< FieldValidationException, т.к. 1.1 не является int

Tuple unwrap

fn = infl.schema_to_inflator(
        (('a', int), TupleSchemaItem(Optional[list[int]], key_name='b', has_default=True, default=None)))

Создаёт fn: (dict[str,Any]) -> tuple[int, Optional[list[int]]]: ... (сигнатура остаётся (dict[str,Any])->tuple)

Description
Автоматическая валидация данных по схеме и сборка объекта в одном флаконе
Readme LGPL-3.0 216 KiB
Languages
Python 84%
Jinja 16%