def _validate_doc(self, doc, struct, path=""):
        if type(struct) is type or struct is None:
            if struct is None:
                if type(doc) not in self.authorized_types:
                    self._raise_exception(AuthorizedTypeError, type(doc).__name__,
                                          "%s is not an authorized types" % type(doc).__name__)
            elif not isinstance(doc, struct) and doc is not None:
                self._raise_exception(SchemaTypeError, path,
                                      "%s must be an instance of %s not %s" % (
                                          path, struct.__name__, type(doc).__name__))
        elif isinstance(struct, CustomType):
            if not isinstance(doc, struct.mongo_type) and doc is not None:
                self._raise_exception(SchemaTypeError, path,
                                      "%s must be an instance of %s not %s" % (
                                          path, struct.mongo_type.__name__, type(doc).__name__))
            struct.validate(doc, path=path)
        elif isinstance(struct, SchemaOperator):
            if not struct.validate(doc) and doc is not None:
                if isinstance(struct, IS):
                    self._raise_exception(SchemaTypeError, path,
                                          "%s must be in %s not %s" % (path, struct._operands, doc))
                else:
                    self._raise_exception(SchemaTypeError, path,
                                          "%s must be an instance of %s not %s" % (path, struct, type(doc).__name__))
        elif isinstance(struct, dict):
            if not isinstance(doc, type(struct)):
                self._raise_exception(SchemaTypeError, path,
                                      "%s must be an instance of %s not %s" % (
                                          path, type(struct).__name__, type(doc).__name__))
            struct_length = len(struct) if not '_id' in struct else len(struct) - 1
            if len(doc) != struct_length:
                struct_doc_diff = list(set(struct).difference(set(doc)))
                if struct_doc_diff:
                    for field in struct_doc_diff:
                        if (type(field) is not type) and (not self.use_schemaless):
                            self._raise_exception(StructureError, None,
                                                  "missed fields %s in %s" % (struct_doc_diff, type(doc).__name__))
                else:
                    struct_struct_diff = list(set(doc).difference(set(struct)))
                    bad_fields = [s for s in struct_struct_diff if s not in STRUCTURE_KEYWORDS]
                    if bad_fields and not self.use_schemaless:
                        self._raise_exception(StructureError, None,
                                              "unknown fields %s in %s" % (bad_fields, type(doc).__name__))
            for key in struct:
                if type(key) is type:
                    new_key = "$%s" % key.__name__
                else:
                    new_key = key
                new_path = ".".join([path, new_key]).strip('.')
                if new_key.split('.')[-1].startswith("$"):
                    for doc_key in doc:
                        if not isinstance(doc_key, key):
                            self._raise_exception(SchemaTypeError, path,
                                                  "key of %s must be an instance of %s not %s" % (
                                                      path, key.__name__, type(doc_key).__name__))
                        self._validate_doc(doc[doc_key], struct[key], new_path)
                else:
                    if key in doc:
                        self._validate_doc(doc[key], struct[key],  new_path)
        elif isinstance(struct, list):
            if not isinstance(doc, list) and not isinstance(doc, tuple):
                self._raise_exception(SchemaTypeError, path,
                                      "%s must be an instance of list not %s" % (path, type(doc).__name__))
            if not len(struct):
                struct = None
            else:
                struct = struct[0]
            for obj in doc:
                self._validate_doc(obj, struct, path)
        elif isinstance(struct, tuple):
            if not isinstance(doc, list) and not isinstance(doc, tuple):
                self._raise_exception(SchemaTypeError, path,
                                      "%s must be an instance of list not %s" % (
                                          path, type(doc).__name__))
            if len(doc) != len(struct):
                self._raise_exception(SchemaTypeError, path, "%s must have %s items not %s" % (
                    path, len(struct), len(doc)))
            for i in range(len(struct)):
                self._validate_doc(doc[i], struct[i], path)
check if doc field types match the doc field structure
dataset/ETHPy150Open namlook/mongokit/mongokit/schema_document.py/SchemaDocument._validate_doc