Skip to content

Commit 4483cdc

Browse files
committed
Merge branch 'PYTHON-2679'
2 parents 6913738 + 3844220 commit 4483cdc

9 files changed

+42
-19
lines changed

doc/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ Breaking Changes in 4.0
100100
- Removed :class:`bson.binary.UUIDLegacy`.
101101
- The "tls" install extra is no longer necessary or supported and will be
102102
ignored by pip.
103+
- ``directConnection`` URI option and keyword argument to :class:`~pymongo
104+
.mongo_client.MongoClient` defaults to ``False`` instead of ``None``,
105+
allowing for the automatic discovery of replica sets. This means that if you
106+
want a direct connection to a single server you must pass
107+
``directConnection=True`` as a URI option or keyword argument.
103108

104109
Notable improvements
105110
....................

doc/migrate-to-pymongo4.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ get the same behavior.
6262
MongoClient
6363
-----------
6464

65+
``directConnection`` defaults to False
66+
......................................
67+
68+
``directConnection`` URI option and keyword argument to :class:`~pymongo
69+
.mongo_client.MongoClient` defaults to ``False`` instead of ``None``,
70+
allowing for the automatic discovery of replica sets. This means that if you
71+
want a direct connection to a single server you must pass
72+
``directConnection=True`` as a URI option or keyword argument.
73+
6574
The waitQueueMultiple parameter is removed
6675
..........................................
6776

@@ -174,6 +183,7 @@ can be changed to this::
174183

175184
names = client.list_database_names()
176185

186+
177187
Database
178188
--------
179189

pymongo/mongo_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,13 +919,15 @@ def address(self):
919919
.. versionadded:: 3.0
920920
"""
921921
topology_type = self._topology._description.topology_type
922-
if topology_type == TOPOLOGY_TYPE.Sharded:
922+
if (topology_type == TOPOLOGY_TYPE.Sharded and
923+
len(self.topology_description.server_descriptions()) > 1):
923924
raise InvalidOperation(
924925
'Cannot use "address" property when load balancing among'
925926
' mongoses, use "nodes" instead.')
926927
if topology_type not in (TOPOLOGY_TYPE.ReplicaSetWithPrimary,
927928
TOPOLOGY_TYPE.Single,
928-
TOPOLOGY_TYPE.LoadBalanced):
929+
TOPOLOGY_TYPE.LoadBalanced,
930+
TOPOLOGY_TYPE.Sharded):
929931
return None
930932
return self._server_property('address')
931933

pymongo/settings.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __init__(self,
3939
heartbeat_frequency=common.HEARTBEAT_FREQUENCY,
4040
server_selector=None,
4141
fqdn=None,
42-
direct_connection=None,
42+
direct_connection=False,
4343
load_balanced=None):
4444
"""Represent MongoClient's configuration.
4545
@@ -62,10 +62,7 @@ def __init__(self,
6262
self._fqdn = fqdn
6363
self._heartbeat_frequency = heartbeat_frequency
6464

65-
if direct_connection is None:
66-
self._direct = (len(self._seeds) == 1 and not self.replica_set_name)
67-
else:
68-
self._direct = direct_connection
65+
self._direct = direct_connection
6966
self._load_balanced = load_balanced
7067

7168
self._topology_id = ObjectId()

pymongo/topology_description.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ def apply_local_threshold(selection):
248248
common_wv))
249249

250250
if self.topology_type in (TOPOLOGY_TYPE.Single,
251-
TOPOLOGY_TYPE.LoadBalanced):
251+
TOPOLOGY_TYPE.LoadBalanced,
252+
TOPOLOGY_TYPE.Unknown):
252253
# Ignore selectors for standalone and load balancer mode.
253254
return self.known_servers
254255
elif address:

test/test_sdam_monitoring_spec.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
sys.path[0:0] = [""]
2323

