From 197ba165781c85fef4f33a13bbef4db2de0ceb63 Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Tue, 1 Apr 2025 14:04:52 -0400 Subject: [PATCH 1/8] DOCSP-48153: Add sync vs. async content to migration page --- .../motor-comparison-table-pymongo.rst | 22 ++ source/reference/compatibility.txt | 9 +- source/reference/migration.txt | 348 ++++-------------- 3 files changed, 100 insertions(+), 279 deletions(-) create mode 100644 source/includes/motor-comparison-table-pymongo.rst diff --git a/source/includes/motor-comparison-table-pymongo.rst b/source/includes/motor-comparison-table-pymongo.rst new file mode 100644 index 00000000..68628344 --- /dev/null +++ b/source/includes/motor-comparison-table-pymongo.rst @@ -0,0 +1,22 @@ +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :class: compatibility-large + + * - Motor Version + - {+driver-short+} Version + + * - 3.7 + - 4.10 + + * - 3.6 + - 4.9 + + * - 3.3 + - 4.4 + + * - 3.1 + - 4.2 + + * - 3.0 + - 4.0 \ No newline at end of file diff --git a/source/reference/compatibility.txt b/source/reference/compatibility.txt index 91d64e0c..b46f1295 100644 --- a/source/reference/compatibility.txt +++ b/source/reference/compatibility.txt @@ -48,4 +48,11 @@ The following compatibility table specifies the recommended version of {+driver-short+} for use with a specific version of Python. The first column lists the driver version. -.. include:: /includes/language-compatibility-table-pymongo.rst \ No newline at end of file +.. include:: /includes/language-compatibility-table-pymongo.rst + +Motor Compatibility +------------------- + +The following table shows the equivalent versions of Motor and {+driver-short+}. + +.. include:: /includes/motor-comparison-table-pymongo.rst diff --git a/source/reference/migration.txt b/source/reference/migration.txt index febf2911..d2343426 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -28,6 +28,39 @@ library `__. In this guide, you can identify the changes you must make to migrate an application from {+driver-short+} or Motor to the {+driver-async+} driver. +.. note:: + + The {+driver-async+} driver is currently in beta. To learn how to provide feedback + or report issues, see :ref:`pymongo-issues-help`. + +Synchronous Versus Asynchronous +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To determine whether to migrate to the {+driver-async+} driver or to continue using +Synchronous {+driver-short+}, consider the information in this section. + +Synchronous {+driver-short+} is preferable if the following criteria applies to your +application or usecase: + +- Your application is simple in execution, or you prefer to avoid using asynchronous calls + in your code + +- Your application relies on non-concurrent workloads or workloads with very fast + response times + +- You prefer the simplicity of synchronous logic when debugging your application + +Consider migrating to the {+driver-async+} driver if the following criteria applies +to your application or usecase: + +- Your application implements large, highly concurrent workloads (on the order of + thousands of concurrent operations) + +- Your application relies on workloads that spend a long time waiting for responses or + writing data + +- Your application relies on other asynchronous libraries or frameworks, such as FastAPI + Migrate From Motor ------------------ @@ -56,6 +89,10 @@ driver, see the :ref:`pymongo-async-methods` section in the {+driver-short+} to The following section shows the method signature changes that you must implement in your application when migrating from Motor to the {+driver-async+} driver. +.. warning:: + + The {+driver-async+} driver does not support Tornado. + Method Signature Changes ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -70,6 +107,16 @@ The following Motor method signatures behave differently in the {+driver-async+} ``AsyncMongoClient`` is not thread safe and should only be used by a single event loop. +.. warning:: + + Motor users may experience a degradation of performance when switching to the + {+driver-async+} driver. This is due to the {+driver-async+} driver using the native + ``asyncio`` library instead of thread-based executors. + + Users experiencing performance slowdown should consider using synchronous {+driver-short+} + with ``async.loop.run_in_executor()`` for asynchronous compatibility. To learn more, see + the `Event Loop API documentation `__. + .. _pymongo-to-async-guide: Migrate from {+driver-short+} @@ -82,294 +129,39 @@ in the following ways: - Replace all uses of ``MongoClient`` with ``AsyncMongoClient``. - Add the ``await`` keyword to all asynchronous method calls. -- If you call an asynchronous method inside of a function, mark the function as ``async``. - -The following sections describe how to implement the asynchronous API. - -.. _pymongo-async-methods: - -Asynchronous Methods -~~~~~~~~~~~~~~~~~~~~ - -The following tables list the asynchronous methods that are available in the -{+driver-async+} driver. To call these methods, you must ``await`` them and call them -inside an ``async`` function. - -Client Methods -`````````````` - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Method - - Example - - * - ``AsyncMongoClient()`` - - .. code-block:: python - - from pymongo import AsyncMongoClient - - async with AsyncMongoClient(...) - - * - ``watch()`` - - .. code-block:: python - - async with await client.watch(...) as stream: - ... - - * - ``server_info()`` - - .. code-block:: python - - await client.server_info(...) - - * - ``list_databases()`` - - .. code-block:: python - - await client.list_databases() - - * - ``list_database_names()`` - - .. code-block:: python - - await client.list_database_names() - - * - ``drop_database()`` - - .. code-block:: python - - await client.drop_database(...) - -Database Methods -```````````````` - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Method - - Example - - * - ``watch()`` - - .. code-block:: python - - async with await db.watch(...) as stream: - ... - - * - ``create_collection()`` - - .. code-block:: python - - await db.create_collection(...) - - * - ``aggregate()`` - - .. code-block:: python - - async with await client.admin.aggregate(...) as cursor: - ... - - * - ``command()`` - - .. code-block:: python - - await db.command(...) - - * - ``cursor_command()`` - - .. code-block:: python - - await db.cursor_command(...) - - * - ``list_collections()`` - - .. code-block:: python - - await db.list_collections() - - * - ``list_collection_names()`` - - .. code-block:: python +- If you call an asynchronous method inside a function, mark the function as ``async``. - await db.list_collection_names() +Keep the following points in mind when migrating from synchronous {+driver-short+} +to the {+driver-async+} driver: - * - ``drop_collection()`` - - .. code-block:: python +- To convert an ``AsyncCursor`` to a list, you must use the asynchronous ``cursor.to_list()`` + method. +- The ``AsyncCollection.find()`` method in the {+driver-async+} driver is synchronous, but + returns an ``AsyncCursor``. To iterate through the cursor, you must use ``async for`` + loop. +- The ``AsyncMongoClient`` object does not support the ``connect`` keyword argument. +- You cannot share ``AsyncMongoClient`` objects across threads or event loops. +- To access a property or method of a result returned by an asynchronous call, you must + properly wrap the call in parentheses, as shown in the following example: - await db.drop_collection(...) + .. code-block:: python + + id = (await posts.insert_one(doc)).inserted_id - * - ``validate_collection()`` - - .. code-block:: python - - await db.validate_collection(...) - - * - ``dereference()`` - - .. code-block:: python - - await db.dereference(...) - -Collection Methods -`````````````````` - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Method - - Example - - * - ``watch()`` - - .. code-block:: python - - async with await collection.watch(...) as stream: - ... - - * - ``insert_one()`` - - .. code-block:: python - - await collection.insert_one(...) - - * - ``insert_many()`` - - .. code-block:: python - - await collection.insert_many(...) - - * - ``replace_one()`` - - .. code-block:: python - - await collection.replace_one(...) - - * - ``update_one()`` - - .. code-block:: python - - await collection.update_one(...) - - * - ``update_many()`` - - .. code-block:: python - - await collection.update_many(...) - - * - ``drop()`` - - .. code-block:: python - - await collection.drop() - - * - ``delete_one()`` - - .. code-block:: python - - await collection.delete_one(...) - - * - ``delete_many()`` - - .. code-block:: python - - await collection.delete_many(...) - - * - ``find_one()`` - - .. code-block:: python - - await collection.find_one(...) - - * - ``estimated_document_count()`` - - .. code-block:: python - - await collection.estimated_document_count() - - * - ``count_documents()`` - - .. code-block:: python - - await collection.count_documents(...) - - * - ``create_index()`` - - .. code-block:: python - - await collection.create_index(...) - - * - ``create_indexes()`` - - .. code-block:: python - - await collection.create_indexes(...) - - * - ``drop_index()`` - - .. code-block:: python - - await collection.drop_index(...) - - * - ``drop_indexes()`` - - .. code-block:: python - - await collection.drop_indexes() - - * - ``list_indexes()`` - - .. code-block:: python - - await collection.list_indexes() - - * - ``index_information()`` - - .. code-block:: python - - await collection.index_information() - - * - ``list_search_indexes()`` - - .. code-block:: python - - await collection.list_search_indexes() - - * - ``create_search_index()`` - - .. code-block:: python - - await collection.create_search_index(...) - - * - ``create_search_indexes()`` - - .. code-block:: python - - await collection.create_search_indexes(...) - - * - ``drop_search_index()`` - - .. code-block:: python - - await collection.drop_search_index(...) - - * - ``update_search_index()`` - - .. code-block:: python - - await collection.update_search_index(...) - - * - ``options()`` - - .. code-block:: python - - await collection.options() - - * - ``aggregate()`` - - .. code-block:: python - - async for doc in await collection.aggregate(...): - ... - - * - ``aggregate_raw_batches()`` - - .. code-block:: python - - async for batch in await collection.aggregate_raw_batches(...): - ... - - * - ``rename()`` - - .. code-block:: python - - await collection.rename(...) - - * - ``distinct()`` - - .. code-block:: python - - await collection.distinct(...) - - * - ``find_one_and_delete()`` - - .. code-block:: python - - await collection.find_one_and_delete(...) +.. _pymongo-async-methods: - * - ``find_one_and_replace()`` - - .. code-block:: python +Asynchronous Methods +-------------------- - await collection.find_one_and_replace(...) +For a complete list of asynchronous methods available in the {+driver-async+} driver, +see the `API documentation <{+api-root+}pymongo/asynchronous/index.html>`__. - * - ``find_one_and_update()`` - - .. code-block:: python +.. note:: - await collection.find_one_and_update(...) + Any methods not listed in the preceding API documentation link are still synchronous. Additional Information ---------------------- To learn more about asynchronous Python, see the `Python Asyncio documentation -`__. \ No newline at end of file +`__. From c01f8320a743d163037e00fe6b857b7f8a81cf07 Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Wed, 2 Apr 2025 15:31:43 -0400 Subject: [PATCH 2/8] Fix --- source/includes/motor-comparison-table-pymongo.rst | 1 - source/reference/migration.txt | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/source/includes/motor-comparison-table-pymongo.rst b/source/includes/motor-comparison-table-pymongo.rst index 68628344..a9700e46 100644 --- a/source/includes/motor-comparison-table-pymongo.rst +++ b/source/includes/motor-comparison-table-pymongo.rst @@ -1,6 +1,5 @@ .. list-table:: :header-rows: 1 - :stub-columns: 1 :class: compatibility-large * - Motor Version diff --git a/source/reference/migration.txt b/source/reference/migration.txt index d2343426..783178ad 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -137,7 +137,7 @@ to the {+driver-async+} driver: - To convert an ``AsyncCursor`` to a list, you must use the asynchronous ``cursor.to_list()`` method. - The ``AsyncCollection.find()`` method in the {+driver-async+} driver is synchronous, but - returns an ``AsyncCursor``. To iterate through the cursor, you must use ``async for`` + returns an ``AsyncCursor``. To iterate through the cursor, you must use an ``async for`` loop. - The ``AsyncMongoClient`` object does not support the ``connect`` keyword argument. - You cannot share ``AsyncMongoClient`` objects across threads or event loops. @@ -158,7 +158,7 @@ see the `API documentation <{+api-root+}pymongo/asynchronous/index.html>`__. .. note:: - Any methods not listed in the preceding API documentation link are still synchronous. + Any methods not listed in the preceding API documentation are synchronous. Additional Information ---------------------- From a3802aed3946451aed8741b2ede6005eb6c453da Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Wed, 2 Apr 2025 15:37:10 -0400 Subject: [PATCH 3/8] Fix --- source/reference/compatibility.txt | 2 ++ source/reference/migration.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/source/reference/compatibility.txt b/source/reference/compatibility.txt index b46f1295..2798a5a1 100644 --- a/source/reference/compatibility.txt +++ b/source/reference/compatibility.txt @@ -50,6 +50,8 @@ The first column lists the driver version. .. include:: /includes/language-compatibility-table-pymongo.rst +.. _pymongo-motor-compatibility: + Motor Compatibility ------------------- diff --git a/source/reference/migration.txt b/source/reference/migration.txt index 783178ad..86aa721d 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -84,7 +84,8 @@ read and write operations in Motor compared to {+driver-async+}: To see a list of the asynchronous methods available in the {+driver-async+} driver, see the :ref:`pymongo-async-methods` section in the {+driver-short+} to -{+driver-async+} guide. +{+driver-async+} guide. To learn about the versions of Motor that correspond to {+driver-short+}, +see the :ref:`_pymongo-motor-compatibility` section of the Compatibility guide. The following section shows the method signature changes that you must implement in your application when migrating from Motor to the {+driver-async+} driver. From 9f78ffa6e3e3f7fb3c5aa11c18a77c865068c49c Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Thu, 3 Apr 2025 09:35:13 -0400 Subject: [PATCH 4/8] SA feedback + additional admonition --- source/reference/migration.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source/reference/migration.txt b/source/reference/migration.txt index 86aa721d..756a07e3 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -28,11 +28,6 @@ library `__. In this guide, you can identify the changes you must make to migrate an application from {+driver-short+} or Motor to the {+driver-async+} driver. -.. note:: - - The {+driver-async+} driver is currently in beta. To learn how to provide feedback - or report issues, see :ref:`pymongo-issues-help`. - Synchronous Versus Asynchronous ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -40,7 +35,7 @@ To determine whether to migrate to the {+driver-async+} driver or to continue us Synchronous {+driver-short+}, consider the information in this section. Synchronous {+driver-short+} is preferable if the following criteria applies to your -application or usecase: +application or use case: - Your application is simple in execution, or you prefer to avoid using asynchronous calls in your code @@ -51,7 +46,7 @@ application or usecase: - You prefer the simplicity of synchronous logic when debugging your application Consider migrating to the {+driver-async+} driver if the following criteria applies -to your application or usecase: +to your application or use case: - Your application implements large, highly concurrent workloads (on the order of thousands of concurrent operations) @@ -64,6 +59,12 @@ to your application or usecase: Migrate From Motor ------------------ +.. warning:: Motor deprecation + + Motor will be deprecated one year after the production release of the {+driver-async+} + driver. We strongly recomend that Motor users migrate to the {+driver-async+} driver while + Motor is still supported. + The {+driver-async+} driver functions similarly to the Motor library, but allows for improved latency and throughput due to directly using Python Asyncio instead of delegating work to a thread pool. In most cases, you can directly migrate @@ -83,9 +84,9 @@ read and write operations in Motor compared to {+driver-async+}: from pymongo import AsyncMongoClient To see a list of the asynchronous methods available in the {+driver-async+} -driver, see the :ref:`pymongo-async-methods` section in the {+driver-short+} to -{+driver-async+} guide. To learn about the versions of Motor that correspond to {+driver-short+}, -see the :ref:`_pymongo-motor-compatibility` section of the Compatibility guide. +driver, see the :ref:`pymongo-async-methods` section. To learn about the versions of Motor +that correspond to {+driver-short+}, see the :ref:`pymongo-motor-compatibility` section of +the Compatibility guide. The following section shows the method signature changes that you must implement in your application when migrating from Motor to the {+driver-async+} driver. From 10a57c2d951ccab6184d0a6c55424096fdb8eb84 Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Thu, 3 Apr 2025 12:47:39 -0400 Subject: [PATCH 5/8] SA feedback --- source/reference/migration.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/reference/migration.txt b/source/reference/migration.txt index 756a07e3..d7a3339e 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -59,10 +59,10 @@ to your application or use case: Migrate From Motor ------------------ -.. warning:: Motor deprecation +.. warning:: Motor Deprecation Motor will be deprecated one year after the production release of the {+driver-async+} - driver. We strongly recomend that Motor users migrate to the {+driver-async+} driver while + driver. We strongly recommend that Motor users migrate to the {+driver-async+} driver while Motor is still supported. The {+driver-async+} driver functions similarly to the Motor library, but allows From 9fd64691fab0d2fd45d2f0372eddff2b269e8fba Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Thu, 3 Apr 2025 13:17:28 -0400 Subject: [PATCH 6/8] NS feedback --- source/reference/migration.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/source/reference/migration.txt b/source/reference/migration.txt index d7a3339e..52339fe5 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -40,7 +40,7 @@ application or use case: - Your application is simple in execution, or you prefer to avoid using asynchronous calls in your code -- Your application relies on non-concurrent workloads or workloads with very fast +- Your application relies on serial workloads or workloads with very fast response times - You prefer the simplicity of synchronous logic when debugging your application @@ -113,10 +113,15 @@ The following Motor method signatures behave differently in the {+driver-async+} Motor users may experience a degradation of performance when switching to the {+driver-async+} driver. This is due to the {+driver-async+} driver using the native - ``asyncio`` library instead of thread-based executors. - - Users experiencing performance slowdown should consider using synchronous {+driver-short+} - with ``async.loop.run_in_executor()`` for asynchronous compatibility. To learn more, see + ``asyncio`` library instead of thread-based executors. Thread-based executors + have similar performance characteristics to the synchronous driver, but slower. + This means they perform better for workloads that do not fit the preceding criteria + for the {+driver-async+} driver. + + If you are experiencing performance slowdown, identify whether the {+driver-async+} driver + is necessary for your usecase. If you determine your use case is better served by + synchronous {+driver-short+}, consider using synchronous {+driver-short+} + with ``asyncio.loop.run_in_executor()`` for asynchronous compatibility. To learn more, see the `Event Loop API documentation `__. .. _pymongo-to-async-guide: From a027a8700f44513d501cc9b566eae25d2e7ef40c Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Thu, 3 Apr 2025 13:18:14 -0400 Subject: [PATCH 7/8] Fix --- source/reference/migration.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/reference/migration.txt b/source/reference/migration.txt index 52339fe5..8893680b 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -120,7 +120,7 @@ The following Motor method signatures behave differently in the {+driver-async+} If you are experiencing performance slowdown, identify whether the {+driver-async+} driver is necessary for your usecase. If you determine your use case is better served by - synchronous {+driver-short+}, consider using synchronous {+driver-short+} + synchronous {+driver-short+}, consider using the synchronous driver with ``asyncio.loop.run_in_executor()`` for asynchronous compatibility. To learn more, see the `Event Loop API documentation `__. From b5474f9e4ed9fc83582d338f705688ca170dd7a6 Mon Sep 17 00:00:00 2001 From: Michael Morisi Date: Thu, 3 Apr 2025 14:00:19 -0400 Subject: [PATCH 8/8] Fix --- source/reference/migration.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/reference/migration.txt b/source/reference/migration.txt index 8893680b..919739ef 100644 --- a/source/reference/migration.txt +++ b/source/reference/migration.txt @@ -112,8 +112,8 @@ The following Motor method signatures behave differently in the {+driver-async+} .. warning:: Motor users may experience a degradation of performance when switching to the - {+driver-async+} driver. This is due to the {+driver-async+} driver using the native - ``asyncio`` library instead of thread-based executors. Thread-based executors + {+driver-async+} driver. This is due to the {+driver-async+} driver using native + ``asyncio`` tasks instead of thread-based executors. Thread-based executors have similar performance characteristics to the synchronous driver, but slower. This means they perform better for workloads that do not fit the preceding criteria for the {+driver-async+} driver.