1

I'm using Cerberus to validate payloads that have a type and a data field. Depending on the value of type (test or build), I want to validate data against different constraints.

So far, I hav this setup:

test_task = {"folder": {"required": True}}
build_task = {"environment": {"allowed": ["staging", "product"]}}
abstract_task = {'type': {'allowed': ['test', 'build']},
                 'data': {'type': 'dict',
                          'required': True,
                          'anyof': [{'schema': test_task},
                                    {'schema': build_task}]}}

But when the intended subschema fails, also an error regarding the other will be reported:

>>> validator = cerberus.Validator(schemas.abstract_task)
>>> validator.validate({
...     "type": "build",
...     "data": {"environment": "staging"}})
>>> pp validator.errors
{'data': {'anyof': 'no definitions validated',
          'definition 0': {'environment': 'unknown field',
                           'folder': 'required field'},
          'definition 1': {'environment': 'unallowed value bad'}}}

Is there a way to conditionally use definition 1 when the sibling type has the value build?

This question is derived from this issue.

funky-future
  • 3,716
  • 1
  • 30
  • 43

1 Answers1

3

With a single schema and validation you cannot exactly achieve that, but you can make use of the oneof and the dependencies rules to get a clearer error reporting:

test_task = {"folder": {"required": True}}
build_task = {"environment": {"allowed": ["staging", "product"]}}
abstract_task = {'type': {'allowed': ['test', 'build']},
                 'data': {'type': 'dict',
                          'required': True,
                          'oneof': [{'dependencies': {'type': 'test'},
                                     'schema': test_task},
                                    {'dependencies': {'type': 'build'},
                                     'schema': build_task}]}}

This is how it turns out with an unallowed value for one of the subschemas:

>>> document = {"type": "build", "data": {"environment": "legacy"}}
>>> validator(document, abstract_task)
{'data': [{'oneof': ['none or more than one rule validate',
                     {'oneof definition 0': ["depends on these values: {'type': 'test'}",
                                             {'environment': ['unknown field'],
                                              'folder': ['required field']}],
                      'oneof definition 1': [{'environment': ['unallowed value legacy']}]}
                     ]}]}
funky-future
  • 3,716
  • 1
  • 30
  • 43