Skip to content

Commit fce79d8

Browse files
committed
Merged changes to include new connection manager.
1 parent 4672ad2 commit fce79d8

31 files changed

+619
-170
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ python:
1010
- pypy3
1111

1212
env:
13-
- MONGOENGINE=0.7
1413
- MONGOENGINE=0.8
1514
- MONGOENGINE=0.9
1615
- MONGOENGINE=0.10.0

AUTHORS

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
The PRIMARY AUTHORS are (and/or have been):
22

33
Ross Lawley <[email protected]>
4+
Bright Dadson <[email protected]>
45
Jorge Bastida <[email protected]>
56
Dan Jacob https://bitbucket.org/danjac
67
Marat Khabibullin https://bitbucket.org/maratfm
@@ -29,3 +30,5 @@ that much better:
2930
* Len Buckens - https://github.com/buckensl
3031
* Garito - https://github.com/garito
3132
* Jérôme Lafréchoux (Nobatek) - http://nobatek.com
33+
* Bruno Belarmino - https://github.com/brunobelarmino
34+
* Sibelius Seraphini - https://github.com/sibelius

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2010-2012 See AUTHORS.
1+
Copyright (c) 2010-2016 See AUTHORS.
22

33
Some rights reserved.
44

docs/changelog.rst

+21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22
Changelog
33
=========
44

5+
Changes in 0.8
6+
==============
7+
8+
- Dropped MongoEngine 0.7 support
9+
- Added MongoEngine 0.10 support
10+
- Added PyMongo 3 support
11+
- Added Python3 support up to 3.5
12+
- Allowed empying value list in SelectMultipleField
13+
- Fixed paginator issues
14+
- Use InputRequired validator to allow 0 in required field
15+
- Made help_text Field attribute optional
16+
- Added RadioField
17+
- Added field parameters (validators, filters...)
18+
- Fixed 'False' connection settings ignored
19+
- Fixed bug to allow multiple instances of extension
20+
- Added MongoEngineSessionInterface support for PyMongo's tz_aware option
21+
- Support arbitrary primary key fields (not "id")
22+
- Configurable httponly flag for MongoEngineSessionInterface
23+
- Various bugfixes, code cleanup and documentation improvements
24+
- Move from deprecated flask.ext.* to flask_* syntax in imports
25+
526
Changes in 0.7
627
==============
728
- Fixed only / exclude in model forms (#49)

docs/index.rst

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Configuration
2020
Basic setup is easy, just fetch the extension::
2121

2222
from flask import Flask
23-
from flask.ext.mongoengine import MongoEngine
23+
from flask_mongoengine import MongoEngine
2424

2525
app = Flask(__name__)
2626
app.config.from_pyfile('the-config.cfg')
@@ -29,7 +29,7 @@ Basic setup is easy, just fetch the extension::
2929
Or, if you are setting up your database before your app is initialized, as is the case with application factories::
3030

3131
from flask import Flask
32-
from flask.ext.mongoengine import MongoEngine
32+
from flask_mongoengine import MongoEngine
3333
db = MongoEngine()
3434
...
3535
app = Flask(__name__)
@@ -130,7 +130,7 @@ MongoEngine and WTForms
130130

131131
You can use MongoEngine and WTForms like so::
132132

133-
from flask.ext.mongoengine.wtf import model_form
133+
from flask_mongoengine.wtf import model_form
134134

135135
class User(db.Document):
136136
email = db.StringField(required=True)
@@ -187,7 +187,7 @@ Session Interface
187187

188188
To use MongoEngine as your session store simple configure the session interface::
189189

190-
from flask.ext.mongoengine import MongoEngine, MongoEngineSessionInterface
190+
from flask_mongoengine import MongoEngine, MongoEngineSessionInterface
191191

192192
app = Flask(__name__)
193193
db = MongoEngine(app)
@@ -201,14 +201,14 @@ Debug Toolbar Panel
201201
:target: #debug-toolbar-panel
202202

203203
If you use the Flask-DebugToolbar you can add
204-
`'flask.ext.mongoengine.panels.MongoDebugPanel'` to the `DEBUG_TB_PANELS` config
204+
`'flask_mongoengine.panels.MongoDebugPanel'` to the `DEBUG_TB_PANELS` config
205205
list and then it will automatically track your queries::
206206

207207
from flask import Flask
208208
from flask_debugtoolbar import DebugToolbarExtension
209209

210210
app = Flask(__name__)
211-
app.config['DEBUG_TB_PANELS'] = ['flask.ext.mongoengine.panels.MongoDebugPanel']
211+
app.config['DEBUG_TB_PANELS'] = ['flask_mongoengine.panels.MongoDebugPanel']
212212
db = MongoEngine(app)
213213
toolbar = DebugToolbarExtension(app)
214214

examples/biggerapp/app.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
app.config['SECRET_KEY'] = 'flask+mongoengine=<3'
1414
app.debug = True
1515
app.config['DEBUG_TB_PANELS'] = (
16-
'flask.ext.debugtoolbar.panels.versions.VersionDebugPanel',
17-
'flask.ext.debugtoolbar.panels.timer.TimerDebugPanel',
18-
'flask.ext.debugtoolbar.panels.headers.HeaderDebugPanel',
19-
'flask.ext.debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
20-
'flask.ext.debugtoolbar.panels.template.TemplateDebugPanel',
21-
'flask.ext.debugtoolbar.panels.logger.LoggingPanel',
22-
'flask.ext.mongoengine.panels.MongoDebugPanel'
16+
'flask_debugtoolbar.panels.versions.VersionDebugPanel',
17+
'flask_debugtoolbar.panels.timer.TimerDebugPanel',
18+
'flask_debugtoolbar.panels.headers.HeaderDebugPanel',
19+
'flask_debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
20+
'flask_debugtoolbar.panels.template.TemplateDebugPanel',
21+
'flask_debugtoolbar.panels.logger.LoggingPanel',
22+
'flask_mongoengine.panels.MongoDebugPanel'
2323
)
2424

2525
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False

examples/biggerapp/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from flask.ext.mongoengine import MongoEngine
2+
from flask_mongoengine import MongoEngine
33

44
db = MongoEngine()
55

examples/simpleapp/app.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '../../')))
88

