Skip to content

Commit 3c786f5

Browse files
authored
PYTHON-3606 - Document best practice for closing MongoClients and cursors (#2465)
1 parent f105789 commit 3c786f5

File tree

6 files changed

+132
-2
lines changed

6 files changed

+132
-2
lines changed

pymongo/asynchronous/collection.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,15 @@ def find(self, *args: Any, **kwargs: Any) -> AsyncCursor[_DocumentType]:
17761776
improper type. Returns an instance of
17771777
:class:`~pymongo.asynchronous.cursor.AsyncCursor` corresponding to this query.
17781778
1779+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
1780+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
1781+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
1782+
or use the cursor in a with statement::
1783+
1784+
async with collection.find() as cursor:
1785+
async for doc in cursor:
1786+
print(doc)
1787+
17791788
The :meth:`find` method obeys the :attr:`read_preference` of
17801789
this :class:`AsyncCollection`.
17811790
@@ -2503,6 +2512,15 @@ async def list_indexes(
25032512
...
25042513
SON([('v', 2), ('key', SON([('_id', 1)])), ('name', '_id_')])
25052514
2515+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2516+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2517+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
2518+
or use the cursor in a with statement::
2519+
2520+
async with await collection.list_indexes() as cursor:
2521+
async for index in cursor:
2522+
print(index)
2523+
25062524
:param session: a
25072525
:class:`~pymongo.asynchronous.client_session.AsyncClientSession`.
25082526
:param comment: A user-provided comment to attach to this
@@ -2620,6 +2638,15 @@ async def list_search_indexes(
26202638
) -> AsyncCommandCursor[Mapping[str, Any]]:
26212639
"""Return a cursor over search indexes for the current collection.
26222640
2641+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2642+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2643+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
2644+
or use the cursor in a with statement::
2645+
2646+
async with await collection.list_search_indexes() as cursor:
2647+
async for index in cursor:
2648+
print(index)
2649+
26232650
:param name: If given, the name of the index to search
26242651
for. Only indexes with matching index names will be returned.
26252652
If not given, all search indexes for the current collection
@@ -2922,6 +2949,15 @@ async def aggregate(
29222949
.. note:: The :attr:`~pymongo.asynchronous.collection.AsyncCollection.write_concern` of
29232950
this collection is automatically applied to this operation.
29242951
2952+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2953+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2954+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
2955+
or use the cursor in a with statement::
2956+
2957+
async with await collection.aggregate() as cursor:
2958+
async for operation in cursor:
2959+
print(operation)
2960+
29252961
:param pipeline: a list of aggregation pipeline stages
29262962
:param session: a
29272963
:class:`~pymongo.asynchronous.client_session.AsyncClientSession`.

pymongo/asynchronous/database.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,15 +643,20 @@ async def aggregate(
643643
.. code-block:: python
644644
645645
# Lists all operations currently running on the server.
646-
with client.admin.aggregate([{"$currentOp": {}}]) as cursor:
647-
for operation in cursor:
646+
async with await client.admin.aggregate([{"$currentOp": {}}]) as cursor:
647+
async for operation in cursor:
648648
print(operation)
649649
650650
The :meth:`aggregate` method obeys the :attr:`read_preference` of this
651651
:class:`AsyncDatabase`, except when ``$out`` or ``$merge`` are used, in
652652
which case :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`
653653
is used.
654654
655+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
656+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
657+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
658+
or use the cursor in a with statement.
659+
655660
.. note:: This method does not support the 'explain' option. Please
656661
use :meth:`~pymongo.asynchronous.database.AsyncDatabase.command` instead.
657662
@@ -1154,6 +1159,15 @@ async def list_collections(
11541159
) -> AsyncCommandCursor[MutableMapping[str, Any]]:
11551160
"""Get a cursor over the collections of this database.
11561161
1162+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
1163+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
1164+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
1165+
or use the cursor in a with statement::
1166+
1167+
async with await database.list_collections() as cursor:
1168+
async for collection in cursor:
1169+
print(collection)
1170+
11571171
:param session: a
11581172
:class:`~pymongo.asynchronous.client_session.AsyncClientSession`.
11591173
:param filter: A query document to filter the list of

pymongo/asynchronous/mongo_client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ def __init__(
202202
exception (recognizing that the operation failed) and then continue to
203203
execute.
204204
205+
Best practice is to call :meth:`AsyncMongoClient.close` when the client is no longer needed,
206+
or use the client in a with statement::
207+
208+
async with AsyncMongoClient(url) as client:
209+
# Use client here.
210+
205211
The `host` parameter can be a full `mongodb URI
206212
<https://dochub.mongodb.org/core/connections>`_, in addition to
207213
a simple hostname. It can also be a list of hostnames but no more
@@ -2345,6 +2351,15 @@ async def list_databases(
23452351
) -> AsyncCommandCursor[dict[str, Any]]:
23462352
"""Get a cursor over the databases of the connected server.
23472353
2354+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2355+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2356+
To avoid this, best practice is to call :meth:`AsyncCursor.close` when the cursor is no longer needed,
2357+
or use the cursor in a with statement::
2358+
2359+
async with await client.list_databases() as cursor:
2360+
async for database in cursor:
2361+
print(database)
2362+
23482363
:param session: a
23492364
:class:`~pymongo.asynchronous.client_session.AsyncClientSession`.
23502365
:param comment: A user-provided comment to attach to this

pymongo/synchronous/collection.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,15 @@ def find(self, *args: Any, **kwargs: Any) -> Cursor[_DocumentType]:
17751775
improper type. Returns an instance of
17761776
:class:`~pymongo.cursor.Cursor` corresponding to this query.
17771777
1778+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
1779+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
1780+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
1781+
or use the cursor in a with statement::
1782+
1783+
with collection.find() as cursor:
1784+
for doc in cursor:
1785+
print(doc)
1786+
17781787
The :meth:`find` method obeys the :attr:`read_preference` of
17791788
this :class:`Collection`.
17801789
@@ -2500,6 +2509,15 @@ def list_indexes(
25002509
...
25012510
SON([('v', 2), ('key', SON([('_id', 1)])), ('name', '_id_')])
25022511
2512+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2513+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2514+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
2515+
or use the cursor in a with statement::
2516+
2517+
with collection.list_indexes() as cursor:
2518+
for index in cursor:
2519+
print(index)
2520+
25032521
:param session: a
25042522
:class:`~pymongo.client_session.ClientSession`.
25052523
:param comment: A user-provided comment to attach to this
@@ -2617,6 +2635,15 @@ def list_search_indexes(
26172635
) -> CommandCursor[Mapping[str, Any]]:
26182636
"""Return a cursor over search indexes for the current collection.
26192637
2638+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2639+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2640+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
2641+
or use the cursor in a with statement::
2642+
2643+
with collection.list_search_indexes() as cursor:
2644+
for index in cursor:
2645+
print(index)
2646+
26202647
:param name: If given, the name of the index to search
26212648
for. Only indexes with matching index names will be returned.
26222649
If not given, all search indexes for the current collection
@@ -2915,6 +2942,15 @@ def aggregate(
29152942
.. note:: The :attr:`~pymongo.collection.Collection.write_concern` of
29162943
this collection is automatically applied to this operation.
29172944
2945+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2946+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2947+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
2948+
or use the cursor in a with statement::
2949+
2950+
with collection.aggregate() as cursor:
2951+
for operation in cursor:
2952+
print(operation)
2953+
29182954
:param pipeline: a list of aggregation pipeline stages
29192955
:param session: a
29202956
:class:`~pymongo.client_session.ClientSession`.

pymongo/synchronous/database.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,11 @@ def aggregate(
652652
which case :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`
653653
is used.
654654
655+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
656+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
657+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
658+
or use the cursor in a with statement.
659+
655660
.. note:: This method does not support the 'explain' option. Please
656661
use :meth:`~pymongo.database.Database.command` instead.
657662
@@ -1148,6 +1153,15 @@ def list_collections(
11481153
) -> CommandCursor[MutableMapping[str, Any]]:
11491154
"""Get a cursor over the collections of this database.
11501155
1156+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
1157+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
1158+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
1159+
or use the cursor in a with statement::
1160+
1161+
with database.list_collections() as cursor:
1162+
for collection in cursor:
1163+
print(collection)
1164+
11511165
:param session: a
11521166
:class:`~pymongo.client_session.ClientSession`.
11531167
:param filter: A query document to filter the list of

pymongo/synchronous/mongo_client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ def __init__(
199199
exception (recognizing that the operation failed) and then continue to
200200
execute.
201201
202+
Best practice is to call :meth:`MongoClient.close` when the client is no longer needed,
203+
or use the client in a with statement::
204+
205+
with MongoClient(url) as client:
206+
# Use client here.
207+
202208
The `host` parameter can be a full `mongodb URI
203209
<https://dochub.mongodb.org/core/connections>`_, in addition to
204210
a simple hostname. It can also be a list of hostnames but no more
@@ -2335,6 +2341,15 @@ def list_databases(
23352341
) -> CommandCursor[dict[str, Any]]:
23362342
"""Get a cursor over the databases of the connected server.
23372343
2344+
Cursors are closed automatically when they are exhausted (the last batch of data is retrieved from the database).
2345+
If a cursor is not exhausted, it will be closed automatically upon garbage collection, which leaves resources open but unused for a potentially long period of time.
2346+
To avoid this, best practice is to call :meth:`Cursor.close` when the cursor is no longer needed,
2347+
or use the cursor in a with statement::
2348+
2349+
with client.list_databases() as cursor:
2350+
for database in cursor:
2351+
print(database)
2352+
23382353
:param session: a
23392354
:class:`~pymongo.client_session.ClientSession`.
23402355
:param comment: A user-provided comment to attach to this

0 commit comments

Comments
 (0)