4

So I'm using Cerberus for schema validation, but I'm running into a particular with validating a subdictionary of a dictionary whose key is unknown.

So say I have the following document:

dict = {
   'things': {
       '0463': {
           'foo': 'blah',
           'bar': 'bleep'
        },
        '0464': {
           'foo': 'x',
           'bar': 'y'
        },
        'another_random_id': {
           'foo': 'blah',
           'bar': 'bleep'
        }
}

So i want to validate that the subdictionaries have a specific structure (foo and bar as keys), but I can't figure out a way to validate this without knowing the keys ahead of time (which in my case are random id's. I figured this was a good use of valueschema but i can't seem to get valueschema to work with something of type 'dict'. I tried to set the following schema in cerberus:

schema = {
    'things': {
        'type': 'dict',
        'valueschema': {
             'type': 'dict',
             'foo': {'type': 'string'},
             'bar': {'type': 'string'}
         }
     }
}

Am i defining my schema incorrectly or is this not possible with the current implementation of valueschema. I saw some tests in the repository that used valueschema, but they were only testing where the type of valueschema was an int or a string.

Sir Neuman
  • 1,385
  • 1
  • 14
  • 23
  • If this is still an issue, please open a bug report that includes a description of the behaviour that you encountered and that you expect. – funky-future Oct 24 '17 at 13:06

1 Answers1

4

So I figured out that cerberus will handle valueschema if it's of type dict if I put a schema field after the valueschema key. So my structure should be:

schema = {
    'things': {
        'type': 'dict',
        'valueschema': {
             'type': 'dict',
             'schema':{
                 'foo': {'type': 'string'},
                 'bar': {'type': 'string'}
             }
         }
     }
}

Now there's still some weirdness because it doesn't seem like valueschema was designed with the expectation that it would validate a value of type dict. For example when I extend from the validator, I had to override the validate_valueschema method so that the required validation acts the same as it would for a regular schema, because when it calls validate on the schema it doesn't pass in the update parameter. So my overridden validate_valueschema looks like this:

def _validate_valueschema(self, schema, field, value):
    if isinstance(value, Mapping):
        for key, document in value.items():
            validator = self._Validator__get_child_validator()
            validator.validate(
                {key: document}, {key: schema}, 
                context=self.document, update=self.update)
            if len(validator.errors):
                self._error(field, validator.errors)

The update=self.update is all I added.

funky-future
  • 3,716
  • 1
  • 30
  • 43
Sir Neuman
  • 1,385
  • 1
  • 14
  • 23
  • Not sure if I misunderstood the documentation because on the site it uses "schema" not "valueschema" >>> schema = { ... 'test_field': {}, ... 'a_dict': { ... 'type': 'dict', ... 'schema': { ... 'foo': {'type': 'string'}, ... 'bar': {'type': 'string', 'dependencies': '^test_field'} ... } ... } ... } – Illegal Operator May 28 '19 at 13:20
  • Changed in version 0.9: renamed `keyschema` to `valueschema`. Changed in version 1.3: renamed `valueschema` to `valuesrules`. _Source: [docs.python-cerberus.org](https://docs.python-cerberus.org/en/stable/validation-rules.html?highlight=valueschema#valuesrules)_ – Henrik Aug 23 '19 at 15:27