@@ -1422,7 +1422,9 @@ class NotKeywordSchema(KeywordMapper):
1422
1422
"""
1423
1423
Allows specifying specific schema conditions that fails underlying schema definition validation if present.
1424
1424
1425
- This is equivalent to OpenAPI object mapping with ``additionalProperties: false``, but is more explicit in
1425
+ Corresponds to the ``not`` specifier of `OpenAPI` specification.
1426
+
1427
+ This is equivalent to `OpenAPI` object mapping with ``additionalProperties: false``, but is more explicit in
1426
1428
the definition of invalid or conflicting field names with explicit definitions during deserialization.
1427
1429
1428
1430
Example::
@@ -1436,9 +1438,21 @@ class MappingWithType(ExtendedMappingSchema):
1436
1438
class MappingWithoutType(NotKeywordSchema, RequiredItem):
1437
1439
_not = [MappingWithType()]
1438
1440
1441
+ class MappingOnlyNotType(NotKeywordSchema):
1442
+ _not = [MappingWithType()]
1443
+
1439
1444
# following will raise invalid error even if 'item' is valid because 'type' is also present
1440
1445
MappingWithoutType().deserialize({"type": "invalid", "item": "valid"})
1441
1446
1447
+ # following will return successfully with only 'item' because 'type' was not present
1448
+ MappingWithoutType().deserialize({"item": "valid", "value": "ignore"})
1449
+ # result: {"item": "valid"}
1450
+
1451
+ # following will return an empty mapping dropping 'item' since it only needs to ensure 'type' was not present,
1452
+ # but did not provide any additional fields requirement from other class inheritances
1453
+ MappingOnlyNotType().deserialize({"item": "valid"})
1454
+ # result: {}
1455
+
1442
1456
.. seealso::
1443
1457
- :class:`OneOfKeywordSchema`
1444
1458
- :class:`AllOfKeywordSchema`
@@ -1457,7 +1471,7 @@ def _not(cls):
1457
1471
1458
1472
def _deserialize_keyword (self , cstruct ):
1459
1473
"""
1460
- Test each possible case, raise if any corresponding schema was successfully validated.
1474
+ Raise if any sub-node schema that should NOT be present was successfully validated.
1461
1475
"""
1462
1476
invalid_not = dict ()
1463
1477
for schema_class in self ._not : # noqa
@@ -1473,7 +1487,10 @@ def _deserialize_keyword(self, cstruct):
1473
1487
if invalid_not :
1474
1488
message = "Value contains not allowed fields from schema conditions: {}" .format (invalid_not )
1475
1489
raise colander .Invalid (node = self , msg = message , value = cstruct )
1476
- return cstruct
1490
+ # If schema was a plain NotKeywordSchema, the result will be empty as it serves only to validate
1491
+ # that the subnodes are not present. Otherwise, if it derives from other mapping classes, apply them.
1492
+ # If deserialization was not applied here, everything in the original cstruct would bubble up.
1493
+ return ExtendedMappingSchema .deserialize (self , cstruct )
1477
1494
1478
1495
1479
1496
class KeywordTypeConverter (TypeConverter ):
0 commit comments