Search code examples
pythonvalidationcerberus

How can a Cerberus dependency reference a field higher up in the document?


I am trying to create a schema for documents that have dependencies that reference fields higher up in the document. For example:

document = {
    'packages': {
        'some-package': {'version': 1}
    },
    'build-steps': {
        'needs-some-package': {'foo': 'bar'},
        'other-thing': {'funky': 'stuff'}
    }
}

What I'm struggling with here is enforcing the dependency between build-steps.needs-some-package and packages.some-package. Whenever build-steps contains "needs-some-package", packages must contain "some-package".

When "needs-some-package" is not present, "some-package" is not required. So this document should also validate.

other_document = {
    'packages': {
        'other-package': {'version': 1}
    },
    'build-steps': {
        'other-thing': {'funky': 'stuff'}
    }
}

A schema with the dependency in what seems like the appropriate place is

schema = {
    'packages': {
        'type': 'dict',
        'valueschema': {
            'type': 'dict'
        }
    },
    'build-steps': {
        'type': 'dict',
        'schema': {
            'needs-some-package': {
                'type': 'dict',
                'dependencies': 'packages.some-package'
            },
            'other-thing': {
                'type': 'dict'
            }
        }
    }
}

But that doesn't work because it appears that Cerberus is looking for "packages" within the sub-document under "build-steps". Is there any way to go up the document tree? Or to reference something with respect to the root of the document?


Solution

  • Described problem got resolved in version 1.0.2:

    When a subdocument is processed the lookup for a field in question starts at the level of that document. In order to address the processed document as root level, the declaration has to start with a ^. An occurance of two initial carets (^^) is interpreted as a literal, single ^ with no special meaning.

    Example code:

    import cerberus
    
    schema = {
        'packages': {
            'type': 'dict',
            'valueschema': {
                'type': 'dict'
            }
        },
        'build-steps': {
            'type': 'dict',
            'schema': {
                'needs-some-package': {
                    'type': 'dict',
                    'dependencies': '^packages.some-package'
                },
                'other-thing': {
                    'type': 'dict'
                }
            }
        }
    }
    
    document = {
        'packages': {
            'some-package': {'version': 1}
        },
        'build-steps': {
            'needs-some-package': {'foo': 'bar'},
            'other-thing': {'funky': 'stuff'}
        }
    }
    
    validator = cerberus.Validator(schema)
    print(validator.validate(document))