From b342990934b55370ebde40d20ba6423e035b1961 Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Wed, 3 Nov 2021 11:21:33 -0700 Subject: [PATCH] PYTHON-2164 Add MongoClient.options, remove redundant properties (#772) --- doc/api/pymongo/client_options.rst | 7 +++ doc/api/pymongo/index.rst | 1 + doc/api/pymongo/mongo_client.rst | 7 +-- doc/api/pymongo/pool.rst | 5 +- doc/changelog.rst | 11 +++- doc/migrate-to-pymongo4.rst | 31 +++++++++++ pymongo/client_options.py | 18 ++++++- pymongo/encryption.py | 2 +- pymongo/mongo_client.py | 85 ++++-------------------------- pymongo/monitor.py | 2 +- pymongo/monitoring.py | 8 +-- pymongo/pool.py | 47 ++++++++++------- pymongo/topology.py | 6 +-- test/test_auth_spec.py | 2 +- test/test_client.py | 40 ++++++++------ test/test_mongos_load_balancing.py | 4 +- test/test_pooling.py | 4 +- test/test_read_preferences.py | 12 ++--- test/test_retryable_reads.py | 10 ++-- test/test_sdam_monitoring_spec.py | 2 +- test/test_session.py | 4 +- 21 files changed, 159 insertions(+), 149 deletions(-) create mode 100644 doc/api/pymongo/client_options.rst diff --git a/doc/api/pymongo/client_options.rst b/doc/api/pymongo/client_options.rst new file mode 100644 index 000000000..3ffc10bad --- /dev/null +++ b/doc/api/pymongo/client_options.rst @@ -0,0 +1,7 @@ +:mod:`client_options` -- Read only configuration options for a MongoClient. +=========================================================================== + +.. automodule:: pymongo.client_options + + .. autoclass:: pymongo.client_options.ClientOptions() + :members: diff --git a/doc/api/pymongo/index.rst b/doc/api/pymongo/index.rst index 8a3a99b81..6e6e33795 100644 --- a/doc/api/pymongo/index.rst +++ b/doc/api/pymongo/index.rst @@ -29,6 +29,7 @@ Sub-modules: bulk change_stream + client_options client_session collation collection diff --git a/doc/api/pymongo/mongo_client.rst b/doc/api/pymongo/mongo_client.rst index ba95e0647..83dab27f2 100644 --- a/doc/api/pymongo/mongo_client.rst +++ b/doc/api/pymongo/mongo_client.rst @@ -14,7 +14,6 @@ Raises :class:`~pymongo.errors.InvalidName` if an invalid database name is used. - .. autoattribute:: event_listeners .. autoattribute:: topology_description .. autoattribute:: address .. autoattribute:: primary @@ -22,16 +21,12 @@ .. autoattribute:: arbiters .. autoattribute:: is_primary .. autoattribute:: is_mongos - .. autoattribute:: max_pool_size - .. autoattribute:: min_pool_size - .. autoattribute:: max_idle_time_ms .. autoattribute:: nodes - .. autoattribute:: local_threshold_ms - .. autoattribute:: server_selection_timeout .. autoattribute:: codec_options .. autoattribute:: read_preference .. autoattribute:: write_concern .. autoattribute:: read_concern + .. autoattribute:: options .. automethod:: start_session .. automethod:: list_databases .. automethod:: list_database_names diff --git a/doc/api/pymongo/pool.rst b/doc/api/pymongo/pool.rst index 4e37de4a3..78274e8f8 100644 --- a/doc/api/pymongo/pool.rst +++ b/doc/api/pymongo/pool.rst @@ -2,5 +2,6 @@ ============================================================== .. automodule:: pymongo.pool - :synopsis: Pool module for use with a MongoDB client. - :members: + + .. autoclass:: pymongo.pool.PoolOptions() + :members: diff --git a/doc/changelog.rst b/doc/changelog.rst index b5f32d21b..31e5d5d1d 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -36,6 +36,13 @@ Breaking Changes in 4.0 - Removed :attr:`pymongo.mongo_client.MongoClient.max_bson_size`. - Removed :attr:`pymongo.mongo_client.MongoClient.max_message_size`. - Removed :attr:`pymongo.mongo_client.MongoClient.max_write_batch_size`. +- Removed :attr:`pymongo.mongo_client.MongoClient.event_listeners`. +- Removed :attr:`pymongo.mongo_client.MongoClient.max_pool_size`. +- Removed :attr:`pymongo.mongo_client.MongoClient.max_idle_time_ms`. +- Removed :attr:`pymongo.mongo_client.MongoClient.local_threshold_ms`. +- Removed :attr:`pymongo.mongo_client.MongoClient.server_selection_timeout`. +- Removed :attr:`pymongo.mongo_client.MongoClient.retry_writes`. +- Removed :attr:`pymongo.mongo_client.MongoClient.retry_reads`. - Removed :meth:`pymongo.database.Database.eval`, :data:`pymongo.database.Database.system_js` and :class:`pymongo.database.SystemJS`. @@ -180,6 +187,8 @@ Notable improvements will connect to. More specifically, when a mongodb+srv:// connection string resolves to more than `srvMaxHosts` number of hosts, the client will randomly choose a `srvMaxHosts` sized subset of hosts. +- Added :attr:`pymongo.mongo_client.MongoClient.options` for read-only access + to a client's configuration options. Issues Resolved ............... @@ -2121,7 +2130,7 @@ Important new features: - The ``max_pool_size`` option for :class:`~pymongo.mongo_client.MongoClient` and :class:`~pymongo.mongo_replica_set_client.MongoReplicaSetClient` now actually caps the number of sockets the pool will open concurrently. - Once the pool has reached :attr:`~pymongo.mongo_client.MongoClient.max_pool_size` + Once the pool has reaches max_pool_size operations will block waiting for a socket to become available. If ``waitQueueTimeoutMS`` is set, an operation that blocks waiting for a socket will raise :exc:`~pymongo.errors.ConnectionFailure` after the timeout. By diff --git a/doc/migrate-to-pymongo4.rst b/doc/migrate-to-pymongo4.rst index b83071805..c0288c104 100644 --- a/doc/migrate-to-pymongo4.rst +++ b/doc/migrate-to-pymongo4.rst @@ -196,6 +196,37 @@ can be changed to this:: .. _hello command: https://docs.mongodb.com/manual/reference/command/hello/ +MongoClient.event_listeners and other configuration option helpers are removed +.............................................................................. + +The following client configuration option helpers are removed: +- :attr:`pymongo.mongo_client.MongoClient.event_listeners`. +- :attr:`pymongo.mongo_client.MongoClient.max_pool_size`. +- :attr:`pymongo.mongo_client.MongoClient.max_idle_time_ms`. +- :attr:`pymongo.mongo_client.MongoClient.local_threshold_ms`. +- :attr:`pymongo.mongo_client.MongoClient.server_selection_timeout`. +- :attr:`pymongo.mongo_client.MongoClient.retry_writes`. +- :attr:`pymongo.mongo_client.MongoClient.retry_reads`. + +These helpers have been replaced by +:attr:`pymongo.mongo_client.MongoClient.options`. Code like this:: + + client.event_listeners + client.local_threshold_ms + client.server_selection_timeout + client.max_pool_size + client.min_pool_size + client.max_idle_time_ms + +can be changed to this:: + + client.options.event_listeners + client.options.local_threshold_ms + client.options.server_selection_timeout + client.options.pool_options.max_pool_size + client.options.pool_options.min_pool_size + client.options.pool_options.max_idle_time_seconds + ``tz_aware`` defaults to ``False`` .................................. diff --git a/pymongo/client_options.py b/pymongo/client_options.py index 77c3f85a2..845d4ef9a 100644 --- a/pymongo/client_options.py +++ b/pymongo/client_options.py @@ -153,8 +153,12 @@ def _parse_pool_options(options): class ClientOptions(object): + """Read only configuration options for a MongoClient. - """ClientOptions""" + Should not be instantiated directly by application developers. Access + a client's options via :attr:`pymongo.mongo_client.MongoClient.options` + instead. + """ def __init__(self, username, password, database, options): self.__options = options @@ -200,7 +204,7 @@ class ClientOptions(object): return self.__codec_options @property - def credentials(self): + def _credentials(self): """A :class:`~pymongo.auth.MongoCredentials` instance or None.""" return self.__credentials @@ -272,3 +276,13 @@ class ClientOptions(object): def load_balanced(self): """True if the client was configured to connect to a load balancer.""" return self.__load_balanced + + @property + def event_listeners(self): + """The event listeners registered for this client. + + See :mod:`~pymongo.monitoring` for details. + + .. versionadded:: 4.0 + """ + return self.__pool_options._event_listeners.event_listeners() diff --git a/pymongo/encryption.py b/pymongo/encryption.py index 2c3f8eb0f..ad19b2642 100644 --- a/pymongo/encryption.py +++ b/pymongo/encryption.py @@ -261,7 +261,7 @@ class _Encrypter(object): self._internal_client = None def _get_internal_client(encrypter, mongo_client): - if mongo_client.max_pool_size is None: + if mongo_client.options.pool_options.max_pool_size is None: # Unlimited pool size, use the same client. return mongo_client # Else - limited pool size, use an internal client. diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 9c0695e6c..a308219cf 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -722,14 +722,14 @@ class MongoClient(common.BaseObject): self.__lock = threading.Lock() self.__kill_cursors_queue = [] - self._event_listeners = options.pool_options.event_listeners + self._event_listeners = options.pool_options._event_listeners super(MongoClient, self).__init__(options.codec_options, options.read_preference, options.write_concern, options.read_concern) self.__all_credentials = {} - creds = options.credentials + creds = options._credentials if creds: self.__all_credentials[creds.source] = creds @@ -893,14 +893,6 @@ class MongoClient(common.BaseObject): batch_size, collation, start_at_operation_time, session, start_after) - @property - def event_listeners(self): - """The event listeners registered for this client. - - See :mod:`~pymongo.monitoring` for details. - """ - return self._event_listeners.event_listeners() - @property def topology_description(self): """The description of the connected MongoDB deployment. @@ -1005,40 +997,6 @@ class MongoClient(common.BaseObject): """ return self._server_property('server_type') == SERVER_TYPE.Mongos - @property - def max_pool_size(self): - """The maximum allowable number of concurrent connections to each - connected server. Requests to a server will block if there are - `maxPoolSize` outstanding connections to the requested server. - Defaults to 100. Can be either 0 or None, in which case there is no - limit on the number of concurrent connections. - - When a server's pool has reached `max_pool_size`, operations for that - server block waiting for a socket to be returned to the pool. If - ``waitQueueTimeoutMS`` is set, a blocked operation will raise - :exc:`~pymongo.errors.ConnectionFailure` after a timeout. - By default ``waitQueueTimeoutMS`` is not set. - """ - return self.__options.pool_options.max_pool_size - - @property - def min_pool_size(self): - """The minimum required number of concurrent connections that the pool - will maintain to each connected server. Default is 0. - """ - return self.__options.pool_options.min_pool_size - - @property - def max_idle_time_ms(self): - """The maximum number of milliseconds that a connection can remain - idle in the pool before being removed and replaced. Defaults to - `None` (no limit). - """ - seconds = self.__options.pool_options.max_idle_time_seconds - if seconds is None: - return None - return 1000 * seconds - @property def nodes(self): """Set of all currently connected servers. @@ -1054,38 +1012,15 @@ class MongoClient(common.BaseObject): return frozenset(s.address for s in description.known_servers) @property - def local_threshold_ms(self): - """The local threshold for this instance.""" - return self.__options.local_threshold_ms + def options(self): + """The configuration options for this client. - @property - def server_selection_timeout(self): - """The server selection timeout for this instance in seconds.""" - return self.__options.server_selection_timeout + :Returns: + An instance of :class:`~pymongo.client_options.ClientOptions`. - @property - def retry_writes(self): - """If this instance should retry supported write operations.""" - return self.__options.retry_writes - - @property - def retry_reads(self): - """If this instance should retry supported write operations.""" - return self.__options.retry_reads - - def _is_writable(self): - """Attempt to connect to a writable server, or return False. + .. versionadded:: 4.0 """ - topology = self._get_topology() # Starts monitors if necessary. - try: - svr = topology.select_server(writable_server_selector) - - # When directly connected to a secondary, arbiter, etc., - # select_server returns it, whatever the selector. Check - # again if the server is writable. - return svr.description.is_writable - except ConnectionFailure: - return False + return self.__options def _end_sessions(self, session_ids): """Send endSessions command(s) with the given session ids.""" @@ -1282,7 +1217,7 @@ class MongoClient(common.BaseObject): Re-raises any exception thrown by func(). """ - retryable = (retryable and self.retry_writes + retryable = (retryable and self.options.retry_writes and session and not session.in_transaction) return self._retry_internal(retryable, func, session, bulk) @@ -1353,7 +1288,7 @@ class MongoClient(common.BaseObject): Re-raises any exception thrown by func(). """ retryable = (retryable and - self.retry_reads + self.options.retry_reads and not (session and session.in_transaction)) last_error = None retrying = False diff --git a/pymongo/monitor.py b/pymongo/monitor.py index 5359ee054..37b894bd5 100644 --- a/pymongo/monitor.py +++ b/pymongo/monitor.py @@ -123,7 +123,7 @@ class Monitor(MonitorBase): self._server_description = server_description self._pool = pool self._settings = topology_settings - self._listeners = self._settings._pool_options.event_listeners + self._listeners = self._settings._pool_options._event_listeners pub = self._listeners is not None self._publish = pub and self._listeners.enabled_for_server_heartbeat self._cancel_context = None diff --git a/pymongo/monitoring.py b/pymongo/monitoring.py index ba9bbe812..b877e19a2 100644 --- a/pymongo/monitoring.py +++ b/pymongo/monitoring.py @@ -1318,10 +1318,10 @@ class _EventListeners(object): def event_listeners(self): """List of registered event listeners.""" - return (self.__command_listeners[:] + - self.__server_heartbeat_listeners[:] + - self.__server_listeners[:] + - self.__topology_listeners[:] + + return (self.__command_listeners + + self.__server_heartbeat_listeners + + self.__server_listeners + + self.__topology_listeners + self.__cmap_listeners) def publish_command_start(self, command, database_name, diff --git a/pymongo/pool.py b/pymongo/pool.py index 952874abb..f9b370c66 100644 --- a/pymongo/pool.py +++ b/pymongo/pool.py @@ -256,6 +256,17 @@ def _cond_wait(condition, deadline): class PoolOptions(object): + """Read only connection pool options for a MongoClient. + + Should not be instantiated directly by application developers. Access + a client's pool options via + :attr:`~pymongo.client_options.ClientOptions.pool_options` instead:: + + pool_opts = client.options.pool_options + pool_opts.max_pool_size + pool_opts.min_pool_size + + """ __slots__ = ('__max_pool_size', '__min_pool_size', '__max_idle_time_seconds', @@ -394,7 +405,7 @@ class PoolOptions(object): return self.__wait_queue_timeout @property - def ssl_context(self): + def _ssl_context(self): """An SSLContext instance or None. """ return self.__ssl_context @@ -406,7 +417,7 @@ class PoolOptions(object): return self.__tls_allow_invalid_hostnames @property - def event_listeners(self): + def _event_listeners(self): """An instance of pymongo.monitoring._EventListeners. """ return self.__event_listeners @@ -424,7 +435,7 @@ class PoolOptions(object): return self.__driver @property - def compression_settings(self): + def _compression_settings(self): return self.__compression_settings @property @@ -506,9 +517,9 @@ class SocketInfo(object): self.hello_ok = None self.is_mongos = False self.op_msg_enabled = False - self.listeners = pool.opts.event_listeners + self.listeners = pool.opts._event_listeners self.enabled_for_cmap = pool.enabled_for_cmap - self.compression_settings = pool.opts.compression_settings + self.compression_settings = pool.opts._compression_settings self.compression_context = None self.socket_checker = SocketChecker() # Support for mechanism negotiation on the initial handshake. @@ -1000,7 +1011,7 @@ def _configured_socket(address, options): Sets socket's SSL and timeout options. """ sock = _create_connection(address, options) - ssl_context = options.ssl_context + ssl_context = options._ssl_context if ssl_context is not None: host = address[0] @@ -1123,8 +1134,8 @@ class Pool: # Don't publish events in Monitor pools. self.enabled_for_cmap = ( self.handshake and - self.opts.event_listeners is not None and - self.opts.event_listeners.enabled_for_cmap) + self.opts._event_listeners is not None and + self.opts._event_listeners.enabled_for_cmap) # The first portion of the wait queue. # Enforces: maxPoolSize @@ -1141,7 +1152,7 @@ class Pool: self._max_connecting = self.opts.max_connecting self._pending = 0 if self.enabled_for_cmap: - self.opts.event_listeners.publish_pool_created( + self.opts._event_listeners.publish_pool_created( self.address, self.opts.non_default_options) # Similar to active_sockets but includes threads in the wait queue. self.operation_count = 0 @@ -1158,7 +1169,7 @@ class Pool: if self.state != PoolState.READY: self.state = PoolState.READY if self.enabled_for_cmap: - self.opts.event_listeners.publish_pool_ready(self.address) + self.opts._event_listeners.publish_pool_ready(self.address) @property def closed(self): @@ -1197,7 +1208,7 @@ class Pool: self._max_connecting_cond.notify_all() self.size_cond.notify_all() - listeners = self.opts.event_listeners + listeners = self.opts._event_listeners # CMAP spec says that close() MUST close sockets before publishing the # PoolClosedEvent but that reset() SHOULD close sockets *after* # publishing the PoolClearedEvent. @@ -1301,7 +1312,7 @@ class Pool: conn_id = self.next_connection_id self.next_connection_id += 1 - listeners = self.opts.event_listeners + listeners = self.opts._event_listeners if self.enabled_for_cmap: listeners.publish_connection_created(self.address, conn_id) @@ -1353,7 +1364,7 @@ class Pool: - `all_credentials`: dict, maps auth source to MongoCredential. - `handler` (optional): A _MongoClientErrorHandler. """ - listeners = self.opts.event_listeners + listeners = self.opts._event_listeners if self.enabled_for_cmap: listeners.publish_connection_check_out_started(self.address) @@ -1391,7 +1402,7 @@ class Pool: def _raise_if_not_ready(self, emit_event): if self.state != PoolState.READY: if self.enabled_for_cmap and emit_event: - self.opts.event_listeners.publish_connection_check_out_failed( + self.opts._event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.CONN_ERROR) _raise_connection_failure( self.address, AutoReconnect('connection pool paused')) @@ -1406,7 +1417,7 @@ class Pool: if self.closed: if self.enabled_for_cmap: - self.opts.event_listeners.publish_connection_check_out_failed( + self.opts._event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.POOL_CLOSED) raise _PoolClosedError( 'Attempted to check out a connection from closed connection ' @@ -1486,7 +1497,7 @@ class Pool: self.size_cond.notify() if self.enabled_for_cmap and not emitted_event: - self.opts.event_listeners.publish_connection_check_out_failed( + self.opts._event_listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.CONN_ERROR) raise @@ -1505,7 +1516,7 @@ class Pool: sock_info.pinned_txn = False sock_info.pinned_cursor = False self.__pinned_sockets.discard(sock_info) - listeners = self.opts.event_listeners + listeners = self.opts._event_listeners if self.enabled_for_cmap: listeners.publish_connection_checked_in(self.address, sock_info.id) if self.pid != os.getpid(): @@ -1578,7 +1589,7 @@ class Pool: return False def _raise_wait_queue_timeout(self): - listeners = self.opts.event_listeners + listeners = self.opts._event_listeners if self.enabled_for_cmap: listeners.publish_connection_check_out_failed( self.address, ConnectionCheckOutFailedReason.TIMEOUT) diff --git a/pymongo/topology.py b/pymongo/topology.py index 4083d7f33..c6a702fde 100644 --- a/pymongo/topology.py +++ b/pymongo/topology.py @@ -73,7 +73,7 @@ class Topology(object): """Monitor a topology of one or more servers.""" def __init__(self, topology_settings): self._topology_id = topology_settings._topology_id - self._listeners = topology_settings._pool_options.event_listeners + self._listeners = topology_settings._pool_options._event_listeners pub = self._listeners is not None self._publish_server = pub and self._listeners.enabled_for_server self._publish_tp = pub and self._listeners.enabled_for_topology @@ -728,9 +728,9 @@ class Topology(object): monitor_pool_options = PoolOptions( connect_timeout=options.connect_timeout, socket_timeout=options.connect_timeout, - ssl_context=options.ssl_context, + ssl_context=options._ssl_context, tls_allow_invalid_hostnames=options.tls_allow_invalid_hostnames, - event_listeners=options.event_listeners, + event_listeners=options._event_listeners, appname=options.appname, driver=options.driver, pause_enabled=False, diff --git a/test/test_auth_spec.py b/test/test_auth_spec.py index 1b6b919e8..8bf0dcb21 100644 --- a/test/test_auth_spec.py +++ b/test/test_auth_spec.py @@ -44,7 +44,7 @@ def create_test(test_case): self.assertRaises(Exception, MongoClient, uri, connect=False) else: client = MongoClient(uri, connect=False) - credentials = client._MongoClient__options.credentials + credentials = client._MongoClient__options._credentials if credential is None: self.assertIsNone(credentials) else: diff --git a/test/test_client.py b/test/test_client.py index 2b32dee97..34922d109 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -36,6 +36,7 @@ from bson.son import SON from bson.tz_util import utc import pymongo from pymongo import event_loggers, message, monitoring +from pymongo.client_options import ClientOptions from pymongo.command_cursor import CommandCursor from pymongo.common import CONNECT_TIMEOUT, _UUID_REPRESENTATIONS from pymongo.compression_support import _HAVE_SNAPPY, _HAVE_ZSTD @@ -56,7 +57,7 @@ from pymongo.hello import HelloCompat from pymongo.mongo_client import MongoClient from pymongo.monitoring import (ServerHeartbeatListener, ServerHeartbeatStartedEvent) -from pymongo.pool import SocketInfo, _METADATA +from pymongo.pool import SocketInfo, _METADATA, PoolOptions from pymongo.read_preferences import ReadPreference from pymongo.server_description import ServerDescription from pymongo.server_selectors import (readable_server_selector, @@ -128,10 +129,10 @@ class ClientUnitTest(unittest.TestCase): # socket.Socket.settimeout takes a float in seconds self.assertEqual(20.0, pool_opts.connect_timeout) self.assertEqual(None, pool_opts.wait_queue_timeout) - self.assertEqual(None, pool_opts.ssl_context) + self.assertEqual(None, pool_opts._ssl_context) self.assertEqual(None, options.replica_set_name) self.assertEqual(ReadPreference.PRIMARY, client.read_preference) - self.assertAlmostEqual(12, client.server_selection_timeout) + self.assertAlmostEqual(12, client.options.server_selection_timeout) def test_connect_timeout(self): client = MongoClient(connect=False, connectTimeoutMS=None, @@ -465,14 +466,23 @@ class ClientUnitTest(unittest.TestCase): def test_event_listeners(self): c = MongoClient(event_listeners=[], connect=False) - self.assertEqual(c.event_listeners, []) + self.assertEqual(c.options.event_listeners, []) listeners = [event_loggers.CommandLogger(), event_loggers.HeartbeatLogger(), event_loggers.ServerLogger(), event_loggers.TopologyLogger(), event_loggers.ConnectionPoolLogger()] c = MongoClient(event_listeners=listeners, connect=False) - self.assertEqual(c.event_listeners, listeners) + self.assertEqual(c.options.event_listeners, listeners) + + def test_client_options(self): + c = MongoClient(connect=False) + self.assertIsInstance(c.options, ClientOptions) + self.assertIsInstance(c.options.pool_options, PoolOptions) + self.assertEqual(c.options.server_selection_timeout, 30) + self.assertEqual(c.options.pool_options.max_idle_time_seconds, None) + self.assertIsInstance(c.options.retry_writes, bool) + self.assertIsInstance(c.options.retry_reads, bool) class TestClient(IntegrationTest): @@ -635,7 +645,7 @@ class TestClient(IntegrationTest): c = rs_or_single_client(connect=False) self.assertIsInstance(c.is_mongos, bool) c = rs_or_single_client(connect=False) - self.assertIsInstance(c.max_pool_size, int) + self.assertIsInstance(c.options.pool_options.max_pool_size, int) self.assertIsInstance(c.nodes, frozenset) c = rs_or_single_client(connect=False) @@ -1003,8 +1013,8 @@ class TestClient(IntegrationTest): self.assertEqual(10.5, get_pool(client).opts.connect_timeout) self.assertEqual(10.5, get_pool(client).opts.socket_timeout) self.assertEqual(10.5, get_pool(client).opts.max_idle_time_seconds) - self.assertEqual(10500, client.max_idle_time_ms) - self.assertEqual(10.5, client.server_selection_timeout) + self.assertEqual(10.5, client.options.pool_options.max_idle_time_seconds) + self.assertEqual(10.5, client.options.server_selection_timeout) def test_socket_timeout_ms_validation(self): c = rs_or_single_client(socketTimeoutMS=10 * 1000) @@ -1044,10 +1054,10 @@ class TestClient(IntegrationTest): def test_server_selection_timeout(self): client = MongoClient(serverSelectionTimeoutMS=100, connect=False) - self.assertAlmostEqual(0.1, client.server_selection_timeout) + self.assertAlmostEqual(0.1, client.options.server_selection_timeout) client = MongoClient(serverSelectionTimeoutMS=0, connect=False) - self.assertAlmostEqual(0, client.server_selection_timeout) + self.assertAlmostEqual(0, client.options.server_selection_timeout) self.assertRaises(ValueError, MongoClient, serverSelectionTimeoutMS="foo", connect=False) @@ -1058,20 +1068,20 @@ class TestClient(IntegrationTest): client = MongoClient( 'mongodb://localhost/?serverSelectionTimeoutMS=100', connect=False) - self.assertAlmostEqual(0.1, client.server_selection_timeout) + self.assertAlmostEqual(0.1, client.options.server_selection_timeout) client = MongoClient( 'mongodb://localhost/?serverSelectionTimeoutMS=0', connect=False) - self.assertAlmostEqual(0, client.server_selection_timeout) + self.assertAlmostEqual(0, client.options.server_selection_timeout) # Test invalid timeout in URI ignored and set to default. client = MongoClient( 'mongodb://localhost/?serverSelectionTimeoutMS=-1', connect=False) - self.assertAlmostEqual(30, client.server_selection_timeout) + self.assertAlmostEqual(30, client.options.server_selection_timeout) client = MongoClient( 'mongodb://localhost/?serverSelectionTimeoutMS=', connect=False) - self.assertAlmostEqual(30, client.server_selection_timeout) + self.assertAlmostEqual(30, client.options.server_selection_timeout) def test_waitQueueTimeoutMS(self): client = rs_or_single_client(waitQueueTimeoutMS=2000) @@ -1379,7 +1389,7 @@ class TestClient(IntegrationTest): def test_compression(self): def compression_settings(client): pool_options = client._MongoClient__options.pool_options - return pool_options.compression_settings + return pool_options._compression_settings uri = "mongodb://localhost:27017/?compressors=zlib" client = MongoClient(uri, connect=False) diff --git a/test/test_mongos_load_balancing.py b/test/test_mongos_load_balancing.py index 575bc458c..c110b8b10 100644 --- a/test/test_mongos_load_balancing.py +++ b/test/test_mongos_load_balancing.py @@ -127,7 +127,7 @@ class TestMongosLoadBalancing(MockClientTest): def test_local_threshold(self): client = connected(self.mock_client(localThresholdMS=30)) - self.assertEqual(30, client.local_threshold_ms) + self.assertEqual(30, client.options.local_threshold_ms) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') topology = client._topology @@ -139,7 +139,7 @@ class TestMongosLoadBalancing(MockClientTest): client.admin.command('ping') client = connected(self.mock_client(localThresholdMS=0)) - self.assertEqual(0, client.local_threshold_ms) + self.assertEqual(0, client.options.local_threshold_ms) # No error client.db.command('ping') # Our chosen mongos goes down. diff --git a/test/test_pooling.py b/test/test_pooling.py index ce0bed87c..045638081 100644 --- a/test/test_pooling.py +++ b/test/test_pooling.py @@ -169,7 +169,7 @@ class _TestPoolingBase(IntegrationTest): **kwargs): # Start the pool with the correct ssl options. pool_options = client_context.client._topology_settings.pool_options - kwargs['ssl_context'] = pool_options.ssl_context + kwargs['ssl_context'] = pool_options._ssl_context kwargs['tls_allow_invalid_hostnames'] = pool_options.tls_allow_invalid_hostnames kwargs['server_api'] = pool_options.server_api pool = Pool(pair, PoolOptions(*args, **kwargs)) @@ -187,7 +187,7 @@ class TestPooling(_TestPoolingBase): ValueError, MongoClient, host=host, port=port, maxPoolSize='foo') c = MongoClient(host=host, port=port, maxPoolSize=100, connect=False) - self.assertEqual(c.max_pool_size, 100) + self.assertEqual(c.options.pool_options.max_pool_size, 100) def test_no_disconnect(self): run_cases(self.c, [NonUnique, Unique, InsertOneAndFind]) diff --git a/test/test_read_preferences.py b/test/test_read_preferences.py index 128b41d5f..18dbd0bee 100644 --- a/test/test_read_preferences.py +++ b/test/test_read_preferences.py @@ -209,20 +209,16 @@ class TestReadPreferences(TestReadPreferencesBase): def test_threshold_validation(self): self.assertEqual(17, rs_client( - localThresholdMS=17 - ).local_threshold_ms) + localThresholdMS=17, connect=False).options.local_threshold_ms) self.assertEqual(42, rs_client( - localThresholdMS=42 - ).local_threshold_ms) + localThresholdMS=42, connect=False).options.local_threshold_ms) self.assertEqual(666, rs_client( - localthresholdms=666 - ).local_threshold_ms) + localThresholdMS=666, connect=False).options.local_threshold_ms) self.assertEqual(0, rs_client( - localthresholdms=0 - ).local_threshold_ms) + localThresholdMS=0, connect=False).options.local_threshold_ms) self.assertRaises(ValueError, rs_client, diff --git a/test/test_retryable_reads.py b/test/test_retryable_reads.py index 665aa9fd3..c4c093f66 100644 --- a/test/test_retryable_reads.py +++ b/test/test_retryable_reads.py @@ -48,19 +48,19 @@ _TEST_PATH = os.path.join( class TestClientOptions(PyMongoTestCase): def test_default(self): client = MongoClient(connect=False) - self.assertEqual(client.retry_reads, True) + self.assertEqual(client.options.retry_reads, True) def test_kwargs(self): client = MongoClient(retryReads=True, connect=False) - self.assertEqual(client.retry_reads, True) + self.assertEqual(client.options.retry_reads, True) client = MongoClient(retryReads=False, connect=False) - self.assertEqual(client.retry_reads, False) + self.assertEqual(client.options.retry_reads, False) def test_uri(self): client = MongoClient('mongodb://h/?retryReads=true', connect=False) - self.assertEqual(client.retry_reads, True) + self.assertEqual(client.options.retry_reads, True) client = MongoClient('mongodb://h/?retryReads=false', connect=False) - self.assertEqual(client.retry_reads, False) + self.assertEqual(client.options.retry_reads, False) class TestSpec(SpecRunner): diff --git a/test/test_sdam_monitoring_spec.py b/test/test_sdam_monitoring_spec.py index e51283f85..02807f05a 100644 --- a/test/test_sdam_monitoring_spec.py +++ b/test/test_sdam_monitoring_spec.py @@ -290,7 +290,7 @@ class TestSdamMonitoring(IntegrationTest): 'data': data, } with self.fail_point(fail_insert): - if self.test_client.retry_writes: + if self.test_client.options.retry_writes: self.coll.insert_one({}) else: with self.assertRaises(expected_error): diff --git a/test/test_session.py b/test/test_session.py index 9ab0c349f..e844ae3a0 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -104,7 +104,7 @@ class TestSession(IntegrationTest): self.assertLessEqual(used_lsids, current_lsids) def _test_ops(self, client, *ops): - listener = client.event_listeners[0] + listener = client.options.event_listeners[0] for f, args, kw in ops: with client.start_session() as s: @@ -626,7 +626,7 @@ class TestSession(IntegrationTest): lambda cursor: list(cursor)) def _test_unacknowledged_ops(self, client, *ops): - listener = client.event_listeners[0] + listener = client.options.event_listeners[0] for f, args, kw in ops: with client.start_session() as s: