Source code for umongo.embedded_document

"""umongo EmbeddedDocument"""
import marshmallow as ma

from .template import Implementation, Template
from .data_objects import BaseDataObject
from .expose_missing import EXPOSE_MISSING
from .exceptions import AbstractDocumentError


__all__ = (
    'EmbeddedDocumentTemplate',
    'EmbeddedDocument',
    'EmbeddedDocumentOpts',
    'EmbeddedDocumentImplementation'
)


[docs]class EmbeddedDocumentTemplate(Template): """ Base class to define a umongo embedded document. .. note:: Once defined, this class must be registered inside a :class:`umongo.instance.BaseInstance` to obtain it corresponding :class:`umongo.embedded_document.EmbeddedDocumentImplementation`. """
EmbeddedDocument = EmbeddedDocumentTemplate "Shortcut to EmbeddedDocumentTemplate"
[docs]class EmbeddedDocumentOpts: """ Configuration for an :class:`umongo.embedded_document.EmbeddedDocument`. Should be passed as a Meta class to the :class:`EmbeddedDocument` .. code-block:: python @instance.register class MyEmbeddedDoc(EmbeddedDocument): class Meta: abstract = True assert MyEmbeddedDoc.opts.abstract == True ==================== ====================== =========== attribute configurable in Meta description ==================== ====================== =========== template no Origin template of the embedded document instance no Implementation's instance abstract yes Embedded document can only be inherited is_child no Embedded document inherit of a non-abstract embedded document strict yes Don't accept unknown fields from mongo (default: True) offspring no List of embedded documents inheriting this one ==================== ====================== =========== """ def __repr__(self): return ('<{ClassName}(' 'instance={self.instance}, ' 'template={self.template}, ' 'abstract={self.abstract}, ' 'is_child={self.is_child}, ' 'strict={self.strict}, ' 'offspring={self.offspring})>' .format(ClassName=self.__class__.__name__, self=self)) def __init__(self, instance, template, abstract=False, is_child=False, strict=True, offspring=None): self.instance = instance self.template = template self.abstract = abstract self.is_child = is_child self.strict = strict self.offspring = set(offspring) if offspring else set()
[docs]class EmbeddedDocumentImplementation(Implementation, BaseDataObject): """ Represent an embedded document once it has been implemented inside a :class:`umongo.instance.BaseInstance`. """ __slots__ = ('_data', ) opts = EmbeddedDocumentOpts(None, EmbeddedDocumentTemplate, abstract=True) def __init__(self, **kwargs): super().__init__() if self.opts.abstract: raise AbstractDocumentError("Cannot instantiate an abstract EmbeddedDocument") self._data = self.DataProxy(kwargs) def __repr__(self): return '<object EmbeddedDocument %s.%s(%s)>' % ( self.__module__, self.__class__.__name__, dict(self._data.items())) def __eq__(self, other): if isinstance(other, dict): return self._data == other if hasattr(other, '_data'): return self._data == other._data return NotImplemented def is_modified(self): return self._data.is_modified()
[docs] def clear_modified(self): """ Reset the list of document's modified items. """ self._data.clear_modified()
def required_validate(self): self._data.required_validate()
[docs] @classmethod def build_from_mongo(cls, data, use_cls=True): """ Create an embedded document instance from MongoDB data :param data: data as retrieved from MongoDB :param use_cls: if the data contains a ``_cls`` field, use it determine the EmbeddedDocument class to instanciate """ # If a _cls is specified, we have to use this document class if use_cls and '_cls' in data: cls = cls.opts.instance.retrieve_embedded_document(data['_cls']) doc = cls() doc.from_mongo(data) return doc
def from_mongo(self, data): self._data.from_mongo(data) def to_mongo(self, update=False): return self._data.to_mongo(update=update)
[docs] def update(self, data): """ Update the embedded document with the given data. """ return self._data.update(data)
[docs] def dump(self): """ Dump the embedded document. """ return self._data.dump()
def items(self): return self._data.items() # Data-proxy accessor shortcuts def __getitem__(self, name): value = self._data.get(name) return None if value is ma.missing and not EXPOSE_MISSING.get() else value def __delitem__(self, name): self._data.delete(name) def __setitem__(self, name, value): self._data.set(name, value) def __setattr__(self, name, value): if name in self._fields: self._data.set(name, value) else: super().__setattr__(name, value) def __getattr__(self, name): if name in self._fields: value = self._data.get(name) return None if value is ma.missing and not EXPOSE_MISSING.get() else value raise AttributeError(name) def __delattr__(self, name): if name in self._fields: self._data.delete(name) else: super().__delattr__(name) def __dir__(self): return dir(type(self)) + list(self._fields)