Skip to content

Commit 81089dd

Browse files
authored
Merge pull request #988 from marshmallow-code/unknown_default_raise
Set additionnalProperties to False if unknown is not set / support setting unknown at schema instantiation
2 parents 9c0c577 + becb0a9 commit 81089dd

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/apispec/ext/marshmallow/openapi.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def list2param(self, field: marshmallow.fields.Field, **kwargs: typing.Any) -> d
240240

241241
def schema2jsonschema(self, schema):
242242
"""Return the JSON Schema Object for a given marshmallow
243-
:class:`Schema <marshmallow.Schema>` instance. Schema may optionally
243+
:class:`Schema <marshmallow.Schema>`. Schema may optionally
244244
provide the ``title`` and ``description`` class Meta options.
245245
246246
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject
@@ -254,12 +254,16 @@ def schema2jsonschema(self, schema):
254254

255255
jsonschema = self.fields2jsonschema(fields, partial=partial)
256256

257+
schema_instance = resolve_schema_instance(schema)
258+
257259
if hasattr(Meta, "title"):
258260
jsonschema["title"] = Meta.title
259261
if hasattr(Meta, "description"):
260262
jsonschema["description"] = Meta.description
261-
if hasattr(Meta, "unknown") and Meta.unknown != marshmallow.EXCLUDE:
262-
jsonschema["additionalProperties"] = Meta.unknown == marshmallow.INCLUDE
263+
elif schema_instance.unknown != marshmallow.EXCLUDE:
264+
jsonschema["additionalProperties"] = (
265+
schema_instance.unknown == marshmallow.INCLUDE
266+
)
263267

264268
return jsonschema
265269

tests/test_ext_marshmallow_openapi.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import importlib.metadata
12
from datetime import datetime
23

34
import pytest
@@ -10,6 +11,8 @@
1011
from .schemas import CustomList, CustomStringField
1112
from .utils import build_ref, get_schemas, validate_spec
1213

14+
MA_VERSION = Version(importlib.metadata.version("marshmallow"))
15+
1316

1417
class TestMarshmallowFieldToOpenAPI:
1518
def test_fields_with_load_default_load(self, openapi):
@@ -133,6 +136,13 @@ class Meta:
133136
res = openapi.schema2jsonschema(WhiteStripesSchema)
134137
assert set(res["properties"].keys()) == {"guitarist", "drummer"}
135138

139+
def test_unknown_values_default_disallow(self, openapi):
140+
class UnknownDefaultSchema(Schema):
141+
first = fields.Str()
142+
143+
res = openapi.schema2jsonschema(UnknownDefaultSchema)
144+
assert res["additionalProperties"] is False
145+
136146
def test_unknown_values_disallow(self, openapi):
137147
class UnknownRaiseSchema(Schema):
138148
class Meta:
@@ -163,6 +173,30 @@ class Meta:
163173
res = openapi.schema2jsonschema(UnknownExcludeSchema)
164174
assert "additionalProperties" not in res
165175

176+
@pytest.mark.parametrize("meta_unknown", (RAISE, INCLUDE, EXCLUDE, None))
177+
@pytest.mark.parametrize(
178+
"instance_unknown,expected", ((RAISE, False), (INCLUDE, True), (EXCLUDE, None))
179+
)
180+
def test_unknown_values_instance_override_meta(
181+
self, openapi, instance_unknown, expected, meta_unknown
182+
):
183+
class UnknownSchema(Schema):
184+
if meta_unknown is not None:
185+
186+
class Meta:
187+
unknown = meta_unknown
188+
189+
first = fields.Str()
190+
191+
res = openapi.schema2jsonschema(UnknownSchema(unknown=instance_unknown))
192+
if expected is None:
193+
assert "additionalProperties" not in res
194+
else:
195+
assert res["additionalProperties"] is expected
196+
197+
@pytest.mark.skipif(
198+
MA_VERSION.major >= 4, reason="marshmallow 4 drop inferred fields"
199+
)
166200
def test_only_explicitly_declared_fields_are_translated(self, openapi):
167201
class UserSchema(Schema):
168202
_id = fields.Int()

0 commit comments

Comments
 (0)