Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
db673a9
ditch the old "except Exception, e" syntax
wojcikstefan Dec 6, 2016
6b2cebb
healthier, cleaner imports
wojcikstefan Dec 6, 2016
bc6c84c
remove unnecessary sys.path manipulation in tests
wojcikstefan Dec 6, 2016
50df653
imports working in py2 and py3 in mongoengine/__init__.py
wojcikstefan Dec 6, 2016
548c743
dont re-implement six
wojcikstefan Dec 6, 2016
59cac2b
remove last few uses of "unicode"
wojcikstefan Dec 6, 2016
557f9bd
flake8 tweaks
wojcikstefan Dec 6, 2016
7dd4639
pk as a property with a setter + get rid of basestring
wojcikstefan Dec 7, 2016
1b36ca0
minor health tweak to benchmark.py
wojcikstefan Dec 7, 2016
0fc44ef
minor tweak to python_support
wojcikstefan Dec 7, 2016
bc83ba6
minor tweaks to Document._build_index_specs
wojcikstefan Dec 7, 2016
c1993de
remove one last unicode + safer default param
wojcikstefan Dec 7, 2016
c43a5fe
add .landscape.yml
wojcikstefan Dec 7, 2016
f6b8899
fix broken inheritance for Document and EmbeddedDocument
wojcikstefan Dec 8, 2016
8f657e0
cleaner code + prefer top-level import over _import_class
wojcikstefan Dec 8, 2016
4373ea9
more import fixes
wojcikstefan Dec 8, 2016
edbecb4
minimize cyclic import warnings
wojcikstefan Dec 8, 2016
bb81652
nicer imports
wojcikstefan Dec 8, 2016
205a975
fix flake8
wojcikstefan Dec 8, 2016
0189818
clearer .landscape.yml + change self.__class__._meta to self._meta
wojcikstefan Dec 8, 2016
ae777e4
better comment about overriding allow_inheritance
wojcikstefan Dec 8, 2016
18a91cc
drop an unnecessary ALLOW_INHERITANCE
wojcikstefan Dec 8, 2016
fa6949e
no need to redefine PY3 - six already has it
wojcikstefan Dec 8, 2016
c86155e
cleaner connection code
wojcikstefan Dec 8, 2016
b02904e
BREAKING CHANGE rename ConnectionError to MongoEngineConnectionError …
wojcikstefan Dec 8, 2016
b282511
remove unnecessary parentheses
wojcikstefan Dec 8, 2016
4b02440
fix benchmark.py + ignore it in landscape
wojcikstefan Dec 8, 2016
9a32ff4
document and slightly simplify BaseDocument._lookup_field
wojcikstefan Dec 8, 2016
f1f999a
cleanup + nicer EmbeddedDocumentList.__match_all and __only_matches
wojcikstefan Dec 8, 2016
44b86e2
more cleanup
wojcikstefan Dec 9, 2016
7621990
nicer merge_index_specs (thanks @gukoff!)
wojcikstefan Dec 9, 2016
5b7b65a
Prefer ' over " + minor docstring tweaks
wojcikstefan Dec 9, 2016
4e1145d
improve documentation regarding allow_inheritance
wojcikstefan Dec 9, 2016
b99985e
slightly cleaner and more performant BaseQuerySet.delete
wojcikstefan Dec 9, 2016
756d8b2
remove ridiculous try-finally clause from BaseQuerySet.distinct
wojcikstefan Dec 9, 2016
6eb470a
remove unnecessary usage of the "global" keyword
wojcikstefan Dec 9, 2016
e50b23f
remove xrange and unused variables
wojcikstefan Dec 9, 2016
cb1eda4
remove outdated migration tests
wojcikstefan Dec 9, 2016
37c8635
drop Python v2.6 support and use dict comprehensions
wojcikstefan Dec 10, 2016
5778cb4
merge master into improve-health-2
wojcikstefan Dec 10, 2016
566e8ee
readd accidentally dropped line in setup.cfg
wojcikstefan Dec 10, 2016
30ebe7c
make the delete rules nicer and safer in BaseQuerySet.delete
wojcikstefan Dec 10, 2016
94870d7
merge master into improve-health-2
wojcikstefan Dec 10, 2016
1e9a120
drop unused imports
wojcikstefan Dec 10, 2016
d89cdff
remove unused import and dont override built-in "id"
wojcikstefan Dec 10, 2016
fa9ca25
remove more python 2.6 code + upgrade coverage + cleaner setup.py
wojcikstefan Dec 11, 2016
a9c205b
remove ridiculous verify_exists option from URLField
wojcikstefan Dec 11, 2016
05fea58
remove a print statement
wojcikstefan Dec 11, 2016
5b70a45
fix improper syntax for datetimes
wojcikstefan Dec 11, 2016
500b182
deprecate explain's format param
wojcikstefan Dec 11, 2016
b32cd19
setup.cfg cleanup + only run coveralls on py27
wojcikstefan Dec 11, 2016
eb90398
remove a print statement
wojcikstefan Dec 11, 2016
a888439
restore cover-package in setup.cfg
wojcikstefan Dec 11, 2016
3ebe374
use with self.assertRaises for readability
wojcikstefan Dec 11, 2016
7ffaace
update setup.py classifiers
wojcikstefan Dec 11, 2016
a12abe2
add xrange as a valid built-in in landscape
wojcikstefan Dec 11, 2016
688ea4f
add long to built-ins in landscape
wojcikstefan Dec 11, 2016
dc15195
merge master into improve-health-2
wojcikstefan Dec 11, 2016
93d8d97
fix .landscape.yml
wojcikstefan Dec 11, 2016
d517880
Merge branch 'master' of github.com:MongoEngine/mongoengine into impr…
wojcikstefan Dec 11, 2016
af6601a
update changelog and upgrade docs
wojcikstefan Dec 11, 2016
1199f0d
another attempt at the right landscape config
wojcikstefan Dec 11, 2016
501f6f1
try another landscape approach
wojcikstefan Dec 11, 2016
828d5d6
*finally* a working .landscape.yml
wojcikstefan Dec 11, 2016
fdc1d94
slightly simpler condition in _clear_changed_fields
wojcikstefan Dec 11, 2016
953123b
minor compat tweak
wojcikstefan Dec 11, 2016
60571ce
document breaking change where we dont allow outdated "from mongoengi…
wojcikstefan Dec 11, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .landscape.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pylint:
disable:
# We use this a lot (e.g. via document._meta)
- protected-access

