Skip to content

Commit 835d3c3

Browse files
authored
Improve the health of this package (#1428)
1 parent 3135b45 commit 835d3c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1567
-1896
lines changed

.landscape.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pylint:
2+
disable:
3+
# We use this a lot (e.g. via document._meta)
4+
- protected-access
5+
6+
options:
7+
additional-builtins:
8+
# add xrange and long as valid built-ins. In Python 3, xrange is
9+
# translated into range and long is translated into int via 2to3 (see
10+
# "use_2to3" in setup.py). This should be removed when we drop Python
11+
# 2 support (which probably won't happen any time soon).
12+
- xrange
13+
- long
14+
15+
pyflakes:
16+
disable:
17+
# undefined variables are already covered by pylint (and exclude
18+
# xrange & long)
19+
- F821
20+
21+
ignore-paths:
22+
- benchmark.py

.travis.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
language: python
22

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

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

4851
notifications:
4952
irc: irc.freenode.org#mongoengine

benchmark.py

Lines changed: 38 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,41 @@
11
#!/usr/bin/env python
22

3-
import timeit
4-
5-
6-
def cprofile_main():
7-
from pymongo import Connection
8-
connection = Connection()
9-
connection.drop_database('timeit_test')
10-
connection.disconnect()
11-
12-
from mongoengine import Document, DictField, connect
13-
connect("timeit_test")
14-
15-
class Noddy(Document):
16-
fields = DictField()
3+
"""
4+
Simple benchmark comparing PyMongo and MongoEngine.
5+
6+
Sample run on a mid 2015 MacBook Pro (commit b282511):
7+
8+
Benchmarking...
9+
----------------------------------------------------------------------------------------------------
10+
Creating 10000 dictionaries - Pymongo
11+
2.58979988098
12+
----------------------------------------------------------------------------------------------------
13+
Creating 10000 dictionaries - Pymongo write_concern={"w": 0}
14+
1.26657605171
15+
----------------------------------------------------------------------------------------------------
16+
Creating 10000 dictionaries - MongoEngine
17+
8.4351580143
18+
----------------------------------------------------------------------------------------------------
19+
Creating 10000 dictionaries without continual assign - MongoEngine
20+
7.20191693306
21+
----------------------------------------------------------------------------------------------------
22+
Creating 10000 dictionaries - MongoEngine - write_concern={"w": 0}, cascade = True
23+
6.31104588509
24+
----------------------------------------------------------------------------------------------------
25+
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False, cascade=True
26+
6.07083487511
27+
----------------------------------------------------------------------------------------------------
28+
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False
29+
5.97704291344
30+
----------------------------------------------------------------------------------------------------
31+
Creating 10000 dictionaries - MongoEngine, force_insert=True, write_concern={"w": 0}, validate=False
32+
5.9111430645
33+
"""
1734

18-
for i in range(1):
19-
noddy = Noddy()
20-
for j in range(20):
21-
noddy.fields["key" + str(j)] = "value " + str(j)
22-
noddy.save()
35+
import timeit
2336

2437

2538
def main():
26-
"""
27-
0.4 Performance Figures ...
28-
29-
----------------------------------------------------------------------------------------------------
30-
Creating 10000 dictionaries - Pymongo
31-
3.86744189262
32-
----------------------------------------------------------------------------------------------------
33-
Creating 10000 dictionaries - MongoEngine
34-
6.23374891281
35-
----------------------------------------------------------------------------------------------------
36-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
37-
5.33027005196
38-
----------------------------------------------------------------------------------------------------
39-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
40-
pass - No Cascade
41-
42-
0.5.X
43-
----------------------------------------------------------------------------------------------------
44-
Creating 10000 dictionaries - Pymongo
45-
3.89597702026
46-
----------------------------------------------------------------------------------------------------
47-
Creating 10000 dictionaries - MongoEngine
48-
21.7735359669
49-
----------------------------------------------------------------------------------------------------
50-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
51-
19.8670389652
52-
----------------------------------------------------------------------------------------------------
53-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
54-
pass - No Cascade
55-
56-
0.6.X
57-
----------------------------------------------------------------------------------------------------
58-
Creating 10000 dictionaries - Pymongo
59-
3.81559205055
60-
----------------------------------------------------------------------------------------------------
61-
Creating 10000 dictionaries - MongoEngine
62-
10.0446798801
63-
----------------------------------------------------------------------------------------------------
64-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
65-
9.51354718208
66-
----------------------------------------------------------------------------------------------------
67-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
68-
9.02567505836
69-
----------------------------------------------------------------------------------------------------
70-
Creating 10000 dictionaries - MongoEngine, force=True
71-
8.44933390617
72-
73-
0.7.X
74-
----------------------------------------------------------------------------------------------------
75-
Creating 10000 dictionaries - Pymongo
76-
3.78801012039
77-
----------------------------------------------------------------------------------------------------
78-
Creating 10000 dictionaries - MongoEngine
79-
9.73050498962
80-
----------------------------------------------------------------------------------------------------
81-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False
82-
8.33456707001
83-
----------------------------------------------------------------------------------------------------
84-
Creating 10000 dictionaries - MongoEngine, safe=False, validate=False, cascade=False
85-
8.37778115273
86-
----------------------------------------------------------------------------------------------------
87-
Creating 10000 dictionaries - MongoEngine, force=True
88-
8.36906409264
89-
0.8.X
90-
----------------------------------------------------------------------------------------------------
91-
Creating 10000 dictionaries - Pymongo
92-
3.69964408875
93-
----------------------------------------------------------------------------------------------------
94-
Creating 10000 dictionaries - Pymongo write_concern={"w": 0}
95-
3.5526599884
96-
----------------------------------------------------------------------------------------------------
97-
Creating 10000 dictionaries - MongoEngine
98-
7.00959801674
99-
----------------------------------------------------------------------------------------------------
100-
Creating 10000 dictionaries without continual assign - MongoEngine
101-
5.60943293571
102-
----------------------------------------------------------------------------------------------------
103-
Creating 10000 dictionaries - MongoEngine - write_concern={"w": 0}, cascade=True
104-
6.715102911
105-
----------------------------------------------------------------------------------------------------
106-
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False, cascade=True
107-
5.50644683838
108-
----------------------------------------------------------------------------------------------------
109-
Creating 10000 dictionaries - MongoEngine, write_concern={"w": 0}, validate=False
110-
4.69851183891
111-
----------------------------------------------------------------------------------------------------
112-
Creating 10000 dictionaries - MongoEngine, force_insert=True, write_concern={"w": 0}, validate=False
113-
4.68946313858
114-
----------------------------------------------------------------------------------------------------
115-
"""
11639
print("Benchmarking...")
11740

11841
setup = """
@@ -131,7 +54,7 @@ def main():
13154
for i in range(10000):
13255
example = {'fields': {}}
13356
for j in range(20):
134-
example['fields']["key"+str(j)] = "value "+str(j)
57+
example['fields']['key' + str(j)] = 'value ' + str(j)
13558
13659
noddy.save(example)
13760
@@ -146,17 +69,18 @@ def main():
14669

14770
stmt = """
14871
from pymongo import MongoClient
72+
from pymongo.write_concern import WriteConcern
14973
connection = MongoClient()
15074
151-
db = connection.timeit_test
75+
db = connection.get_database('timeit_test', write_concern=WriteConcern(w=0))
15276
noddy = db.noddy
15377
15478
for i in range(10000):
15579
example = {'fields': {}}
15680
for j in range(20):
15781
example['fields']["key"+str(j)] = "value "+str(j)
15882
159-
noddy.save(example, write_concern={"w": 0})
83+
noddy.save(example)
16084
16185
myNoddys = noddy.find()
16286
[n for n in myNoddys] # iterate
@@ -171,10 +95,10 @@ def main():
17195
from pymongo import MongoClient
17296
connection = MongoClient()
17397
connection.drop_database('timeit_test')
174-
connection.disconnect()
98+
connection.close()
17599
176100
from mongoengine import Document, DictField, connect
177-
connect("timeit_test")
101+
connect('timeit_test')
178102
179103
class Noddy(Document):
180104
fields = DictField()

docs/changelog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Changelog
44

55
Development
66
===========
7+
- (Fill this out as you fix issues and develop you features).
8+
9+
Changes in 0.11.0
10+
=================
11+
- BREAKING CHANGE: Renamed `ConnectionError` to `MongoEngineConnectionError` since the former is a built-in exception name in Python v3.x. #1428
12+
- BREAKING CHANGE: Dropped Python 2.6 support. #1428
13+
- 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
714
- Fixed absent rounding for DecimalField when `force_string` is set. #1103
815

916
Changes in 0.10.8

docs/upgrade.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@
22
Upgrading
33
#########
44

5+
0.11.0
6+
******
7+
This release includes a major rehaul of MongoEngine's code quality and
8+
introduces a few breaking changes. It also touches many different parts of
9+
the package and although all the changes have been tested and scrutinized,
10+
you're encouraged to thorougly test the upgrade.
11+
12+
First breaking change involves renaming `ConnectionError` to `MongoEngineConnectionError`.
13+
If you import or catch this exception, you'll need to rename it in your code.
14+
15+
Second breaking change drops Python v2.6 support. If you run MongoEngine on
16+
that Python version, you'll need to upgrade it first.
17+
18+
Third breaking change drops an old backward compatibility measure where
19+
`from mongoengine.base import ErrorClass` would work on top of
20+
`from mongoengine.errors import ErrorClass` (where `ErrorClass` is e.g.
21+
`ValidationError`). If you import any exceptions from `mongoengine.base`,
22+
change it to `mongoengine.errors`.
23+
24+
0.10.8
25+
******
26+
This version fixed an issue where specifying a MongoDB URI host would override
27+
more information than it should. These changes are minor, but they still
28+
subtly modify the connection logic and thus you're encouraged to test your
29+
MongoDB connection before shipping v0.10.8 in production.
30+
531
0.10.7
632
******
733

mongoengine/__init__.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
1-
import connection
2-
from connection import *
3-
import document
4-
from document import *
5-
import errors
6-
from errors import *
7-
import fields
8-
from fields import *
9-
import queryset
10-
from queryset import *
11-
import signals
12-
from signals import *
13-
14-
__all__ = (list(document.__all__) + fields.__all__ + connection.__all__ +
15-
list(queryset.__all__) + signals.__all__ + list(errors.__all__))
1+
# Import submodules so that we can expose their __all__
2+
from mongoengine import connection
3+
from mongoengine import document
4+
from mongoengine import errors
5+
from mongoengine import fields
6+
from mongoengine import queryset
7+
from mongoengine import signals
8+
9+
# Import everything from each submodule so that it can be accessed via
10+
# mongoengine, e.g. instead of `from mongoengine.connection import connect`,
11+
# users can simply use `from mongoengine import connect`, or even
12+
# `from mongoengine import *` and then `connect('testdb')`.
13+
from mongoengine.connection import *
14+
from mongoengine.document import *
15+
from mongoengine.errors import *
16+
from mongoengine.fields import *
17+
from mongoengine.queryset import *
18+
from mongoengine.signals import *
19+
20+
21+
__all__ = (list(document.__all__) + list(fields.__all__) +
22+
list(connection.__all__) + list(queryset.__all__) +
23+
list(signals.__all__) + list(errors.__all__))
24+
1625

1726
VERSION = (0, 10, 9)
1827

1928

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

2535

mongoengine/base/__init__.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1+
# Base module is split into several files for convenience. Files inside of
2+
# this module should import from a specific submodule (e.g.
3+
# `from mongoengine.base.document import BaseDocument`), but all of the
4+
# other modules should import directly from the top-level module (e.g.
5+
# `from mongoengine.base import BaseDocument`). This approach is cleaner and
6+
# also helps with cyclical import errors.
17
from mongoengine.base.common import *
28
from mongoengine.base.datastructures import *
39
from mongoengine.base.document import *
410
from mongoengine.base.fields import *
511
from mongoengine.base.metaclasses import *
612

7-
# Help with backwards compatibility
8-
from mongoengine.errors import *
13+
__all__ = (
14+
# common
15+
'UPDATE_OPERATORS', '_document_registry', 'get_document',
16+
17+
# datastructures
18+
'BaseDict', 'BaseList', 'EmbeddedDocumentList',
19+
20+
# document
21+
'BaseDocument',
22+
23+
# fields
24+
'BaseField', 'ComplexBaseField', 'ObjectIdField', 'GeoJsonBaseField',
25+
26+
# metaclasses
27+
'DocumentMetaclass', 'TopLevelDocumentMetaclass'
28+
)

mongoengine/base/common.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
from mongoengine.errors import NotRegistered
22

3-
__all__ = ('ALLOW_INHERITANCE', 'get_document', '_document_registry')
3+
__all__ = ('UPDATE_OPERATORS', 'get_document', '_document_registry')
4+
5+
6+
UPDATE_OPERATORS = set(['set', 'unset', 'inc', 'dec', 'pop', 'push',
7+
'push_all', 'pull', 'pull_all', 'add_to_set',
8+
'set_on_insert', 'min', 'max'])
49

5-
ALLOW_INHERITANCE = False
610

711
_document_registry = {}
812

913

1014
def get_document(name):
15+
"""Get a document class by name."""
1116
doc = _document_registry.get(name, None)
1217
if not doc:
1318
# Possible old style name

0 commit comments

Comments
 (0)