Compare commits

...

15 Commits

Author SHA1 Message Date
Stefan Wojcik
8a84398cf6 fix .travis.yml 2016-11-28 18:16:06 -05:00
Stefan Wojcik
5de80f0327 restore the virtualenv install in travis 2016-11-28 17:00:36 -05:00
Stefan Wojcik
ea91383558 fix a test that fails from time to time depending on an order of a dict 2016-11-28 16:56:18 -05:00
Stefan Wojcik
081b0e1edd remove an unused variable 2016-11-28 16:32:18 -05:00
Stefan Wojcik
5f2cd8ac75 flake8 tweaks for mongoengine.queryset 2016-11-28 16:21:02 -05:00
Stefan Wojcik
f2b8dcf292 flake8 tweaks for mongoengine.base 2016-11-28 16:15:46 -05:00
Stefan Wojcik
e2097061e9 flake8 tweaks to mongoengine.fields + ignore tests for now 2016-11-28 16:06:38 -05:00
Stefan Wojcik
c72465cbb4 flake8 tweaks for mongoengine.document 2016-11-28 16:00:56 -05:00
Stefan Wojcik
5d093e1011 flake8 tweaks for mongoengine.dereference 2016-11-28 15:56:28 -05:00
Stefan Wojcik
13ddef2033 flake8 tweaks to mongoengine/__init__.py 2016-11-28 15:53:40 -05:00
Stefan Wojcik
0229ebff4b flake8 tweaks to setup.py 2016-11-28 15:52:11 -05:00
Stefan Wojcik
fd8cfbf610 flake8 tweaks to tests.queryset.queryset 2016-11-28 15:49:30 -05:00
Stefan Wojcik
43adba115b flake8 tweaks to tests.queryset.transform 2016-11-28 15:22:38 -05:00
Stefan Wojcik
3985bd3e53 flake8 tweaks to tests.queryset.visitor 2016-11-28 15:17:32 -05:00
Stefan Wojcik
c35dab9541 add flake8 and flake8-import-order to travis for py27 2016-11-28 15:17:01 -05:00
22 changed files with 354 additions and 299 deletions

View File

@ -1,4 +1,5 @@
language: python language: python
python: python:
- '2.6' - '2.6'
- '2.7' - '2.7'
@ -7,35 +8,51 @@ python:
- '3.5' - '3.5'
- pypy - pypy
- pypy3 - pypy3
env: env:
- PYMONGO=2.7 - PYMONGO=2.7
- PYMONGO=2.8 - PYMONGO=2.8
- PYMONGO=3.0 - PYMONGO=3.0
- PYMONGO=dev - PYMONGO=dev
matrix: matrix:
fast_finish: true fast_finish: true
before_install: before_install:
- travis_retry sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 - travis_retry sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
- echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | - echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' |
sudo tee /etc/apt/sources.list.d/mongodb.list sudo tee /etc/apt/sources.list.d/mongodb.list
- travis_retry sudo apt-get update - travis_retry sudo apt-get update
- travis_retry sudo apt-get install mongodb-org-server - travis_retry sudo apt-get install mongodb-org-server
install: install:
- sudo apt-get install python-dev python3-dev libopenjpeg-dev zlib1g-dev libjpeg-turbo8-dev - sudo apt-get install python-dev python3-dev libopenjpeg-dev zlib1g-dev libjpeg-turbo8-dev
libtiff4-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev libtiff4-dev libjpeg8-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev
python-tk python-tk
# virtualenv>=14.0.0 has dropped Python 3.2 support - travis_retry pip install --upgrade pip
- travis_retry pip install "virtualenv<14.0.0" "tox>=1.9" coveralls - travis_retry pip install coveralls
- travis_retry pip install flake8
- travis_retry pip install tox>=1.9
- travis_retry pip install "virtualenv<14.0.0" # virtualenv>=14.0.0 has dropped Python 3.2 support (and pypy3 is based on py32)
- travis_retry tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- -e test - travis_retry tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- -e test
# Run flake8 for py27
before_script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then tox -e flake8; fi
script: script:
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- --with-coverage - tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- --with-coverage
after_script: coveralls --verbose after_script: coveralls --verbose
notifications: notifications:
irc: irc.freenode.org#mongoengine irc: irc.freenode.org#mongoengine
branches: branches:
only: only:
- master - master
- /^v.*$/ - /^v.*$/
deploy: deploy:
provider: pypi provider: pypi
user: the_drow user: the_drow

View File

@ -1,15 +1,15 @@
import document
from document import *
import fields
from fields import *
import connection import connection
from connection import * from connection import *
import document
from document import *
import errors
from errors import *
import fields
from fields import *
import queryset import queryset
from queryset import * from queryset import *
import signals import signals
from signals import * from signals import *
from errors import *
import errors
__all__ = (list(document.__all__) + fields.__all__ + connection.__all__ + __all__ = (list(document.__all__) + fields.__all__ + connection.__all__ +
list(queryset.__all__) + signals.__all__ + list(errors.__all__)) list(queryset.__all__) + signals.__all__ + list(errors.__all__))
@ -22,4 +22,5 @@ def get_version():
return '.'.join(map(str, VERSION[:-1])) + VERSION[-1] return '.'.join(map(str, VERSION[:-1])) + VERSION[-1]
return '.'.join(map(str, VERSION)) return '.'.join(map(str, VERSION))
__version__ = get_version() __version__ = get_version()

View File

@ -1,5 +1,5 @@
import weakref
import itertools import itertools
import weakref
from mongoengine.common import _import_class from mongoengine.common import _import_class
from mongoengine.errors import DoesNotExist, MultipleObjectsReturned from mongoengine.errors import DoesNotExist, MultipleObjectsReturned
@ -199,8 +199,9 @@ class BaseList(list):
def _mark_as_changed(self, key=None): def _mark_as_changed(self, key=None):
if hasattr(self._instance, '_mark_as_changed'): if hasattr(self._instance, '_mark_as_changed'):
if key: if key:
self._instance._mark_as_changed('%s.%s' % (self._name, self._instance._mark_as_changed(
key % len(self))) '%s.%s' % (self._name, key % len(self))
)
else: else:
self._instance._mark_as_changed(self._name) self._instance._mark_as_changed(self._name)

View File