99

10-
from flask.ext.mongoengine import MongoEngine
10+
from flask_mongoengine import MongoEngine
1111
from flask_debugtoolbar import DebugToolbarExtension
1212

1313
app = flask.Flask(__name__)
@@ -17,13 +17,13 @@
1717
app.config['SECRET_KEY'] = 'flask+mongoengine=<3'
1818
app.debug = True
1919
app.config['DEBUG_TB_PANELS'] = (
20-
'flask.ext.debugtoolbar.panels.versions.VersionDebugPanel',
21-
'flask.ext.debugtoolbar.panels.timer.TimerDebugPanel',
22-
'flask.ext.debugtoolbar.panels.headers.HeaderDebugPanel',
23-
'flask.ext.debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
24-
'flask.ext.debugtoolbar.panels.template.TemplateDebugPanel',
25-
'flask.ext.debugtoolbar.panels.logger.LoggingPanel',
26-
'flask.ext.mongoengine.panels.MongoDebugPanel'
20+
'flask_debugtoolbar.panels.versions.VersionDebugPanel',
21+
'flask_debugtoolbar.panels.timer.TimerDebugPanel',
22+
'flask_debugtoolbar.panels.headers.HeaderDebugPanel',
23+
'flask_debugtoolbar.panels.request_vars.RequestVarsDebugPanel',
24+
'flask_debugtoolbar.panels.template.TemplateDebugPanel',
25+
'flask_debugtoolbar.panels.logger.LoggingPanel',
26+
'flask_mongoengine.panels.MongoDebugPanel'
2727
)
2828

2929
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False

flask_mongoengine/__init__.py

+69-64
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,44 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import
3-
import inspect
3+
import mongoengine, inspect
44

55
from flask import abort, current_app
6+
from mongoengine.base.fields import BaseField
7+
from mongoengine.queryset import (MultipleObjectsReturned,
8+
DoesNotExist, QuerySet)
69

7-
import mongoengine
8-
9-
if mongoengine.__version__ == '0.7.10':
10-
from mongoengine.base import BaseField
11-
else:
12-
from mongoengine.base.fields import BaseField
13-
14-
15-
from mongoengine.queryset import MultipleObjectsReturned, DoesNotExist, QuerySet
1610
from mongoengine.base import ValidationError
17-
1811
from pymongo import uri_parser
19-
2012
from .sessions import *
2113
from .pagination import *
2214
from .metadata import *
23-
from .json import overide_json_encoder
15+
from .json import override_json_encoder
2416
from .wtf import WtfBaseField
17+
from .connection import *
18+
import flask_mongoengine
2519

26-
def _patch_base_field(object, name):
20+
def redirect_connection_calls(cls):
21+
"""
22+
Redirect mongonengine.connection
23+
calls via flask_mongoengine.connection
24+
"""
25+
26+
# Proxy all 'mongoengine.connection'
27+
# specific attr via 'flask_mongoengine'
28+
connection_methods = {
29+
'get_db' : get_db,
30+
'DEFAULT_CONNECTION_NAME' : DEFAULT_CONNECTION_NAME,
31+
'get_connection' : get_connection
32+
}
33+
34+
cls_module = inspect.getmodule(cls)
35+
if cls_module != mongoengine.connection:
36+
for attr in inspect.getmembers(cls_module):
37+
n = attr[0]
38+
if connection_methods.get(n, None):
39+
setattr(cls_module, n, connection_methods.get(n, None))
40+
41+
def _patch_base_field(obj, name):
2742
"""
2843
If the object submitted has a class whose base class is
2944
mongoengine.base.fields.BaseField, then monkey patch to
@@ -36,12 +51,12 @@ def _patch_base_field(object, name):
3651
@see: flask_mongoengine.wtf.base.WtfBaseField.
3752
@see: model_form in flask_mongoengine.wtf.orm
3853
39-
@param object: The object whose footprint to locate the class.
54+
@param obj: The object whose footprint to locate the class.
4055
@param name: Name of the class to locate.
4156
4257
"""
4358
# locate class
44-
cls = getattr(object, name)
59+
cls = getattr(obj, name)
4560
if not inspect.isclass(cls):
4661
return
4762