options:
additional-builtins:
# add xrange and long as valid built-ins. In Python 3, xrange is
# translated into range and long is translated into int via 2to3 (see
# "use_2to3" in setup.py). This should be removed when we drop Python
# 2 support (which probably won't happen any time soon).
- xrange
- long

pyflakes:
disable:
# undefined variables are already covered by pylint (and exclude
# xrange & long)
- F821

ignore-paths:
- benchmark.py
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: python

python:
- '2.6' # TODO remove in v0.11.0
- '2.7'
- '3.3'
- '3.4'
Expand Down Expand Up @@ -43,7 +42,11 @@ before_script:
script:
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- --with-coverage

after_script: coveralls --verbose
# For now only submit coveralls for Python v2.7. Python v3.x currently shows
# 0% coverage. That's caused by 'use_2to3', which builds the py3-compatible
# code in a separate dir and runs tests on that.
after_script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls --verbose; fi

notifications:
irc: irc.freenode.org#mongoengine
Expand Down
152 changes: 38 additions & 114 deletions benchmark.py
Original file line number Diff line number Diff line change
@@ -1,118 +1,41 @@
#!/usr/bin/env python

import timeit


def cprofile_main():
from pymongo import Connection
connection = Connection()
connection.drop_database('timeit_test')
connection.disconnect()

from mongoengine import Document, DictField, connect
connect("timeit_test")