@ -1,28 +1,28 @@
import copy import copy
import operator
import numbers import numbers
import operator
from collections import Hashable from collections import Hashable
from functools import partial from functools import partial
import pymongo from bson import ObjectId, json_util
from bson import json_util, ObjectId
from bson.dbref import DBRef from bson.dbref import DBRef
from bson.son import SON from bson.son import SON
import pymongo
from mongoengine import signals from mongoengine import signals
from mongoengine.common import _import_class from mongoengine.base.common import ALLOW_INHERITANCE, get_document
from mongoengine.errors import (ValidationError, InvalidDocumentError,
LookUpError, FieldDoesNotExist)
from mongoengine.python_support import PY3, txt_type
from mongoengine.base.common import get_document, ALLOW_INHERITANCE
from mongoengine.base.datastructures import ( from mongoengine.base.datastructures import (
BaseDict, BaseDict,
BaseList, BaseList,
EmbeddedDocumentList, EmbeddedDocumentList,
StrictDict, SemiStrictDict,
SemiStrictDict StrictDict
) )
from mongoengine.base.fields import ComplexBaseField from mongoengine.base.fields import ComplexBaseField
from mongoengine.common import _import_class
from mongoengine.errors import (FieldDoesNotExist, InvalidDocumentError,
LookUpError, ValidationError)
from mongoengine.python_support import PY3, txt_type
__all__ = ('BaseDocument', 'NON_FIELD_ERRORS') __all__ = ('BaseDocument', 'NON_FIELD_ERRORS')
@ -566,8 +566,10 @@ class BaseDocument(object):
continue continue
if isinstance(field, ReferenceField): if isinstance(field, ReferenceField):
continue continue
elif (isinstance(data, (EmbeddedDocument, DynamicEmbeddedDocument)) elif (
and db_field_name not in changed_fields): isinstance(data, (EmbeddedDocument, DynamicEmbeddedDocument)) and
db_field_name not in changed_fields
):
# Find all embedded fields that have been changed # Find all embedded fields that have been changed
changed = data._get_changed_fields(inspected) changed = data._get_changed_fields(inspected)
changed_fields += ["%s%s" % (key, k) for k in changed if k] changed_fields += ["%s%s" % (key, k) for k in changed if k]
@ -775,8 +777,12 @@ class BaseDocument(object):
# Check to see if we need to include _cls # Check to see if we need to include _cls
allow_inheritance = cls._meta.get('allow_inheritance', allow_inheritance = cls._meta.get('allow_inheritance',
ALLOW_INHERITANCE) ALLOW_INHERITANCE)
include_cls = (allow_inheritance and not spec.get('sparse', False) and include_cls = (
spec.get('cls', True) and '_cls' not in spec['fields']) allow_inheritance and
not spec.get('sparse', False) and
spec.get('cls', True) and
'_cls' not in spec['fields']
)
# 733: don't include cls if index_cls is False unless there is an explicit cls with the index # 733: don't include cls if index_cls is False unless there is an explicit cls with the index
include_cls = include_cls and (spec.get('cls', False) or cls._meta.get('index_cls', True)) include_cls = include_cls and (spec.get('cls', False) or cls._meta.get('index_cls', True))

View File

@ -5,12 +5,12 @@ import weakref
from bson import DBRef, ObjectId, SON from bson import DBRef, ObjectId, SON
import pymongo import pymongo
from mongoengine.common import _import_class
from mongoengine.errors import ValidationError
from mongoengine.base.common import ALLOW_INHERITANCE from mongoengine.base.common import ALLOW_INHERITANCE
from mongoengine.base.datastructures import ( from mongoengine.base.datastructures import (
BaseDict, BaseList, EmbeddedDocumentList BaseDict, BaseList, EmbeddedDocumentList
) )
from mongoengine.common import _import_class
from mongoengine.errors import ValidationError
__all__ = ("BaseField", "ComplexBaseField", __all__ = ("BaseField", "ComplexBaseField",
"ObjectIdField", "GeoJsonBaseField") "ObjectIdField", "GeoJsonBaseField")
@ -206,7 +206,6 @@ class BaseField(object):
elif value not in choice_list: elif value not in choice_list:
self.error('Value must be one of %s' % unicode(choice_list)) self.error('Value must be one of %s' % unicode(choice_list))
def _validate(self, value, **kwargs): def _validate(self, value, **kwargs):
# Check the Choices Constraint # Check the Choices Constraint
if self.choices: if self.choices:

View File

@ -1,5 +1,7 @@
import warnings import warnings
from mongoengine.base.common import ALLOW_INHERITANCE, _document_registry
from mongoengine.base.fields import BaseField, ComplexBaseField, ObjectIdField
from mongoengine.common import _import_class from mongoengine.common import _import_class
from mongoengine.errors import InvalidDocumentError from mongoengine.errors import InvalidDocumentError
from mongoengine.python_support import PY3 from mongoengine.python_support import PY3
@ -7,16 +9,14 @@ from mongoengine.queryset import (DO_NOTHING, DoesNotExist,
MultipleObjectsReturned, MultipleObjectsReturned,
QuerySetManager) QuerySetManager)
from mongoengine.base.common import _document_registry, ALLOW_INHERITANCE
from mongoengine.base.fields import BaseField, ComplexBaseField, ObjectIdField
__all__ = ('DocumentMetaclass', 'TopLevelDocumentMetaclass') __all__ = ('DocumentMetaclass', 'TopLevelDocumentMetaclass')
class DocumentMetaclass(type): class DocumentMetaclass(type):
"""Metaclass for all documents. """Metaclass for all documents."""
"""
# TODO lower complexity of this method
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
flattened_bases = cls._get_bases(bases) flattened_bases = cls._get_bases(bases)
super_new = super(DocumentMetaclass, cls).__new__ super_new = super(DocumentMetaclass, cls).__new__
@ -162,7 +162,7 @@ class DocumentMetaclass(type):
# copies __func__ into im_func and __self__ into im_self for # copies __func__ into im_func and __self__ into im_self for
# classmethod objects in Document derived classes. # classmethod objects in Document derived classes.
if PY3: if PY3:
for key, val in new_class.__dict__.items(): for val in new_class.__dict__.values():
if isinstance(val, classmethod): if isinstance(val, classmethod):
f = val.__get__(new_class) f = val.__get__(new_class)
if hasattr(f, '__func__') and not hasattr(f, 'im_func'): if hasattr(f, '__func__') and not hasattr(f, 'im_func'):

View File

@ -1,15 +1,14 @@
from bson import DBRef, SON from bson import DBRef, SON
from mongoengine.python_support import txt_type from .base import (
from base import (
BaseDict, BaseList, EmbeddedDocumentList, BaseDict, BaseList, EmbeddedDocumentList,
TopLevelDocumentMetaclass, get_document TopLevelDocumentMetaclass, get_document
) )
from fields import (ReferenceField, ListField, DictField, MapField) from .connection import get_db
from connection import get_db from .document import Document, EmbeddedDocument
from queryset import QuerySet from .fields import DictField, ListField, MapField, ReferenceField
from document import Document, EmbeddedDocument from .python_support import txt_type
from .queryset import QuerySet
class DeReference(object): class DeReference(object):

View File

