Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle the empty MappingSchema with require=False #291

Closed
btall opened this issue May 26, 2017 · 1 comment
Closed

Handle the empty MappingSchema with require=False #291

btall opened this issue May 26, 2017 · 1 comment

Comments

@btall
Copy link

btall commented May 26, 2017

In the case where a field is a empty MappingSchema, require=False doesn't works.

Example:

Workaround

--- schema.py	2017-05-26 16:59:00.979227881 +0200
+++ schema_workaround.py	2017-05-26 16:58:43.656278244 +0200
@@ -5,6 +5,8 @@
 import sys
 import colander
 
+from contextlib import contextmanager
+
 person_1 = {
     'firstname': 'foo',
     'lastname': 'bar',
@@ -33,6 +35,29 @@
     firstname = colander.SchemaNode(colander.String())
     address = Address(missing=colander.null)
 
+    @contextmanager
+    def _handle_empty_address(self, cstruct):
+        """
+        Skip it, just  the time to validation
+        And reinject it to the end of validating.
+        """
+        try:
+            address = cstruct['address']
+            is_empty = all((address[field] == colander.null) for field in address)
+            if is_empty:
+                cstruct['address'] = colander.null
+
+            yield cstruct
+
+        finally:
+            cstruct['address'] = address
+
+    def deserialize(self, cstruct=colander.null):
+        with self._handle_empty_address(cstruct) as cstruct:
+            cstruct = super(Person, self).deserialize(cstruct)
+
+        return cstruct
+
 
 def main():
     validator = Person()

Maybe that a sexy solution exists, but I don't found it in the examples of the documentation. 😄

@tseaver
Copy link
Member

tseaver commented May 20, 2024

@btall your example uses a spelling for the address field which does not mean anything to colander:

class Person(colander.Schema):
    ...
    address = Address(require=False)

colander doesn't use the require keyword: it just passes it on to the schema node, like any other unknown keyword argument.

Depending on your usecase, I would either spell this as:

class Person(colander.Schema):
    ...
    address = Address(missing=colander.drop)

which would allow deserializing a person structure with no address key at all. Or else I would make the city, country, and zipcode fields optional:

class Address(colander.MappingSchema):
    city = colander.SchemaNode(colander.String(), missing=colander.drop)
    country = colander.SchemaNode(colander.String(), missing=colander.drop)
    zipcode = colander.SchemaNode(colander.Integer(), missing=colander.drop)

which would preserve the "empty" address structure in your example.

Please see the docs on the Null and Drop values for a description of how colander handles this kind of case.

@tseaver tseaver closed this as completed May 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants