Source code for umongo.instance
import abc
from .document import DocumentTemplate
from .embedded_document import EmbeddedDocumentTemplate
from .exceptions import (
AlreadyRegisteredDocumentError,
NoDBDefinedError,
NotRegisteredDocumentError,
)
from .template import get_template
[docs]
class Instance(abc.ABC):
"""Abstract instance class
Instances aims at collecting and implementing :class:`umongo.template.Template`::
# Doc is a template, cannot use it for the moment
class Doc(DocumentTemplate):
pass
instance = MyFrameworkInstance()
# doc_cls is the instance's implementation of Doc
doc_cls = instance.register(Doc)
# Implementations are registered as attribute into the instance
instance.Doc is doc_cls
# Now we can work with the implementations
doc_cls.find()
.. note::
Instance registration is divided between :class:`umongo.Document` and
:class:`umongo.EmbeddedDocument`.
"""
BUILDER_CLS = None
def __init__(self, db=None):
self.builder = self.BUILDER_CLS(self)
self._doc_lookup = {}
self._embedded_lookup = {}
self._mixin_lookup = {}
self._db = db
if db is not None:
self.set_db(db)
@classmethod
def from_db(cls, db):
from .frameworks import find_instance_from_db # noqa: PLC0415
instance_cls = find_instance_from_db(db)
instance = instance_cls()
instance.set_db(db)
return instance
[docs]
def retrieve_document(self, name_or_template):
"""Retrieve a :class:`umongo.document.DocumentImplementation` registered
into this instance from its name or its template class
(i.e. :class:`umongo.Document`).
"""
if not isinstance(name_or_template, str):
name_or_template = name_or_template.__name__
if name_or_template not in self._doc_lookup:
raise NotRegisteredDocumentError(
f'Unknown document class "{name_or_template}"'
)
return self._doc_lookup[name_or_template]
[docs]
def retrieve_embedded_document(self, name_or_template):
"""Retrieve a :class:`umongo.embedded_document.EmbeddedDocumentImplementation`
registered into this instance from it name or it template class
(i.e. :class:`umongo.EmbeddedDocument`).
"""
if not isinstance(name_or_template, str):
name_or_template = name_or_template.__name__
if name_or_template not in self._embedded_lookup:
raise NotRegisteredDocumentError(
f'Unknown embedded document class "{name_or_template}"',
)
return self._embedded_lookup[name_or_template]
[docs]
def register(self, template):
"""Generate an :class:`umongo.template.Implementation` from the given
:class:`umongo.template.Template` for this instance.
:param template: :class:`umongo.template.Template` to implement
:return: The :class:`umongo.template.Implementation` generated
.. note::
This method can be used as a decorator. This is useful when you
only have a single instance to work with to directly use the
class you defined::
@instance.register
class MyEmbedded(EmbeddedDocument):
pass
@instance.register
class MyDoc(Document):
emb = fields.EmbeddedField(MyEmbedded)
MyDoc.find()
"""
# Retrieve the template if another implementation has been provided instead
template = get_template(template)
if issubclass(template, DocumentTemplate):
implementation = self._register_doc(template)
elif issubclass(template, EmbeddedDocumentTemplate):
implementation = self._register_embedded_doc(template)
else: # MixinDocument
implementation = self._register_mixin_doc(template)
return implementation
def _register_doc(self, template):
implementation = self.builder.build_from_template(template)
if implementation.__name__ in self._doc_lookup:
raise AlreadyRegisteredDocumentError(
f'Document "{implementation.__name__}" already registered'
)
self._doc_lookup[implementation.__name__] = implementation
return implementation
def _register_embedded_doc(self, template):
implementation = self.builder.build_from_template(template)
if implementation.__name__ in self._embedded_lookup:
raise AlreadyRegisteredDocumentError(
f'EmbeddedDocument "{implementation.__name__}" already registered'
)
self._embedded_lookup[implementation.__name__] = implementation
return implementation
def _register_mixin_doc(self, template):
implementation = self.builder.build_from_template(template)
if implementation.__name__ in self._mixin_lookup:
raise AlreadyRegisteredDocumentError(
f'MixinDocument "{implementation.__name__}" already registered'
)
self._mixin_lookup[implementation.__name__] = implementation
return implementation
@property
def db(self):
if self._db is None:
raise NoDBDefinedError("db not set, please call set_db")
return self._db
@abc.abstractmethod
def is_compatible_with(self, db):
return NotImplemented
[docs]
def set_db(self, db):
"""Set the database to use whithin this instance.
.. note::
The documents registered in the instance cannot be used
before this function is called.
"""
assert self.is_compatible_with(db)
self._db = db