@ -1,28 +1,29 @@
import warnings
import pymongo
import re import re
import warnings
from pymongo.read_preferences import ReadPreference
from bson.dbref import DBRef from bson.dbref import DBRef
import pymongo
from pymongo.read_preferences import ReadPreference
from mongoengine import signals from mongoengine import signals
from mongoengine.common import _import_class
from mongoengine.base import ( from mongoengine.base import (
DocumentMetaclass,
TopLevelDocumentMetaclass,
BaseDocument,
BaseDict,
BaseList,
EmbeddedDocumentList,
ALLOW_INHERITANCE, ALLOW_INHERITANCE,
BaseDict,
BaseDocument,
BaseList,
DocumentMetaclass,
EmbeddedDocumentList,
TopLevelDocumentMetaclass,
get_document get_document
) )
from mongoengine.errors import (InvalidQueryError, InvalidDocumentError, from mongoengine.common import _import_class
from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db
from mongoengine.context_managers import switch_collection, switch_db
from mongoengine.errors import (InvalidDocumentError, InvalidQueryError,
SaveConditionError) SaveConditionError)
from mongoengine.python_support import IS_PYMONGO_3 from mongoengine.python_support import IS_PYMONGO_3
from mongoengine.queryset import (OperationError, NotUniqueError, from mongoengine.queryset import (NotUniqueError, OperationError,
QuerySet, transform) QuerySet, transform)
from mongoengine.connection import get_db, DEFAULT_CONNECTION_NAME
from mongoengine.context_managers import switch_db, switch_collection
__all__ = ('Document', 'EmbeddedDocument', 'DynamicDocument', __all__ = ('Document', 'EmbeddedDocument', 'DynamicDocument',
'DynamicEmbeddedDocument', 'OperationError', 'DynamicEmbeddedDocument', 'OperationError',
@ -332,8 +333,10 @@ class Document(BaseDocument):
# Correct behaviour in 2.X and in 3.0.1+ versions # Correct behaviour in 2.X and in 3.0.1+ versions
if not object_id and pymongo.version_tuple == (3, 0): if not object_id and pymongo.version_tuple == (3, 0):
pk_as_mongo_obj = self._fields.get(self._meta['id_field']).to_mongo(self.pk) pk_as_mongo_obj = self._fields.get(self._meta['id_field']).to_mongo(self.pk)
object_id = self._qs.filter(pk=pk_as_mongo_obj).first() and \ object_id = (
self._qs.filter(pk=pk_as_mongo_obj).first() and
self._qs.filter(pk=pk_as_mongo_obj).first().pk self._qs.filter(pk=pk_as_mongo_obj).first().pk
) # TODO doesn't this make 2 queries?
else: else:
object_id = doc['_id'] object_id = doc['_id']
updates, removals = self._delta() updates, removals = self._delta()

View File

@ -8,6 +8,9 @@ import uuid
import warnings import warnings
from operator import itemgetter from operator import itemgetter
from bson import Binary, DBRef, ObjectId, SON
import gridfs
import pymongo
import six import six
try: try:
@ -17,22 +20,18 @@ except ImportError:
else: else:
import dateutil.parser import dateutil.parser
import pymongo
import gridfs
from bson import Binary, DBRef, SON, ObjectId
try: try:
from bson.int64 import Int64 from bson.int64 import Int64
except ImportError: except ImportError:
Int64 = long Int64 = long
from mongoengine.errors import ValidationError, DoesNotExist from .base import (BaseDocument, BaseField, ComplexBaseField, GeoJsonBaseField,
from mongoengine.python_support import (PY3, bin_type, txt_type, ObjectIdField, get_document)
str_types, StringIO) from .connection import DEFAULT_CONNECTION_NAME, get_db
from base import (BaseField, ComplexBaseField, ObjectIdField, GeoJsonBaseField, from .document import Document, EmbeddedDocument
get_document, BaseDocument) from .errors import DoesNotExist, ValidationError
from queryset import DO_NOTHING, QuerySet from .python_support import PY3, StringIO, bin_type, str_types, txt_type
from document import Document, EmbeddedDocument from .queryset import DO_NOTHING, QuerySet
from connection import get_db, DEFAULT_CONNECTION_NAME
try: try:
from PIL import Image, ImageOps from PIL import Image, ImageOps
@ -1015,12 +1014,11 @@ class ReferenceField(BaseField):
if self.document_type._meta.get('abstract') and \ if self.document_type._meta.get('abstract') and \
not isinstance(value, self.document_type): not isinstance(value, self.document_type):
self.error('%s is not an instance of abstract reference' self.error(
' type %s' % (value._class_name, '%s is not an instance of abstract reference type %s' % (
self.document_type._class_name) self.document_type._class_name)
) )
def lookup_member(self, member_name): def lookup_member(self, member_name):
return self.document_type._fields.get(member_name) return self.document_type._fields.get(member_name)

View File

@ -1,6 +1,6 @@
from mongoengine.errors import (DoesNotExist, MultipleObjectsReturned, from mongoengine.errors import (DoesNotExist, InvalidQueryError,
InvalidQueryError, OperationError, MultipleObjectsReturned, NotUniqueError,
NotUniqueError) OperationError)
from mongoengine.queryset.field_list import * from mongoengine.queryset.field_list import *
from mongoengine.queryset.manager import * from mongoengine.queryset.manager import *
from mongoengine.queryset.queryset import * from mongoengine.queryset.queryset import *

View File

@ -7,20 +7,19 @@ import pprint
import re import re
import warnings import warnings
from bson import SON from bson import SON, json_util
from bson.code import Code from bson.code import Code
from bson import json_util
import pymongo import pymongo
import pymongo.errors import pymongo.errors
from pymongo.common import validate_read_preference from pymongo.common import validate_read_preference
from mongoengine import signals from mongoengine import signals
from mongoengine.base.common import get_document
from mongoengine.common import _import_class
from mongoengine.connection import get_db from mongoengine.connection import get_db
from mongoengine.context_managers import switch_db from mongoengine.context_managers import switch_db
from mongoengine.common import _import_class from mongoengine.errors import (InvalidQueryError, LookUpError,
from mongoengine.base.common import get_document NotUniqueError, OperationError)
from mongoengine.errors import (OperationError, NotUniqueError,
InvalidQueryError, LookUpError)
from mongoengine.python_support import IS_PYMONGO_3 from mongoengine.python_support import IS_PYMONGO_3
from mongoengine.queryset import transform from mongoengine.queryset import transform
from mongoengine.queryset.field_list import QueryFieldList from mongoengine.queryset.field_list import QueryFieldList
@ -155,10 +154,8 @@ class BaseQuerySet(object):
# forse load cursor # forse load cursor
# self._cursor # self._cursor
def __getitem__(self, key): def __getitem__(self, key):
"""Support skip and limit using getitem and slicing syntax. """Support skip and limit using getitem and slicing syntax."""
"""
queryset = self.clone() queryset = self.clone()
# Slice provided # Slice provided
@ -529,7 +526,8 @@ class BaseQuerySet(object):
.. versionadded:: 0.10.2 .. versionadded:: 0.10.2
""" """
atomic_update = self.update(multi=False, upsert=True, write_concern=write_concern, atomic_update = self.update(multi=False, upsert=True,
write_concern=write_concern,
full_result=True, **update) full_result=True, **update)
if atomic_update['updatedExisting']: if atomic_update['updatedExisting']:

View File

@ -1,6 +1,6 @@
from mongoengine.errors import OperationError from mongoengine.errors import OperationError
from mongoengine.queryset.base import (BaseQuerySet, DO_NOTHING, NULLIFY, from mongoengine.queryset.base import (BaseQuerySet, CASCADE, DENY, DO_NOTHING,
CASCADE, DENY, PULL) NULLIFY, PULL)
__all__ = ('QuerySet', 'QuerySetNoCache', 'DO_NOTHING', 'NULLIFY', 'CASCADE', __all__ = ('QuerySet', 'QuerySetNoCache', 'DO_NOTHING', 'NULLIFY', 'CASCADE',
'DENY', 'PULL') 'DENY', 'PULL')

View File

@ -1,11 +1,11 @@
from collections import defaultdict from collections import defaultdict
import pymongo
from bson import SON from bson import SON
import pymongo
from mongoengine.base.fields import UPDATE_OPERATORS from mongoengine.base.fields import UPDATE_OPERATORS
from mongoengine.connection import get_connection
from mongoengine.common import _import_class from mongoengine.common import _import_class
from mongoengine.connection import get_connection
from mongoengine.errors import InvalidQueryError from mongoengine.errors import InvalidQueryError
from mongoengine.python_support import IS_PYMONGO_3 from mongoengine.python_support import IS_PYMONGO_3
@ -108,8 +108,11 @@ def query(_doc_cls=None, **kwargs):
elif op in ('match', 'elemMatch'): elif op in ('match', 'elemMatch'):
ListField = _import_class('ListField') ListField = _import_class('ListField')
EmbeddedDocumentField = _import_class('EmbeddedDocumentField') EmbeddedDocumentField = _import_class('EmbeddedDocumentField')
if (isinstance(value, dict) and isinstance(field, ListField) and if (
isinstance(field.field, EmbeddedDocumentField)): isinstance(value, dict) and
isinstance(field, ListField) and
isinstance(field.field, EmbeddedDocumentField)
):
value = query(field.field.document_type, **value) value = query(field.field.document_type, **value)
else: else:
value = field.prepare_query_value(op, value) value = field.prepare_query_value(op, value)

View File

@ -29,7 +29,7 @@ except ImportError:
'because the blinker library is ' 'because the blinker library is '
'not installed.') 'not installed.')
send = lambda *a, **kw: None send = lambda *a, **kw: None # noqa
connect = disconnect = has_receivers_for = receivers_for = \ connect = disconnect = has_receivers_for = receivers_for = \
temporarily_connected_to = _fail temporarily_connected_to = _fail
del _fail del _fail

