diff --git a/mongomap/__init__.py b/mongomap/__init__.py index 1b7da2b3..eb72c30a 100644 --- a/mongomap/__init__.py +++ b/mongomap/__init__.py @@ -3,7 +3,38 @@ from document import * import fields from fields import * -__all__ = document.__all__ + fields.__all__ +from pymongo import Connection + +__all__ = document.__all__ + fields.__all__ + ['connect'] __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) diff --git a/mongomap/base.py b/mongomap/base.py index 3138e426..ddae4615 100644 --- a/mongomap/base.py +++ b/mongomap/base.py @@ -24,12 +24,13 @@ class BaseField(object): # Get value from document instance if available, if not use default value = instance._data.get(self.name) - if value is not None: - value = self._to_python(value) - elif self.default is not None: - value = self.default - if callable(value): - value = value() + if value is None: + if self.default is not None: + value = self.default + if callable(value): + value = value() + else: + raise AttributeError(self.name) return value def __set__(self, instance, value): @@ -40,7 +41,6 @@ class BaseField(object): try: value = self._to_python(value) self._validate(value) - value = self._to_mongo(value) except ValueError: raise ValidationError('Invalid value for field of type "' + self.__class__.__name__ + '"') @@ -61,7 +61,7 @@ class BaseField(object): def _validate(self, value): """Perform validation on a value. """ - return value + pass class DocumentMetaclass(type): @@ -143,7 +143,7 @@ class BaseDocument(object): if attr_value.required: raise ValidationError('Field "%s" is required' % self.name) # Use default value - setattr(self, attr_name, getattr(self, attr_name)) + setattr(self, attr_name, getattr(self, attr_name, None)) def __iter__(self): # Use _data rather than _fields as iterator only looks at names so @@ -161,11 +161,21 @@ class BaseDocument(object): def __setitem__(self, name, value): """Dictionary-style field access, set a field's value. """ - # Ensure that the field exists before settings its value + # Ensure that the field exists before settings its value if name not in self._fields: raise KeyError(name) return setattr(self, name, value) + def __contains__(self, name): + try: + getattr(self, name) + return True + except AttributeError: + return False + + def __len__(self): + return len(self._data) + def _to_mongo(self): """Return data dictionary ready for use with MongoDB. """ diff --git a/tests/document.py b/tests/document.py index 862cbe97..177560f1 100644 --- a/tests/document.py +++ b/tests/document.py @@ -61,6 +61,13 @@ class DocumentTest(unittest.TestCase): person['name'] = 'Another User' self.assertEquals(person['name'], 'Another User') + self.assertEquals(len(person), 2) + + self.assertTrue('age' in person) + person.age = None + self.assertFalse('age' in person) + self.assertFalse('nationality' in person) + def test_embedded_document(self): """Ensure that embedded documents are set up correctly. """