Repository: Scille/umongo
Pull request #314 (2020-11-10 10:37:02)

Rework instance
Remove `templates` argument to `BaseInstance` (undocumented and untested).
Merge `BaseInstance`, `Instance` and `LazyLoaderInstance` into `Instance`.
Make `Instance` an abstract base class.
Rename `Instance.init` into `Instance.set_db`.
Don't expose framework instances in `umongo` top module. They must be imported from `umongo.frameworks`.


Before this change, one could use `Instance(db)` and get the right builder class, but not the right instance class, which works fine because there is no specific method in each framework instance class (for now).

After this change, one must pick a specific framework instance or explicitly call the factory method `Instance.from_db`.

The use case of registering documents then setting the db didn't work before the change because one would either call `Instance(db)` or pick the dedicated framework instance. The only difference between the two is that the latter allows to pass the db object after registering documents. But still, the instance type must be defined.

I'm keeping the `Instance.from_db` factory method in case it is useful to anyone, but I don't really see the use case. Since the db object exists, the user probably knows what framework he is using, so he could pick the right framework instance himself.

Lazy loading still works: one can instantiate a framework specific instance, register documents, and then call `set_db` to actually pass a DB connection. Typical use case, the flask app factory: load all model code and register all documents in the instance at import time, then in app init, set a DB connection.


Patch:
diff --git a/docs/apireference.rst b/docs/apireference.rst
index a44a4b2..47c27ed 100644
--- a/docs/apireference.rst
+++ b/docs/apireference.rst
@@ -9,13 +9,8 @@ API Reference
 Instance
 ========
 
-.. autoclass:: umongo.instance.BaseInstance
-    :inherited-members:
-
-.. autoclass:: umongo.Instance
-
-.. autoclass:: umongo.instance.LazyLoaderInstance
-  :members:
+.. autoclass:: umongo.instance.Instance
+    :members:
 
 .. autoclass:: umongo.PyMongoInstance
 
diff --git a/umongo/__init__.py b/umongo/__init__.py
index f638051..6736fbc 100644
--- a/umongo/__init__.py
+++ b/umongo/__init__.py
@@ -1,12 +1,7 @@
 from marshmallow import ValidationError, missing  # noqa, republishing
 
 from .instance import Instance