View File

@ -1,3 +1,5 @@
nose nose
pymongo>=2.7.1 pymongo>=2.7.1
six==1.10.0 six==1.10.0
flake8
flake8-import-order

View File

@ -5,3 +5,9 @@ cover-erase = 1
cover-branches = 1 cover-branches = 1
cover-package = mongoengine cover-package = mongoengine
tests = tests tests = tests
[flake8]
ignore=E501,F401,F403,F405,I201
exclude=build,dist,docs,venv,.tox,.eggs,tests
max-complexity=42
application-import-names=mongoengine,tests

View File

@ -1,6 +1,6 @@
import os import os
import sys import sys
from setuptools import setup, find_packages from setuptools import find_packages, setup
# Hack to silence atexit traceback in newer python versions # Hack to silence atexit traceback in newer python versions
try: try:
@ -8,8 +8,10 @@ try:
except ImportError: except ImportError:
pass pass
DESCRIPTION = 'MongoEngine is a Python Object-Document ' + \ DESCRIPTION = (
'MongoEngine is a Python Object-Document '
'Mapper for working with MongoDB.' 'Mapper for working with MongoDB.'
)
try: try:
with open('README.rst') as fin: with open('README.rst') as fin:
@ -23,6 +25,7 @@ def get_version(version_tuple):
return '.'.join(map(str, version_tuple[:-1])) + version_tuple[-1] return '.'.join(map(str, version_tuple[:-1])) + version_tuple[-1]
return '.'.join(map(str, version_tuple)) return '.'.join(map(str, version_tuple))
# Dirty hack to get version number from monogengine/__init__.py - we can't # Dirty hack to get version number from monogengine/__init__.py - we can't
# import it as it depends on PyMongo and PyMongo isn't installed until this # import it as it depends on PyMongo and PyMongo isn't installed until this
# file is read # file is read
@ -64,7 +67,8 @@ else:
if sys.version_info[0] == 2 and sys.version_info[1] == 6: if sys.version_info[0] == 2 and sys.version_info[1] == 6:
extra_opts['tests_require'].append('unittest2') extra_opts['tests_require'].append('unittest2')
setup(name='mongoengine', setup(
name='mongoengine',
version=VERSION, version=VERSION,
author='Harry Marr', author='Harry Marr',
author_email='harry.marr@{nospam}gmail.com', author_email='harry.marr@{nospam}gmail.com',

View File

@ -844,7 +844,12 @@ class IndexesTest(unittest.TestCase):
self.assertEqual({'text': 'OK', '_id': {'term': 'ok', 'name': 'n'}}, self.assertEqual({'text': 'OK', '_id': {'term': 'ok', 'name': 'n'}},
report.to_mongo()) report.to_mongo())
self.assertEqual(report, ReportDictField.objects.get(pk=my_key))
# We can't directly call ReportDictField.objects.get(pk=my_key),
# because dicts are unordered, and if the order in MongoDB is
# different than the one in `my_key`, this test will fail.
self.assertEqual(report, ReportDictField.objects.get(pk__name=my_key['name']))
self.assertEqual(report, ReportDictField.objects.get(pk__term=my_key['term']))
def test_string_indexes(self): def test_string_indexes(self):

View File

@ -1,28 +1,23 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import datetime
sys.path[0:0] = [""]
import unittest import unittest
import uuid import uuid
from bson import DBRef, ObjectId
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from datetime import datetime, timedelta
import pymongo import pymongo
from pymongo.errors import ConfigurationError from pymongo.errors import ConfigurationError
from pymongo.read_preferences import ReadPreference from pymongo.read_preferences import ReadPreference
from bson import ObjectId, DBRef
from mongoengine import * from mongoengine import *
from mongoengine.connection import get_connection, get_db from mongoengine.connection import get_connection, get_db
from mongoengine.python_support import PY3, IS_PYMONGO_3
from mongoengine.context_managers import query_counter, switch_db from mongoengine.context_managers import query_counter, switch_db
from mongoengine.queryset import (QuerySet, QuerySetManager,
MultipleObjectsReturned, DoesNotExist,
queryset_manager)
from mongoengine.errors import InvalidQueryError from mongoengine.errors import InvalidQueryError
from mongoengine.python_support import IS_PYMONGO_3, PY3
from mongoengine.queryset import (DoesNotExist, MultipleObjectsReturned,
QuerySet, QuerySetManager, queryset_manager)
__all__ = ("QuerySetTest",) __all__ = ("QuerySetTest",)
@ -184,12 +179,14 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(self.Person.objects.count(), 55) self.assertEqual(self.Person.objects.count(), 55)
self.assertEqual("Person object", "%s" % self.Person.objects[0]) self.assertEqual("Person object", "%s" % self.Person.objects[0])
self.assertEqual( self.assertEqual("[<Person: Person object>, <Person: Person object>]",
"[<Person: Person object>, <Person: Person object>]", "%s" % self.Person.objects[1:3]) "%s" % self.Person.objects[1:3])
self.assertEqual( self.assertEqual("[<Person: Person object>, <Person: Person object>]",
"[<Person: Person object>, <Person: Person object>]", "%s" % self.Person.objects[51:53]) "%s" % self.Person.objects[51:53])
# Test only after limit # Test only after limit
self.assertEqual(self.Person.objects().limit(2).only('name')[0].age, None) self.assertEqual(self.Person.objects().limit(2).only('name')[0].age, None)
# Test only after skip # Test only after skip
self.assertEqual(self.Person.objects().skip(2).only('name')[0].age, None) self.assertEqual(self.Person.objects().skip(2).only('name')[0].age, None)
@ -287,6 +284,9 @@ class QuerySetTest(unittest.TestCase):
blog = Blog.objects(posts__0__comments__0__name='testa').get() blog = Blog.objects(posts__0__comments__0__name='testa').get()
self.assertEqual(blog, blog1) self.assertEqual(blog, blog1)
blog = Blog.objects(posts__0__comments__0__name='testb').get()
self.assertEqual(blog, blog2)
query = Blog.objects(posts__1__comments__1__name='testb') query = Blog.objects(posts__1__comments__1__name='testb')
self.assertEqual(query.count(), 2) self.assertEqual(query.count(), 2)
@ -694,7 +694,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(30, bobby.age) self.assertEqual(30, bobby.age)
self.assertEqual(bob.id, bobby.id) self.assertEqual(bob.id, bobby.id)
def test_set_on_insert(self): def test_set_on_insert(self):
self.Person.drop_collection() self.Person.drop_collection()
@ -1113,24 +1112,29 @@ class QuerySetTest(unittest.TestCase):
blog_2.save() blog_2.save()
blog_3.save() blog_3.save()
blog_post_1 = BlogPost(blog=blog_1, title="Blog Post #1", BlogPost.objects.create(
blog=blog_1,
title="Blog Post #1",
is_published=True, is_published=True,
published_date=datetime(2010, 1, 5, 0, 0, 0)) published_date=datetime.datetime(2010, 1, 5, 0, 0, 0)
blog_post_2 = BlogPost(blog=blog_2, title="Blog Post #2", )
BlogPost.objects.create(
blog=blog_2,
title="Blog Post #2",
is_published=True, is_published=True,
published_date=datetime(2010, 1, 6, 0, 0, 0)) published_date=datetime.datetime(2010, 1, 6, 0, 0, 0)
blog_post_3 = BlogPost(blog=blog_3, title="Blog Post #3", )
BlogPost.objects.create(
blog=blog_3,
title="Blog Post #3",
is_published=True, is_published=True,
published_date=datetime(2010, 1, 7, 0, 0, 0)) published_date=datetime.datetime(2010, 1, 7, 0, 0, 0)
)
blog_post_1.save()
blog_post_2.save()
blog_post_3.save()
# find all published blog posts before 2010-01-07 # find all published blog posts before 2010-01-07
published_posts = BlogPost.published() published_posts = BlogPost.published()
published_posts = published_posts.filter( published_posts = published_posts.filter(
published_date__lt=datetime(2010, 1, 7, 0, 0, 0)) published_date__lt=datetime.datetime(2010, 1, 7, 0, 0, 0))
self.assertEqual(published_posts.count(), 2) self.assertEqual(published_posts.count(), 2)
blog_posts = BlogPost.objects blog_posts = BlogPost.objects
@ -1161,16 +1165,18 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
blog_post_1 = BlogPost(title="Blog Post #1", blog_post_1 = BlogPost.objects.create(
published_date=datetime(2010, 1, 5, 0, 0, 0)) title="Blog Post #1",
blog_post_2 = BlogPost(title="Blog Post #2", published_date=datetime.datetime(2010, 1, 5, 0, 0, 0)
published_date=datetime(2010, 1, 6, 0, 0, 0)) )
blog_post_3 = BlogPost(title="Blog Post #3", blog_post_2 = BlogPost.objects.create(
published_date=datetime(2010, 1, 7, 0, 0, 0)) title="Blog Post #2",
published_date=datetime.datetime(2010, 1, 6, 0, 0, 0)
blog_post_1.save() )
blog_post_2.save() blog_post_3 = BlogPost.objects.create(
blog_post_3.save() title="Blog Post #3",
published_date=datetime.datetime(2010, 1, 7, 0, 0, 0)
)
# get the "first" BlogPost using default ordering # get the "first" BlogPost using default ordering
# from BlogPost.meta.ordering # from BlogPost.meta.ordering
@ -1219,7 +1225,7 @@ class QuerySetTest(unittest.TestCase):
} }
BlogPost.objects.create( BlogPost.objects.create(
title='whatever', published_date=datetime.utcnow()) title='whatever', published_date=datetime.datetime.utcnow())
with db_ops_tracker() as q: with db_ops_tracker() as q:
BlogPost.objects.get(title='whatever') BlogPost.objects.get(title='whatever')
@ -2082,18 +2088,22 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
blog_post_3 = BlogPost(title="Blog Post #3", blog_post_3 = BlogPost.objects.create(
published_date=datetime(2010, 1, 6, 0, 0, 0)) title="Blog Post #3",
blog_post_2 = BlogPost(title="Blog Post #2", published_date=datetime.datetime(2010, 1, 6, 0, 0, 0)
published_date=datetime(2010, 1, 5, 0, 0, 0)) )
blog_post_4 = BlogPost(title="Blog Post #4", blog_post_2 = BlogPost.objects.create(
published_date=datetime(2010, 1, 7, 0, 0, 0)) title="Blog Post #2",
blog_post_1 = BlogPost(title="Blog Post #1", published_date=None) published_date=datetime.datetime(2010, 1, 5, 0, 0, 0)
)
blog_post_3.save() blog_post_4 = BlogPost.objects.create(
blog_post_1.save() title="Blog Post #4",
blog_post_4.save() published_date=datetime.datetime(2010, 1, 7, 0, 0, 0)
blog_post_2.save() )
blog_post_1 = BlogPost.objects.create(
title="Blog Post #1",
published_date=None
)
expected = [blog_post_1, blog_post_2, blog_post_3, blog_post_4] expected = [blog_post_1, blog_post_2, blog_post_3, blog_post_4]
self.assertSequence(BlogPost.objects.order_by('published_date'), self.assertSequence(BlogPost.objects.order_by('published_date'),
@ -2112,16 +2122,18 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
blog_post_1 = BlogPost(title="A", blog_post_1 = BlogPost.objects.create(
published_date=datetime(2010, 1, 6, 0, 0, 0)) title="A",
blog_post_2 = BlogPost(title="B", published_date=datetime.datetime(2010, 1, 6, 0, 0, 0)
published_date=datetime(2010, 1, 6, 0, 0, 0)) )
blog_post_3 = BlogPost(title="C", blog_post_2 = BlogPost.objects.create(
published_date=datetime(2010, 1, 7, 0, 0, 0)) title="B",
published_date=datetime.datetime(2010, 1, 6, 0, 0, 0)
blog_post_2.save() )
blog_post_3.save() blog_post_3 = BlogPost.objects.create(
blog_post_1.save() title="C",
published_date=datetime.datetime(2010, 1, 7, 0, 0, 0)
)
qs = BlogPost.objects.order_by('published_date', 'title') qs = BlogPost.objects.order_by('published_date', 'title')
expected = [blog_post_1, blog_post_2, blog_post_3] expected = [blog_post_1, blog_post_2, blog_post_3]
@ -2425,7 +2437,7 @@ class QuerySetTest(unittest.TestCase):
Link.drop_collection() Link.drop_collection()
now = datetime.utcnow() now = datetime.datetime.utcnow()
# Note: Test data taken from a custom Reddit homepage on # Note: Test data taken from a custom Reddit homepage on
# Fri, 12 Feb 2010 14:36:00 -0600. Link ordering should # Fri, 12 Feb 2010 14:36:00 -0600. Link ordering should
@ -2434,27 +2446,27 @@ class QuerySetTest(unittest.TestCase):
Link(title="Google Buzz auto-followed a woman's abusive ex ...", Link(title="Google Buzz auto-followed a woman's abusive ex ...",
up_votes=1079, up_votes=1079,
down_votes=553, down_votes=553,
submitted=now - timedelta(hours=4)).save() submitted=now - datetime.timedelta(hours=4)).save()
Link(title="We did it! Barbie is a computer engineer.", Link(title="We did it! Barbie is a computer engineer.",
up_votes=481, up_votes=481,
down_votes=124, down_votes=124,
submitted=now - timedelta(hours=2)).save() submitted=now - datetime.timedelta(hours=2)).save()
Link(title="This Is A Mosquito Getting Killed By A Laser", Link(title="This Is A Mosquito Getting Killed By A Laser",
up_votes=1446, up_votes=1446,
down_votes=530, down_votes=530,
submitted=now - timedelta(hours=13)).save() submitted=now - datetime.timedelta(hours=13)).save()
Link(title="Arabic flashcards land physics student in jail.", Link(title="Arabic flashcards land physics student in jail.",
up_votes=215, up_votes=215,
down_votes=105, down_votes=105,
submitted=now - timedelta(hours=6)).save() submitted=now - datetime.timedelta(hours=6)).save()
Link(title="The Burger Lab: Presenting, the Flood Burger", Link(title="The Burger Lab: Presenting, the Flood Burger",
up_votes=48, up_votes=48,
down_votes=17, down_votes=17,
submitted=now - timedelta(hours=5)).save() submitted=now - datetime.timedelta(hours=5)).save()
Link(title="How to see polarization with the naked eye", Link(title="How to see polarization with the naked eye",
up_votes=74, up_votes=74,
down_votes=13, down_votes=13,
submitted=now - timedelta(hours=10)).save() submitted=now - datetime.timedelta(hours=10)).save()
map_f = """ map_f = """
function() { function() {
@ -2504,7 +2516,7 @@ class QuerySetTest(unittest.TestCase):
# provide the reddit epoch (used for ranking) as a variable available # provide the reddit epoch (used for ranking) as a variable available
# to all phases of the map/reduce operation: map, reduce, and finalize. # to all phases of the map/reduce operation: map, reduce, and finalize.
reddit_epoch = mktime(datetime(2005, 12, 8, 7, 46, 43).timetuple()) reddit_epoch = mktime(datetime.datetime(2005, 12, 8, 7, 46, 43).timetuple())
scope = {'reddit_epoch': reddit_epoch} scope = {'reddit_epoch': reddit_epoch}
# run a map/reduce operation across all links. ordering is set # run a map/reduce operation across all links. ordering is set
@ -3096,13 +3108,11 @@ class QuerySetTest(unittest.TestCase):
mark_twain = Author(name="Mark Twain") mark_twain = Author(name="Mark Twain")
john_tolkien = Author(name="John Ronald Reuel Tolkien") john_tolkien = Author(name="John Ronald Reuel Tolkien")
book = Book(title="Tom Sawyer", authors=[mark_twain]).save() Book.objects.create(title="Tom Sawyer", authors=[mark_twain])
book = Book( Book.objects.create(title="The Lord of the Rings", authors=[john_tolkien])
title="The Lord of the Rings", authors=[john_tolkien]).save() Book.objects.create(title="The Stories", authors=[mark_twain, john_tolkien])
book = Book(
title="The Stories", authors=[mark_twain, john_tolkien]).save()
authors = Book.objects.distinct("authors")
authors = Book.objects.distinct("authors")
self.assertEqual(authors, [mark_twain, john_tolkien]) self.assertEqual(authors, [mark_twain, john_tolkien])
def test_distinct_ListField_EmbeddedDocumentField_EmbeddedDocumentField(self): def test_distinct_ListField_EmbeddedDocumentField_EmbeddedDocumentField(self):
@ -3132,17 +3142,14 @@ class QuerySetTest(unittest.TestCase):
mark_twain = Author(name="Mark Twain", country=scotland) mark_twain = Author(name="Mark Twain", country=scotland)
john_tolkien = Author(name="John Ronald Reuel Tolkien", country=tibet) john_tolkien = Author(name="John Ronald Reuel Tolkien", country=tibet)
book = Book(title="Tom Sawyer", authors=[mark_twain]).save() Book.objects.create(title="Tom Sawyer", authors=[mark_twain])
book = Book( Book.objects.create(title="The Lord of the Rings", authors=[john_tolkien])
title="The Lord of the Rings", authors=[john_tolkien]).save() Book.objects.create(title="The Stories", authors=[mark_twain, john_tolkien])
book = Book(
title="The Stories", authors=[mark_twain, john_tolkien]).save()
country_list = Book.objects.distinct("authors.country")
country_list = Book.objects.distinct("authors.country")
self.assertEqual(country_list, [scotland, tibet]) self.assertEqual(country_list, [scotland, tibet])
continent_list = Book.objects.distinct("authors.country.continent") continent_list = Book.objects.distinct("authors.country.continent")
self.assertEqual(continent_list, [europe, asia]) self.assertEqual(continent_list, [europe, asia])
def test_distinct_ListField_ReferenceField(self): def test_distinct_ListField_ReferenceField(self):
@ -3174,7 +3181,7 @@ class QuerySetTest(unittest.TestCase):
class BlogPost(Document): class BlogPost(Document):
tags = ListField(StringField()) tags = ListField(StringField())
deleted = BooleanField(default=False) deleted = BooleanField(default=False)
date = DateTimeField(default=datetime.now) date = DateTimeField(default=datetime.datetime.now)
@queryset_manager @queryset_manager
def objects(cls, qryset): def objects(cls, qryset):
@ -3997,8 +4004,8 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
"A0", "%s" % self.Person.objects.scalar('name').order_by('name')[0]) "A0", "%s" % self.Person.objects.scalar('name').order_by('name')[0])
if PY3: if PY3:
self.assertEqual( self.assertEqual("['A1', 'A2']", "%s" % self.Person.objects.order_by(
"['A1', 'A2']", "%s" % self.Person.objects.order_by('age').scalar('name')[1:3]) 'age').scalar('name')[1:3])
self.assertEqual("['A51', 'A52']", "%s" % self.Person.objects.order_by( self.assertEqual("['A51', 'A52']", "%s" % self.Person.objects.order_by(
'age').scalar('name')[51:53]) 'age').scalar('name')[51:53])
else: else:
@ -4013,12 +4020,12 @@ class QuerySetTest(unittest.TestCase):
self.Person.objects.scalar('name').with_id(person.id)) self.Person.objects.scalar('name').with_id(person.id))
pks = self.Person.objects.order_by('age').scalar('pk')[1:3] pks = self.Person.objects.order_by('age').scalar('pk')[1:3]
names = self.Person.objects.scalar('name').in_bulk(list(pks)).values()
if PY3: if PY3:
self.assertEqual("['A1', 'A2']", "%s" % sorted( expected = "['A1', 'A2']"
self.Person.objects.scalar('name').in_bulk(list(pks)).values()))
else: else:
self.assertEqual("[u'A1', u'A2']", "%s" % sorted( expected = "[u'A1', u'A2']"
self.Person.objects.scalar('name').in_bulk(list(pks)).values())) self.assertEqual(expected, "%s" % sorted(names))
def test_elem_match(self): def test_elem_match(self):
class Foo(EmbeddedDocument): class Foo(EmbeddedDocument):
@ -4130,47 +4137,47 @@ class QuerySetTest(unittest.TestCase):
# read_preference as a kwarg # read_preference as a kwarg
bars = Bar.objects(read_preference=ReadPreference.SECONDARY_PREFERRED) bars = Bar.objects(read_preference=ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
# read_preference as a query set method # read_preference as a query set method
bars = Bar.objects.read_preference(ReadPreference.SECONDARY_PREFERRED) bars = Bar.objects.read_preference(ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
# read_preference after skip # read_preference after skip
bars = Bar.objects.skip(1) \ bars = Bar.objects.skip(1) \
.read_preference(ReadPreference.SECONDARY_PREFERRED) .read_preference(ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
# read_preference after limit # read_preference after limit
bars = Bar.objects.limit(1) \ bars = Bar.objects.limit(1) \
.read_preference(ReadPreference.SECONDARY_PREFERRED) .read_preference(ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
# read_preference after order_by # read_preference after order_by
bars = Bar.objects.order_by('txt') \ bars = Bar.objects.order_by('txt') \
.read_preference(ReadPreference.SECONDARY_PREFERRED) .read_preference(ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
# read_preference after hint # read_preference after hint
bars = Bar.objects.hint([('txt', 1)]) \ bars = Bar.objects.hint([('txt', 1)]) \
.read_preference(ReadPreference.SECONDARY_PREFERRED) .read_preference(ReadPreference.SECONDARY_PREFERRED)
self.assertEqual( self.assertEqual(bars._read_preference,
bars._read_preference, ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
@ -4208,7 +4215,7 @@ class QuerySetTest(unittest.TestCase):
int_field = IntField(default=1) int_field = IntField(default=1)
float_field = FloatField(default=1.1) float_field = FloatField(default=1.1)
boolean_field = BooleanField(default=True) boolean_field = BooleanField(default=True)
datetime_field = DateTimeField(default=datetime.now) datetime_field = DateTimeField(default=datetime.datetime.now)
embedded_document_field = EmbeddedDocumentField( embedded_document_field = EmbeddedDocumentField(
EmbeddedDoc, default=lambda: EmbeddedDoc()) EmbeddedDoc, default=lambda: EmbeddedDoc())
list_field = ListField(default=lambda: [1, 2, 3]) list_field = ListField(default=lambda: [1, 2, 3])
@ -4218,7 +4225,7 @@ class QuerySetTest(unittest.TestCase):
Simple, default=lambda: Simple().save()) Simple, default=lambda: Simple().save())
map_field = MapField(IntField(), default=lambda: {"simple": 1}) map_field = MapField(IntField(), default=lambda: {"simple": 1})
decimal_field = DecimalField(default=1.0) decimal_field = DecimalField(default=1.0)
complex_datetime_field = ComplexDateTimeField(default=datetime.now) complex_datetime_field = ComplexDateTimeField(default=datetime.datetime.now)
url_field = URLField(default="http://mongoengine.org") url_field = URLField(default="http://mongoengine.org")
dynamic_field = DynamicField(default=1) dynamic_field = DynamicField(default=1)
generic_reference_field = GenericReferenceField( generic_reference_field = GenericReferenceField(
@ -4565,8 +4572,7 @@ class QuerySetTest(unittest.TestCase):
B.drop_collection() B.drop_collection()
a = A.objects.create(id='custom_id') a = A.objects.create(id='custom_id')
B.objects.create(a=a)
b = B.objects.create(a=a)
self.assertEqual(B.objects.count(), 1) self.assertEqual(B.objects.count(), 1)
self.assertEqual(B.objects.get(a=a).a, a) self.assertEqual(B.objects.get(a=a).a, a)

View File

@ -1,11 +1,7 @@
import sys
sys.path[0:0] = [""]
import unittest import unittest
from mongoengine import * from mongoengine import *
from mongoengine.queryset import Q from mongoengine.queryset import Q, transform
from mongoengine.queryset import transform
__all__ = ("TransformTest",) __all__ = ("TransformTest",)
@ -41,8 +37,8 @@ class TransformTest(unittest.TestCase):
DicDoc.drop_collection() DicDoc.drop_collection()
Doc.drop_collection() Doc.drop_collection()
DicDoc().save()
doc = Doc().save() doc = Doc().save()
dic_doc = DicDoc().save()
for k, v in (("set", "$set"), ("set_on_insert", "$setOnInsert"), ("push", "$push")): for k, v in (("set", "$set"), ("set_on_insert", "$setOnInsert"), ("push", "$push")):
update = transform.update(DicDoc, **{"%s__dictField__test" % k: doc}) update = transform.update(DicDoc, **{"%s__dictField__test" % k: doc})
@ -55,7 +51,6 @@ class TransformTest(unittest.TestCase):
update = transform.update(DicDoc, pull__dictField__test=doc) update = transform.update(DicDoc, pull__dictField__test=doc)
self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict)) self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict))
def test_query_field_name(self): def test_query_field_name(self):
"""Ensure that the correct field name is used when querying. """Ensure that the correct field name is used when querying.
""" """
@ -156,16 +151,23 @@ class TransformTest(unittest.TestCase):
class Doc(Document): class Doc(Document):
meta = {'allow_inheritance': False} meta = {'allow_inheritance': False}
raw_query = Doc.objects(__raw__={'deleted': False, raw_query = Doc.objects(__raw__={
'deleted': False,
'scraped': 'yes', 'scraped': 'yes',
'$nor': [{'views.extracted': 'no'}, '$nor': [
{'attachments.views.extracted':'no'}] {'views.extracted': 'no'},
{'attachments.views.extracted': 'no'}
]
})._query })._query
expected = {'deleted': False, 'scraped': 'yes', self.assertEqual(raw_query, {
'$nor': [{'views.extracted': 'no'}, 'deleted': False,
{'attachments.views.extracted': 'no'}]} 'scraped': 'yes',
self.assertEqual(expected, raw_query) '$nor': [
{'views.extracted': 'no'},
{'attachments.views.extracted': 'no'}
]
})
def test_geojson_PointField(self): def test_geojson_PointField(self):
class Location(Document): class Location(Document):
@ -238,5 +240,6 @@ class TransformTest(unittest.TestCase):
events = Event.objects(location__within=box) events = Event.objects(location__within=box)
self.assertRaises(InvalidQueryError, lambda: events.count()) self.assertRaises(InvalidQueryError, lambda: events.count())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -1,14 +1,12 @@
import sys import datetime
sys.path[0:0] = [""] import re
import unittest import unittest
from bson import ObjectId from bson import ObjectId
from datetime import datetime
from mongoengine import * from mongoengine import *
from mongoengine.queryset import Q
from mongoengine.errors import InvalidQueryError from mongoengine.errors import InvalidQueryError
from mongoengine.queryset import Q
__all__ = ("QTest",) __all__ = ("QTest",)
@ -132,12 +130,12 @@ class QTest(unittest.TestCase):
TestDoc(x=10).save() TestDoc(x=10).save()
TestDoc(y=True).save() TestDoc(y=True).save()
self.assertEqual(query, self.assertEqual(query, {
{'$and': [ '$and': [
{'$or': [{'x': {'$gt': 0}}, {'x': {'$exists': False}}]}, {'$or': [{'x': {'$gt': 0}}, {'x': {'$exists': False}}]},
{'$or': [{'x': {'$lt': 100}}, {'y': True}]} {'$or': [{'x': {'$lt': 100}}, {'y': True}]}
]}) ]
})
self.assertEqual(2, TestDoc.objects(q1 & q2).count()) self.assertEqual(2, TestDoc.objects(q1 & q2).count())
def test_or_and_or_combination(self): def test_or_and_or_combination(self):
@ -157,15 +155,14 @@ class QTest(unittest.TestCase):
q2 = (Q(x__lt=100) & (Q(y=False) | Q(y__exists=False))) q2 = (Q(x__lt=100) & (Q(y=False) | Q(y__exists=False)))
query = (q1 | q2).to_query(TestDoc) query = (q1 | q2).to_query(TestDoc)
self.assertEqual(query, self.assertEqual(query, {
{'$or': [ '$or': [
{'$and': [{'x': {'$gt': 0}}, {'$and': [{'x': {'$gt': 0}},
{'$or': [{'y': True}, {'y': {'$exists': False}}]}]}, {'$or': [{'y': True}, {'y': {'$exists': False}}]}]},
{'$and': [{'x': {'$lt': 100}}, {'$and': [{'x': {'$lt': 100}},
{'$or': [{'y': False}, {'y': {'$exists': False}}]}]} {'$or': [{'y': False}, {'y': {'$exists': False}}]}]}
]} ]
) })
self.assertEqual(2, TestDoc.objects(q1 | q2).count()) self.assertEqual(2, TestDoc.objects(q1 | q2).count())
def test_multiple_occurence_in_field(self): def test_multiple_occurence_in_field(self):
@ -215,19 +212,19 @@ class QTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
post1 = BlogPost(title='Test 1', publish_date=datetime(2010, 1, 8), published=False) post1 = BlogPost(title='Test 1', publish_date=datetime.datetime(2010, 1, 8), published=False)
post1.save() post1.save()
post2 = BlogPost(title='Test 2', publish_date=datetime(2010, 1, 15), published=True) post2 = BlogPost(title='Test 2', publish_date=datetime.datetime(2010, 1, 15), published=True)
post2.save() post2.save()
post3 = BlogPost(title='Test 3', published=True) post3 = BlogPost(title='Test 3', published=True)
post3.save() post3.save()
post4 = BlogPost(title='Test 4', publish_date=datetime(2010, 1, 8)) post4 = BlogPost(title='Test 4', publish_date=datetime.datetime(2010, 1, 8))
post4.save() post4.save()
post5 = BlogPost(title='Test 1', publish_date=datetime(2010, 1, 15)) post5 = BlogPost(title='Test 1', publish_date=datetime.datetime(2010, 1, 15))
post5.save() post5.save()
post6 = BlogPost(title='Test 1', published=False) post6 = BlogPost(title='Test 1', published=False)
@ -250,7 +247,7 @@ class QTest(unittest.TestCase):
self.assertTrue(all(obj.id in posts for obj in published_posts)) self.assertTrue(all(obj.id in posts for obj in published_posts))
# Check Q object combination # Check Q object combination
date = datetime(2010, 1, 10) date = datetime.datetime(2010, 1, 10)
q = BlogPost.objects(Q(publish_date__lte=date) | Q(published=True)) q = BlogPost.objects(Q(publish_date__lte=date) | Q(published=True))
posts = [post.id for post in q] posts = [post.id for post in q]
@ -273,8 +270,10 @@ class QTest(unittest.TestCase):
# Test invalid query objs # Test invalid query objs
def wrong_query_objs(): def wrong_query_objs():
self.Person.objects('user1') self.Person.objects('user1')
def wrong_query_objs_filter(): def wrong_query_objs_filter():
self.Person.objects('user1') self.Person.objects('user1')
self.assertRaises(InvalidQueryError, wrong_query_objs) self.assertRaises(InvalidQueryError, wrong_query_objs)
self.assertRaises(InvalidQueryError, wrong_query_objs_filter) self.assertRaises(InvalidQueryError, wrong_query_objs_filter)
@ -284,7 +283,6 @@ class QTest(unittest.TestCase):
person = self.Person(name='Guido van Rossum') person = self.Person(name='Guido van Rossum')
person.save() person.save()
import re
obj = self.Person.objects(Q(name=re.compile('^Gui'))).first() obj = self.Person.objects(Q(name=re.compile('^Gui'))).first()
self.assertEqual(obj, person) self.assertEqual(obj, person)
obj = self.Person.objects(Q(name=re.compile('^gui'))).first() obj = self.Person.objects(Q(name=re.compile('^gui'))).first()

10
tox.ini
View File

@ -1,6 +1,5 @@
[tox] [tox]
envlist = {py26,py27,py33,py34,py35,pypy,pypy3}-{mg27,mg28} envlist = {py26,py27,py33,py34,py35,pypy,pypy3}-{mg27,mg28},flake8
#envlist = {py26,py27,py33,py34,pypy,pypy3}-{mg27,mg28,mg30,mgdev}
[testenv] [testenv]
commands = commands =
@ -14,3 +13,10 @@ deps =
setenv = setenv =
PYTHON_EGG_CACHE = {envdir}/python-eggs PYTHON_EGG_CACHE = {envdir}/python-eggs
passenv = windir passenv = windir
[testenv:flake8]
deps =
flake8
flake8-import-order
commands =
flake8