Skip to content

Latest commit

 

History

History
1487 lines (1120 loc) · 54.2 KB

changelog.rst

File metadata and controls

1487 lines (1120 loc) · 54.2 KB

Changelog

motor.motor_tornado

Motor 3.0

Motor 3.0 adds support for PyMongo 4.0+. It inherits a number of improvemnts and breaking API changes from PyMongo 4.0+. See migrate-to-motor-3 for more information.

Breaking Changes

  • 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 ~motor.motor_tornado.MotorClient.
  • Removed motor.motor_tornado.MotorClient.fsync, motor.motor_tornado.MotorClient.unlock, and motor.motor_tornado.MotorClient.is_locked.
  • Removed motor.motor_tornado.MotorClient.max_bson_size.
  • Removed motor.motor_tornado.MotorClient.max_message_size.
  • Removed motor.motor_tornado.MotorClient.max_write_batch_size.
  • Removed motor.motor_tornado.MotorClient.event_listeners.
  • Removed motor.motor_tornado.MotorClient.max_pool_size.
  • Removed motor.motor_tornado.MotorClient.max_idle_time_ms.
  • Removed motor.motor_tornado.MotorClient.local_threshold_ms.
  • Removed motor.motor_tornado.MotorClient.server_selection_timeout.
  • Removed motor.motor_tornado.MotorClient.retry_writes.
  • Removed motor.motor_tornado.MotorClient.retry_reads.
  • Removed support for database profiler helpers ~motor.motor_tornado.MotorDatabase.profiling_level, ~motor.motor_tornado.MotorDatabase.set_profiling_level, and ~motor.motor_tornado.MotorDatabase.profiling_info. Instead, users should run the profile command with the ~motor.motor_tornado.MotorDatabase.command helper directly.
  • Removed pymongo.OFF, pymongo.SLOW_ONLY, and pymongo.ALL.
  • Removed motor.motor_tornado.MotorCollection.map_reduce and motor.motor_tornado.MotorCollection.inline_map_reduce.
  • Removed the useCursor option for ~motor.motor_tornado.MotorCollection.aggregate.
  • Removed pymongo.son_manipulator, motor.motor_tornado.MotorDatabase.add_son_manipulator, motor.motor_tornado.MotorDatabase.outgoing_copying_manipulators, motor.motor_tornado.MotorDatabase.outgoing_manipulators, motor.motor_tornado.MotorDatabase.incoming_copying_manipulators, and motor.motor_tornado.MotorDatabase.incoming_manipulators.
  • Removed the manipulate and modifiers parameters from ~motor.motor_tornado.MotorCollection.find, ~motor.motor_tornado.MotorCollection.find_one, ~motor.motor_tornado.MotorCollection.find_raw_batches, and ~motor.motor_tornado.MotorCursor.
  • directConnection URI option and keyword argument to ~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 ~motor.motor_tornado.MotorCollection.find.
  • When providing a "mongodb+srv://" URI to ~motor.motor_tornado.MotorClient constructor you can now use the srvServiceName URI option to specify your own SRV service name.
  • ~motor.motor_tornado.MotorCollection and 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.
  • ~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 ~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.
  • ~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 :exc:~pymongo.errors.InvalidURI` exception when it encounters unescaped percent signs in username and password when parsing MongoDB URIs.
  • Comparing two ~motor.motor_tornado.MotorClient instances now uses a set of immutable properties rather than ~motor.motor_tornado.MotorClient.address which can change.
  • Removed the disable_md5 parameter for ~gridfs.GridFSBucket and ~gridfs.GridFS. See 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 ~motor.motor_tornado.MotorClient keyword argument.
  • ~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 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 ~motor.motor_tornado.MotorCollection.insert_one.
  • Added support for the let parameter to ~motor.motor_tornado.MotorCollection.update_one, ~motor.motor_tornado.MotorCollection.update_many, ~motor.motor_tornado.MotorCollection.delete_one, ~motor.motor_tornado.MotorCollection.delete_many, ~motor.motor_tornado.MotorCollection.replace_one, ~motor.motor_tornado.MotorCollection.aggregate, ~motor.motor_tornado.MotorCollection.find_one_and_delete, ~motor.motor_tornado.MotorCollection.find_one_and_replace, ~motor.motor_tornado.MotorCollection.find_one_and_update, ~motor.motor_tornado.MotorCollection.find, ~motor.motor_tornado.MotorCollection.find_one, and ~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.
  • ~motor.motor_tornado.MotorCollection.aggregate now supports $merge and $out executing on secondaries on MongoDB >=5.0. aggregate() now always obeys the collection's read_preference on MongoDB >= 5.0.
  • gridfs.grid_file.GridOut.seek now returns the new position in the file, to conform to the behavior of io.IOBase.seek.

Issues Resolved

See the Motor 3.0 release notes in JIRA for the list of resolved issues in this release.

Motor 2.5.1

Motor 2.5.1 fixes a bug where MotorCursor.to_list could return more than length documents.

Issues Resolved

See the Motor 2.5.1 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.5

Motor 2.5 adds support for MongoDB 5.0. It depends on PyMongo 3.12 or later.

New features:

  • Added support for MongoDB 5.0.
  • Support for MongoDB Stable API, see ~pymongo.server_api.ServerApi.
  • Support for snapshot reads on secondaries via the new snapshot option to ~motor.motor_asyncio.AsyncIOMotorClient.start_session.
  • Support for Azure and GCP KMS providers for client side field level encryption. See the examples in examples/encryption.
  • Support AWS authentication with temporary credentials when connecting to KMS in client side field level encryption.
  • Support for connecting to load balanced MongoDB clusters via the new loadBalanced URI option.
  • Support for creating timeseries collections via the timeseries and expireAfterSeconds arguments to ~motor.motor_asyncio.AsyncIOMotorDatabase.create_collection.
  • Added motor.motor_asyncio.AsyncIOMotorClient.topology_description.
  • Added hash support to motor.motor_asyncio.AsyncIOMotorClient, motor.motor_asyncio.AsyncIOMotorDatabase, and motor.motor_asyncio.AsyncIOMotorCollection classes.
  • Added session and read concern support to ~motor.motor_asyncio.AsyncIOMotorCollection.find_raw_batches and ~motor.motor_asyncio.AsyncIOMotorCollection.aggregate_raw_batches.

Deprecations:

  • Deprecated support for Python 3.5.
  • Deprecated ~motor.motor_asyncio.AsyncIOMotorDatabase.profiling_info, ~motor.motor_asyncio.AsyncIOMotorDatabase.profiling_level, and ~motor.motor_asyncio.AsyncIOMotorDatabase.set_profiling_level.

Issues Resolved

See the Motor 2.5 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.4

Motor 2.4 adds support for client-side field-level encryption and Python 3.9.

New Features:

  • Added the motor.motor_asyncio.AsyncIOMotorClientEncryption class, with the same interface as the corresponding PyMongo class. See examples/encryption for examples.
  • Added support for Python 3.9

Issues Resolved

See the Motor 2.4 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.3.1

Motor 2.3.1 fixes two bugs related to change streams.

Bug-fixes:

  • The motor.motor_asyncio.AsyncIOMotorCollection.watch, motor.motor_asyncio.AsyncIOMotorDatabase.watch, and motor.motor_asyncio.AsyncIOMotorClient.watch methods now properly support passing ~motor.motor_asyncio.AsyncIOMotorClientSession via the session argument.
  • Avoid exhausting Motor's worker thread pool when many change streams are being iterated simultaneously.

Issues Resolved

See the Motor 2.3.1 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.3

Motor 2.3 adds support for contextvars.

New features:

  • Added supported for the contextvars module. Specifically, it is now possible to access context variables inside ~pymongo.monitoring.CommandListener callbacks.

Bug-fixes:

  • Fixed a bug that prohibited users from subclassing the motor.motor_asyncio.AsyncIOMotorClient, motor.motor_asyncio.AsyncIOMotorDatabase, and motor.motor_asyncio.AsyncIOMotorCollection classes.
  • Updated the documentation to indicate full support for Windows. Previously, the documentation stated that Windows support was experimental.

Issues Resolved

See the Motor 2.3 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.2

Motor 2.2 adds support for MongoDB 4.4 features. It depends on PyMongo 3.11 or later. Motor continues to support MongoDB 3.0 and later. Motor 2.2 also drops support for Python 2.7 and Python 3.4.

New features:

  • Added the AsyncIOMotorCursor method ~motor.motor_asyncio.AsyncIOMotorCursor.next that advances the cursor one document at a time, similar to to the AsyncIOMotorChangeStream method ~motor.motor_asyncio.AsyncIOMotorChangeStream.next.
  • Added index-hinting support to the ~motor.motor_asyncio.AsyncIOMotorCollection.replace_one, ~motor.motor_asyncio.AsyncIOMotorCollection.update_one, ~motor.motor_asyncio.AsyncIOMotorCollection.update_many, ~motor.motor_asyncio.AsyncIOMotorCollection.delete_one, ~motor.motor_asyncio.AsyncIOMotorCollection.delete_many, ~motor.motor_asyncio.AsyncIOMotorCollection.find_one_and_replace, ~motor.motor_asyncio.AsyncIOMotorCollection.find_one_and_update, and ~motor.motor_asyncio.AsyncIOMotorCollection.find_one_and_delete methods.
  • Added support for the allow_disk_use parameter to ~motor.motor_asyncio.AsyncIOMotorCollection.find.
  • Modified the ~motor.motor_asyncio.AsyncIOMotorChangeStream class' async context manager such that the change stream cursor is now created during the call to async with. Previously, the cursor was only created when the application iterated the ~motor.motor_asyncio.AsyncIOMotorChangeStream object which could result in the application missing some changes.
  • Motor now advertises the framework used by the application to the MongoDB server as asyncio or Tornado. Previously, no framework information was reported if the application used asyncio.

Bug-fixes:

  • Fixed a bug that caused calls to the ~motor.motor_asyncio.AsyncIOMotorGridOut.open() method to raise AttributeError.
  • Fixed a bug that sometimes caused ~asyncio.Future.set_result to be called on a cancelled ~asyncio.Future when iterating a ~motor.motor_asyncio.AsyncIOMotorCommandCursor.

Deprecations:

  • Deprecated AsyncIOMotorCursor method ~motor.motor_asyncio.AsyncIOMotorCursor.next_object and property ~motor.motor_asyncio.AsyncIOMotorCursor.fetch_next. Applications should use async for to iterate over cursors instead.
  • Deprecated the ~motor.motor_asyncio.AsyncIOMotorClient.fsync method. Applications should run the fsync command directly with ~motor.motor_asyncio.AsyncIOMotorDatabase.command instead.

Issues Resolved

See the Motor 2.2 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.1

Motor 2.1 adds support for MongoDB 4.2 features. It depends on PyMongo 3.10 or later. Motor continues to support MongoDB 3.0 and later. Motor 2.1 also adds support for Python 3.8.

Motor now offers experimental support for Windows when it is using the asyncio event loop. This means it supports Windows exclusively with Python 3, either integrating with asyncio directly or with Tornado 5 or later: starting in version 5, Tornado uses the asyncio event loop on Python 3 by default.

Additional changes:

  • Support for MongoDB 4.2 sharded transactions. Sharded transactions have the same API as replica set transactions.
  • New method ~motor.motor_asyncio.AsyncIOMotorClientSession.with_transaction to support conveniently running a transaction in a session with automatic retries and at-most-once semantics.
  • Added the max_commit_time_ms parameter to ~motor.motor_asyncio.AsyncIOMotorClientSession.start_transaction.
  • The retryWrites URI option now defaults to True. Supported write operations that fail with a retryable error will automatically be retried one time, with at-most-once semantics.
  • Support for retryable reads and the retryReads URI option which is enabled by default. See the ~pymongo.mongo_client.MongoClient documentation for details. Now that supported operations are retried automatically and transparently, users should consider adjusting any custom retry logic to prevent an application from inadvertently retrying for too long.
  • Support zstandard for wire protocol compression.
  • Support for periodically polling DNS SRV records to update the mongos proxy list without having to change client configuration.
  • New method motor.motor_asyncio.AsyncIOMotorDatabase.aggregate to support running database level aggregations.
  • Change stream enhancements for MongoDB 4.2:
    • Resume tokens can now be accessed from a AsyncIOMotorChangeStream cursor using the ~motor.motor_asyncio.AsyncIOMotorChangeStream.resume_token attribute.
    • New AsyncIOMotorChangeStream method ~motor.motor_asyncio.AsyncIOMotorChangeStream.try_next and attribute ~motor.motor_asyncio.AsyncIOMotorChangeStream.alive.
    • New parameter start_after for change stream motor.motor_asyncio.AsyncIOMotorCollection.watch, motor.motor_asyncio.AsyncIOMotorDatabase.watch, and motor.motor_asyncio.AsyncIOMotorClient.watch methods.
  • New parameters bucket_name, chunk_size_bytes, write_concern, and read_preference for motor.motor_asyncio.AsyncIOMotorGridFSBucket.

Issues Resolved

See the Motor 2.1 release notes in JIRA for the complete list of resolved issues in this release.

Motor 2.0

Motor 2.0 drops support for MongoDB 2.6 and adds supports MongoDB 4.0 features, including multi-document transactions, and change stream notifications on entire databases or entire MongoDB servers. It adds support for Python 3.7. This version of Motor requires PyMongo 3.7 or later.

This is a major release that removes previously deprecated APIs.

To support multi-document transactions, Motor had to make breaking changes to the session API and release a major version bump. Since this is a major release it also deletes many helper methods and APIs that had been deprecated over the time since Motor 1.0, most notably the old CRUD methods insert, update, remove, and save, and the original callback-based API. Read the migrate-to-motor-2 carefully to upgrade your existing Motor application.

Documentation is updated to warn about obsolete TLS versions, see configuration. Motor is now tested on Travis in addition to MongoDB's Evergreen system.

Added support for aiohttp 3.0 and later, and dropped older aiohttp versions. The aiohttp integration now requires Python 3.5+.

The MotorDatabase.add_user and MotorDatabase.remove_user methods are deleted. Manage user accounts with four database commands: createUser, usersInfo, updateUser, and dropUser. You can run any database command with the MotorDatabase.command method.

The deprecated GridFS classes MotorGridFS and AsyncIOMotorGridFS are deleted in favor of ~motor.motor_tornado.MotorGridFSBucket and ~motor.motor_asyncio.AsyncIOMotorGridFSBucket, which conform to driver specs for GridFS.

Additional changes:

  • New methods for retrieving batches of raw BSON:
    • MotorCollection.find_raw_batches
    • MotorCollection.aggregate_raw_batches
  • Motor adds its name, version, and Tornado's version (if appropriate) to the client data logged by the MongoDB server when Motor connects, in addition to the data added by PyMongo.
  • Calling ~MotorCommandCursor.batch_size on a cursor returned from ~MotorCollection.aggregate no longer raises AttributeError.

Motor 1.3.1

Fix a Python 3.7 compatibility bug caused by importing "async", which is a keyword in Python 3.7. Drop support for Python 3.4.3 and older.

Motor 1.3.0

Deprecate Motor's old callback-based async API in preparation for removing it in Motor 2.0. Raise DeprecationWarning whenever a callback is passed.

See the migrate-to-motor-2.

Motor 1.2.5

Fix a Python 3.7 compatibility bug caused by importing "async", which is a keyword in Python 3.7. Drop support for Python 3.4.3 and older.

Motor 1.2.4

Fix a Python 3.7 compatibility bug in the MotorChangeStream class returned by MotorCollection.watch. It is now possible to use change streams in async for loops in Python 3.7.

Motor 1.2.3

Compatibility with latest Sphinx and document how to use the latest TLS protocols.

Motor 1.2.2

Motor 1.2.0 requires PyMongo 3.6 or later. The dependency was properly documented, but not enforced in setup.py. PyMongo 3.6 is now an install-time requirement; thanks to Shane Harvey for the fix.

Motor 1.2.1

An asyncio application that created a Change Stream with MotorCollection.watch and shut down while the Change Stream was open would print several errors. I have rewritten MotorChangeStream.next and some Motor internals to allow clean shutdown with asyncio.

Motor 1.2

Motor 1.2 drops support for MongoDB 2.4 and adds support for MongoDB 3.6 features. It depends on PyMongo 3.6 or later. Motor continues to support MongoDB 2.6 and later.

Dropped support for Python 2.6 and 3.3. Motor continues to support Python 2.7, and 3.4+.

Dropped support for Tornado 3. A recent version of Tornado 4 is required.

Dropped support for the Python 3.5.0 and Python 3.5.1 "async for" protocol. Motor allows "async for" with cursors in Python 3.5.2 and later.

See the Compatibility Matrix <compatibility-matrix> for the relationships among Motor, Python, Tornado, and MongoDB versions.

Added support for aiohttp 2.0 and later, and dropped older aiohttp versions.

Highlights include:

  • New method MotorCollection.watch to acquire a Change Stream on a collection.
  • New Session API to support causal consistency, see MotorClient.start_session.
  • Support for array_filters in ~MotorCollection.update_one, ~MotorCollection.update_many, ~MotorCollection.find_one_and_update, ~MotorCollection.bulk_write.
  • MotorClient.list_databases and MotorClient.list_database_names.
  • Support for mongodb+srv:// URIs. See ~pymongo.mongo_client.MongoClient for details.
  • Support for retryable writes and the retryWrites URI option. See ~pymongo.mongo_client.MongoClient for details.

The maximum number of workers in the thread pool can be overridden with an environment variable, see configuration.

MotorCollection accepts codec_options, read_preference, write_concern, and read_concern arguments. This is rarely needed; you typically create a MotorCollection from a MotorDatabase, not by calling its constructor directly.

Deleted obsolete class motor.Op.

Motor 1.1

Motor depends on PyMongo 3.4 or later. It wraps the latest PyMongo code which support the new server features introduced in MongoDB 3.4. (It is a coincidence that the latest MongoDB and PyMongo versions are the same number.)

Highlights include:

  • Complete support for MongoDB 3.4:
    • Unicode aware string comparison using collations. See PyMongo's examples for collation <collation-on-operation>.
    • MotorCursor and MotorGridOutCursor have a new attribute ~MotorCursor.collation.
    • Support for the new ~bson.decimal128.Decimal128 BSON type.
    • A new maxStalenessSeconds read preference option.
    • A username is no longer required for the MONGODB-X509 authentication mechanism when connected to MongoDB >= 3.4.
    • ~MotorCollection.parallel_scan supports maxTimeMS.
    • ~pymongo.write_concern.WriteConcern is automatically applied by all helpers for commands that write to the database when connected to MongoDB 3.4+. This change affects the following helpers:
      • MotorClient.drop_database
      • MotorDatabase.create_collection
      • MotorDatabase.drop_collection
      • MotorCollection.aggregate (when using $out)
      • MotorCollection.create_indexes
      • MotorCollection.create_index
      • MotorCollection.drop_indexes
      • MotorCollection.drop_indexes
      • MotorCollection.drop_index
      • MotorCollection.map_reduce (when output is not "inline")
      • MotorCollection.reindex
      • MotorCollection.rename
  • Improved support for logging server discovery and monitoring events. See PyMongo's monitoring documentation <pymongo.monitoring> for examples.
  • Support for matching iPAddress subjectAltName values for TLS certificate verification.
  • TLS compression is now explicitly disabled when possible.
  • The Server Name Indication (SNI) TLS extension is used when possible.
  • PyMongo's bson module provides finer control over JSON encoding/decoding with ~bson.json_util.JSONOptions.
  • Allow ~bson.code.Code objects to have a scope of None, signifying no scope. Also allow encoding Code objects with an empty scope (i.e. {}).

Warning

Starting in PyMongo 3.4, bson.code.Code.scope may return None, as the default scope is None instead of {}.

Note

PyMongo 3.4+ attempts to create sockets non-inheritable when possible (i.e. it sets the close-on-exec flag on socket file descriptors). Support is limited to a subset of POSIX operating systems (not including Windows) and the flag usually cannot be set in a single atomic operation. CPython 3.4+ implements PEP 446, creating all file descriptors non-inheritable by default. Users that require this behavior are encouraged to upgrade to CPython 3.4+.

Motor 1.0

Motor now depends on PyMongo 3.3 and later. The move from PyMongo 2 to 3 brings a large number of API changes, read the the PyMongo 3 changelog carefully.

MotorReplicaSetClient is removed

In Motor 1.0, MotorClient is the only class. Connect to a replica set with a "replicaSet" URI option or parameter:

MotorClient("mongodb://hostname/?replicaSet=my-rs")
MotorClient(host, port, replicaSet="my-rs")

New features

New classes ~motor.motor_tornado.MotorGridFSBucket and ~motor.motor_asyncio.AsyncIOMotorGridFSBucket conform to the GridFS API Spec for MongoDB drivers. These classes supersede the old MotorGridFS and AsyncIOMotorGridFS. See GridFS changes below, especially note the breaking change in ~motor.motor_web.GridFSHandler.

Serve GridFS files over HTTP using aiohttp and ~motor.aiohttp.AIOHTTPGridFS.

MotorClient changes

Removed:

  • MotorClient.open; clients have opened themselves automatically on demand since version 0.2.
  • MotorClient.seeds, use pymongo.uri_parser.parse_uri on your MongoDB URI.
  • MotorClient.alive

Added:

  • MotorClient.event_listeners
  • MotorClient.max_idle_time_ms
  • MotorClient.min_pool_size

Unix domain socket paths must be quoted with urllib.parse.quote_plus (or urllib.quote_plus in Python 2) before they are included in a URI:

path = '/tmp/mongodb-27017.sock'
MotorClient('mongodb://%s' % urllib.parse.quote_plus(path))

~motor.motor_tornado.MotorCollection changes

Added:

  • MotorCollection.create_indexes
  • MotorCollection.list_indexes

New bypass_document_validation parameter for ~.MotorCollection.initialize_ordered_bulk_op and ~.MotorCollection.initialize_unordered_bulk_op.

Changes to ~motor.motor_tornado.MotorCollection.find and ~motor.motor_tornado.MotorCollection.find_one

The following find/find_one options have been renamed:

These renames only affect your code if you passed these as keyword arguments, like find(fields=['fieldname']). If you passed only positional parameters these changes are not significant for your application.

  • spec -> filter
  • fields -> projection
  • partial -> allow_partial_results

The following find/find_one options have been added:

  • cursor_type (see ~pymongo.cursor.CursorType for values)
  • oplog_replay
  • modifiers

The following find/find_one options have been removed:

  • network_timeout (use ~motor.motor_tornado.MotorCursor.max_time_ms instead)
  • read_preference (use ~motor.motor_tornado.MotorCollection.with_options instead)
  • tag_sets (use one of the read preference classes from ~pymongo.read_preferences and ~motor.motor_tornado.MotorCollection.with_options instead)
  • secondary_acceptable_latency_ms (use the localThresholdMS URI option instead)
  • max_scan (use the new modifiers option instead)
  • snapshot (use the new modifiers option instead)
  • tailable (use the new cursor_type option instead)
  • await_data (use the new cursor_type option instead)
  • exhaust (use the new cursor_type option instead)
  • as_class (use ~motor.motor_tornado.MotorCollection.with_options with ~bson.codec_options.CodecOptions instead)
  • compile_re (BSON regular expressions are always decoded to ~bson.regex.Regex)

The following find/find_one options are deprecated:

  • manipulate

The following renames need special handling.

  • timeout -> no_cursor_timeout -By default, MongoDB closes a cursor after 10 minutes of inactivity. In previous Motor versions, you disabled the timeout by passing timeout=False to .MotorCollection.find or .MotorGridFS.find. The timeout parameter has been renamed to no_cursor_timeout, it defaults to False, and you must now pass no_cursor_timeout=True to disable timeouts.

~motor.motor_tornado.MotorCursor

Added:

  • .MotorCursor.address
  • .MotorCursor.max_await_time_ms

Removed:

  • .MotorCursor.conn_id, use ~.MotorCursor.address

GridFS

The old GridFS classes MotorGridFS and AsyncIOMotorGridFS are deprecated in favor of ~motor.motor_tornado.MotorGridFSBucket and ~motor.motor_asyncio.AsyncIOMotorGridFSBucket, which comply with MongoDB's cross-language driver spec for GridFS.

The old classes are still supported, but will be removed in Motor 2.0.

BREAKING CHANGE: The overridable method ~motor.web.GridFSHandler.get_gridfs_file of ~motor.web.GridFSHandler now takes a ~motor.motor_tornado.MotorGridFSBucket, not a ~motor.motor_tornado.MotorGridFS. It also takes an additional request parameter.

~motor.motor_tornado.MotorGridOutCursor

Added:

  • .MotorGridOutCursor.address
  • .MotorGridOutCursor.max_await_time_ms

Removed:

  • .MotorGridOutCursor.conn_id, use ~.MotorGridOutCursor.address

~motor.motor_tornado.MotorGridIn

New method .MotorGridIn.abort.

In a Python 3.5 native coroutine, the "async with" statement calls ~MotorGridIn.close automatically:

async def upload():
    my_db = MotorClient().test
    fs = MotorGridFSBucket(my_db)
    async with await fs.open_upload_stream(
                "test_file", metadata={"contentType": "text/plain"}) as gridin:
        await gridin.write(b'First part\n')
        await gridin.write(b'Second part')

    # gridin is now closed automatically.

~motor.motor_tornado.MotorGridOut

~motor.motor_tornado.MotorGridOut is now an async iterable, so reading a chunk at a time is much simpler with a Python 3 native coroutine:

async def read_file(file_id):
    fs = motor.motor_tornado.MotorGridFS(db)
    gridout = await fs.get(file_id)

    async for chunk in gridout:
        sys.stdout.write(chunk)

    sys.stdout.flush()

Documentation

The /api-asyncio/index is now fully documented, side by side with the /api-tornado/index.

New developer-guide added.

Motor 0.7

For asynchronous I/O Motor now uses a thread pool, which is faster and simpler than the prior implementation with greenlets. It no longer requires the greenlet package, and now requires the futures backport package on Python 2.

This version updates the PyMongo dependency from 2.8.0 to 2.9.x, and wraps PyMongo 2.9's new APIs.

Most of Motor 1.0's API is now implemented, and APIs that will be removed in Motor 1.0 are now deprecated and raise warnings.

MotorClient changes

The ~MotorClient.get_database method is added for getting a MotorDatabase instance with its options configured differently than the MotorClient's.

New read-only attributes:

  • ~MotorClient.codec_options
  • ~MotorClient.local_threshold_ms
  • ~MotorClient.max_write_batch_size

MotorReplicaSetClient changes

The ~MotorReplicaSetClient.get_database method is added for getting a MotorDatabase instance with its options configured differently than the MotorReplicaSetClient's.

New read-only attributes:

  • ~MotorReplicaSetClient.codec_options
  • ~MotorReplicaSetClient.local_threshold_ms

MotorDatabase changes

The ~MotorDatabase.get_collection method is added for getting a MotorCollection instance with its options configured differently than the MotorDatabase's.

The connection property is deprecated in favor of a new read-only attribute ~MotorDatabase.client.

New read-only attribute:

  • ~MotorDatabase.codec_options

MotorCollection changes

The ~MotorCollection.with_options method is added for getting a MotorCollection instance with its options configured differently than this MotorCollection's.

New read-only attribute:

  • ~MotorCollection.codec_options

The following methods wrap PyMongo's implementation of the standard CRUD API Spec for MongoDB Drivers:

  • ~MotorCollection.bulk_write
  • ~MotorCollection.insert_one
  • ~MotorCollection.insert_many
  • ~MotorCollection.update_one
  • ~MotorCollection.update_many
  • ~MotorCollection.replace_one
  • ~MotorCollection.delete_one
  • ~MotorCollection.delete_many
  • ~MotorCollection.find_one_and_delete
  • ~MotorCollection.find_one_and_replace
  • ~MotorCollection.find_one_and_update

These new methods do not apply SON Manipulators.

GridFS <api-tornado/gridfs> changes

New MotorGridOutCursor methods:

  • ~MotorGridOutCursor.add_option
  • ~MotorGridOutCursor.remove_option
  • ~MotorGridOutCursor.clone

Added MotorGridOut documentation:

  • ~MotorGridOut.aliases
  • ~MotorGridOut.chunk_size
  • ~MotorGridOut.close
  • ~MotorGridOut.content_type
  • ~MotorGridOut.filename
  • ~MotorGridOut.length
  • ~MotorGridOut.md5
  • ~MotorGridOut.metadata
  • ~MotorGridOut.name
  • ~MotorGridOut.upload_date

Bugfix

MOTOR-124: an import deadlock in Python 2 and Tornado 3 led to an ~pymongo.errors.AutoReconnect exception with some replica sets.

Motor 0.6.2

Fix "from motor import *" for Python 3.

Motor 0.6.1

Fix source distribution, which hadn't included the "frameworks" submodules.

Motor 0.6

This is a bugfix release. Fixing these bugs has introduced tiny API changes that may affect some programs.

motor_asyncio and motor_tornado submodules

These modules have been moved from:

  • motor_asyncio.py
  • motor_tornado.py

To:

  • motor_asyncio/__init__.py
  • motor_tornado/__init__.py

Motor had to make this change in order to omit the motor_asyncio submodule entirely and avoid a spurious SyntaxError being printed when installing in Python 2. The change should be invisible to application code.

Database and collection names with leading underscores

A database or collection whose name starts with an underscore can no longer be accessed as a property:

# Now raises AttributeError.
db = MotorClient()._mydatabase
collection = db._mycollection
subcollection = collection._subcollection

Such databases and collections can still be accessed dict-style:

# Continues to work the same as previous Motor versions.
db = MotorClient()['_mydatabase']
collection = db['_mycollection']

To ensure a "sub-collection" with a name that includes an underscore is accessible, Motor collections now allow dict-style access, the same as Motor clients and databases always have:

# New in Motor 0.6
subcollection = collection['_subcollection']

These changes solve problems with iPython code completion and the Python 3 ABC abstract base class.

Motor 0.5

asyncio

Motor can now integrate with asyncio, as an alternative to Tornado. My gratitude to Rémi Jolin, Andrew Svetlov, and Nikolay Novik for their huge contributions to Motor's asyncio integration.

Python 3.5

Motor is now compatible with Python 3.5, which required some effort. Motor not only supports users' coroutines, it uses coroutines to implement some of its own features, like ~MotorClient.open and ~MotorGridFS.put. There is no single way to return a value from a Python 3.5 native coroutine or a Python 2 generator-based coroutine, so Motor internal coroutines that return values were rewritten. (See commit message dc19418c for an explanation.)

async and await

Motor now supports Python 3.5 native coroutines, written with the async and await syntax:

async def f():
    await collection.insert({'_id': 1})

Cursors from ~MotorCollection.find, ~MotorCollection.aggregate, or ~MotorGridFS.find can be iterated elegantly and very efficiently in native coroutines with `async for`:

async def f():
    async for doc in collection.find():
        do_something_with(doc)

~MotorCollection.aggregate

MotorCollection.aggregate now returns a cursor by default, and the cursor is returned immediately without a yield. The old syntax is no longer supported:

# Motor 0.4 and older, no longer supported.
cursor = yield collection.aggregate(pipeline, cursor={})
while (yield cursor.fetch_next):
    doc = cursor.next_object()
    print(doc)

In Motor 0.5, simply do:

# Motor 0.5: no "cursor={}", no "yield".
cursor = collection.aggregate(pipeline)
while (yield cursor.fetch_next):
    doc = cursor.next_object()
    print(doc)

Or with Python 3.5 and later:

# Motor 0.5, Python 3.5.
async for doc in collection.aggregate(pipeline):
    print(doc)

MongoDB versions 2.4 and older do not support aggregation cursors. For compatibility with older MongoDBs, ~MotorCollection.aggregate now takes an argument cursor=False, and returns a Future that you can yield to get all the results in one document:

# Motor 0.5 with MongoDB 2.4 and older.
reply = yield collection.aggregate(cursor=False)
for doc in reply['results']:
    print(doc)

Deprecations

Motor 0.5 deprecates a large number of APIs that will be removed in version 1.0:

`MotorClient`:
  • ~MotorClient.host
  • ~MotorClient.port
  • ~MotorClient.document_class
  • ~MotorClient.tz_aware
  • ~MotorClient.secondary_acceptable_latency_ms
  • ~MotorClient.tag_sets
  • ~MotorClient.uuid_subtype
  • ~MotorClient.disconnect
  • ~MotorClient.alive
`MotorReplicaSetClient`:
  • ~MotorReplicaSetClient.document_class
  • ~MotorReplicaSetClient.tz_aware
  • ~MotorReplicaSetClient.secondary_acceptable_latency_ms
  • ~MotorReplicaSetClient.tag_sets
  • ~MotorReplicaSetClient.uuid_subtype
  • ~MotorReplicaSetClient.alive
`MotorDatabase`:
  • ~MotorDatabase.secondary_acceptable_latency_ms
  • ~MotorDatabase.tag_sets
  • ~MotorDatabase.uuid_subtype
`MotorCollection`:
  • ~MotorCollection.secondary_acceptable_latency_ms
  • ~MotorCollection.tag_sets
  • ~MotorCollection.uuid_subtype

Cursor slicing

Cursors can no longer be indexed like cursor[n] or sliced like cursor[start:end], see MOTOR-84. If you wrote code like this:

cursor = collection.find()[i]
yield cursor.fetch_next
doc = cursor.next_object()

Then instead, write:

cursor = collection.find().skip(i).limit(-1)
yield cursor.fetch_next
doc = cursor.next_object()

The negative limit ensures the server closes the cursor after one result, saving Motor the work of closing it. See cursor.limit.

SSL hostname validation error

When you use Motor with Tornado and SSL hostname validation fails, Motor used to raise a ~pymongo.errors.ConnectionFailure with a useful messsage like "hostname 'X' doesn't match 'Y'". The message is now empty and Tornado logs a warning instead.

Configuring uuid_subtype

You can now get and set ~MotorClient.uuid_subtype on MotorClient, MotorReplicaSetClient, and MotorDatabase instances, not just on MotorCollection.

Motor 0.4.1

Fix MOTOR-66, deadlock when initiating MotorReplicaSetClient connection from multiple operations at once.

Motor 0.4

Supports MongoDB 3.0. In particular, supports MongoDB 3.0's new SCRAM-SHA-1 authentication mechanism and updates the implementations of MotorClient.database_names and MotorDatabase.collection_names.

Updates PyMongo dependency from 2.7.1 to 2.8, therefore inheriting PyMongo 2.7.2's bug fixes and PyMongo 2.8's bug fixes and features.

Fixes a connection-pool timeout when waitQueueMultipleMS is set and two bugs in replica set monitoring.

The copy_database method has been removed. It was overly complex and no one used it, see MOTOR-56. You can still use the MotorDatabase.command method directly. The only scenario not supported is copying a database from one host to another, if the remote host requires authentication. For this, use PyMongo's copy_database method, or, since PyMongo's copy_database will be removed in a future release too, use the mongo shell.

Motor 0.3.3

Fix MOTOR-45, a stack-context leak in domain name resolution that could lead to an infinite loop and rapid memory leak.

Document Motor's requirements in detail.

Motor 0.3.2

Fix MOTOR-44, a socket leak in MotorClient.copy_database and MotorReplicaSetClient.copy_database.

Motor 0.3.1

Fix MOTOR-43, a TypeError when using ~motor.web.GridFSHandler with a timezone-aware ~motor.motor_tornado.MotorClient.

Fix GridFS examples that hadn't been updated for Motor 0.2's new syntax.

Fix a unittest that hadn't been running.

Motor 0.3

No new features.

  • Updates PyMongo dependency from 2.7 to 2.7.1, therefore inheriting PyMongo 2.7.1's bug fixes.
  • Motor continues to support Python 2.6, 2.7, 3.3, and 3.4, but now with single-source. 2to3 no longer runs during installation with Python 3.
  • nosetests is no longer required for regular Motor tests.
  • Fixes a mistake in the docstring for aggregate().

Motor 0.2.1

Fixes two bugs:

  • MOTOR-32: The documentation for MotorCursor.close claimed it immediately halted execution of MotorCursor.each, but it didn't.
  • MOTOR-33: An incompletely iterated cursor's __del__ method sometimes got stuck and cost 100% CPU forever, even though the application was still responsive.

Motor 0.2

This version includes API changes that break backward compatibility with applications written for Motor 0.1. For most applications, the migration chores will be minor. In exchange, Motor 0.2 offers a cleaner style, and it wraps the new and improved PyMongo 2.7 instead of 2.5.

Changes in Dependencies

Motor now requires PyMongo 2.7.0 exactly and Tornado 3 or later. It drops support for Python 2.5 since Tornado 3 has dropped it.

Motor continues to work with Python 2.6 through 3.4. It still requires Greenlet.

API Changes

open_sync

The open_sync method has been removed from MotorClient and MotorReplicaSetClient. Clients now connect to MongoDB automatically on first use. Simply delete the call to open_sync from your application.

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.motor_tornado.MotorClient(host, port)
try:
    loop.run_sync(client.open)
except pymongo.errors.ConnectionFailure:
    print "Can't connect"

Similarly, calling MotorGridOut.open is now optional. MotorGridIn and MotorGridFS no longer have an open method at all.

Futures

Motor 0.2 takes advantage of Tornado's tidy new coroutine syntax:

# Old style:
document = yield motor.Op(collection.find_one, {'_id': my_id})

# New style:
document = yield collection.find_one({'_id': my_id})

To make this possible, Motor asynchronous methods (except MotorCursor.each) now return a ~tornado.concurrent.Future.

Using Motor with callbacks is still possible: If a callback is passed, it will be executed with the (result, error) of the operation, same as in Motor 0.1:

def callback(document, error):
    if error:
        logging.error("Oh no!")
    else:
        print document

collection.find_one({'_id': my_id}, callback=callback)

If no callback is passed, a Future is returned that resolves to the method's result or error:

document = yield collection.find_one({'_id': my_id})

motor.Op works the same as before, but it's deprecated.

WaitOp and WaitAllOps have been removed. Code that used them can now yield a Future or a list of them. Consider this function written for Tornado 2 and Motor 0.1:

@gen.engine
def get_some_documents():
    cursor = collection.find().sort('_id').limit(2)
    cursor.to_list(callback=(yield gen.Callback('key')))
    do_something_while_we_wait()
    try:
        documents = yield motor.WaitOp('key')
        print documents
    except Exception, e:
        print e

The function now becomes:

@gen.coroutine
def f():
    cursor = collection.find().sort('_id').limit(2)
    future = cursor.to_list(2)
    do_something_while_we_wait()
    try:
        documents = yield future
        print documents
    except Exception, e:
        print e

Similarly, a function written like so in the old style:

@gen.engine
def get_two_documents_in_parallel(collection):
    collection.find_one(
        {'_id': 1}, callback=(yield gen.Callback('one')))

    collection.find_one(
        {'_id': 2}, callback=(yield gen.Callback('two')))

    try:
        doc_one, doc_two = yield motor.WaitAllOps(['one', 'two'])
        print doc_one, doc_two
    except Exception, e:
        print e

Now becomes:

@gen.coroutine
def get_two_documents_in_parallel(collection):
    future_0 = collection.find_one({'_id': 1})
    future_1 = collection.find_one({'_id': 2})

    try:
        doc_one, doc_two = yield [future_0, future_1]
        print doc_one, doc_two
    except Exception, e:
        print e
to_list

Any calls to MotorCursor.to_list that omitted the length argument must now include it:

result = yield collection.find().to_list(100)

None is acceptable, meaning "unlimited." Use with caution.

Connection Pooling

MotorPool has been rewritten. It supports the new options introduced in PyMongo 2.6, and drops all Motor-specific options.

MotorClient and MotorReplicaSetClient have an option max_pool_size. It used to mean "minimum idle sockets to keep open", but its meaning has changed to "maximum sockets open per host." Once this limit is reached, operations will pause waiting for a socket to become available. Therefore the default has been raised from 10 to 100. If you pass a value for max_pool_size make sure it's large enough for the expected load. (Sockets are only opened when needed, so there's no cost to having a max_pool_size larger than necessary. Err towards a larger value.) If you've been accepting the default, continue to do so.

max_pool_size is now synonymous with Motor's special max_concurrent option, so max_concurrent has been removed.

max_wait_time has been renamed waitQueueTimeoutMS for consistency with PyMongo. If you pass max_wait_time, rename it and multiply by 1000.

The MotorPoolTimeout exception is gone; catch PyMongo's ~pymongo.errors.ConnectionFailure instead.

DNS

Motor can take advantage of Tornado 3's asynchronous resolver interface. By default, Motor still uses blocking DNS, but you can enable non-blocking lookup with a threaded resolver:

Resolver.configure('tornado.netutil.ThreadedResolver')

Or install pycares and use the c-ares resolver:

Resolver.configure('tornado.platform.caresresolver.CaresResolver')
MotorCursor.tail

The MotorCursor.tail method has been removed. It was complex, diverged from PyMongo's feature set, and encouraged overuse of MongoDB capped collections as message queues when a purpose-built message queue is more appropriate. An example of tailing a capped collection is provided instead: examples/tailable-cursors.

MotorClient.is_locked

is_locked has been removed since calling it from Motor would be bizarre. If you called MotorClient.is_locked like:

locked = yield motor.Op(client.is_locked)

you should now do:

result = yield client.admin.current_op()
locked = bool(result.get('fsyncLock', None))

The result is True only if an administrator has called fsyncLock on the mongod. It is unlikely that you have any use for this.

GridFSHandler

~web.GridFSHandler.get_gridfs_file now returns a Future instead of accepting a callback.

New Features

The introduction of a Futures-based API <changelog-futures> is the most pervasive new feature. In addition Motor 0.2 includes new features from PyMongo 2.6 and 2.7:

  • MotorCollection.aggregate can return a cursor.
  • Support for all current MongoDB authentication mechanisms (see PyMongo's authentication examples).
  • A new MotorCollection.parallel_scan method.
  • An API for bulk writes <examples/bulk>.
  • Support for wire protocol changes in MongoDB 2.6.
  • The ability to specify a server-side timeout for operations with ~MotorCursor.max_time_ms.
  • A new MotorGridFS.find method for querying GridFS.

Bugfixes

MotorReplicaSetClient.open threw an error if called without a callback.

MotorCursor.to_list ignored SON manipulators. (Thanks to Eren Güven for the report and the fix.)

The full list is in Jira.

Motor 0.1.2

Fixes innocuous unittest failures when running against Tornado 3.1.1.

Motor 0.1.1

Fixes issue MOTOR-12 by pinning its PyMongo dependency to PyMongo version 2.5.0 exactly.

Motor relies on some of PyMongo's internal details, so changes to PyMongo can break Motor, and a change in PyMongo 2.5.1 did. Eventually PyMongo will expose stable hooks for Motor to use, but for now I changed Motor's dependency from PyMongo>=2.4.2 to PyMongo==2.5.0.