-from .frameworks import (
-    PyMongoInstance,
-    TxMongoInstance,
-    MotorAsyncIOInstance,
-    MongoMockInstance
-)
+
 from .document import (
     Document,
     pre_load,
@@ -39,10 +34,6 @@ __all__ = (
     'missing',
 
     'Instance',
-    'PyMongoInstance',
-    'TxMongoInstance',
-    'MotorAsyncIOInstance',
-    'MongoMockInstance',
 
     'Document',
     'pre_load',
diff --git a/umongo/exceptions.py b/umongo/exceptions.py
index 41f963c..32ac052 100644
--- a/umongo/exceptions.py
+++ b/umongo/exceptions.py
@@ -5,8 +5,8 @@ class UMongoError(Exception):
     """Base umongo error"""
 
 
-class NoCompatibleBuilderError(UMongoError):
-    """Can't find builder compatible with database"""
+class NoCompatibleInstanceError(UMongoError):
+    """Can't find instance compatible with database"""
 
 
 class AbstractDocumentError(UMongoError):
diff --git a/umongo/frameworks/__init__.py b/umongo/frameworks/__init__.py
index 5c21080..2ba2b3c 100644
--- a/umongo/frameworks/__init__.py
+++ b/umongo/frameworks/__init__.py
@@ -2,21 +2,17 @@
 Frameworks
 ==========
 """
-
-from importlib import import_module
-
-from ..exceptions import NoCompatibleBuilderError
-from ..instance import LazyLoaderInstance
-from .pymongo import PyMongoBuilder
+from ..exceptions import NoCompatibleInstanceError
+from .pymongo import PyMongoInstance
 
 
 __all__ = (
-    'BuilderRegisterer',
+    'InstanceRegisterer',
 
-    'default_builder_registerer',
-    'register_builder',
-    'unregister_builder',
-    'find_builder_from_db',
+    'default_instance_registerer',
+    'register_instance',
+    'unregister_instance',
+    'find_instance_from_db',
 
     'PyMongoInstance',
     'TxMongoInstance',
@@ -25,86 +21,55 @@ __all__ = (
 )
 
 
-class BuilderRegisterer:
+class InstanceRegisterer:
 
     def __init__(self):
-        self.builders = []
+        self.instances = []
 
-    def register(self, builder):
-        if builder not in self.builders:
-            # Insert new item first to overload older compatible builders
-            self.builders.insert(0, builder)
+    def register(self, instance):
+        if instance not in self.instances:
+            # Insert new item first to overload older compatible instances
+            self.instances.insert(0, instance)
 
-    def unregister(self, builder):
+    def unregister(self, instance):
         # Basically only used for tests
-        self.builders.remove(builder)
+        self.instances.remove(instance)
 
     def find_from_db(self, db):
-        for builder in self.builders:
-            if builder.is_compatible_with(db):
-                return builder
-        raise NoCompatibleBuilderError(
-            'Cannot find a umongo builder compatible with %s' % type(db))
-
-
-default_builder_registerer = BuilderRegisterer()
-register_builder = default_builder_registerer.register
-unregister_builder = default_builder_registerer.unregister
-find_builder_from_db = default_builder_registerer.find_from_db
-
-
-# Define lazy loader instances for each builder
+        for instance in self.instances:
+            if instance.is_compatible_with(db):
+                return instance
+        raise NoCompatibleInstanceError(
+            'Cannot find a umongo instance compatible with %s' % type(db))
 
-class PyMongoInstance(LazyLoaderInstance):
-    """
-    :class:`umongo.instance.LazyLoaderInstance` implementation for pymongo
-    """
-    def __init__(self, *args, **kwargs):
-        self.BUILDER_CLS = import_module('umongo.frameworks.pymongo').PyMongoBuilder
-        super().__init__(*args, **kwargs)
 
+default_instance_registerer = InstanceRegisterer()
+register_instance = default_instance_registerer.register
+unregister_instance = default_instance_registerer.unregister
+find_instance_from_db = default_instance_registerer.find_from_db
 
-class TxMongoInstance(LazyLoaderInstance):
-    """
-    :class:`umongo.instance.LazyLoaderInstance` implementation for txmongo
-    """
-    def __init__(self, *args, **kwargs):
-        self.BUILDER_CLS = import_module('umongo.frameworks.txmongo').TxMongoBuilder
-        super().__init__(*args, **kwargs)
 
+# Define lazy loader instances for each instance
 
-class MotorAsyncIOInstance(LazyLoaderInstance):
-    """
-    :class:`umongo.instance.LazyLoaderInstance` implementation for motor-asyncio
-    """
-    def __init__(self, *args, **kwargs):
-        self.BUILDER_CLS = import_module('umongo.frameworks.motor_asyncio').MotorAsyncIOBuilder
-        super().__init__(*args, **kwargs)
+register_instance(PyMongoInstance)
 
 
-class MongoMockInstance(LazyLoaderInstance):
-    """
-    :class:`umongo.instance.LazyLoaderInstance` implementation for mongomock
-    """
-    def __init__(self, *args, **kwargs):
-        self.BUILDER_CLS = import_module('umongo.frameworks.mongomock').MongoMockBuilder
-        super().__init__(*args, **kwargs)
-
-
-# try to load all the builders by default
-register_builder(PyMongoBuilder)
 try:
-    from .txmongo import TxMongoBuilder
-    register_builder(TxMongoBuilder)
+    from .txmongo import TxMongoInstance
+    register_instance(TxMongoInstance)
 except ImportError:  # pragma: no cover
     pass
+
+
 try:
-    from .motor_asyncio import MotorAsyncIOBuilder
-    register_builder(MotorAsyncIOBuilder)
+    from .motor_asyncio import MotorAsyncIOInstance
+    register_instance(MotorAsyncIOInstance)
 except ImportError:  # pragma: no cover
     pass
+
+
 try:
-    from .mongomock import MongoMockBuilder
-    register_builder(MongoMockBuilder)
+    from .mongomock import MongoMockInstance
+    register_instance(MongoMockInstance)
 except ImportError:  # pragma: no cover
     pass
diff --git a/umongo/frameworks/mongomock.py b/umongo/frameworks/mongomock.py
index cbec615..f17c2a8 100644
--- a/umongo/frameworks/mongomock.py
+++ b/umongo/frameworks/mongomock.py
@@ -2,6 +2,7 @@ from mongomock.database import Database
 from mongomock.collection import Cursor
 
 from .pymongo import PyMongoBuilder, PyMongoDocument, BaseWrappedCursor
+from ..instance import Instance
 from ..document import DocumentImplementation
 
 
@@ -21,6 +22,13 @@ class MongoMockDocument(PyMongoDocument):
 class MongoMockBuilder(PyMongoBuilder):
     BASE_DOCUMENT_CLS = MongoMockDocument
 
+
+class MongoMockInstance(Instance):
+    """
+    :class:`umongo.instance.Instance` implementation for mongomock
+    """
+    BUILDER_CLS = MongoMockBuilder
+
     @staticmethod
     def is_compatible_with(db):
         return isinstance(db, Database)
diff --git a/umongo/frameworks/motor_asyncio.py b/umongo/frameworks/motor_asyncio.py
index 7300238..afdb3d3 100644
--- a/umongo/frameworks/motor_asyncio.py
+++ b/umongo/frameworks/motor_asyncio.py
@@ -6,6 +6,7 @@ from pymongo.errors import DuplicateKeyError
 import marshmallow as ma
 
 from ..builder import BaseBuilder
+from ..instance import Instance
 from ..document import DocumentImplementation
 from ..data_objects import Reference
 from ..exceptions import NotCreatedError, UpdateError, DeleteError, NoneReferenceError
@@ -370,10 +371,6 @@ class MotorAsyncIOBuilder(BaseBuilder):
 
     BASE_DOCUMENT_CLS = MotorAsyncIODocument
 
-    @staticmethod
-    def is_compatible_with(db):
-        return isinstance(db, AsyncIOMotorDatabase)
-
     def _patch_field(self, field):
         super()._patch_field(field)
 
@@ -396,3 +393,14 @@ class MotorAsyncIOBuilder(BaseBuilder):
             field.reference_cls = MotorAsyncIOReference
         if isinstance(field, EmbeddedField):
             field.io_validate_recursive = _embedded_document_io_validate
+
+
+class MotorAsyncIOInstance(Instance):
+    """
+    :class:`umongo.instance.Instance` implementation for motor-asyncio
+    """
+    BUILDER_CLS = MotorAsyncIOBuilder
+
+    @staticmethod
+    def is_compatible_with(db):
+        return isinstance(db, AsyncIOMotorDatabase)
diff --git a/umongo/frameworks/pymongo.py b/umongo/frameworks/pymongo.py
index 4992aef..db03725 100644
--- a/umongo/frameworks/pymongo.py
+++ b/umongo/frameworks/pymongo.py
@@ -4,6 +4,7 @@ from pymongo.errors import DuplicateKeyError
 import marshmallow as ma
 
 from ..builder import BaseBuilder
+from ..instance import Instance
 from ..document import DocumentImplementation
 from ..data_objects import Reference
 from ..exceptions import NotCreatedError, UpdateError, DeleteError, NoneReferenceError
@@ -307,10 +308,6 @@ class PyMongoBuilder(BaseBuilder):
 
     BASE_DOCUMENT_CLS = PyMongoDocument
 
-    @staticmethod
-    def is_compatible_with(db):
-        return isinstance(db, Database)
-
     def _patch_field(self, field):
         super()._patch_field(field)
 
@@ -329,3 +326,14 @@ class PyMongoBuilder(BaseBuilder):
             field.reference_cls = PyMongoReference
         if isinstance(field, EmbeddedField):
             field.io_validate_recursive = _embedded_document_io_validate
+
+
+class PyMongoInstance(Instance):
+    """
+    :class:`umongo.instance.Instance` implementation for pymongo
+    """
+    BUILDER_CLS = PyMongoBuilder
+
+    @staticmethod
+    def is_compatible_with(db):
+        return isinstance(db, Database)
diff --git a/umongo/frameworks/txmongo.py b/umongo/frameworks/txmongo.py
index 8c1164b..700e9f5 100644
--- a/umongo/frameworks/txmongo.py
+++ b/umongo/frameworks/txmongo.py
@@ -6,6 +6,7 @@ from pymongo.errors import DuplicateKeyError
 import marshmallow as ma
 
 from ..builder import BaseBuilder
+from ..instance import Instance
 from ..document import DocumentImplementation
 from ..data_objects import Reference
 from ..exceptions import NotCreatedError, UpdateError, DeleteError, NoneReferenceError
@@ -318,10 +319,6 @@ class TxMongoBuilder(BaseBuilder):
 
     BASE_DOCUMENT_CLS = TxMongoDocument
 
-    @staticmethod
-    def is_compatible_with(db):
-        return isinstance(db, Database)
-
     def _patch_field(self, field):
         super()._patch_field(field)
 
@@ -341,3 +338,14 @@ class TxMongoBuilder(BaseBuilder):
             field.reference_cls = TxMongoReference
         if isinstance(field, EmbeddedField):
             field.io_validate_recursive = _embedded_document_io_validate
+
+
+class TxMongoInstance(Instance):
+    """
+    :class:`umongo.instance.Instance` implementation for txmongo
+    """
+    BUILDER_CLS = TxMongoBuilder
+
+    @staticmethod
+    def is_compatible_with(db):
+        return isinstance(db, Database)
diff --git a/umongo/instance.py b/umongo/instance.py
index bb3ce0c..4a34f37 100644
--- a/umongo/instance.py
+++ b/umongo/instance.py
@@ -1,3 +1,5 @@
+import abc
+
 from .exceptions import (
     NotRegisteredDocumentError, AlreadyRegisteredDocumentError, NoDBDefinedError)
 from .document import DocumentTemplate
@@ -5,9 +7,9 @@ from .embedded_document import EmbeddedDocumentTemplate
 from .template import get_template
 
 
-class BaseInstance:
+class Instance(abc.ABC):
     """
-    Base class for instance.
+    Abstract instance class
 
     Instances aims at collecting and implementing :class:`umongo.template.Template`::
 
@@ -15,7 +17,7 @@ class BaseInstance:
         class Doc(DocumentTemplate):
             pass
 
-        instance = Instance()
+        instance = MyFrameworkInstance()
         # doc_cls is the instance's implementation of Doc
         doc_cls = instance.register(Doc)
         # Implementations are registered as attribute into the instance
@@ -27,22 +29,24 @@ class BaseInstance:
         Instance registration is divided between :class:`umongo.Document` and
         :class:`umongo.EmbeddedDocument`.
     """
-
     BUILDER_CLS = None
 
-    def __init__(self, templates=()):
-        assert self.BUILDER_CLS, 'BUILDER_CLS must be defined.'
+    def __init__(self, db=None):
         self.builder = self.BUILDER_CLS(self)
         self._doc_lookup = {}
         self._embedded_lookup = {}
         self._mixin_lookup = {}
-        for template in templates:
-            self.register(template)
+        self._db = db
+        if db is not None:
+            self.init(db)
 
-    @property
-    def db(self):
-        """Database used within the instance."""
-        raise NotImplementedError
+    @classmethod
+    def from_db(cls, db):
+        from .frameworks import find_instance_from_db
+        instance_cls = find_instance_from_db(db)
+        instance = instance_cls()
+        instance.set_db(db)
+        return instance
 
     def retrieve_document(self, name_or_template):
         """
@@ -127,46 +131,17 @@ class BaseInstance:
         self._mixin_lookup[implementation.__name__] = implementation
         return implementation
 
-
-class Instance(BaseInstance):
-    """
-    Automatically configured instance according to the type of
-    the provided database.
-    """
-
-    def __init__(self, db, templates=()):
-        self._db = db
-        # Dynamically find a builder compatible with the db
-        from .frameworks import find_builder_from_db
-        self.BUILDER_CLS = find_builder_from_db(db)
-        super().__init__(templates=templates)
-
-    @property
-    def db(self):
-        return self._db
-
-
-class LazyLoaderInstance(BaseInstance):
-    """
-    Base class for instance with database lazy loading.
-
-    .. note::
-        This class should not be used directly but instead overloaded.
-        See :class:`umongo.PyMongoInstance` for example.
-
-    """
-
-    def __init__(self, templates=()):
-        self._db = None
-        super().__init__(templates=templates)
-
     @property
     def db(self):
         if not self._db:
-            raise NoDBDefinedError('init must be called to define a db')
+            raise NoDBDefinedError('db not set, please call set_db')
         return self._db
 
-    def init(self, db):
+    @abc.abstractmethod
+    def is_compatible_with(self, db):
+        return NotImplemented
+
+    def set_db(self, db):
         """
         Set the database to use whithin this instance.
 
@@ -174,5 +149,5 @@ class LazyLoaderInstance(BaseInstance):
             The documents registered in the instance cannot be used
             before this function is called.
         """
-        assert self.BUILDER_CLS.is_compatible_with(db)
+        assert self.is_compatible_with(db)
         self._db = db


Test patch:
diff --git a/tests/common.py b/tests/common.py
index a267b23..314862b 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -1,9 +1,9 @@
 import pymongo
 
 from umongo.document import DocumentImplementation
-from umongo.instance import Instance, LazyLoaderInstance
+from umongo.instance import Instance
 from umongo.builder import BaseBuilder
-from umongo.frameworks import register_builder
+from umongo.frameworks import register_instance
 
 
 TEST_DB = 'umongo_test'
@@ -57,22 +57,22 @@ class MockedBuilder(BaseBuilder):
 
     BASE_DOCUMENT_CLS = DocumentImplementation
 
+
+class MockedInstance(Instance):
+    BUILDER_CLS = MockedBuilder
+
     @staticmethod
     def is_compatible_with(db):
         return isinstance(db, MockedDB)
 
 
-register_builder(MockedBuilder)
-
-
-class MockedInstance(LazyLoaderInstance):
-    BUILDER_CLS = MockedBuilder
+register_instance(MockedInstance)
 
 
 class BaseTest:
 
     def setup(self):
-        self.instance = Instance(MockedDB('my_moked_db'))
+        self.instance = Instance.from_db(MockedDB('my_moked_db'))
 
 
 class BaseDBTest:
diff --git a/tests/conftest.py b/tests/conftest.py
index 652dd54..11942e6 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -8,7 +8,7 @@ from umongo.instance import Instance
 @pytest.fixture
 def instance(db):
     # `db` should be a fixture provided by the current framework's testbench
-    return Instance(db)
+    return Instance.from_db(db)
 
 
 @pytest.fixture
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 056a65f..30ad6c8 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -1,61 +1,65 @@
 import pytest
 
-from umongo.frameworks import BuilderRegisterer
+from umongo.frameworks import InstanceRegisterer
 from umongo.builder import BaseBuilder
+from umongo.instance import Instance
 from umongo.document import DocumentImplementation
-from umongo.exceptions import NoCompatibleBuilderError
+from umongo.exceptions import NoCompatibleInstanceError
 
 
 def create_env(prefix):
-    db_cls = type('%sDB' % prefix, (), {})
-    document_cls = type('%sDocument' % prefix, (DocumentImplementation, ), {})
-    builder_cls = type('%sBuilder' % prefix, (BaseBuilder, ), {
+    db_cls = type("f{prefix}DB", (), {})
+    document_cls = type(f"{prefix}Document", (DocumentImplementation, ), {})
+    builder_cls = type(f"{prefix}Builder", (BaseBuilder, ), {
         'BASE_DOCUMENT_CLS': document_cls,
+    })
+    instance_cls = type(f"{prefix}Instance", (Instance, ), {
+        'BUILDER_CLS': builder_cls,
         'is_compatible_with': staticmethod(lambda db: isinstance(db, db_cls))
     })
-    return db_cls, document_cls, builder_cls
+    return db_cls, document_cls, builder_cls, instance_cls
 
 
 class TestBuilder:
 
     def test_basic_builder_registerer(self):
-        registerer = BuilderRegisterer()
-        AlphaDB, AlphaDocument, AlphaBuilder = create_env('Alpha')
+        registerer = InstanceRegisterer()
+        AlphaDB, _, _, AlphaInstance = create_env('Alpha')
 
-        with pytest.raises(NoCompatibleBuilderError):
+        with pytest.raises(NoCompatibleInstanceError):
             registerer.find_from_db(AlphaDB())
-        registerer.register(AlphaBuilder)
-        assert registerer.find_from_db(AlphaDB()) is AlphaBuilder
+        registerer.register(AlphaInstance)
+        assert registerer.find_from_db(AlphaDB()) is AlphaInstance
         # Multiple registers does nothing
-        registerer.register(AlphaBuilder)
-        registerer.unregister(AlphaBuilder)
-        with pytest.raises(NoCompatibleBuilderError):
+        registerer.register(AlphaInstance)
+        registerer.unregister(AlphaInstance)
+        with pytest.raises(NoCompatibleInstanceError):
             registerer.find_from_db(AlphaDB())
 
     def test_multi_builder(self):
-        registerer = BuilderRegisterer()
-        AlphaDB, AlphaDocument, AlphaBuilder = create_env('Alpha')
-        BetaDB, BetaDocument, BetaBuilder = create_env('Beta')
+        registerer = InstanceRegisterer()
+        AlphaDB, _, _, AlphaInstance = create_env('Alpha')
+        BetaDB, _, _, BetaInstance = create_env('Beta')
 
-        registerer.register(AlphaBuilder)
-        assert registerer.find_from_db(AlphaDB()) is AlphaBuilder
-        with pytest.raises(NoCompatibleBuilderError):
+        registerer.register(AlphaInstance)
+        assert registerer.find_from_db(AlphaDB()) is AlphaInstance
+        with pytest.raises(NoCompatibleInstanceError):
             registerer.find_from_db(BetaDB())
-        registerer.register(BetaBuilder)
-        assert registerer.find_from_db(BetaDB()) is BetaBuilder
-        assert registerer.find_from_db(AlphaDB()) is AlphaBuilder
+        registerer.register(BetaInstance)
+        assert registerer.find_from_db(BetaDB()) is BetaInstance
+        assert registerer.find_from_db(AlphaDB()) is AlphaInstance
 
     def test_overload_builder(self):
-        registerer = BuilderRegisterer()
-        AlphaDB, AlphaDocument, AlphaBuilder = create_env('Alpha')
+        registerer = InstanceRegisterer()
+        AlphaDB, _, _, AlphaInstance = create_env('Alpha')
 
-        registerer.register(AlphaBuilder)
+        registerer.register(AlphaInstance)
 
         # Create a new builder compatible with AlphaDB
-        class Alpha2Builder(AlphaBuilder):
+        class Alpha2Instance(AlphaInstance):
             pass
 
-        registerer.register(Alpha2Builder)
+        registerer.register(Alpha2Instance)
 
         # Last registered builder should be tested first
-        assert registerer.find_from_db(AlphaDB()) is Alpha2Builder
+        assert registerer.find_from_db(AlphaDB()) is Alpha2Instance
diff --git a/tests/test_instance.py b/tests/test_instance.py
index 38eb83b..f84eb56 100644
--- a/tests/test_instance.py
+++ b/tests/test_instance.py
@@ -8,9 +8,7 @@ from umongo import Document, fields, EmbeddedDocument
 from umongo.instance import Instance
 from umongo.document import DocumentTemplate, DocumentImplementation
 from umongo.embedded_document import EmbeddedDocumentTemplate, EmbeddedDocumentImplementation
-from umongo.frameworks import (
-    MongoMockInstance, MotorAsyncIOInstance, TxMongoInstance, PyMongoInstance
-)
+import umongo.frameworks
 from umongo.exceptions import (
     AlreadyRegisteredDocumentError, NotRegisteredDocumentError, NoDBDefinedError
 )
@@ -19,13 +17,18 @@ from .common import MockedDB, MockedInstance
 
 
 # Try to retrieve framework's db to test against each of them
-DB_AND_INSTANCE_PER_FRAMEWORK = [(MockedDB('my_db'), MockedInstance)]
-for name, inst in (('mongomock', MongoMockInstance),
-                   ('motor_asyncio', MotorAsyncIOInstance),
-                   ('txmongo', TxMongoInstance),
-                   ('pymongo', PyMongoInstance)):
-    mod = importlib.import_module('tests.frameworks.test_%s' % name)
-    if not mod.dep_error:
+DB_AND_INSTANCE_PER_FRAMEWORK = [
+    (MockedDB('my_db'), MockedInstance),
+]
+for mod_name, inst_name in (
+        ('mongomock', 'MongoMockInstance'),
+        ('motor_asyncio', 'MotorAsyncIOInstance'),
+        ('txmongo', 'TxMongoInstance'),
+        ('pymongo', 'PyMongoInstance'),
+):
+    inst = getattr(umongo.frameworks, inst_name, None)
+    if inst is not None:
+        mod = importlib.import_module(f"tests.frameworks.test_{mod_name}")
         DB_AND_INSTANCE_PER_FRAMEWORK.append((mod.make_db(), inst))
 
 
@@ -74,8 +77,8 @@ class TestInstance:
             Doc2(nested={})
 
     def test_multiple_instances(self, db):
-        instance1 = Instance(db)
-        instance2 = Instance(db)
+        instance1 = Instance.from_db(db)
+        instance2 = Instance.from_db(db)
 
         class Doc(Document):
             pass
@@ -98,8 +101,8 @@ class TestInstance:
         assert Embedded2.opts.instance is instance2
 
     def test_register_other_implementation(self, db):
-        instance1 = Instance(db)
-        instance2 = Instance(db)
+        instance1 = Instance.from_db(db)
+        instance2 = Instance.from_db(db)
 
         class Doc(Document):
             pass
@@ -181,17 +184,17 @@ class TestInstance:
 
         doc_impl_cls = instance.register(Doc)
 
-        with pytest.raises(NoDBDefinedError):
+        with pytest.raises(NoDBDefinedError, match="db not set, please call set_db"):
             doc_impl_cls.collection
 
-        instance.init(db)
+        instance.set_db(db)
 
         assert doc_impl_cls.collection == db['doc']
 
     def test_patched_fields(self, db):
 
-        instance1 = Instance(db)
-        instance2 = Instance(db)
+        instance1 = Instance.from_db(db)
+        instance2 = Instance.from_db(db)
 
         class Embedded(EmbeddedDocument):
             simple = fields.IntField()