Commits

Thomas Waldmann committed ac21bb4

implemented mongodb store, add pymongo to setup.py

  • Participants
  • Parent commits 614005b

Comments (0)

Files changed (4)

MoinMoin/storage/stores/_tests/conftest.py

 except Exception:
     pass
 
+try:
+    # check if we can connect to the mongodb server
+    check_connection(27017)
+    STORES.append('mongodb')
+except Exception:
+    pass
+
 constructors = {
     'memory': lambda store, _: store(),
     'fs': lambda store, tmpdir: store(str(tmpdir.join('store'))),
                                           'test_table', compression_level=1),
     'kc': lambda store, tmpdir: store(str(tmpdir.join('store.kch'))),
     'kt': lambda store, _: store(),
+    'mongodb': lambda store, _: store(),
     'sqla': lambda store, tmpdir: store('sqlite:///{0!s}'.format(tmpdir.join('store.sqlite')),
                                         'test_table'),
 }
     store = construct(klass, tmpdir)
     store.create()
     store.open()
-    # no destroy in the normal finalizer
-    # so we can keep the data for example if it's a tmpdir
     request.addfinalizer(store.close)
+    # for debugging, you can disable the next line to see the stuff in the
+    # store and examine it, but usually we want to clean up afterwards:
+    request.addfinalizer(store.destroy)
     return store
 
 
     storename, kind = request.param
     if kind == 'FileStore':
         store = ByteToStreamWrappingStore(store)
+    # store here always is a ByteStore and can be tested as such
     return store

MoinMoin/storage/stores/_tests/test_mongodb.py

+# Copyright: 2011 MoinMoin:RonnyPfannschmidt
+# Copyright: 2012 Ionut Artarisi <ionut@artarisi.eu>
+# Copyright: 2012 MoinMoin:ThomasWaldmann
+# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
+
+"""
+MoinMoin - mongodb store tests
+"""
+
+import pytest
+pytest.importorskip('MoinMoin.storage.stores.mongodb')
+from ..mongodb import BytesStore, FileStore
+
+from MoinMoin._tests import check_connection
+try:
+    check_connection(27017)
+except Exception as err:
+    pytest.skip(str(err))
+
+
+@pytest.mark.multi(Store=[BytesStore, FileStore])
+def test_create(Store):
+    store = Store()
+    store.create()
+    return store
+
+@pytest.mark.multi(Store=[BytesStore, FileStore])
+def test_destroy(Store):
+    store = Store()
+    store.destroy()
+
+@pytest.mark.multi(Store=[BytesStore, FileStore])
+def test_from_uri(Store):
+    store = Store.from_uri("mongodb://localhost/test_base::test_coll")
+    assert store.uri == 'mongodb://localhost/test_base'
+    assert store.collection_name == 'test_coll'

MoinMoin/storage/stores/mongodb.py

+# Copyright: 2012 Ionut Artarisi <ionut@artarisi.eu>
+# Copyright: 2012 MoinMoin:ThomasWaldmann
+# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
+
+"""
+MoinMoin - mongodb store
+
+Stores k/v pairs into a MongoDB server using pymongo.
+"""
+
+from __future__ import absolute_import, division
+
+import pymongo, gridfs
+
+from . import MutableStoreBase, BytesMutableStoreBase, FileMutableStoreBase
+
+
+class _Store(MutableStoreBase):
+    """
+    MongoDB based store.
+    """
+    @classmethod
+    def from_uri(cls, uri):
+        params = uri.split('::') # moin_uri -> mongodb_uri::collection_name
+        return cls(*params)
+
+    def __init__(self, uri='mongodb://127.0.0.1/moin_db', collection_name='moin_coll'):
+        """
+        Store params for .open().
+
+        :param uri: MongoDB server uri
+        """
+        self.uri = uri
+        self.dbname = uri.rsplit('/', 1)[-1]
+        self.collection_name = collection_name
+
+    def create(self):
+        pass
+
+    def open(self):
+        self.conn = pymongo.Connection(self.uri)
+        self.db = self.conn[self.dbname]
+        self.coll = self.db[self.collection_name]
+
+    def close(self):
+        self.conn.close()
+
+
+class BytesStore(_Store, BytesMutableStoreBase):
+    def destroy(self):
+        self.open()
+        self.db.drop_collection(self.coll)
+        self.close()
+
+    def __getitem__(self, key):
+        d = self.coll.find_one(dict(key=key))
+        if d is None:
+            raise KeyError(key)
+        return d['value']
+
+    def __setitem__(self, key, value):
+        self.coll.insert(dict(key=key, value=value))
+
+    def __delitem__(self, key):
+        self.coll.remove(dict(key=key))
+
+    def __iter__(self):
+        for result in self.coll.find(fields=['key']):
+            yield result['key']
+
+
+class FileStore(_Store, FileMutableStoreBase):
+    def open(self):
+        super(FileStore, self).open()
+        self.gridfs = gridfs.GridFS(self.db, self.collection_name)
+
+    def destroy(self):
+        self.open()
+        self.db.drop_collection(self.coll.files)
+        self.db.drop_collection(self.coll.chunks)
+        self.db.drop_collection(self.coll)
+        self.close()
+
+    def __getitem__(self, key):
+        try:
+            value = self.gridfs.get(key)
+        except gridfs.NoFile:
+            raise KeyError(key)
+        return value
+
+    def __setitem__(self, key, stream):
+        self.gridfs.delete(key)
+        self.gridfs.put(stream, _id=key)
+
+    def __delitem__(self, key):
+        self.gridfs.delete(key)
+
+    def __iter__(self):
+        for result in self.coll.files.find(fields=['_id']):
+            yield result['_id']
         'ldap': ["python-ldap>=2.0.0"], # used by ldap auth
         'openid': ["python-openid>=2.2.4"], # used by openid rp auth
         'sqla': ["sqlalchemy>=0.7.1"], # used by sqla store
+        'mongodb': ["pymongo"], # used by mongodb store
     },
     entry_points=dict(
         console_scripts=['moin = MoinMoin.script:main'],