24+
from pymongo import MongoClient
2425
from bson.json_util import object_hook
2526
from pymongo import monitoring
2627
from pymongo.common import clean_node
@@ -32,7 +33,6 @@
3233
from pymongo.topology_description import TOPOLOGY_TYPE
3334
from test import unittest, client_context, client_knobs, IntegrationTest
3435
from test.utils import (ServerAndTopologyEventListener,
35-
single_client,
3636
server_name_to_type,
3737
rs_or_single_client,
3838
wait_until)
@@ -186,9 +186,9 @@ class NoopMonitor(Monitor):
186186
def _run(self):
187187
time.sleep(0.05)
188188

189-
m = single_client(h=scenario_def['uri'], p=27017,
190-
event_listeners=[self.all_listener],
191-
_monitor_class=NoopMonitor)
189+
m = MongoClient(host=scenario_def['uri'], port=27017,
190+
event_listeners=[self.all_listener],
191+
_monitor_class=NoopMonitor)
192192
topology = m._get_topology()
193193

194194
try:

test/test_topology.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ def get_topology_type(self):
5252
def create_mock_topology(
5353
seeds=None,
5454
replica_set_name=None,
55-
monitor_class=DummyMonitor):
55+
monitor_class=DummyMonitor,
56+
direct_connection=False):
5657
partitioned_seeds = list(map(common.partition_node, seeds or ['a']))
5758
topology_settings = TopologySettings(
5859
partitioned_seeds,
5960
replica_set_name=replica_set_name,
6061
pool_class=MockPool,
61-
monitor_class=monitor_class)
62+
monitor_class=monitor_class, direct_connection=direct_connection)
6263

6364
t = Topology(topology_settings)
6465
t.open()
@@ -166,7 +167,7 @@ def test_direct_connection(self):
166167
'ismaster': False,
167168
'maxWireVersion': 6}),
168169
]:
169-
t = create_mock_topology()
170+
t = create_mock_topology(direct_connection=True)
170171

171172
# Can't select a server while the only server is of type Unknown.
172173
with self.assertRaisesRegex(ConnectionFailure,

test/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,14 +515,16 @@ def _connection_string(h, authenticate):
515515
return "mongodb://%s" % (str(h),)
516516

517517

518-
def _mongo_client(host, port, authenticate=True, directConnection=False,
518+
def _mongo_client(host, port, authenticate=True, directConnection=None,
519519
**kwargs):
520520
"""Create a new client over SSL/TLS if necessary."""
521521
host = host or client_context.host
522522
port = port or client_context.port
523523
client_options = client_context.default_client_options.copy()
524524
if client_context.replica_set_name and not directConnection:
525525
client_options['replicaSet'] = client_context.replica_set_name
526+
if directConnection is not None:
527+
client_options['directConnection'] = directConnection
526528
client_options.update(kwargs)
527529

528530
client = MongoClient(_connection_string(host, authenticate), port,

test/utils_selection_tests.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ def create_topology(scenario_def, **kwargs):
127127
topology_type = get_topology_type_name(scenario_def)
128128
if topology_type == 'LoadBalanced':
129129
kwargs.setdefault('load_balanced', True)
130-
130+
# Force topology description to ReplicaSet
131+
elif topology_type in ['ReplicaSetNoPrimary', 'ReplicaSetWithPrimary']:
132+
kwargs.setdefault('replica_set_name', 'rs')
131133
settings = get_topology_settings_dict(
132134
heartbeat_frequency=frequency,
133135
seeds=seeds,
@@ -145,8 +147,9 @@ def create_topology(scenario_def, **kwargs):
145147
server_description = make_server_description(server, hosts)
146148
topology.on_change(server_description)
147149

148-
if topology_type == 'LoadBalanced':
149-
assert topology.description.topology_type_name == 'LoadBalanced'
150+
# Assert that descriptions match
151+
assert (scenario_def['topology_description']['type'] ==
152+
topology.description.topology_type_name)
150153

151154
return topology
152155

@@ -252,6 +255,8 @@ class TestAllScenarios(unittest.TestCase):
252255
dirname = os.path.split(dirname[-2])[-1] + '_' + dirname[-1]
253256

254257
for filename in filenames:
258+
if os.path.splitext(filename)[1] != ".json":
259+
continue
255260
with open(os.path.join(dirpath, filename)) as scenario_stream:
256261
scenario_def = json_util.loads(scenario_stream.read())
257262

0 commit comments

Comments
 (0)