Ejemplo n.º 1
0
    def __get__(self, instance, owner):

        if instance is None:
            return self

        # The thing here is that I don't want to dereference lists
        # references in embedded documents now. It has the advantage of
        # keeping the same API for embedded documents and references
        # (ie returning a future for references and not a future for
        # embedded documentts) and the disadvantage of not being able to
        # retrieve all references in bulk.
        value = super(fields.ComplexBaseField, self).__get__(instance, owner)
        if isinstance(value, (list, dict, tuple, BaseList, BaseDict)):
            value = self._convert_value(instance, value)
            # It is not in fact dereferenced, we are cheating.
            value._dereferenced = True
        super_meth = super().__get__
        if isinstance(self.field, ReferenceField) and self._auto_dereference \
           and greenlet.getcurrent().parent is None:
            # we only need to asynchronize this if we we are not in a
            # child greenlet
            r = asynchronize(super_meth)(instance, owner)
        else:
            r = super_meth(instance, owner)

        return r
Ejemplo n.º 2
0
    def __getitem__(self, index):
        # If we received an slice we will return a queryset
        # and as we will not touch the db now we do not need a future
        # here
        if isinstance(index, slice):
            return super().__getitem__(index)

        else:
            sync_getitem = BaseQuerySet.__getitem__
            async_getitem = asynchronize(sync_getitem)
            return async_getitem(self, index)
Ejemplo n.º 3
0
    def insert(self, doc_or_docs, load_bulk=True, write_concern=None):
        """bulk insert documents

        :param doc_or_docs: a document or list of documents to be inserted
        :param load_bulk (optional): If True returns the list of document
            instances
        :param write_concern: Extra keyword arguments are passed down to
                :meth:`~pymongo.collection.Collection.insert`
                which will be used as options for the resultant
                ``getLastError`` command.  For example,
                ``insert(..., {w: 2, fsync: True})`` will wait until at least
                two servers have recorded the write and will force an fsync on
                each server being written to.

        By default returns document instances, set ``load_bulk`` to False to
        return just ``ObjectIds``
        """

        super_insert = BaseQuerySet.insert
        async_in_bulk = self.in_bulk
        # this sync method is not really sync, it uses motor sockets and
        # greenlets events, but looks like sync, so...
        sync_in_bulk = functools.partial(self.in_bulk.__wrapped__, self)
        insert_future = get_future(self)

        with MonkeyPatcher() as patcher:
            # here we change the method with the async api for the method
            # with a sync api so I don't need to rewrite the mongoengine
            # method.
            patcher.patch_item(self, 'in_bulk', sync_in_bulk, undo=False)
            future = asynchronize(super_insert)(self,
                                                doc_or_docs,
                                                load_bulk=load_bulk,
                                                write_concern=write_concern)

            def cb(future):
                try:
                    result = future.result()
                    insert_future.set_result(result)
                except Exception as e:
                    insert_future.set_exception(e)
                finally:
                    patcher.patch_item(self,
                                       'in_bulk',
                                       async_in_bulk,
                                       undo=False)

            future.add_done_callback(cb)

        return insert_future
Ejemplo n.º 4
0
    def __get__(self, instance, owner):
        # When we are getting the field from a class not from an
        # instance we don't need a Future
        if instance is None:
            return self

        meth = super().__get__
        if self._auto_dereference:
            if isinstance(instance, EmbeddedDocument):
                # It's used when there's a reference in a EmbeddedDocument.
                # We use it to get the async framework to be used.
                instance._get_db = self.document_type._get_db
            meth = asynchronize(meth)

        return meth(instance, owner)
Ejemplo n.º 5
0
    def test_find_references(self):

        ref = self.test_ref(attr='bla')
        yield from ref.save()

        doc = self.test_cls(someattr='ble', ref=ref)
        yield from doc.save()

        qs = self.test_cls.objects

        def find_ref(*a, **kw):
            qs._dereference.max_depth = 1
            qs._dereference(*a, **kw)
            return qs._dereference.reference_map

        find_ref = asynchronize(find_ref)
        ref_map = yield from find_ref(qs)
        for doc in ref_map.keys():
            self.assertTrue(doc.__name__.startswith('Patched'))
Ejemplo n.º 6
0
    def test_asynchornize_cls(self):

        test_mock = Mock()

        class TestClass:
            @classmethod
            def _get_db(cls):
                db = Mock()
                db._framework = asyncio_framework
                return db

            @classmethod
            def sync(cls):
                test_mock()

        TestClass.sync = metaprogramming.asynchronize(TestClass.sync.__func__,
                                                      cls_meth=True)
        self.assertTrue(isinstance(TestClass.sync(), Future))

        yield from TestClass.sync()
        self.assertTrue(test_mock.called)
Ejemplo n.º 7
0
    def delete(self,
               write_concern=None,
               _from_doc_delete=False,
               cascade_refs=None):
        """Deletes the documents matched by the query.

        :param write_concern: Extra keyword arguments are passed down which
            will be used as options for the resultant
            ``getLastError`` command.  For example,
            ``save(..., write_concern={w: 2, fsync: True}, ...)`` will
            wait until at least two servers have recorded the write and
            will force an fsync on the primary server.
        :param _from_doc_delete: True when called from document delete
          therefore signals will have been triggered so don't loop.

        :returns number of deleted documents
        """

        queryset = self.clone()
        doc = queryset._document

        if write_concern is None:
            write_concern = {}

        # Handle deletes where skips or limits have been applied or
        # there is an untriggered delete signal
        has_delete_signal = signals.signals_available and (
            signals.pre_delete.has_receivers_for(self._document)
            or signals.post_delete.has_receivers_for(self._document))

        call_document_delete = (queryset._skip or queryset._limit
                                or has_delete_signal) and not _from_doc_delete

        if call_document_delete:
            async_method = asynchronize(self._document_delete)
            return async_method(queryset, write_concern)

        dr_future = self._check_delete_rules(doc, queryset, cascade_refs,
                                             write_concern)

        ret_future = get_future(self)

        def dr_cb(dr_future):
            """callback for _check_delete_rules future"""
            try:
                dr_future.result()

                remove_future = queryset._collection.remove(
                    queryset._query, **write_concern)

                def r_cb(remove_future):
                    """Callback for _collection.remove"""

                    try:
                        result = remove_future.result()
                        if result:
                            ret_future.set_result(result.get('n'))
                    except Exception as e:
                        ret_future.set_exception(e)

                remove_future.add_done_callback(r_cb)

            except Exception as e:
                ret_future.set_exception(e)

        dr_future.add_done_callback(dr_cb)
        return ret_future