MOTOR-698 Motor 2 to 3 migration guide (#166)

This commit is contained in:
Steven Silvester 2022-04-27 21:14:13 -05:00 committed by GitHub
parent 19537bbafe
commit 92b4d51ecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 593 additions and 4 deletions

View File

@ -6,12 +6,138 @@ Changelog
Motor 3.0
---------
Motor 3.0 requires PyMongo 4.0+ and Python 3.7+.
Motor 3.0 adds support for PyMongo 4.0+. It inherits a number
of improvemnts and breaking API changes from PyMongo 4.0+.
See :doc:`migrate-to-motor-3` for more information.
Breaking Changes
~~~~~~~~~~~~~~~~
- Prevent use of :class:`~pymongo.database.Database` and :class:`~pymongo.collection.Collection` in boolean expressions.
- Requires PyMongo 4.0+.
- Removed support for Python 3.5 and 3.6. Python 3.7+ is now required.
- Removed the ``socketKeepAlive`` keyword argument to
:class:`~motor.motor_tornado.MotorClient`.
- Removed :meth:`motor.motor_tornado.MotorClient.fsync`,
:meth:`motor.motor_tornado.MotorClient.unlock`, and
:attr:`motor.motor_tornado.MotorClient.is_locked`.
- Removed :attr:`motor.motor_tornado.MotorClient.max_bson_size`.
- Removed :attr:`motor.motor_tornado.MotorClient.max_message_size`.
- Removed :attr:`motor.motor_tornado.MotorClient.max_write_batch_size`.
- Removed :attr:`motor.motor_tornado.MotorClient.event_listeners`.
- Removed :attr:`motor.motor_tornado.MotorClient.max_pool_size`.
- Removed :attr:`motor.motor_tornado.MotorClient.max_idle_time_ms`.
- Removed :attr:`motor.motor_tornado.MotorClient.local_threshold_ms`.
- Removed :attr:`motor.motor_tornado.MotorClient.server_selection_timeout`.
- Removed :attr:`motor.motor_tornado.MotorClient.retry_writes`.
- Removed :attr:`motor.motor_tornado.MotorClient.retry_reads`.
- Removed support for database profiler helpers
:meth:`~motor.motor_tornado.MotorDatabase.profiling_level`,
:meth:`~motor.motor_tornado.MotorDatabase.set_profiling_level`,
and :meth:`~motor.motor_tornado.MotorDatabase.profiling_info`. Instead, users
should run the profile command with the
:meth:`~motor.motor_tornado.MotorDatabase.command` helper directly.
- Removed :attr:`pymongo.OFF`, :attr:`pymongo.SLOW_ONLY`, and
:attr:`pymongo.ALL`.
- Removed :meth:`motor.motor_tornado.MotorCollection.map_reduce` and
:meth:`motor.motor_tornado.MotorCollection.inline_map_reduce`.
- Removed the ``useCursor`` option for
:meth:`~motor.motor_tornado.MotorCollection.aggregate`.
- Removed :mod:`pymongo.son_manipulator`,
:meth:`motor.motor_tornado.MotorDatabase.add_son_manipulator`,
:attr:`motor.motor_tornado.MotorDatabase.outgoing_copying_manipulators`,
:attr:`motor.motor_tornado.MotorDatabase.outgoing_manipulators`,
:attr:`motor.motor_tornado.MotorDatabase.incoming_copying_manipulators`, and
:attr:`motor.motor_tornado.MotorDatabase.incoming_manipulators`.
- Removed the ``manipulate`` and ``modifiers`` parameters from
:meth:`~motor.motor_tornado.MotorCollection.find`,
:meth:`~motor.motor_tornado.MotorCollection.find_one`,
:meth:`~motor.motor_tornado.MotorCollection.find_raw_batches`, and
:meth:`~motor.motor_tornado.MotorCursor`.
- ``directConnection`` URI option and keyword argument to :class:`~motor.motor_tornado.MotorClient`
defaults to ``False`` instead of ``None``, allowing for the automatic
discovery of replica sets. This means that if you
want a direct connection to a single server you must pass
``directConnection=True`` as a URI option or keyword argument.
- The ``hint`` option is now required when using ``min`` or ``max`` queries
with :meth:`~motor.motor_tornado.MotorCollection.find`.
- When providing a "mongodb+srv://" URI to
:class:`~motor.motor_tornado.MotorClient` constructor you can now use the
``srvServiceName`` URI option to specify your own SRV service name.
- :class:`~motor.motor_tornado.MotorCollection` and :class:`motor.motor_tornado.MotorDatabase`
now raises an error upon evaluating as a Boolean, please use the
syntax ``if collection is not None:`` or ``if database is not None:`` as
opposed to
the previous syntax which was simply ``if collection:`` or ``if database:``.
You must now explicitly compare with None.
- :class:`~motor.motor_tornado.MotorClient` cannot execute any operations
after being closed. The previous behavior would simply reconnect. However,
now you must create a new instance.
- Empty projections (eg {} or []) for
:meth:`~motor.motor_tornado.MotorCollection.find`, and
:meth:`~motor.motor_tornado.MotorCollection.find_one`
are passed to the server as-is rather than the previous behavior which
substituted in a projection of ``{"_id": 1}``. This means that an empty
projection will now return the entire document, not just the ``"_id"`` field.
- :class:`~motor.motor_tornado.MotorClient` now raises a
:exc:`~pymongo.errors.ConfigurationError` when more than one URI is passed
into the ``hosts`` argument.
- :class:`~motor.motor_tornado.MotorClient`` now raises an
:exc:`~pymongo.errors.InvalidURI` exception
when it encounters unescaped percent signs in username and password when
parsing MongoDB URIs.
- Comparing two :class:`~motor.motor_tornado.MotorClient` instances now
uses a set of immutable properties rather than
:attr:`~motor.motor_tornado.MotorClient.address` which can change.
- Removed the `disable_md5` parameter for :class:`~gridfs.GridFSBucket` and
:class:`~gridfs.GridFS`. See :ref:`removed-gridfs-checksum` for details.
- PyMongoCrypt 1.2.0 or later is now required for client side field level
encryption support.
Notable improvements
~~~~~~~~~~~~~~~~~~~~
- Enhanced connection pooling to create connections more efficiently and
avoid connection storms.
- Added the ``maxConnecting`` URI and
:class:`~motor.motor_tornado.MotorClient` keyword argument.
- :class:`~motor.motor_tornado.MotorClient` now accepts a URI and keyword
argument `srvMaxHosts` that limits the number of mongos-like hosts a client
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:`motor.motor_tornado.MotorClient.options` for read-only access
to a client's configuration options.
- Added support for the ``comment`` parameter to all helpers. For example see
:meth:`~motor.motor_tornado.MotorCollection.insert_one`.
- Added support for the ``let`` parameter to
:meth:`~motor.motor_tornado.MotorCollection.update_one`,
:meth:`~motor.motor_tornado.MotorCollection.update_many`,
:meth:`~motor.motor_tornado.MotorCollection.delete_one`,
:meth:`~motor.motor_tornado.MotorCollection.delete_many`,
:meth:`~motor.motor_tornado.MotorCollection.replace_one`,
:meth:`~motor.motor_tornado.MotorCollection.aggregate`,
:meth:`~motor.motor_tornado.MotorCollection.find_one_and_delete`,
:meth:`~motor.motor_tornado.MotorCollection.find_one_and_replace`,
:meth:`~motor.motor_tornado.MotorCollection.find_one_and_update`,
:meth:`~motor.motor_tornado.MotorCollection.find`,
:meth:`~motor.motor_tornado.MotorCollection.find_one`,
and :meth:`~motor.motor_tornado.MotorCollection.bulk_write`.
``let`` is a map of parameter names and values.
Parameters can then be accessed as variables in an aggregate expression
context.
- :meth:`~motor.motor_tornado.MotorCollection.aggregate` now supports
$merge and $out executing on secondaries on MongoDB >=5.0.
aggregate() now always obeys the collection's :attr:`read_preference` on
MongoDB >= 5.0.
- :meth:`gridfs.grid_file.GridOut.seek` now returns the new position in the file, to
conform to the behavior of :meth:`io.IOBase.seek`.
Issues Resolved
~~~~~~~~~~~~~~~
See the `Motor 3.0 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _Motor 3.0 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=11182&version=29710
Motor 2.5.1
-----------
@ -1123,7 +1249,7 @@ If it's important to test that MongoDB is available before continuing
your application's startup, use ``IOLoop.run_sync``::
loop = tornado.ioloop.IOLoop.current()
client = motor.MotorClient(host, port)
client = motor.motor_tornado.MotorClient(host, port)
try:
loop.run_sync(client.open)
except pymongo.errors.ConnectionFailure:

View File

@ -85,6 +85,7 @@ Contents
examples/index
changelog
migrate-to-motor-2
migrate-to-motor-3
developer-guide
contributors

462
doc/migrate-to-motor-3.rst Normal file
View File

@ -0,0 +1,462 @@
Motor 3.0 Migration Guide
=========================
.. currentmodule:: motor.motor_tornado
Motor 3.0 brings a number of changes to Motor 2.0's API. The major version is
required in order to bring support for PyMongo 4.0+.
To add compatibility with PyMongo 4, several methods were removed, as detailed below.
Some of the underlying behaviors and method arguments have changed in PyMongo
4.0 as well.
Follow this guide to migrate an existing application that had used Motor 2.x.
Check compatibility
-------------------
Read the :doc:`requirements` page and ensure your MongoDB server and Python
interpreter are compatible, and your Tornado version if you are using Tornado.
Upgrade to Motor 2.5
--------------------
The first step in migrating to Motor 3.0 is to upgrade to at least Motor 2.5.
If your project has a
``requirements.txt`` file, add the line::
motor >= 2.5, < 3.0
Python 3.7+
-----------
Motor 3.0 drops support for Python 3.5 and 3.6. Users who wish to upgrade to 3.x must first upgrade to Python 3.7+.
Enable Deprecation Warnings
---------------------------
A :exc:`DeprecationWarning` is raised by most changes made in PyMongo 4.0.
Make sure you enable runtime warnings to see where
deprecated functions and methods are being used in your application::
python -Wd <your application>
Warnings can also be changed to errors::
python -Wd -Werror <your application>
Note that there are some deprecation warnings raised by Motor itself for
APIs that are deprecated but not yet removed, like :meth:`~motor.motor_tornado.MotorCursor.fetch_next`.
MotorClient
-----------
``directConnection`` defaults to False
......................................
``directConnection`` URI option and keyword argument to :class:`~motor
.MotorClient` defaults to ``False`` instead of ``None``,
allowing for the automatic discovery of replica sets. This means that if you
want a direct connection to a single server you must pass
``directConnection=True`` as a URI option or keyword argument.
Renamed URI options
...................
Several deprecated URI options have been renamed to the standardized
option names defined in the
`URI options specification <https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.rst>`_.
The old option names and their renamed equivalents are summarized in the table
below. Some renamed options have different semantics from the option being
replaced as noted in the 'Migration Notes' column.
+--------------------+-------------------------------+--------------------------------------------------------+
| Old URI Option | Renamed URI Option | Migration Notes |
+====================+===============================+========================================================+
| ssl_pem_passphrase | tlsCertificateKeyFilePassword | - |
+--------------------+-------------------------------+--------------------------------------------------------+
| ssl_ca_certs | tlsCAFile | - |
+--------------------+-------------------------------+--------------------------------------------------------+
| ssl_crlfile | tlsCRLFile | - |
+--------------------+-------------------------------+--------------------------------------------------------+
| ssl_match_hostname | tlsAllowInvalidHostnames | ``ssl_match_hostname=True`` is equivalent to |
| | | ``tlsAllowInvalidHostnames=False`` and vice-versa. |
+--------------------+-------------------------------+--------------------------------------------------------+
| ssl_cert_reqs | tlsAllowInvalidCertificates | Instead of ``ssl.CERT_NONE``, ``ssl.CERT_OPTIONAL`` |
| | | and ``ssl.CERT_REQUIRED``, the new option expects |
| | | a boolean value - ``True`` is equivalent to |
| | | ``ssl.CERT_NONE``, while ``False`` is equivalent to |
| | | ``ssl.CERT_REQUIRED``. |
+--------------------+-------------------------------+--------------------------------------------------------+
| ssl_certfile | tlsCertificateKeyFile | Instead of using ``ssl_certfile`` and ``ssl_keyfile`` |
| | | to specify the certificate and private key files |
+--------------------+ | respectively, use ``tlsCertificateKeyFile`` to pass |
| ssl_keyfile | | a single file containing both the client certificate |
| | | and the private key. |
+--------------------+-------------------------------+--------------------------------------------------------+
| j | journal | - |
+--------------------+-------------------------------+--------------------------------------------------------+
| wtimeout | wTimeoutMS | - |
+--------------------+-------------------------------+--------------------------------------------------------+
MotorClient.fsync is removed
............................
Removed :meth:`~motor.motor_tornado.MotorClient.fsync`. Run the
`fsync command`_ directly with :meth:`~motor.motor_tornado.MotorDatabase.command`
instead. For example::
await client.admin.command('fsync', lock=True)
.. _fsync command: https://mongodb.com/docs/manual/reference/command/fsync/
MotorClient.unlock is removed
.............................
Removed :meth:`~motor.motor_tornado.MotorClient.unlock`. Run the
`fsyncUnlock command`_ directly with
:meth:`~motor.motor_tornado.MotorDatabase.command` instead. For example::
await client.admin.command('fsyncUnlock')
.. _fsyncUnlock command: https://mongodb.com/docs/manual/reference/command/fsyncUnlock/
MotorClient.max_bson_size/max_message_size/max_write_batch_size are removed
...........................................................................
Removed :attr:`~motor.motor_tornado.MotorClient.max_bson_size`,
:attr:`~motor.motor_tornado.MotorClient.max_message_size`, and
:attr:`~motor.motor_tornado.MotorClient.max_write_batch_size`. These helpers
were incorrect when in ``loadBalanced=true mode`` and ambiguous in clusters
with mixed versions. Use the `hello command`_ to get the authoritative
value from the remote server instead. Code like this::
max_bson_size = client.max_bson_size
max_message_size = client.max_message_size
max_write_batch_size = client.max_write_batch_size
can be changed to this::
doc = await client.admin.command('hello')
max_bson_size = doc['maxBsonObjectSize']
max_message_size = doc['maxMessageSizeBytes']
max_write_batch_size = doc['maxWriteBatchSize']
.. _hello command: https://mongodb.com/docs/manual/reference/command/hello/
MotorClient.event_listeners and other configuration option helpers are removed
..............................................................................
The following client configuration option helpers are removed:
- :attr:`~motor.motor_tornado.MotorClient.event_listeners`.
- :attr:`~motor.motor_tornado.MotorClient.max_pool_size`.
- :attr:`~motor.motor_tornado.MotorClient.min_pool_size`.
- :attr:`~motor.motor_tornado.MotorClient.max_idle_time_ms`.
- :attr:`~motor.motor_tornado.MotorClient.local_threshold_ms`.
- :attr:`~motor.motor_tornado.MotorClient.server_selection_timeout`.
- :attr:`~motor.motor_tornado.MotorClient.retry_writes`.
- :attr:`~motor.motor_tornado.MotorClient.retry_reads`.
These helpers have been replaced by
:attr:`~motor.motor_tornado.MotorClient.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``
..................................
``tz_aware``, an argument for :class:`~bson.json_util.JSONOptions`,
now defaults to ``False`` instead of ``True``. ``json_util.loads`` now
decodes datetime as naive by default.
MotorClient cannot execute operations after ``close()``
.......................................................
:class:`~motor.motor_tornado.MotorClient` cannot execute any operations
after being closed. The previous behavior would simply reconnect. However,
now you must create a new instance.
MotorClient raises exception when given more than one URI
.........................................................
:class:`~motor.motor_tornado.MotorClient` now raises a :exc:`~pymongo.errors.ConfigurationError`
when more than one URI is passed into the ``hosts`` argument.
MotorClient raises exception when given unescaped percent sign in login info
............................................................................
:class:`~motor.motor_tornado.MotorClient` now raises an
:exc:`~pymongo.errors.InvalidURI` exception
when it encounters unescaped percent signs in username and password.
Database
--------
MotorDatabase.current_op is removed
...................................
Removed :meth:`~motor.motor_tornado.MotorDatabase.current_op`. Use
:meth:`~motor.motor_tornado.MotorDatabase.aggregate` instead with the
`$currentOp aggregation pipeline stage`_. Code like
this::
ops = client.admin.current_op()['inprog']
can be changed to this::
ops = await client.admin.aggregate([{'$currentOp': {}}]).to_list()
.. _$currentOp aggregation pipeline stage: https://mongodb.com/docs/manual/reference/operator/aggregation/currentOp/
MotorDatabase.profiling_level is removed
........................................
Removed :meth:`~motor.motor_tornado.MotorDatabase.profiling_level` which was deprecated in
PyMongo 3.12. Use the `profile command`_ instead. Code like this::
level = db.profiling_level()
Can be changed to this::
profile = await db.command('profile', -1)
level = profile['was']
.. _profile command: https://mongodb.com/docs/manual/reference/command/profile/
MotorDatabase.set_profiling_level is removed
............................................
Removed :meth:`~motor.motor_tornado.MotorDatabase.set_profiling_level` which was deprecated in
PyMongo 3.12. Use the `profile command`_ instead. Code like this::
db.set_profiling_level(pymongo.ALL, filter={'op': 'query'})
Can be changed to this::
res = await db.command('profile', 2, filter={'op': 'query'})
MotorDatabase.profiling_info is removed
.......................................
Removed :meth:`~motor.motor_tornado.MotorDatabase.profiling_info` which was deprecated in
PyMongo 3.12. Query the `'system.profile' collection`_ instead. Code like this::
profiling_info = db.profiling_info()
Can be changed to this::
profiling_info = await db['system.profile'].find().to_list()
.. _'system.profile' collection: https://mongodb.com/docs/manual/reference/database-profiler/
MotorDatabase.__bool__ raises NotImplementedError
.................................................
:class:`~motor.motor_tornado.MotorDatabase` now raises an error upon evaluating as a
Boolean. Code like this::
if database:
Can be changed to this::
if database is not None:
You must now explicitly compare with None.
MotorCollection
---------------
MotorCollection.map_reduce and MotorCollection.inline_map_reduce are removed
............................................................................
Removed :meth:`~motor.motor_tornado.MotorCollection.map_reduce` and
:meth:`~motor.motor_tornado.MotorCollection.inline_map_reduce`.
Migrate to :meth:`~motor.motor_tornado.MotorCollection.aggregate` or run the
`mapReduce command`_ directly with :meth:`~motor.motor_tornado.MotorDatabase.command`
instead. For more guidance on this migration see:
- https://mongodb.com/docs/manual/reference/map-reduce-to-aggregation-pipeline/
- https://mongodb.com/docs/manual/reference/aggregation-commands-comparison/
.. _mapReduce command: https://mongodb.com/docs/manual/reference/command/mapReduce/
MotorCollection.reindex is removed
..................................
Removed :meth:`motor.motor_tornado.MotorCollection.reindex`. Run the
`reIndex command`_ directly instead. Code like this::
>>> result = await database.my_collection.reindex()
can be changed to this::
>>> result = await database.command('reIndex', 'my_collection')
.. _reIndex command: https://mongodb.com/docs/manual/reference/command/reIndex/
The modifiers parameter is removed
..................................
Removed the ``modifiers`` parameter from
:meth:`~motor.motor_tornado.MotorCollection.find`,
:meth:`~motor.motor_tornado.MotorCollection.find_one`,
:meth:`~motor.motor_tornado.MotorCollection.find_raw_batches`, and
:meth:`~motor.motor_tornado.MotorCursor`. Pass the options directly to the method
instead. Code like this::
cursor = await coll.find({}, modifiers={
"$comment": "comment",
"$hint": {"_id": 1},
"$min": {"_id": 0},
"$max": {"_id": 6},
"$maxTimeMS": 6000,
"$returnKey": False,
"$showDiskLoc": False,
})
can be changed to this::
cursor = await coll.find(
{},
comment="comment",
hint={"_id": 1},
min={"_id": 0},
max={"_id": 6},
max_time_ms=6000,
return_key=False,
show_record_id=False,
)
The hint parameter is required with min/max
...........................................
The ``hint`` option is now required when using ``min`` or ``max`` queries
with :meth:`~motor.motor_tornado.MotorCollection.find` to ensure the query utilizes
the correct index. For example, code like this::
cursor = await coll.find({}, min={'x', min_value})
can be changed to this::
cursor = await coll.find({}, min={'x', min_value}, hint=[('x', ASCENDING)])
MotorCollection.__bool__ raises NotImplementedError
...................................................
:class:`~motor.motor_tornado.MotorCollection` now raises an error upon evaluating
as a Boolean. Code like this::
if collection:
Can be changed to this::
if collection is not None:
You must now explicitly compare with None.
MotorCollection.find returns entire document with empty projection
..................................................................
Empty projections (eg {} or []) for
:meth:`~motor.motor_tornado.MotorCollection.find`, and
:meth:`~motor.motor_tornado.MotorCollection.find_one`
are passed to the server as-is rather than the previous behavior which
substituted in a projection of ``{"_id": 1}``. This means that an empty
projection will now return the entire document, not just the ``"_id"`` field.
To ensure that behavior remains consistent, code like this::
await coll.find({}, projection={})
Can be changed to this::
await coll.find({}, projection={"_id":1})
SONManipulator is removed
-------------------------
PyMongo 4.0 removed :mod:`pymongo.son_manipulator`.
Motor 3.0 removed :meth:`motor.MotorDatabase.add_son_manipulator`,
:attr:`motor.MotorDatabase.outgoing_copying_manipulators`,
:attr:`motor.MotorDatabase.outgoing_manipulators`,
:attr:`motor.MotorDatabase.incoming_copying_manipulators`, and
:attr:`motor.MotorDatabase.incoming_manipulators`.
Removed the ``manipulate`` parameter from
:meth:`~motor.motor_tornado.MotorCollection.find`,
:meth:`~motor.motor_tornado.MotorCollection.find_one`, and
:meth:`~motor.motor_tornado.MotorCursor`.
The :class:`pymongo.son_manipulator.SONManipulator` API has limitations as a
technique for transforming your data and was deprecated in PyMongo 3.0.
Instead, it is more flexible and straightforward to transform outgoing
documents in your own code before passing them to PyMongo, and transform
incoming documents after receiving them from PyMongo.
Alternatively, if your application uses the ``SONManipulator`` API to convert
custom types to BSON, the :class:`~bson.codec_options.TypeCodec` and
:class:`~bson.codec_options.TypeRegistry` APIs may be a suitable alternative.
For more information, see the
:doc:`custom type example <examples/custom_type>`.
GridFS changes
--------------
.. _removed-gridfs-checksum:
disable_md5 parameter is removed
................................
Removed the `disable_md5` option for :class:`~motor.motor_tornado.gridfs.MotorGridFSBucket` and
:class:`~motor.motor_tornado.gridfs.MotorGridFS`. GridFS no longer generates checksums.
Applications that desire a file digest should implement it outside GridFS
and store it with other file metadata. For example::
import hashlib
my_db = MotorClient().test
fs = GridFSBucket(my_db)
grid_in = fs.open_upload_stream("test_file")
file_data = b'...'
sha356 = hashlib.sha256(file_data).hexdigest()
await grid_in.write(file_data)
grid_in.sha356 = sha356 # Set the custom 'sha356' field
await grid_in.close()
Note that for large files, the checksum may need to be computed in chunks
to avoid the excessive memory needed to load the entire file at once.
Removed features with no migration path
---------------------------------------
Encoding a UUID raises an error by default
..........................................
The default uuid_representation for :class:`~bson.codec_options.CodecOptions`,
:class:`~bson.json_util.JSONOptions`, and
:class:`~motor.motor_tornado.MotorClient` has been changed from
:data:`bson.binary.UuidRepresentation.PYTHON_LEGACY` to
:data:`bson.binary.UuidRepresentation.UNSPECIFIED`. Attempting to encode a
:class:`uuid.UUID` instance to BSON or JSON now produces an error by default.
See :ref:`handling-uuid-data-example` for details.
Upgrade to Motor 3.0
--------------------
Once your application runs without deprecation warnings with Motor 2.5, upgrade
to Motor 3.0.