From 3b5ff788e05b9c4f1261490ea37d8fb06039f0b8 Mon Sep 17 00:00:00 2001 From: Kuyugama Date: Tue, 24 Jun 2025 01:07:42 +0300 Subject: [PATCH] Add support of the composed metadata into schema and field --- src/kat_transform/__init__.py | 8 +++++--- src/kat_transform/field.py | 7 +++---- src/kat_transform/metadata.py | 21 +++++++++++++-------- src/kat_transform/schema.py | 4 ++-- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/kat_transform/__init__.py b/src/kat_transform/__init__.py index ce3faad..e068e2b 100644 --- a/src/kat_transform/__init__.py +++ b/src/kat_transform/__init__.py @@ -6,9 +6,9 @@ from .field import FieldSpec, I, O from .exceptions import FieldResolveError from .markers import ValueGetter, FieldValue -from .metadata import SchemaMetadata, FieldMetadata from .resolve_fields import resolve_fields, resolve_getter from .util import get_item_type, is_typed_mapping, is_typed_sequence +from .metadata import CombinedMetadata, SchemaMetadata, FieldMetadata __all__ = [ "field", @@ -31,7 +31,7 @@ def field( name: str, transform: typing.Callable[[I], O] | None = None, getter: str | collections.abc.Sequence[str] | typing.Callable[..., I | O] | None = None, - meta: FieldMetadata | None = None, + meta: FieldMetadata | CombinedMetadata[FieldMetadata] | None = None, ) -> FieldSpec[I, O]: """ Shorthand for FieldSpec creation @@ -40,7 +40,9 @@ def field( def schema( - name: str, *fields: FieldSpec[typing.Any, typing.Any], meta: SchemaMetadata | None = None + name: str, + *fields: FieldSpec[typing.Any, typing.Any], + meta: SchemaMetadata | CombinedMetadata[SchemaMetadata] | None = None, ) -> SchemaSpec: """ Shorthand for SchemaSpec creation diff --git a/src/kat_transform/field.py b/src/kat_transform/field.py index 512b586..b169012 100644 --- a/src/kat_transform/field.py +++ b/src/kat_transform/field.py @@ -1,12 +1,11 @@ import typing import collections.abc -from functools import cache -from dataclasses import dataclass, field +from dataclasses import dataclass from .util import get_by_name from .markers import ValueGetter -from .metadata import FieldMetadata +from .metadata import CombinedMetadata, FieldMetadata if typing.TYPE_CHECKING: from .schema import SchemaSpec @@ -34,7 +33,7 @@ class FieldSpec(typing.Generic[I, O]): Define name, list of names or callable that will be used to get input value for this field """ - metadata: FieldMetadata | None = None + metadata: FieldMetadata | CombinedMetadata[FieldMetadata] | None = None """ Define metadata for this field """ diff --git a/src/kat_transform/metadata.py b/src/kat_transform/metadata.py index 117357e..da01b7d 100644 --- a/src/kat_transform/metadata.py +++ b/src/kat_transform/metadata.py @@ -1,11 +1,13 @@ import typing T = typing.TypeVar("T", bound="Metadata") +T_co = typing.TypeVar("T_co", bound="Metadata", covariant=True) class Metadata: - def __init__(self) -> None: - self.entries: tuple[Metadata, ...] = (self,) + @property + def entries(self: T_co) -> tuple[T_co, ...]: + return (self,) def get_metadata(self, metadata_type: type[T], exact: bool = False) -> T | None: for entry in self.entries: @@ -17,14 +19,17 @@ def get_metadata(self, metadata_type: type[T], exact: bool = False) -> T | None: return None - def __or__(self, other: "Metadata") -> "CombinedMetadata": - return CombinedMetadata(*self.entries, *other.entries) + def __or__(self: T_co, other: T_co) -> "CombinedMetadata[T_co]": + return CombinedMetadata[T_co](*self.entries, *other.entries) -class CombinedMetadata(Metadata): - def __init__(self, *entries: Metadata): - super().__init__() - self.entries: tuple[Metadata, ...] = entries +class CombinedMetadata(Metadata, typing.Generic[T_co]): + def __init__(self, *entries: T_co): + self._entries: tuple[T_co, ...] = entries + + @property + def entries(self) -> tuple[T_co, ...]: + return self._entries class FieldMetadata(Metadata): diff --git a/src/kat_transform/schema.py b/src/kat_transform/schema.py index b5803af..4066052 100644 --- a/src/kat_transform/schema.py +++ b/src/kat_transform/schema.py @@ -5,7 +5,7 @@ from .field import FieldSpec from .markers import FieldValue -from .metadata import SchemaMetadata +from .metadata import CombinedMetadata, SchemaMetadata from .util import get_item_type, is_typed_mapping, is_typed_sequence @@ -37,7 +37,7 @@ class SchemaSpec: name: str fields: collections.abc.Sequence[FieldSpec[typing.Any, typing.Any]] - metadata: SchemaMetadata | None = None + metadata: SchemaMetadata | CombinedMetadata[SchemaMetadata] | None = None def get(self, from_: typing.Any) -> frozenset[FieldValue]: """