Skip to content

Commit e4c8d17

Browse files
committed
PYTHON-955 - Backport connect option.
1 parent 8431379 commit e4c8d17

File tree

7 files changed

+69
-7
lines changed

7 files changed

+69
-7
lines changed

doc/migrate-to-pymongo3.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,42 @@ can be replaced by this with PyMongo 2.9 or later:
405405
MongoClient
406406
-----------
407407

408+
MongoClient connects asynchronously
409+
...................................
410+
411+
In PyMongo 3, the :class:`~pymongo.mongo_client.MongoClient` constructor no
412+
longer blocks while connecting to the server or servers, and it no longer
413+
raises :exc:`~pymongo.errors.ConnectionFailure` if they are unavailable, nor
414+
:exc:`~pymongo.errors.ConfigurationError` if the user’s credentials are wrong.
415+
Instead, the constructor returns immediately and launches the connection
416+
process on background threads. The `connect` option is added to control whether
417+
these threads are started immediately, or when the client is first used.
418+
419+
For consistent behavior in PyMongo 2.x and PyMongo 3.x, code like this::
420+
421+
>>> from pymongo.errors import ConnectionFailure
422+
>>> try:
423+
... client = MongoClient()
424+
... except ConnectionFailure:
425+
... print("Server not available")
426+
>>>
427+
428+
can be changed to this with PyMongo 2.9 or later:
429+
430+
.. doctest::
431+
432+
>>> from pymongo.errors import ConnectionFailure
433+
>>> client = MongoClient(connect=False)
434+
>>> try:
435+
... result = client.admin.command("ismaster")
436+
... except ConnectionFailure:
437+
... print("Server not available")
438+
>>>
439+
440+
Any operation can be used to determine if the server is available. We choose
441+
the "ismaster" command here because it is cheap and does not require auth, so
442+
it is a simple way to check whether the server is available.
443+
408444
The max_pool_size parameter is removed
409445
......................................
410446

pymongo/common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,9 @@ def validate_ok_for_update(update):
385385
'authmechanismproperties': validate_auth_mechanism_properties,
386386
'uuidrepresentation': validate_uuid_representation,
387387
'socketkeepalive': validate_boolean,
388-
'maxpoolsize': validate_positive_integer_or_none
388+
'maxpoolsize': validate_positive_integer_or_none,
389+
'connect': validate_boolean,
390+
'_connect': validate_boolean
389391
}
390392

391393

pymongo/connection.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Connection(MongoClient):
4646

4747
def __init__(self, host=None, port=None, max_pool_size=None,
4848
network_timeout=None, document_class=dict,
49-
tz_aware=False, _connect=True, **kwargs):
49+
tz_aware=False, **kwargs):
5050
"""Create a new connection to a single MongoDB instance at *host:port*.
5151
5252
.. warning::
@@ -237,8 +237,8 @@ def __init__(self, host=None, port=None, max_pool_size=None,
237237
kwargs['auto_start_request'] = kwargs.get('auto_start_request', True)
238238
kwargs['safe'] = kwargs.get('safe', False)
239239

240-
super(Connection, self).__init__(host, port,
241-
max_pool_size, document_class, tz_aware, _connect, **kwargs)
240+
super(Connection, self).__init__(
241+
host, port, max_pool_size, document_class, tz_aware, **kwargs)
242242

243243
def __repr__(self):
244244
if len(self.nodes) == 1:

pymongo/mongo_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ class MongoClient(common.BaseObject):
9292
_rs_client = False
9393

9494
def __init__(self, host=None, port=None, max_pool_size=100,
95-
document_class=dict, tz_aware=False, _connect=True,
96-
**kwargs):
95+
document_class=dict, tz_aware=False, **kwargs):
9796
"""Create a new connection to a single MongoDB instance at *host:port*.
9897
9998
The resultant client object has connection-pooling built
@@ -161,6 +160,8 @@ def __init__(self, host=None, port=None, max_pool_size=100,
161160
- `use_greenlets`: If ``True``, :meth:`start_request()` will ensure
162161
that the current greenlet uses the same socket for all
163162
operations until :meth:`end_request()`. Defaults to ``False``.
163+
- `connect`: if True (the default), immediately connect to MongoDB in
164+
the foreground. Otherwise connect on the first operation.
164165
165166
| **Write Concern options:**
166167
| (Only set if passed. No default values.)
@@ -399,6 +400,7 @@ def __init__(self, host=None, port=None, max_pool_size=100,
399400
"use read_preference instead.", DeprecationWarning,
400401
stacklevel=2)
401402

403+
_connect = options.get('_connect', options.get('connect', True))
402404
if _connect:
403405
try:
404406
self._ensure_connected(True)

pymongo/mongo_replica_set_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ class MongoReplicaSetClient(common.BaseObject):
435435
_rs_client = True
436436

437437
def __init__(self, hosts_or_uri=None, max_pool_size=100,
438-
document_class=dict, tz_aware=False, _connect=True, **kwargs):
438+
document_class=dict, tz_aware=False, **kwargs):
439439
"""Create a new connection to a MongoDB replica set.
440440
441441
The resultant client object has connection-pooling built
@@ -514,6 +514,8 @@ def __init__(self, hosts_or_uri=None, max_pool_size=100,
514514
rather than thread-local, socket. Defaults to ``False``.
515515
`use_greenlets` with :class:`MongoReplicaSetClient` requires
516516
`Gevent <http://gevent.org/>`_ to be installed.
517+
- `connect`: if True (the default), immediately connect to MongoDB
518+
in the foreground. Otherwise connect on the first operation.
517519
518520
| **Write Concern options:**
519521
| (Only set if passed. No default values.)
@@ -715,6 +717,7 @@ def __init__(self, hosts_or_uri=None, max_pool_size=100,
715717
"use read_preference instead.", DeprecationWarning,
716718
stacklevel=2)
717719

720+
_connect = self.__opts.get('_connect', self.__opts.get('connect', True))
718721
if _connect:
719722
try:
720723
self.refresh(initial=True)

test/test_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ def test_connect(self):
182182

183183
self.assertTrue(MongoClient(host, port))
184184

185+
# Test that connect=False prevents the constructor from raising
186+
# ConnectionFailure.
187+
client = MongoClient("somedomainthatdoesnotexist.org",
188+
connectTimeoutMS=100, connect=False)
189+
try:
190+
client.admin.command("ismaster")
191+
except AutoReconnect:
192+
pass
193+
185194
def test_equality(self):
186195
client = MongoClient(host, port)
187196
self.assertEqual(client, MongoClient(host, port))

test/test_replica_set_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,16 @@ def test_connect(self):
224224
pair, replicaSet='fdlksjfdslkjfd')
225225
self.assertTrue(MongoReplicaSetClient(pair, replicaSet=self.name))
226226

227+
# Test that connect=False prevents the constructor from raising
228+
# ConnectionFailure.
229+
client = MongoReplicaSetClient("somedomainthatdoesnotexist.org",
230+
connectTimeoutMS=100, connect=False,
231+
replicaSet=self.name)
232+
try:
233+
client.admin.command("ismaster")
234+
except AutoReconnect:
235+
pass
236+
227237
def test_repr(self):
228238
client = self._get_client()
229239

0 commit comments

Comments
 (0)