Source code for mongomotor.core

# -*- coding: utf-8 -*-

# Copyright 2016 Juca Crispim <juca@poraodojuca.net>

# This file is part of mongomotor.

# mongomotor is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# mongomotor is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with mongomotor. If not, see <http://www.gnu.org/licenses/>.

import types
from motor.core import (AgnosticCollection, AgnosticClient, AgnosticDatabase,
                        AgnosticCursor)
from motor.metaprogramming import create_class_with_framework
import pymongo
from pymongo.database import Database
from pymongo.collection import Collection
from mongomotor.metaprogramming import OriginalDelegate


def _rebound(ret, obj):
    try:
        ret = types.MethodType(ret.__func__, obj)
    except AttributeError:
        pass
    return ret


[docs]class MongoMotorAgnosticCursor(AgnosticCursor): __motor_class_name__ = 'MongoMotorCursor' distinct = OriginalDelegate() explain = OriginalDelegate() def __init__(self, *args, **kwargs): super(AgnosticCursor, self).__init__(*args, **kwargs) # here we get the mangled stuff in the delegate class and # set here attrs = [a for a in dir(self.delegate) if a.startswith('_Cursor__')] for attr in attrs: setattr(self, attr, getattr(self.delegate, attr)) # these are used internally. If you try to # iterate using for in a main greenlet you will # see an exception. # To iterate use a queryset and iterate using motor style # with fetch_next/next_object def __iter__(self): return self def __next__(self): return next(self.delegate) def __getitem__(self, index): r = self.delegate[index] if isinstance(r, type(self.delegate)): # If the response is a cursor, transform it into a # mongomotor cursor. r = type(self)(r, self.collection) return r
# @aiter_compat # def __aiter__(self): # return self # async def __anext__(self): # # An optimization: skip the "await" if possible. # if self._buffer_size() or await self.fetch_next: # return self.next_object() # raise StopAsyncIteration()
[docs]class MongoMotorAgnosticCollection(AgnosticCollection): __motor_class_name__ = 'MongoMotorCollection' # Using the original delegate method (but with motor pool and event) # so I don't get a future as the return value and don't need to work # with mongoengine code. # insert = OriginalDelegate() insert_many = OriginalDelegate() insert_one = OriginalDelegate() # save = OriginalDelegate() # update = OriginalDelegate() update_one = OriginalDelegate() update_many = OriginalDelegate() find_one = OriginalDelegate() # find_and_modify = OriginalDelegate() find_one_and_update = OriginalDelegate() find_one_and_delete = OriginalDelegate() index_information = OriginalDelegate() def __init__(self, database, name, _delegate=None): db_class = create_class_with_framework( MongoMotorAgnosticDatabase, self._framework, self.__module__) if not isinstance(database, db_class): raise TypeError("First argument to MongoMotorCollection must be " "MongoMotorDatabase, not %r" % database) delegate = _delegate if _delegate is not None else\ Collection(database.delegate, name) super(AgnosticCollection, self).__init__(delegate) self.database = database def __getattr__(self, name): if name.startswith('_'): # Here first I try to get the _attribute from # from the delegate obj. try: ret = getattr(self.delegate, name) except AttributeError: raise AttributeError( "%s has no attribute %r. To access the %s" " collection, use collection['%s']." % ( self.__class__.__name__, name, name, name)) return _rebound(ret, self) return self[name] def __getitem__(self, name): collection_class = create_class_with_framework( MongoMotorAgnosticCollection, self._framework, self.__module__) return collection_class(self.database, self.name + '.' + name)
[docs] def find(self, *args, **kwargs): """Create a :class:`MongoMotorAgnosticCursor`. Same parameters as for PyMongo's :meth:`~pymongo.collection.Collection.find`. Note that ``find`` does not take a `callback` parameter, nor does it return a Future, because ``find`` merely creates a :class:`MongoMotorAgnosticCursor` without performing any operations on the server. ``MongoMotorAgnosticCursor`` methods such as :meth:`~MongoMotorAgnosticCursor.to_list` or :meth:`~MongoMotorAgnosticCursor.count` perform actual operations. """ if 'callback' in kwargs: raise pymongo.errors.InvalidOperation( "Pass a callback to each, to_list, or count, not to find.") cursor = self.delegate.find(*args, **kwargs) cursor_class = create_class_with_framework( MongoMotorAgnosticCursor, self._framework, self.__module__) return cursor_class(cursor, self)
[docs]class MongoMotorAgnosticDatabase(AgnosticDatabase): __motor_class_name__ = 'MongoMotorDatabase' dereference = OriginalDelegate() # authenticate = OriginalDelegate() def __init__(self, client, name, _delegate=None): if not isinstance(client, AgnosticClient): raise TypeError("First argument to MongoMotorDatabase must be " "a Motor client, not %r" % client) self._client = client delegate = _delegate or Database(client.delegate, name) super(AgnosticDatabase, self).__init__(delegate) def __getattr__(self, name): if name.startswith('_'): # samething. try get from delegate first try: ret = getattr(self.delegate, name) except AttributeError: raise AttributeError( "%s has no attribute %r. To access the %s" " collection, use database['%s']." % ( self.__class__.__name__, name, name, name)) return _rebound(ret, self) return self[name] def __getitem__(self, name): collection_class = create_class_with_framework( MongoMotorAgnosticCollection, self._framework, self.__module__) return collection_class(self, name)
[docs] def eval(self, code, *fields): return self.command('eval', code, *fields)
[docs]class MongoMotorAgnosticClientBase(AgnosticClient): # max_write_batch_size = ReadOnlyProperty() def __getattr__(self, name): if name.startswith('_'): # the same. Try get from delegate. try: ret = getattr(self.delegate, name) except AttributeError: raise AttributeError( "%s has no attribute %r. To access the %s" " database, use client['%s']." % ( self.__class__.__name__, name, name, name)) return _rebound(ret, self) return self[name] def __getitem__(self, name): db_class = create_class_with_framework( MongoMotorAgnosticDatabase, self._framework, self.__module__) return db_class(self, name)
[docs]class MongoMotorAgnosticClient(MongoMotorAgnosticClientBase, AgnosticClient): __motor_class_name__ = 'MongoMotorClient'