Skip to content

Commit a07a40a

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

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

src/marshmallow/experimental/meta.py

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

tests/test_meta.py

+37
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)