Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for connect and socket timeout options #22

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 6 additions & 13 deletions docs/index.rst
Expand Up @@ -85,6 +85,12 @@ directives:
``MONGO_MAX_POOL_SIZE`` (optional): The maximum number of idle connections
maintained in the PyMongo connection pool.
Default: PyMongo default.
``MONGO_SOCKET_TIMEOUT_MS`` (optional): (integer) How long (in milliseconds) a send
or receive on a socket can take before timing out.
Default: PyMongo default.
``MONGO_CONNECT_TIMEOUT_MS`` (optional): (integer) How long (in milliseconds) a
connection can take to be opened before timing out.
Default: PyMongo default.
``MONGO_DBNAME`` The database name to make available as the ``db``
attribute. Default: ``app.name``.
``MONGO_USERNAME`` The user name for authentication. Default: ``None``
Expand All @@ -94,13 +100,6 @@ directives:
deteremined by the `isMaster
<http://www.mongodb.org/display/DOCS/Replica+Set+Commands#ReplicaSetCommands-isMaster>`_
command). Default: ``None``.
``MONGO_READ_PREFERENCE`` Determines how read queries are routed to the
replica set members. Must be one of
:data:`~flask_pymongo.PRIMARY`,
:data:`~flask_pymongo.SECONDARY`, or
:data:`~flask_pymongo.SECONDARY_ONLY`, or the
string names thereof. Default
:data:`~flask_pymongo.PRIMARY`.
``MONGO_DOCUMENT_CLASS`` This tells pymongo to return custom objects instead
of dicts, for example ``bson.son.SON``. Default: ``dict``
============================ ===================================================
Expand Down Expand Up @@ -159,12 +158,6 @@ Constants

.. autodata:: flask_pymongo.DESCENDING

.. autodata:: flask_pymongo.PRIMARY

.. autodata:: flask_pymongo.SECONDARY

.. autodata:: flask_pymongo.SECONDARY_ONLY


Classes
-------
Expand Down
50 changes: 14 additions & 36 deletions flask_pymongo/__init__.py
Expand Up @@ -24,8 +24,7 @@
# POSSIBILITY OF SUCH DAMAGE.


__all__ = ('PyMongo', 'ASCENDING', 'DESCENDING', 'PRIMARY',
'SECONDARY', 'SECONDARY_ONLY')
__all__ = ('PyMongo', 'ASCENDING', 'DESCENDING')

from bson.errors import InvalidId
from bson.objectid import ObjectId
Expand All @@ -43,33 +42,12 @@



PRIMARY = pymongo.ReadPreference.PRIMARY
"""Send all queries to the replica set primary, and fail if none exists."""

SECONDARY = pymongo.ReadPreference.SECONDARY
"""Distribute queries among replica set secondaries unless none exist or
are up, in which case send queries to the primary."""

SECONDARY_ONLY = pymongo.ReadPreference.SECONDARY_ONLY
"""Distribute queries among replica set secondaries, and fail if none
exist."""

DESCENDING = pymongo.DESCENDING
"""Descending sort order."""

ASCENDING = pymongo.ASCENDING
"""Ascending sort order."""

READ_PREFERENCE_MAP = {
# this handles defaulting to PRIMARY for us
None: PRIMARY,

# alias the string names to the correct constants
'PRIMARY': PRIMARY,
'SECONDARY': SECONDARY,
'SECONDARY_ONLY': SECONDARY_ONLY,
}


class BSONObjectIdConverter(BaseConverter):
"""A simple converter for the RESTful URL routing system of Flask.
Expand Down Expand Up @@ -112,8 +90,7 @@ def init_app(self, app, config_prefix='MONGO'):

The app is configured according to the configuration variables
``PREFIX_HOST``, ``PREFIX_PORT``, ``PREFIX_DBNAME``,
``PREFIX_AUTO_START_REQUEST``,
``PREFIX_REPLICA_SET``, ``PREFIX_READ_PREFERENCE``,
``PREFIX_AUTO_START_REQUEST``, ``PREFIX_REPLICA_SET``,
``PREFIX_USERNAME``, ``PREFIX_PASSWORD``, and ``PREFIX_URI`` where
"PREFIX" defaults to "MONGO". If ``PREFIX_URL`` is set, it is
assumed to have all appropriate configurations, and the other
Expand All @@ -140,12 +117,13 @@ def key(suffix):
if 'database' not in parsed:
raise ValueError('MongoDB URI does not contain database name')
app.config[key('DBNAME')] = parsed['database']
app.config[key('READ_PREFERENCE')] = parsed['options'].get('read_preference')
app.config[key('AUTO_START_REQUEST')] = parsed['options'].get('auto_start_request', True)
app.config[key('USERNAME')] = parsed['username']
app.config[key('PASSWORD')] = parsed['password']
app.config[key('REPLICA_SET')] = parsed['options'].get('replica_set')
app.config[key('MAX_POOL_SIZE')] = parsed['options'].get('max_pool_size')
app.config[key('SOCKET_TIMEOUT_MS')] = parsed['options'].get('socket_timeout_ms', None)
app.config[key('CONNECT_TIMEOUT_MS')] = parsed['options'].get('connect_timeout_ms', None)

# we will use the URI for connecting instead of HOST/PORT
app.config.pop(key('HOST'), None)
Expand All @@ -156,8 +134,9 @@ def key(suffix):
app.config.setdefault(key('HOST'), 'localhost')
app.config.setdefault(key('PORT'), 27017)
app.config.setdefault(key('DBNAME'), app.name)
app.config.setdefault(key('READ_PREFERENCE'), None)
app.config.setdefault(key('AUTO_START_REQUEST'), True)
app.config.setdefault(key('SOCKET_TIMEOUT_MS'), None)
app.config.setdefault(key('CONNECT_TIMEOUT_MS'), None)

# these don't have defaults
app.config.setdefault(key('USERNAME'), None)
Expand All @@ -179,17 +158,12 @@ def key(suffix):
if any(auth) and not all(auth):
raise Exception('Must set both USERNAME and PASSWORD or neither')

read_preference = app.config[key('READ_PREFERENCE')]
read_preference = READ_PREFERENCE_MAP.get(read_preference, read_preference)
if read_preference not in (PRIMARY, SECONDARY, SECONDARY_ONLY):
raise Exception('"%s_READ_PREFERENCE" must be one of '
'PRIMARY, SECONDARY, SECONDARY_ONLY (was %r)'
% (config_prefix, read_preference))

replica_set = app.config[key('REPLICA_SET')]
dbname = app.config[key('DBNAME')]
auto_start_request = app.config[key('AUTO_START_REQUEST')]
max_pool_size = app.config[key('MAX_POOL_SIZE')]
socket_timeout_ms = app.config[key('SOCKET_TIMEOUT_MS')]
connect_timeout_ms = app.config[key('CONNECT_TIMEOUT_MS')]

# document class is not supported by URI, using setdefault in all cases
document_class = app.config.setdefault(key('DOCUMENT_CLASS'), None)
Expand All @@ -199,11 +173,15 @@ def key(suffix):

args = [host]
kwargs = {
'read_preference': read_preference,
'auto_start_request': auto_start_request,
'tz_aware': True,
}

kwargs['auto_start_request'] = auto_start_request
if socket_timeout_ms is not None:
kwargs['socketTimeoutMS'] = socket_timeout_ms

if connect_timeout_ms is not None:
kwargs['connectTimeoutMS'] = connect_timeout_ms

if replica_set is not None:
kwargs['replicaSet'] = replica_set
Expand Down