Added CollectionManager, made connection module
All connection-related functions are now in connection.py. Created a ConnectionManager class for interacting with a collection in the database. Top-level document classes have an instance of a ConnectionManager (Document.collection). Defined a 'save' method on top-level document's that uses the collection manager's '_save_document' method to save the document to the database. Added tests for CollectionManagers -- all unit tests now require a valid connection to the database, which is set up in the tests' setUp method.
This commit is contained in:
parent
688fd5af66
commit
c99f5c4ec1
@ -2,39 +2,11 @@ import document
|
||||
from document import *
|
||||
import fields
|
||||
from fields import *
|
||||
import connection
|
||||
from connection import *
|
||||
|
||||
from pymongo import Connection
|
||||
|
||||
__all__ = document.__all__ + fields.__all__ + ['connect']
|
||||
__all__ = document.__all__ + fields.__all__ + connection.__all__
|
||||
|
||||
__author__ = 'Harry Marr'
|
||||
__version__ = '0.1'
|
||||
|
||||
_connection_settings = {
|
||||
'host': 'localhost',
|
||||
'port': 27017,
|
||||
'pool_size': 1,
|
||||
}
|
||||
_connection = None
|
||||
_db = None
|
||||
|
||||
def _get_connection():
|
||||
if _connection is None:
|
||||
_connection = Connection(**_connection_settings)
|
||||
return _connection
|
||||
|
||||
def connect(db=None, username=None, password=None, **kwargs):
|
||||
"""Connect to the database specified by the 'db' argument. Connection
|
||||
settings may be provided here as well if the database is not running on
|
||||
the default port on localhost. If authentication is needed, provide
|
||||
username and password arguments as well.
|
||||
"""
|
||||
if db is None:
|
||||
raise TypeError('"db" argument must be provided to connect()')
|
||||
|
||||
_connection_settings.update(kwargs)
|
||||
connection = _get_connection()
|
||||
# Get DB from connection and auth if necessary
|
||||
_db = connection[db]
|
||||
if username is not None and password is not None:
|
||||
_db.authenticate(username, password)
|
||||
|
@ -1,3 +1,4 @@
|
||||
from collection import CollectionManager
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
@ -128,7 +129,13 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
|
||||
}
|
||||
meta.update(attrs.get('meta', {}))
|
||||
attrs['_meta'] = meta
|
||||
return super_new(cls, name, bases, attrs)
|
||||
|
||||
# Set up collection manager, needs the class to have fields so use
|
||||
# DocumentMetaclass before instantiating CollectionManager object
|
||||
new_class = super_new(cls, name, bases, attrs)
|
||||
setattr(new_class, 'collection', CollectionManager(new_class))
|
||||
|
||||
return new_class
|
||||
|
||||
|
||||
class BaseDocument(object):
|
||||
@ -141,7 +148,7 @@ class BaseDocument(object):
|
||||
setattr(self, attr_name, values.pop(attr_name))
|
||||
else:
|
||||
if attr_value.required:
|
||||
raise ValidationError('Field "%s" is required' % self.name)
|
||||
raise ValidationError('Field "%s" is required' % attr_name)
|
||||
# Use default value
|
||||
setattr(self, attr_name, getattr(self, attr_name, None))
|
||||
|
||||
@ -179,4 +186,9 @@ class BaseDocument(object):
|
||||
def _to_mongo(self):
|
||||
"""Return data dictionary ready for use with MongoDB.
|
||||
"""
|
||||
return dict((k, v) for k, v in self._data.items() if v is not None)
|
||||
data = {}
|
||||
for field_name, field in self._fields.items():
|
||||
value = getattr(self, field_name, None)
|
||||
if value is not None:
|
||||
data[field_name] = field._to_mongo(value)
|
||||
return data
|
||||
|
18
mongomap/collection.py
Normal file
18
mongomap/collection.py
Normal file
@ -0,0 +1,18 @@
|
||||
from connection import _get_db
|
||||
|
||||
class CollectionManager(object):
|
||||
|
||||
def __init__(self, document):
|
||||
"""Set up the collection manager for a specific document.
|
||||
"""
|
||||
db = _get_db()
|
||||
self._document = document
|
||||
self._collection_name = document._meta['collection']
|
||||
# This will create the collection if it doesn't exist
|
||||
self._collection = db[self._collection_name]
|
||||
self._id_field = document._meta['object_id_field']
|
||||
|
||||
def _save_document(self, document):
|
||||
"""Save the provided document to the collection.
|
||||
"""
|
||||
_id = self._collection.save(document)
|
48
mongomap/connection.py
Normal file
48
mongomap/connection.py
Normal file
@ -0,0 +1,48 @@
|
||||
from pymongo import Connection
|
||||
|
||||
|
||||
__all__ = ['ConnectionError', 'connect']
|
||||
|
||||
|
||||
_connection_settings = {
|
||||
'host': 'localhost',
|
||||
'port': 27017,
|
||||
'pool_size': 1,
|
||||
}
|
||||
_connection = None
|
||||
_db = None
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _get_connection():
|
||||
global _connection
|
||||
if _connection is None:
|
||||
_connection = Connection(**_connection_settings)
|
||||
return _connection
|
||||
|
||||
def _get_db():
|
||||
global _db
|
||||
if _db is None:
|
||||
raise ConnectionError('Not connected to database')
|
||||
return _db
|
||||
|
||||
def connect(db=None, username=None, password=None, **kwargs):
|
||||
"""Connect to the database specified by the 'db' argument. Connection
|
||||
settings may be provided here as well if the database is not running on
|
||||
the default port on localhost. If authentication is needed, provide
|
||||
username and password arguments as well.
|
||||
"""
|
||||
global _db
|
||||
if db is None:
|
||||
raise TypeError('"db" argument must be provided to connect()')
|
||||
|
||||
_connection_settings.update(kwargs)
|
||||
connection = _get_connection()
|
||||
# Get DB from connection and auth if necessary
|
||||
_db = connection[db]
|
||||
if username is not None and password is not None:
|
||||
_db.authenticate(username, password)
|
||||
|
@ -1,7 +1,5 @@
|
||||
from base import DocumentMetaclass, TopLevelDocumentMetaclass, BaseDocument
|
||||
|
||||
#import pymongo
|
||||
|
||||
|
||||
__all__ = ['Document', 'EmbeddedDocument']
|
||||
|
||||
@ -15,3 +13,5 @@ class Document(BaseDocument):
|
||||
|
||||
__metaclass__ = TopLevelDocumentMetaclass
|
||||
|
||||
def save(self):
|
||||
self.collection._save_document(self._to_mongo())
|
||||
|
@ -61,7 +61,13 @@ class EmbeddedDocumentField(BaseField):
|
||||
def _to_python(self, value):
|
||||
return value
|
||||
|
||||
def _to_mongo(self, value):
|
||||
return self.document._to_mongo(value)
|
||||
|
||||
def _validate(self, value):
|
||||
"""Make sure that the document instance is an instance of the
|
||||
EmbeddedDocument subclass provided when the document was defined.
|
||||
"""
|
||||
if not isinstance(value, self.document):
|
||||
raise ValidationError('Invalid embedded document instance '
|
||||
'provided to an EmbeddedDocumentField')
|
||||
|
33
tests/collection.py
Normal file
33
tests/collection.py
Normal file
@ -0,0 +1,33 @@
|
||||
import unittest
|
||||
import pymongo
|
||||
|
||||
from mongomap.collection import CollectionManager
|
||||
from mongomap import *
|
||||
|
||||
|
||||
class CollectionManagerTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
connect(db='mongotest')
|
||||
|
||||
class Person(Document):
|
||||
name = StringField()
|
||||
age = IntField()
|
||||
self.Person = Person
|
||||
|
||||
def test_initialisation(self):
|
||||
"""Ensure that CollectionManager is correctly initialised.
|
||||
"""
|
||||
class Person(Document):
|
||||
name = StringField()
|
||||
age = IntField()
|
||||
|
||||
self.assertTrue(isinstance(Person.collection, CollectionManager))
|
||||
self.assertEqual(Person.collection._collection_name,
|
||||
Person._meta['collection'])
|
||||
self.assertTrue(isinstance(Person.collection._collection,
|
||||
pymongo.collection.Collection))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,16 +1,22 @@
|
||||
import unittest
|
||||
|
||||
from mongomap import *
|
||||
from mongomap.connection import _get_db
|
||||
|
||||
|
||||
class DocumentTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
connect(db='mongomaptest')
|
||||
|
||||
class Person(Document):
|
||||
name = StringField()
|
||||
age = IntField()
|
||||
self.Person = Person
|
||||
|
||||
self.db = _get_db()
|
||||
self.db.drop_collection(self.Person._meta['collection'])
|
||||
|
||||
def test_definition(self):
|
||||
"""Ensure that document may be defined using fields.
|
||||
"""
|
||||
@ -77,6 +83,45 @@ class DocumentTest(unittest.TestCase):
|
||||
self.assertTrue('content' in Comment._fields)
|
||||
self.assertFalse(hasattr(Comment, '_meta'))
|
||||
|
||||
def test_save(self):
|
||||
"""Ensure that a document may be saved in the database.
|
||||
"""
|
||||
# Create person object and save it to the database
|
||||
person = self.Person(name='Test User', age=30)
|
||||
person.save()
|
||||
# Ensure that the object is in the database
|
||||
collection = self.db[self.Person._meta['collection']]
|
||||
person_obj = collection.find_one({'name': 'Test User'})
|
||||
self.assertEqual(person_obj['name'], 'Test User')
|
||||
self.assertEqual(person_obj['age'], 30)
|
||||
|
||||
def test_save_embedded_document(self):
|
||||
"""Ensure that a document with an embedded document field may be
|
||||
saved in the database.
|
||||
"""
|
||||
class EmployeeDetails(EmbeddedDocument):
|
||||
position = StringField()
|
||||
|
||||
class Employee(self.Person):
|
||||
salary = IntField()
|
||||
details = EmbeddedDocumentField(EmployeeDetails)
|
||||
|
||||
# Create employee object and save it to the database
|
||||
employee = Employee(name='Test Employee', age=50, salary=20000)
|
||||
employee.details = EmployeeDetails(position='Developer')
|
||||
employee.save()
|
||||
|
||||
# Ensure that the object is in the database
|
||||
collection = self.db[self.Person._meta['collection']]
|
||||
employee_obj = collection.find_one({'name': 'Test Employee'})
|
||||
self.assertEqual(employee_obj['name'], 'Test Employee')
|
||||
self.assertEqual(employee_obj['age'], 50)
|
||||
# Ensure that the 'details' embedded object saved correctly
|
||||
self.assertEqual(employee_obj['details']['position'], 'Developer')
|
||||
|
||||
def tearDown(self):
|
||||
self.db.drop_collection(self.Person._meta['collection'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -5,6 +5,9 @@ from mongomap import *
|
||||
|
||||
class FieldTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
connect(db='mongomaptest')
|
||||
|
||||
def test_default_values(self):
|
||||
"""Ensure that default field values are used when creating a document.
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user