Skip to content

Commit 73cbe0f

Browse files
committed
Add an experimental meta decorator
1 parent f0c6afb commit 73cbe0f

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from __future__ import annotations
2+
3+
import typing
4+
5+
from marshmallow.fields import Field
6+
from marshmallow.schema import SchemaMeta
7+
from marshmallow.types import UnknownOption
8+
9+
10+
@typing.overload
11+
def meta(
12+
*bases: SchemaMeta,
13+
fields: tuple[str, ...] | list[str] | None,
14+
additional: tuple[str, ...] | list[str] | None,
15+
include: dict[str, Field] | None,
16+
exclude: tuple[str, ...] | list[str] | None,
17+
many: bool | None,
18+
dateformat: str | None,
19+
datetimeformat: str | None,
20+
timeformat: str | None,
21+
render_module: typing.Any | None,
22+
index_errors: bool | None,
23+
load_only: tuple[str, ...] | list[str] | None,
24+
dump_only: tuple[str, ...] | list[str] | None,
25+
unknown: UnknownOption | None,
26+
register: bool | None,
27+
**kwargs,
28+
):
29+
"""
30+
:param *bases: The meta classes to inherit from. Inherits from the decorated schema's
31+
Meta class by default. Pass `None` to prevent inheritance.
32+
:param fields: Fields to include in the (de)serialized result
33+
:param additional: Fields to include in addition to the explicitly declared fields.
34+
`additional <marshmallow.Schema.Meta.additional>` and `fields <marshmallow.Schema.Meta.fields>`
35+
are mutually-exclusive options.
36+
:param include: Dictionary of additional fields to include in the schema. It is
37+
usually better to define fields as class variables, but you may need to
38+
use this option, e.g., if your fields are Python keywords.
39+
:param exclude: Fields to exclude in the serialized result.
40+
Nested fields can be represented with dot delimiters.
41+
:param many: Whether data should be (de)serialized as a collection by default.
42+
:param dateformat: Default format for `Date <marshmallow.fields.Date>` fields.
43+
:param datetimeformat: Default format for `DateTime <marshmallow.fields.DateTime>` fields.
44+
:param timeformat: Default format for `Time <marshmallow.fields.Time>` fields.
45+
:param render_module: Module to use for `loads <marshmallow.Schema.loads>` and `dumps <marshmallow.Schema.dumps>`.
46+
Defaults to `json` from the standard library.
47+
:param index_errors: If `True`, errors dictionaries will include the index of invalid items in a collection.
48+
:param load_only: Fields to exclude from serialized results
49+
:param dump_only: Fields to exclude from serialized results
50+
:param unknown: Whether to exclude, include, or raise an error for unknown fields in the data.
51+
Use `EXCLUDE`, `INCLUDE` or `RAISE`.
52+
:param register: Whether to register the `Schema <marshmallow.Schema>` with marshmallow's internal
53+
class registry. Must be `True` if you intend to refer to this `Schema <marshmallow.Schema>`
54+
by class name in `Nested` fields. Only set this to `False` when memory
55+
usage is critical. Defaults to `True`.
56+
"""
57+
58+
59+
@typing.overload
60+
def meta(*bases, **kwargs): ...
61+
62+
63+
def meta(*bases, **kwargs):
64+
def wrapper(schema):
65+
mro = bases if bases else (schema.Meta,)
66+
meta = type(schema.Meta.__name__, mro, kwargs)
67+
return type(schema.__name__, (schema,), {"Meta": meta})
68+
69+
return wrapper

tests/test_meta.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from marshmallow import Schema
2+
from marshmallow.experimental.meta import meta
3+
4+
5+
class Base(Schema):
6+
class Meta:
7+
foo = True
8+
9+
10+
class TestMeta:
11+
def test_default_inheritance(self):
12+
@meta(bar=True)
13+
class Test(Base):
14+
pass
15+
16+
assert getattr(Test.Meta, "foo", None)
17+
assert getattr(Test.Meta, "bar", None)
18+
19+
def test_explicit_inheritance(self):
20+
class Parent(Schema):
21+
class Meta:
22+
bar = True
23+
24+
@meta(Base.Meta, Parent.Meta, baz=True)
25+
class Test(Schema):
26+
pass
27+
28+
assert getattr(Test.Meta, "foo", None)
29+
assert getattr(Test.Meta, "bar", None)
30+
assert getattr(Test.Meta, "baz", None)
31+
32+
def test_clear_inheritance(self):
33+
@meta(Schema.Meta, bar=True)
34+
class Test(Base):
35+
pass
36+
37+
assert not hasattr(Test.Meta, "foo")

0 commit comments

Comments
 (0)