Nesting documents

Documents can contain sub-documents of the same or different types.

To allow the inclusion of sub-documents in your document, add a DocReference to your schema at the position that you expect a sub-document at.

To actually process sub-documents, you need to override the resolve_and_merge_references() method and call load_subdocument() at the positions that you expect a sub-document.

Example for a document class Parent that includes an Example document from the previous chapters at either direct or in the map map as values:

from configcrunch import DocReference, load_subdocument, REMOVE

class Parent(YamlConfigDocument):
    @classmethod
    def header(cls) -> str:
        return "parent"

    @classmethod
    def schema(cls) -> Schema:
        return Schema({
            'name': str,
            'direct': DocReference(Example),
            'map': {str: DocReference(Example)}
        })

    def _load_subdocuments(self, lookup_paths):
        # direct entry processing
        if self["direct"] != REMOVE:
            self["direct"] = load_subdocument(self["direct"], self, Example, lookup_paths)

        # map entry processing
        if self["map"] != REMOVE:
            for key, doc in self["map"].items():
                if doc != REMOVE:
                    self["map"][key] = load_subdocument(doc, self, Example, lookup_paths)

        return self

The following document would be a valid document for Parent:

# fixtures/parent.yml
parent:
  name: parent
  direct:
    this: is an example-type document
  map:
    one:
      this: is also an example-type document
      int: 3

To load and process this document, load the document like an ordinary document. After that call resolve_and_merge_references() on it. The parameter is not relevant in this case (leave it as an empty list) and will be explained in the next chapter.

document = Parent.from_yaml("fixtures/parent.yml")
document.resolve_and_merge_references([])

You can then validate the document. The sub-documents are validated against their schemas. Validating the document before calling this function will return in a SchemaError.

>>> document.validate()
True

>>> document2 = Parent.from_yaml('fixtures/parent.yml')
>>> # No calling of resolve_and_merge_references
>>> try:
...   document2.validate()
... except SchemaError as err:
...   print(err)
Expected an instance of Example while validating.

You can access sub-documents like other fields:

>>> print(document['direct'])
Example({'this': 'is an example-type document'})
>>> print(document['direct']['this'])
is an example-type document