class Noddy(Document):
fields = DictField()
"""
Simple benchmark comparing PyMongo and MongoEngine.

Sample run on a mid 2015 MacBook Pro (commit b282511):

Benchmarking...
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
2.58979988098
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo write_concern={"w": 0}
1.26657605171
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
8.4351580143
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries without continual assign - MongoEngine
7.20191693306
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine - write_concern={"w": 0}, cascade = True
6.31104588509
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False, cascade=True
6.07083487511
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False
5.97704291344
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, force_insert=True, write_concern={"w": 0}, validate=False
5.9111430645
"""

for i in range(1):
noddy = Noddy()
for j in range(20):
noddy.fields["key" + str(j)] = "value " + str(j)
noddy.save()
import timeit


def main():
"""
0.4 Performance Figures ...

----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
3.86744189262
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
6.23374891281
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
5.33027005196
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
pass - No Cascade

0.5.X
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
3.89597702026
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
21.7735359669
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
19.8670389652
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
pass - No Cascade

0.6.X
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
3.81559205055
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
10.0446798801
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
9.51354718208
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
9.02567505836
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, force=True
8.44933390617

0.7.X
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
3.78801012039
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
9.73050498962
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
8.33456707001
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
8.37778115273
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, force=True
8.36906409264
0.8.X
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo
3.69964408875
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - Pymongo write_concern={"w": 0}
3.5526599884
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine
7.00959801674
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries without continual assign - MongoEngine
5.60943293571
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine - write_concern={"w": 0}, cascade=True
6.715102911
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False, cascade=True
5.50644683838
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False
4.69851183891
----------------------------------------------------------------------------------------------------
Creating 10000 dictionaries - MongoEngine, force_insert=True, write_concern={"w": 0}, validate=False
4.68946313858
----------------------------------------------------------------------------------------------------
"""
print("Benchmarking...")

setup = """
Expand All @@ -131,7 +54,7 @@ def main():
for i in range(10000):
example = {'fields': {}}
for j in range(20):
example['fields']["key"+str(j)] = "value "+str(j)
example['fields']['key' + str(j)] = 'value ' + str(j)

noddy.save(example)

Expand All @@ -146,17 +69,18 @@ def main():

stmt = """
from pymongo import MongoClient
from pymongo.write_concern import WriteConcern
connection = MongoClient()

db = connection.timeit_test
db = connection.get_database('timeit_test', write_concern=WriteConcern(w=0))
noddy = db.noddy

for i in range(10000):
example = {'fields': {}}
for j in range(20):
example['fields']["key"+str(j)] = "value "+str(j)

noddy.save(example, write_concern={"w": 0})
noddy.save(example)

myNoddys = noddy.find()
[n for n in myNoddys] # iterate
Expand All @@ -171,10 +95,10 @@ def main():
from pymongo import MongoClient
connection = MongoClient()
connection.drop_database('timeit_test')
connection.disconnect()
connection.close()

from mongoengine import Document, DictField, connect
connect("timeit_test")
connect('timeit_test')

class Noddy(Document):
fields = DictField()
Expand Down
7 changes: 7 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Changelog

Development
===========
- (Fill this out as you fix issues and develop you features).

Changes in 0.11.0
=================
- BREAKING CHANGE: Renamed `ConnectionError` to `MongoEngineConnectionError` since the former is a built-in exception name in Python v3.x. #1428
- BREAKING CHANGE: Dropped Python 2.6 support. #1428
- BREAKING CHANGE: `from mongoengine.base import ErrorClass` won't work anymore for any error from `mongoengine.errors` (e.g. `ValidationError`). Use `from mongoengine.errors import ErrorClass instead`. #1428
- Fixed absent rounding for DecimalField when `force_string` is set. #1103

Changes in 0.10.8
Expand Down
26 changes: 26 additions & 0 deletions docs/upgrade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@
Upgrading
#########

0.11.0
******
This release includes a major rehaul of MongoEngine's code quality and
introduces a few breaking changes. It also touches many different parts of
the package and although all the changes have been tested and scrutinized,
you're encouraged to thorougly test the upgrade.

First breaking change involves renaming `ConnectionError` to `MongoEngineConnectionError`.
If you import or catch this exception, you'll need to rename it in your code.

