diff --git a/doc/api/pymongo/mongo_client.rst b/doc/api/pymongo/mongo_client.rst index ed110e8f9..ac774679c 100644 --- a/doc/api/pymongo/mongo_client.rst +++ b/doc/api/pymongo/mongo_client.rst @@ -34,7 +34,6 @@ .. autoattribute:: read_preference .. autoattribute:: write_concern .. autoattribute:: read_concern - .. autoattribute:: is_locked .. automethod:: start_session .. automethod:: list_databases .. automethod:: list_database_names @@ -43,9 +42,10 @@ .. automethod:: get_default_database .. automethod:: get_database .. automethod:: server_info + .. automethod:: watch .. automethod:: close_cursor .. automethod:: kill_cursors .. automethod:: set_cursor_manager - .. automethod:: watch + .. autoattribute:: is_locked .. automethod:: fsync .. automethod:: unlock diff --git a/doc/changelog.rst b/doc/changelog.rst index b06bc8e11..20c30fd6f 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -46,6 +46,12 @@ Highlights include: :class:`~pymongo.read_preferences.SecondaryPreferred`, :class:`~pymongo.read_preferences.Nearest` to support disabling (or explicitly enabling) hedged reads in MongoDB 4.4+. +- Fixed a bug in change streams that could cause PyMongo to miss some change + documents when resuming a stream that was started without a resume token and + whose first batch did not contain any change documents. + +Deprecations: + - Deprecated the ``oplog_replay`` parameter to :meth:`pymongo.collection.Collection.find`. Starting in MongoDB 4.4, the server optimizes queries against the oplog collection without requiring @@ -53,9 +59,15 @@ Highlights include: - Deprecated :meth:`pymongo.collection.Collection.reindex`. Use :meth:`~pymongo.database.Database.command` to run the ``reIndex`` command instead. -- Fixed a bug in change streams that could cause PyMongo to miss some change - documents when resuming a stream that was started without a resume token and - whose first batch did not contain any change documents. +- Deprecated :meth:`pymongo.mongo_client.MongoClient.fsync`. Use + :meth:`~pymongo.database.Database.command` to run the ``fsync`` command + instead. +- Deprecated :meth:`pymongo.mongo_client.MongoClient.unlock`. Use + :meth:`~pymongo.database.Database.command` to run the ``fsyncUnlock`` command + instead. See the documentation for more information. +- Deprecated :attr:`pymongo.mongo_client.MongoClient.is_locked`. Use + :meth:`~pymongo.database.Database.command` to run the ``currentOp`` command + instead. See the documentation for more information. Unavoidable breaking changes: diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 5d4703c0e..e5545fb79 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -2083,15 +2083,33 @@ class MongoClient(common.BaseObject): @property def is_locked(self): - """Is this server locked? While locked, all write operations - are blocked, although read operations may still be allowed. + """**DEPRECATED**: Is this server locked? While locked, all write + operations are blocked, although read operations may still be allowed. Use :meth:`unlock` to unlock. + + Deprecated. Users of MongoDB version 3.2 or newer can run the + `currentOp command`_ directly with + :meth:`~pymongo.database.Database.command`:: + + is_locked = client.admin.command('currentOp').get('fsyncLock') + + Users of MongoDB version 2.6 and 3.0 can query the "inprog" virtual + collection:: + + is_locked = client.admin["$cmd.sys.inprog"].find_one().get('fsyncLock') + + .. versionchanged:: 3.11 + Deprecated. + + .. _currentOp command: https://docs.mongodb.com/manual/reference/command/currentOp/ """ + warnings.warn("is_locked is deprecated. See the documentation for " + "more information.", DeprecationWarning, stacklevel=2) ops = self._database_default_options('admin')._current_op() return bool(ops.get('fsyncLock', 0)) def fsync(self, **kwargs): - """Flush all pending writes to datafiles. + """**DEPRECATED**: Flush all pending writes to datafiles. Optional parameters can be passed as keyword arguments: - `lock`: If True lock the server to disallow writes. @@ -2106,6 +2124,14 @@ class MongoClient(common.BaseObject): options = {'async': True} client.fsync(**options) + Deprecated. Run the `fsync command`_ directly with + :meth:`~pymongo.database.Database.command` instead. For example:: + + client.admin.command('fsync', lock=True) + + .. versionchanged:: 3.11 + Deprecated. + .. versionchanged:: 3.6 Added ``session`` parameter. @@ -2114,20 +2140,46 @@ class MongoClient(common.BaseObject): .. warning:: MongoDB does not support the `async` option on Windows and will raise an exception on that platform. + + .. _fsync command: https://docs.mongodb.com/manual/reference/command/fsync/ """ + warnings.warn("fsync is deprecated. Use " + "client.admin.command('fsync') instead.", + DeprecationWarning, stacklevel=2) self.admin.command("fsync", read_preference=ReadPreference.PRIMARY, **kwargs) def unlock(self, session=None): - """Unlock a previously locked server. + """**DEPRECATED**: Unlock a previously locked server. :Parameters: - `session` (optional): a :class:`~pymongo.client_session.ClientSession`. + Deprecated. Users of MongoDB version 3.2 or newer can run the + `fsyncUnlock command`_ directly with + :meth:`~pymongo.database.Database.command`:: + + client.admin.command('fsyncUnlock') + + Users of MongoDB version 2.6 and 3.0 can query the "unlock" virtual + collection:: + + client.admin["$cmd.sys.unlock"].find_one() + + .. versionchanged:: 3.11 + Deprecated. + .. versionchanged:: 3.6 Added ``session`` parameter. + + .. _fsyncUnlock command: https://docs.mongodb.com/manual/reference/command/fsyncUnlock/ """ + warnings.warn("unlock is deprecated. Use " + "client.admin.command('fsyncUnlock') instead. For " + "MongoDB 2.6 and 3.0, see the documentation for " + "more information.", + DeprecationWarning, stacklevel=2) cmd = SON([("fsyncUnlock", 1)]) with self._socket_for_writes(session) as sock_info: if sock_info.max_wire_version >= 4: diff --git a/test/test_client.py b/test/test_client.py index 566728289..39234cdc6 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -1120,6 +1120,7 @@ class TestClient(IntegrationTest): self.assertTrue("pymongo_test" in dbs) self.assertTrue("pymongo_test_bernie" in dbs) + @ignore_deprecations @client_context.require_no_mongos def test_fsync_lock_unlock(self): if server_is_master_with_slave(client_context.client): @@ -1143,13 +1144,19 @@ class TestClient(IntegrationTest): time.sleep(1) self.assertFalse(locked) - def test_is_locked_does_not_raise_warning(self): - client = rs_or_single_client() - with warnings.catch_warnings(record=True) as ctx: - warnings.simplefilter("always") - _ = client.is_locked - self.assertFalse( - any(issubclass(w.category, DeprecationWarning) for w in ctx)) + def test_deprecated_methods(self): + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + with self.assertRaisesRegex(DeprecationWarning, + 'is_locked is deprecated'): + _ = self.client.is_locked + if not client_context.is_mongos: + with self.assertRaisesRegex(DeprecationWarning, + 'fsync is deprecated'): + self.client.fsync(lock=True) + with self.assertRaisesRegex(DeprecationWarning, + 'unlock is deprecated'): + self.client.unlock() def test_contextlib(self): client = rs_or_single_client() diff --git a/test/test_monitoring.py b/test/test_monitoring.py index 6cff8fb0d..6b3321115 100644 --- a/test/test_monitoring.py +++ b/test/test_monitoring.py @@ -37,6 +37,7 @@ from test import (client_context, unittest) from test.utils import (EventListener, get_pool, + ignore_deprecations, rs_or_single_client, single_client, wait_until) @@ -1336,12 +1337,13 @@ class TestCommandMonitoring(PyMongoTestCase): self.assertTrue('ok' in succeeded.reply) if not client_context.is_mongos: - self.client.fsync(lock=True) - self.listener.results.clear() - self.client.unlock() - # Wait for async unlock... - wait_until( - lambda: not self.client.is_locked, "unlock the database") + with ignore_deprecations(): + self.client.fsync(lock=True) + self.listener.results.clear() + self.client.unlock() + # Wait for async unlock... + wait_until( + lambda: not self.client.is_locked, "unlock the database") started = results['started'][0] succeeded = results['succeeded'][0] self.assertEqual(0, len(results['failed'])) diff --git a/test/test_session.py b/test/test_session.py index f00f58bd9..1705344da 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -227,6 +227,7 @@ class TestSession(IntegrationTest): client.close() self.assertEqual(len(listener.results['started']), 0) + @ignore_deprecations # fsync and unlock def test_client(self): client = self.client