From c8ce7e87027fdd4d5565c85f82b2008726edc4a1 Mon Sep 17 00:00:00 2001 From: Jared Deckard Date: Thu, 23 May 2024 11:39:25 -0500 Subject: [PATCH] Add a many Meta option --- src/marshmallow/schema.py | 6 ++++-- tests/test_options.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/marshmallow/schema.py b/src/marshmallow/schema.py index 4f2d0c768..99210ce72 100644 --- a/src/marshmallow/schema.py +++ b/src/marshmallow/schema.py @@ -227,6 +227,7 @@ def __init__(self, meta, ordered: bool = False): self.dump_only = getattr(meta, "dump_only", ()) self.unknown = validate_unknown_parameter_value(getattr(meta, "unknown", RAISE)) self.register = getattr(meta, "register", True) + self.many = getattr(meta, "many", False) class Schema(base.SchemaABC, metaclass=SchemaMeta): @@ -343,6 +344,7 @@ class Meta: `OrderedDict`. - ``exclude``: Tuple or list of fields to exclude in the serialized result. Nested fields can be represented with dot delimiters. + - ``many``: Whether the data is a collection by default. - ``dateformat``: Default format for `Date ` fields. - ``datetimeformat``: Default format for `DateTime ` fields. - ``timeformat``: Default format for `Time ` fields. @@ -366,7 +368,7 @@ def __init__( *, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), - many: bool = False, + many: bool | None = None, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), @@ -380,7 +382,7 @@ def __init__( raise StringNotCollectionError('"exclude" should be a list of strings') # copy declared fields from metaclass self.declared_fields = copy.deepcopy(self._declared_fields) - self.many = many + self.many = self.opts.many if many is None else many self.only = only self.exclude: set[typing.Any] | typing.MutableSet[typing.Any] = set( self.opts.exclude diff --git a/tests/test_options.py b/tests/test_options.py index 2b052a31c..4200ab905 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -262,3 +262,19 @@ class AddFieldsChild(self.AddFieldsSchema): assert "email" in s._declared_fields.keys() assert "from" in s._declared_fields.keys() assert isinstance(s._declared_fields["from"], fields.Str) + + +class TestManyOption: + class ManySchema(Schema): + foo = fields.Str() + + class Meta: + many = True + + def test_many_by_default(self): + test = self.ManySchema() + assert test.load([{"foo": "bar"}]) == [{"foo": "bar"}] + + def test_explicit_single(self): + test = self.ManySchema(many=False) + assert test.load({"foo": "bar"}) == {"foo": "bar"}