Skip to content

Commit

Permalink
Added support for ma.INCLUDE, ma.EXCLUDE, ma.RAISE (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
mesemus authored Oct 3, 2023
1 parent e202381 commit dfb2385
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class MarshmallowClass:
base_classes: List[str]
imports: List[Import]
fields: List[MarshmallowField]
strict: bool
unknown: str
order: Optional[int] = None

references: List[MarshmallowReference] = dataclasses.field(default_factory=list)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import List

import marshmallow as ma
import marshmallow.validate
from marshmallow import fields

from oarepo_model_builder.datatypes import DataType, ObjectDataType, datatypes
Expand Down Expand Up @@ -63,6 +64,10 @@ class ObjectMarshmallowExtraSchema(ma.Schema):
metadata={"doc": "Extra fields to generate into the marshmallow class"},
)
skip = fields.Boolean()
unknown = fields.Str(
validate=[marshmallow.validate.OneOf(["RAISE", "INCLUDE", "EXCLUDE"])],
default="RAISE",
)


class ObjectMarshmallowSchema(PropertyMarshmallowSchema, ObjectMarshmallowExtraSchema):
Expand Down Expand Up @@ -195,7 +200,7 @@ def _build_class(
base_classes=marshmallow.get("base-classes", []) or ["ma.Schema"],
imports=Import.from_config(marshmallow.get("imports", [])),
fields=fields,
strict=True,
unknown=marshmallow.get("unknown", "RAISE"),
)
)

Expand Down
4 changes: 1 addition & 3 deletions oarepo_model_builder/invenio/templates/marshmallow.py.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ from marshmallow_utils import schemas as mu_schemas

{% for cls in generated_classes %}
class {{cls.class_name|base_name}}({% for bc in cls.base_classes %}{% if not loop.first%}, {% endif %}{{bc}}{% endfor %}):
{% if cls.strict %}
class Meta:
unknown = ma.RAISE
{% endif %}
unknown = ma.{{ cls.unknown }}
{% for fld in cls.fields %}
{{fld.key}} = {{fld.full_definition}}
{% endfor %}
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = oarepo-model-builder
version = 4.0.51
version = 4.0.52
description = A utility library that generates OARepo required data model files from a JSON specification file
authors = Miroslav Bauer <[email protected]>, Miroslav Simek <[email protected]>
readme = README.md
Expand Down
89 changes: 89 additions & 0 deletions tests/test_marshmallow_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,95 @@ class Meta:
)


def test_strict_object(fulltext_builder):
schema = get_test_schema(
a={
"type": "object",
"properties": {"b": {"type": "integer"}},
}
)
fulltext_builder.filesystem = InMemoryFileSystem()
fulltext_builder.build(
schema, profile="record", model_path=["record"], output_dir=""
)

with fulltext_builder.filesystem.open(
os.path.join("test", "services", "records", "schema.py")
) as f:
data = f.read()
assert (
strip_whitespaces(
"""
class ASchema(ma.Schema):
class Meta:
unknown= ma.RAISE
b= ma.fields.Integer()
"""
)
in strip_whitespaces(data)
)


def test_permissive_object(fulltext_builder):
schema = get_test_schema(
a={
"type": "object",
"marshmallow": {"unknown": "INCLUDE"},
"properties": {"b": {"type": "integer"}},
}
)
fulltext_builder.filesystem = InMemoryFileSystem()
fulltext_builder.build(
schema, profile="record", model_path=["record"], output_dir=""
)

with fulltext_builder.filesystem.open(
os.path.join("test", "services", "records", "schema.py")
) as f:
data = f.read()
assert (
strip_whitespaces(
"""
class ASchema(ma.Schema):
class Meta:
unknown= ma.INCLUDE
b= ma.fields.Integer()
"""
)
in strip_whitespaces(data)
)


def test_excluding_object(fulltext_builder):
schema = get_test_schema(
a={
"type": "object",
"marshmallow": {"unknown": "EXCLUDE"},
"properties": {"b": {"type": "integer"}},
}
)
fulltext_builder.filesystem = InMemoryFileSystem()
fulltext_builder.build(
schema, profile="record", model_path=["record"], output_dir=""
)

with fulltext_builder.filesystem.open(
os.path.join("test", "services", "records", "schema.py")
) as f:
data = f.read()
assert (
strip_whitespaces(
"""
class ASchema(ma.Schema):
class Meta:
unknown= ma.EXCLUDE
b= ma.fields.Integer()
"""
)
in strip_whitespaces(data)
)


def test_generate_nested_schema_same_file(fulltext_builder):
schema = get_test_schema(
a={
Expand Down

0 comments on commit dfb2385

Please sign in to comment.