Second breaking change drops Python v2.6 support. If you run MongoEngine on
that Python version, you'll need to upgrade it first.

Third breaking change drops an old backward compatibility measure where
`from mongoengine.base import ErrorClass` would work on top of
`from mongoengine.errors import ErrorClass` (where `ErrorClass` is e.g.
`ValidationError`). If you import any exceptions from `mongoengine.base`,
change it to `mongoengine.errors`.

0.10.8
******
This version fixed an issue where specifying a MongoDB URI host would override
more information than it should. These changes are minor, but they still
subtly modify the connection logic and thus you're encouraged to test your
MongoDB connection before shipping v0.10.8 in production.

0.10.7
******

Expand Down
44 changes: 27 additions & 17 deletions mongoengine/__init__.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import connection
from connection import *
import document
from document import *
import errors
from errors import *
import fields
from fields import *
import queryset
from queryset import *
import signals
from signals import *

__all__ = (list(document.__all__) + fields.__all__ + connection.__all__ +
list(queryset.__all__) + signals.__all__ + list(errors.__all__))
# Import submodules so that we can expose their __all__
from mongoengine import connection
from mongoengine import document
from mongoengine import errors
from mongoengine import fields
from mongoengine import queryset
from mongoengine import signals

# Import everything from each submodule so that it can be accessed via
# mongoengine, e.g. instead of `from mongoengine.connection import connect`,
# users can simply use `from mongoengine import connect`, or even
# `from mongoengine import *` and then `connect('testdb')`.
from mongoengine.connection import *
from mongoengine.document import *
from mongoengine.errors import *
from mongoengine.fields import *
from mongoengine.queryset import *
from mongoengine.signals import *


__all__ = (list(document.__all__) + list(fields.__all__) +
list(connection.__all__) + list(queryset.__all__) +
list(signals.__all__) + list(errors.__all__))


VERSION = (0, 10, 9)


def get_version():
if isinstance(VERSION[-1], basestring):
return '.'.join(map(str, VERSION[:-1])) + VERSION[-1]
"""Return the VERSION as a string, e.g. for VERSION == (0, 10, 7),
return '0.10.7'.
"""
return '.'.join(map(str, VERSION))


Expand Down
24 changes: 22 additions & 2 deletions mongoengine/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
# Base module is split into several files for convenience. Files inside of
# this module should import from a specific submodule (e.g.
# `from mongoengine.base.document import BaseDocument`), but all of the
# other modules should import directly from the top-level module (e.g.
# `from mongoengine.base import BaseDocument`). This approach is cleaner and
# also helps with cyclical import errors.
from mongoengine.base.common import *
from mongoengine.base.datastructures import *
from mongoengine.base.document import *
from mongoengine.base.fields import *
from mongoengine.base.metaclasses import *

# Help with backwards compatibility
from mongoengine.errors import *
__all__ = (
# common
'UPDATE_OPERATORS', '_document_registry', 'get_document',

# datastructures
'BaseDict', 'BaseList', 'EmbeddedDocumentList',

# document
'BaseDocument',

# fields
'BaseField', 'ComplexBaseField', 'ObjectIdField', 'GeoJsonBaseField',

# metaclasses
'DocumentMetaclass', 'TopLevelDocumentMetaclass'
)
9 changes: 7 additions & 2 deletions mongoengine/base/common.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from mongoengine.errors import NotRegistered

__all__ = ('ALLOW_INHERITANCE', 'get_document', '_document_registry')
__all__ = ('UPDATE_OPERATORS', 'get_document', '_document_registry')


UPDATE_OPERATORS = set(['set', 'unset', 'inc', 'dec', 'pop', 'push',
'push_all', 'pull', 'pull_all', 'add_to_set',
'set_on_insert', 'min', 'max'])

ALLOW_INHERITANCE = False

_document_registry = {}


def get_document(name):
"""Get a document class by name."""
doc = _document_registry.get(name, None)
if not doc:
# Possible old style name
Expand Down
Loading