MOTOR-420 Remove legacy APIs/patterns from documentation (#85)

This commit is contained in:
Prashant Mital 2020-08-13 16:03:48 -07:00 committed by GitHub
parent 70185d1361
commit 84f8a051d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 71 additions and 103 deletions

View File

@ -5,7 +5,7 @@
.. autoclass:: AsyncIOMotorCursor
:members:
:inherited-members:
:class:`~motor.motor_asyncio.AsyncIOMotorCommandCursor`
=======================================================
@ -14,3 +14,4 @@
.. autoclass:: AsyncIOMotorCommandCursor
:members:
:inherited-members:

View File

@ -7,7 +7,6 @@
:members:
:inherited-members:
:class:`~motor.motor_tornado.MotorCommandCursor`
================================================

View File

@ -37,14 +37,13 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Delete a file's metadata and data chunks from a GridFS bucket::
@gen.coroutine
def delete():
async def delete():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# Get _id of file to delete
file_id = yield fs.upload_from_stream("test_file",
file_id = await fs.upload_from_stream("test_file",
b"data I want to store!")
yield fs.delete(file_id)
await fs.delete(file_id)
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
@ -58,16 +57,15 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Downloads the contents of the stored file specified by file_id and
writes the contents to `destination`::
@gen.coroutine
def download():
async def download():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# Get _id of file to read
file_id = yield fs.upload_from_stream("test_file",
file_id = await fs.upload_from_stream("test_file",
b"data I want to store!")
# Get file to write to
file = open('myfile','wb+')
yield fs.download_to_stream(file_id, file)
await fs.download_to_stream(file_id, file)
file.seek(0)
contents = file.read()
@ -86,13 +84,12 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
For example::
@gen.coroutine
def download_by_name():
async def download_by_name():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# Get file to write to
file = open('myfile','wb')
yield fs.download_to_stream_by_name("test_file", file)
await fs.download_to_stream_by_name("test_file", file)
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
@ -165,15 +162,14 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Opens a stream to read the contents of the stored file specified by file_id::
@gen.coroutine
def download_stream():
async def download_stream():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# get _id of file to read.
file_id = yield fs.upload_from_stream("test_file",
file_id = await fs.upload_from_stream("test_file",
b"data I want to store!")
grid_out = yield fs.open_download_stream(file_id)
contents = yield grid_out.read()
grid_out = await fs.open_download_stream(file_id)
contents = await grid_out.read()
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
@ -186,15 +182,14 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Opens a stream to read the contents of `filename` and optional `revision`::
@gen.coroutine
def download_by_name():
async def download_by_name():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# get _id of file to read.
file_id = yield fs.upload_from_stream("test_file",
file_id = await fs.upload_from_stream("test_file",
b"data I want to store!")
grid_out = yield fs.open_download_stream_by_name(file_id)
contents = yield grid_out.read()
grid_out = await fs.open_download_stream_by_name(file_id)
contents = await grid_out.read()
Raises :exc:`~gridfs.errors.NoFile` if no such version of
that file exists.
@ -225,16 +220,15 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Specify the filename, and add any additional information in the metadata
field of the file document or modify the chunk size::
@gen.coroutine
def upload():
async def upload():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
grid_in, file_id = fs.open_upload_stream(
"test_file", chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
yield grid_in.write(b"data I want to store!")
yield grid_in.close() # uploaded on close
await grid_in.write(b"data I want to store!")
await grid_in.close() # uploaded on close
Returns an instance of :class:`MotorGridIn`.
@ -242,8 +236,8 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
that file exists.
Raises :exc:`~ValueError` if `filename` is not a string.
In a Python 3.5 native coroutine, the "async with" statement calls
:meth:`~MotorGridIn.close` automatically::
Using the "async with" statement calls :meth:`~MotorGridIn.close`
automatically::
async def upload():
my_db = MotorClient().test
@ -269,8 +263,7 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
Specify the filed_id and filename, and add any additional information in
the metadata field of the file document, or modify the chunk size::
@gen.coroutine
def upload():
async def upload():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
grid_in, file_id = fs.open_upload_stream_with_id(
@ -279,8 +272,8 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
chunk_size_bytes=4,
metadata={"contentType": "text/plain"})
yield grid_in.write(b"data I want to store!")
yield grid_in.close() # uploaded on close
await grid_in.write(b"data I want to store!")
await grid_in.close() # uploaded on close
Returns an instance of :class:`MotorGridIn`.
@ -305,15 +298,14 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
For example::
@gen.coroutine
def rename():
async def rename():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
# get _id of file to read.
file_id = yield fs.upload_from_stream("test_file",
file_id = await fs.upload_from_stream("test_file",
b"data I want to store!")
yield fs.rename(file_id, "new_test_name")
await fs.rename(file_id, "new_test_name")
Raises :exc:`~gridfs.errors.NoFile` if no file with file_id exists.
@ -331,11 +323,10 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
it to the file `filename`. Source can be a string or file-like object.
For example::
@gen.coroutine
def upload_from_stream():
async def upload_from_stream():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
file_id = yield fs.upload_from_stream(
file_id = await fs.upload_from_stream(
"test_file",
b"data I want to store!",
chunk_size_bytes=4,
@ -365,11 +356,10 @@ Store blobs of data in `GridFS <http://dochub.mongodb.org/core/gridfs>`_.
it to the file `filename`. Source can be a string or file-like object.
For example::
@gen.coroutine
def upload_from_stream_with_id():
async def upload_from_stream_with_id():
my_db = MotorClient().test
fs = MotorGridFSBucket(my_db)
file_id = yield fs.upload_from_stream_with_id(
file_id = await fs.upload_from_stream_with_id(
ObjectId(),
"test_file",
b"data I want to store!",

View File

@ -34,18 +34,18 @@
To create a single key ascending index on the key ``'mike'`` we just
use a string argument::
yield my_collection.create_index("mike")
await my_collection.create_index("mike")
For a compound index on ``'mike'`` descending and ``'eliot'``
ascending we need to use a list of tuples::
yield my_collection.create_index([("mike", pymongo.DESCENDING),
await my_collection.create_index([("mike", pymongo.DESCENDING),
("eliot", pymongo.ASCENDING)])
All optional index creation parameters should be passed as
keyword arguments to this method. For example::
yield my_collection.create_index([("mike", pymongo.DESCENDING)],
await my_collection.create_index([("mike", pymongo.DESCENDING)],
background=True)
Valid options include, but are not limited to:
@ -122,7 +122,7 @@
`map reduce command`_ may be passed as keyword arguments to this
helper method, e.g.::
yield db.test.inline_map_reduce(map, reduce, limit=2)
await db.test.inline_map_reduce(map, reduce, limit=2)
Returns a Future.

View File

@ -64,14 +64,13 @@ GridFS
Updating metadata on a :class:`MotorGridIn` is asynchronous, so
the API is different::
@gen.coroutine
def f():
async def f():
fs = motor.motor_tornado.MotorGridFSBucket(db)
grid_in, file_id = fs.open_upload_stream('test_file')
yield grid_in.close()
await grid_in.close()
# Sends update to server.
yield grid_in.set('my_field', 'my_value')
await grid_in.set('my_field', 'my_value')
.. seealso:: :doc:`../api-tornado/gridfs`.
@ -83,7 +82,7 @@ In PyMongo ``is_locked`` is a property of
server has been fsyncLocked requires I/O, Motor has no such convenience method.
The equivalent in Motor is::
result = yield client.admin.current_op()
result = await client.admin.current_op()
locked = bool(result.get('fsyncLock', None))
system_js
@ -119,7 +118,7 @@ In Motor, however, no exception is raised. The query simply has no results:
# Iterates zero or one times.
async for doc in cursor:
pass
print(doc)
The difference arises because the PyMongo :class:`~pymongo.cursor.Cursor`'s
slicing operator blocks until it has queried the MongoDB server, and determines
@ -151,9 +150,8 @@ only the typical style is allowed:
.. code-block:: python
@gen.coroutine
def f():
yield db.create_collection(
async def f():
await db.create_collection(
'collection1',
capped=True,
size=1000)

View File

@ -30,10 +30,9 @@ bulk insert operations.
.. doctest::
>>> @gen.coroutine
... def f():
... yield db.test.insert_many(({'i': i} for i in range(10000)))
... count = yield db.test.count_documents({})
>>> async def f():
... await db.test.insert_many(({'i': i} for i in range(10000)))
... count = await db.test.count_documents({})
... print("Final count: %d" % count)
>>>
>>> IOLoop.current().run_sync(f)
@ -61,9 +60,8 @@ of operations performed.
>>> from pprint import pprint
>>> from pymongo import InsertOne, DeleteMany, ReplaceOne, UpdateOne
>>> @gen.coroutine
... def f():
... result = yield db.test.bulk_write([
>>> async def f():
... result = await db.test.bulk_write([
... DeleteMany({}), # Remove all documents from the previous example.
... InsertOne({'_id': 1}),
... InsertOne({'_id': 2}),
@ -95,14 +93,13 @@ the failure.
>>> from pymongo import InsertOne, DeleteOne, ReplaceOne
>>> from pymongo.errors import BulkWriteError
>>> @gen.coroutine
... def f():
>>> async def f():
... requests = [
... ReplaceOne({'j': 2}, {'i': 5}),
... InsertOne({'_id': 4}), # Violates the unique key constraint on _id.
... DeleteOne({'i': 5})]
... try:
... yield db.test.bulk_write(requests)
... await db.test.bulk_write(requests)
... except BulkWriteError as bwe:
... pprint(bwe.details)
...
@ -135,15 +132,14 @@ and fourth operations succeed.
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> @gen.coroutine
... def f():
>>> async def f():
... requests = [
... InsertOne({'_id': 1}),
... DeleteOne({'_id': 2}),
... InsertOne({'_id': 3}),
... ReplaceOne({'_id': 4}, {'i': 1})]
... try:
... yield db.test.bulk_write(requests, ordered=False)
... await db.test.bulk_write(requests, ordered=False)
... except BulkWriteError as bwe:
... pprint(bwe.details)
...
@ -178,12 +174,11 @@ after all operations are attempted, regardless of execution order.
.. Standalone MongoDB raises "can't use w>1" with this example, so skip it.
>>> from pymongo import WriteConcern
>>> @gen.coroutine
... def f():
>>> async def f():
... coll = db.get_collection(
... 'test', write_concern=WriteConcern(w=4, wtimeout=1))
... try:
... yield coll.bulk_write([InsertOne({'a': i}) for i in range(4)])
... await coll.bulk_write([InsertOne({'a': i}) for i in range(4)])
... except BulkWriteError as bwe:
... pprint(bwe.details)
...

View File

@ -129,7 +129,7 @@ def get_motor_attr(motor_class, name, *defargs):
attribute. While we're at it, store some info about each attribute
in the global motor_info dict.
"""
attr = safe_getattr(motor_class, name)
attr = safe_getattr(motor_class, name, *defargs)
# Store some info for process_motor_nodes()
full_name = '%s.%s.%s' % (

View File

@ -547,16 +547,9 @@ class AgnosticDatabase(AgnosticBaseProperties):
Returns a :class:`MotorCommandCursor` that can be iterated like a
cursor from :meth:`find`::
# Lists all operations currently running on the server.
pipeline = [{"$currentOp": {}}]
cursor = client.admin.aggregate(pipeline)
async for operation in cursor:
print(operation)
In Python 3.5 and newer, aggregation cursors can be iterated elegantly
in native coroutines with `async for`::
async def f():
# Lists all operations currently running on the server.
pipeline = [{"$currentOp": {}}]
async for operation in client.admin.aggregate(pipeline):
print(operation)
@ -832,15 +825,8 @@ class AgnosticCollection(AgnosticBaseProperties):
Returns a :class:`MotorCommandCursor` that can be iterated like a
cursor from :meth:`find`::
pipeline = [{'$project': {'name': {'$toUpper': '$name'}}}]
cursor = collection.aggregate(pipeline)
async for doc in cursor:
print(doc)
In Python 3.5 and newer, aggregation cursors can be iterated elegantly
in native coroutines with `async for`::
async def f():
pipeline = [{'$project': {'name': {'$toUpper': '$name'}}}]
async for doc in collection.aggregate(pipeline):
print(doc)
@ -1104,10 +1090,10 @@ class AgnosticBaseCursor(AgnosticBase):
.. note::
There is no need to manually close cursors; they are closed
by the server after being fully iterated using `async for`,
:meth:`to_list`, or :meth:`each`, or automatically closed
by the client when the :class:`MotorCursor` is cleaned up by
the garbage collector.
by the server after being fully iterated
with :meth:`to_list`, :meth:`each`, or `async for`, or
automatically closed by the client when the :class:`MotorCursor` is
cleaned up by the garbage collector.
"""
# 'cursor' is a PyMongo Cursor, CommandCursor, or a _LatentCursor.
super(AgnosticBaseCursor, self).__init__(delegate=cursor)
@ -1171,6 +1157,10 @@ class AgnosticBaseCursor(AgnosticBase):
>>> IOLoop.current().run_sync(f)
0, 1, 2, 3, 4, done
While it appears that fetch_next retrieves each document from
the server individually, the cursor actually fetches documents
efficiently in `large batches`_. Example usage:
.. doctest:: fetch_next
>>> async def f():
@ -1185,10 +1175,6 @@ class AgnosticBaseCursor(AgnosticBase):
>>> IOLoop.current().run_sync(f)
0, 1, 2, 3, 4, done
While it appears that fetch_next retrieves each document from
the server individually, the cursor actually fetches documents
efficiently in `large batches`_.
.. versionchanged:: 2.2
Deprecated.
@ -1271,8 +1257,7 @@ class AgnosticBaseCursor(AgnosticBase):
.. note:: Unlike other Motor methods, ``each`` requires a callback and
does not return a Future, so it cannot be used in a coroutine.
``async for``, :meth:`to_list`, :attr:`fetch_next` are much easier to
use.
``async for`` and :meth:`to_list` are much easier to use.
:Parameters:
- `callback`: function taking (document, error)
@ -1582,13 +1567,13 @@ class AgnosticLatentCommandCursor(AgnosticCommandCursor):
__motor_class_name__ = 'MotorLatentCommandCursor'
def __init__(self, collection, start, *args, **kwargs):
# We're being constructed without yield or await, like:
# We're being constructed without await, like:
#
# cursor = collection.aggregate(pipeline)
#
# ... so we can't send the "aggregate" command to the server and get
# a PyMongo CommandCursor back yet. Set self.delegate to a latent
# cursor until the first yield or await triggers _get_more(), which
# cursor until the first await triggers _get_more(), which
# will execute the callback "start", which gets a PyMongo CommandCursor.
super(self.__class__, self).__init__(_LatentCursor(), collection)
self.start = start

View File

@ -47,7 +47,7 @@ basepython =
pypy36: {env:PYTHON_BINARY:pypy3}
# Default Python 3 when we don't care about minor version.
py3: {env:PYTHON_BINARY:python3.6}
py3: {env:PYTHON_BINARY:python3.7}
deps =
tornado5: tornado>=5,<6