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.
Read the requirements
page and ensure your MongoDB server and Python interpreter are compatible, and your Tornado version if you are using Tornado.
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
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+.
A 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 ~motor.motor_tornado.MotorCursor.fetch_next
.
directConnection
URI option and keyword argument to ~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.
Several deprecated URI options have been renamed to the standardized option names defined in the URI options specification. 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 | - | +--------------------+-------------------------------+--------------------------------------------------------+
Removed ~motor.motor_tornado.MotorClient.fsync
. Run the fsync command directly with ~motor.motor_tornado.MotorDatabase.command
instead. For example:
await client.admin.command('fsync', lock=True)
Removed ~motor.motor_tornado.MotorClient.unlock
. Run the fsyncUnlock command directly with ~motor.motor_tornado.MotorDatabase.command
instead. For example:
await client.admin.command('fsyncUnlock')
Removed ~motor.motor_tornado.MotorClient.max_bson_size
, ~motor.motor_tornado.MotorClient.max_message_size
, and ~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']
The following client configuration option helpers are removed: - ~motor.motor_tornado.MotorClient.event_listeners
. - ~motor.motor_tornado.MotorClient.max_pool_size
. - ~motor.motor_tornado.MotorClient.min_pool_size
. - ~motor.motor_tornado.MotorClient.max_idle_time_ms
. - ~motor.motor_tornado.MotorClient.local_threshold_ms
. - ~motor.motor_tornado.MotorClient.server_selection_timeout
. - ~motor.motor_tornado.MotorClient.retry_writes
. - ~motor.motor_tornado.MotorClient.retry_reads
.
These helpers have been replaced by ~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
, an argument for ~bson.json_util.JSONOptions
, now defaults to False
instead of True
. json_util.loads
now decodes datetime as naive by default.
~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.
~motor.motor_tornado.MotorClient
now raises a ~pymongo.errors.ConfigurationError
when more than one URI is passed into the hosts
argument.
~motor.motor_tornado.MotorClient
now raises an ~pymongo.errors.InvalidURI
exception when it encounters unescaped percent signs in username and password.
Removed ~motor.motor_tornado.MotorDatabase.current_op
. Use ~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()
Removed ~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']
Removed ~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'})
Removed ~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()
~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.
Removed ~motor.motor_tornado.MotorCollection.map_reduce
and ~motor.motor_tornado.MotorCollection.inline_map_reduce
. Migrate to ~motor.motor_tornado.MotorCollection.aggregate
or run the mapReduce command directly with ~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/
MotorCollection.reindex is removed .............................
Removed 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')
Removed the modifiers
parameter from ~motor.motor_tornado.MotorCollection.find
, ~motor.motor_tornado.MotorCollection.find_one
, ~motor.motor_tornado.MotorCollection.find_raw_batches
, and ~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
option is now required when using min
or max
queries with ~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)])
~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.
Empty projections (eg {} or []) for ~motor.motor_tornado.MotorCollection.find
, and ~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})
PyMongo 4.0 removed pymongo.son_manipulator
.
Motor 3.0 removed motor.MotorDatabase.add_son_manipulator
, motor.MotorDatabase.outgoing_copying_manipulators
, motor.MotorDatabase.outgoing_manipulators
, motor.MotorDatabase.incoming_copying_manipulators
, and motor.MotorDatabase.incoming_manipulators
.
Removed the manipulate
parameter from ~motor.motor_tornado.MotorCollection.find
, ~motor.motor_tornado.MotorCollection.find_one
, and ~motor.motor_tornado.MotorCursor
.
The 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 ~bson.codec_options.TypeCodec
and ~bson.codec_options.TypeRegistry
APIs may be a suitable alternative. For more information, see the custom type example <examples/custom_type>
.
Removed the disable_md5 option for ~motor.motor_tornado.gridfs.MotorGridFSBucket
and ~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.
The default uuid_representation for ~bson.codec_options.CodecOptions
, ~bson.json_util.JSONOptions
, and ~motor.motor_tornado.MotorClient
has been changed from bson.binary.UuidRepresentation.PYTHON_LEGACY
to bson.binary.UuidRepresentation.UNSPECIFIED
. Attempting to encode a uuid.UUID
instance to BSON or JSON now produces an error by default. See handling-uuid-data-example
for details.
Once your application runs without deprecation warnings with Motor 2.5, upgrade to Motor 3.0.