@@ -57,9 +72,9 @@ def _patch_base_field(object, name):
5772

5873
# re-assign class back to
5974
# object footprint
60-
delattr(object, name)
61-
setattr(object, name, cls)
62-
75+
delattr(obj, name)
76+
setattr(obj, name, cls)
77+
redirect_connection_calls(cls)
6378

6479
def _include_mongoengine(obj):
6580
for module in mongoengine, mongoengine.fields:
@@ -70,30 +85,19 @@ def _include_mongoengine(obj):
7085
# patch BaseField if available
7186
_patch_base_field(obj, key)
7287

73-
74-
def _create_connection(conn_settings):
75-
76-
# Handle multiple connections recursively
77-
if isinstance(conn_settings, list):
78-
connections = {}
79-
for conn in conn_settings:
80-
connections[conn.get('alias')] = _create_connection(conn)
81-
return connections
82-
83-
# Ugly dict comprehention in order to support python 2.6
84-
conn = dict((k.lower(), v) for k, v in conn_settings.items() if v is not None)
85-
86-
if 'replicaset' in conn:
87-
conn['replicaSet'] = conn.pop('replicaset')
88-
89-
# Handle uri style connections
90-
if "://" in conn.get('host', ''):
91-
uri_dict = uri_parser.parse_uri(conn['host'])
92-
conn['db'] = uri_dict['database']
93-
94-
return mongoengine.connect(conn.pop('db', 'test'), **conn)
95-
96-
88+
def current_mongoengine_instance():
89+
"""
90+
Obtain instance of MongoEngine in the
91+
current working app instance.
92+
"""
93+
me = current_app.extensions.get('mongoengine', None)
94+
if current_app and me:
95+
instance_dict = me.items()\
96+
if (sys.version_info >= (3, 0)) else me.iteritems()
97+
for k, v in instance_dict:
98+
if isinstance(k, MongoEngine):
99+
return k
100+
return None
97101

98102
class MongoEngine(object):
99103

@@ -107,11 +111,10 @@ def __init__(self, app=None, config=None):
107111
self.init_app(app, config)
108112

109113
def init_app(self, app, config=None):
110-
111114
app.extensions = getattr(app, 'extensions', {})
112115

113116
# Make documents JSON serializable
114-
overide_json_encoder(app)
117+
override_json_encoder(app)
115118

116119
if not 'mongoengine' in app.extensions:
117120
app.extensions['mongoengine'] = {}
@@ -122,27 +125,30 @@ def init_app(self, app, config=None):
122125
raise Exception('Extension already initialized')
123126

124127
if not config:
125-
# If not passed a config then we read the connection settings
126-
# from the app config.
128+
# If not passed a config then we
129+
# read the connection settings from
130+
# the app config.
127131
config = app.config
128132

129-
if 'MONGODB_SETTINGS' in config:
130-
# Connection settings provided as a dictionary.
131-
connection = _create_connection(config['MONGODB_SETTINGS'])
133+
# Obtain db connection
134+
connection = create_connection(config)
135+
136+
# Store objects in application instance
137+
# so that multiple apps do not end up
138+
# accessing the same objects.
139+
s = {'app': app, 'conn': connection}
140+
app.extensions['mongoengine'][self] = s
141+
142+
def disconnect(self):
143+
conn_settings = fetch_connection_settings(current_app.config)
144+
if isinstance(conn_settings, list):
145+
for setting in conn_settings:
146+
alias = setting.get('alias', DEFAULT_CONNECTION_NAME)
147+
disconnect(alias, setting.get('preserve_temp_db', False))
132148
else:
133-
# Connection settings provided in standard format.
134-
settings = {'alias': config.get('MONGODB_ALIAS', None),
135-
'db': config.get('MONGODB_DB', None),
136-
'host': config.get('MONGODB_HOST', None),
137-
'password': config.get('MONGODB_PASSWORD', None),
138-
'port': config.get('MONGODB_PORT', None),
139-
'username': config.get('MONGODB_USERNAME', None)}
140-
connection = _create_connection(settings)
141-
142-
# Store objects in application instance so that multiple apps do
143-
# not end up accessing the same objects.
144-
app.extensions['mongoengine'][self] = {'app': app,
145-
'conn': connection}
149+
alias = conn_settings.get('alias', DEFAULT_CONNECTION_NAME)
150+
disconnect(alias, conn_settings.get('preserve_temp_db', False))
151+
return True
146152

147153
@property
148154
def connection(self):
@@ -179,7 +185,6 @@ def paginate_field(self, field_name, doc_id, page, per_page,
179185
return ListFieldPagination(self, doc_id, field_name, page, per_page,
180186
total=total)
181187

182-
183188
class Document(mongoengine.Document):
184189
"""Abstract document with extra helpers in the queryset class"""
185190

0 commit comments

Comments
 (0)