Finalize option locations and exports.

- Move ReturnDocument to pymongo.collection.
- Change ReturnDocument.Before to ReturnDocument.BEFORE
- Change ReturnDocument.After to ReturnDocument.AFTER
- Add pymongo.cursor.CursorType.
- Move pymongo.cursor.NON_TAILABLE and friends to attributes of CursorType.
- read_preferences.ReadPreference is once again an "enum".
- Fix docs for read_preferences.ReadPreference.
- Rename pymongo.options to pymongo.operations.
- Export CursorType, ReturnDocument, WriteConcern, and public classes
  from pymongo.opertions through pymongo/__init__.py
- Fix up a number of documentation issues in the process.
This commit is contained in:
Bernie Hackett 2015-03-04 17:37:28 -08:00
parent fcc06e52d5
commit d69f76d380
17 changed files with 214 additions and 172 deletions

View File

@ -11,10 +11,13 @@
.. autodata:: pymongo.GEOSPHERE
.. autodata:: pymongo.HASHED
.. autodata:: pymongo.TEXT
.. autodata:: pymongo.cursor.NON_TAILABLE
.. autodata:: pymongo.cursor.TAILABLE
.. autodata:: pymongo.cursor.TAILABLE_AWAIT
.. autodata:: pymongo.cursor.EXHAUST
.. autoclass:: pymongo.collection.ReturnDocument
.. autoattribute:: BEFORE
:annotation:
.. autoattribute:: AFTER
:annotation:
.. autoclass:: pymongo.collection.Collection(database, name, create=False, **kwargs)
@ -41,7 +44,7 @@
.. automethod:: delete_one
.. automethod:: delete_many
.. automethod:: aggregate
.. automethod:: find(filter=None, projection=None, skip=0, limit=0, no_cursor_timeout=False, cursor_type=NON_TAILABLE, sort=None, allow_partial_results=False, oplog_replay=False, modifiers=None, manipulate=True)
.. automethod:: find(filter=None, projection=None, skip=0, limit=0, no_cursor_timeout=False, cursor_type=CursorType.NON_TAILABLE, sort=None, allow_partial_results=False, oplog_replay=False, modifiers=None, manipulate=True)
.. automethod:: find_one(filter_or_id=None, *args, **kwargs)
.. automethod:: find_one_and_delete
.. automethod:: find_one_and_replace(filter, replacement, projection=None, sort=None, return_document=ReturnDocument.Before, **kwargs)

View File

@ -4,7 +4,18 @@
.. automodule:: pymongo.cursor
:synopsis: Tools for iterating over MongoDB query results
.. autoclass:: pymongo.cursor.Cursor(collection, filter=None, projection=None, skip=0, limit=0, no_cursor_timeout=False, cursor_type=NON_TAILABLE, sort=None, allow_partial_results=False, oplog_replay=False, modifiers=None, manipulate=True)
.. autoclass:: pymongo.cursor.CursorType
.. autoattribute:: NON_TAILABLE
:annotation:
.. autoattribute:: TAILABLE
:annotation:
.. autoattribute:: TAILABLE_AWAIT
:annotation:
.. autoattribute:: EXHAUST
:annotation:
.. autoclass:: pymongo.cursor.Cursor(collection, filter=None, projection=None, skip=0, limit=0, no_cursor_timeout=False, cursor_type=CursorType.NON_TAILABLE, sort=None, allow_partial_results=False, oplog_replay=False, modifiers=None, manipulate=True)
:members:
.. describe:: c[index]

View File

@ -40,7 +40,7 @@ Sub-modules:
message
mongo_client
mongo_replica_set_client
options
operations
pool
read_preferences
results

View File

@ -0,0 +1,6 @@
:mod:`operations` -- Operation class definitions
================================================
.. automodule:: pymongo.operations
:synopsis: Operation class definitions
:members:

View File

@ -1,6 +0,0 @@
:mod:`options` -- Option class definitions
==========================================
.. automodule:: pymongo.options
:synopsis: Option class definitions
:members:

View File

@ -15,5 +15,11 @@
.. autoclass:: pymongo.read_preferences.Nearest
:inherited-members:
.. autodata:: ReadPreference
.. autoclass:: ReadPreference
.. autoattribute:: PRIMARY
.. autoattribute:: PRIMARY_PREFERRED
.. autoattribute:: SECONDARY
.. autoattribute:: SECONDARY_PREFERRED
.. autoattribute:: NEAREST

View File

@ -80,11 +80,20 @@ def get_version_string():
version = get_version_string()
"""Current version of PyMongo."""
from pymongo.collection import ReturnDocument
from pymongo.common import (MIN_SUPPORTED_WIRE_VERSION,
MAX_SUPPORTED_WIRE_VERSION)
from pymongo.cursor import CursorType
from pymongo.mongo_client import MongoClient
from pymongo.mongo_replica_set_client import MongoReplicaSetClient
from pymongo.operations import (InsertOne,
DeleteOne,
DeleteMany,
UpdateOne,
UpdateMany,
ReplaceOne)
from pymongo.read_preferences import ReadPreference
from pymongo.write_concern import WriteConcern
def has_c():
"""Is the C extension installed?"""

View File

@ -35,7 +35,7 @@ from pymongo.cursor import Cursor
from pymongo.errors import ConfigurationError, InvalidName, OperationFailure
from pymongo.helpers import _check_write_command_response, _command
from pymongo.message import _INSERT, _UPDATE, _DELETE
from pymongo.options import ReturnDocument, _WriteOp
from pymongo.operations import _WriteOp
from pymongo.read_preferences import ReadPreference
from pymongo.results import (BulkWriteResult,
DeleteResult,
@ -44,7 +44,6 @@ from pymongo.results import (BulkWriteResult,
UpdateResult)
from pymongo.write_concern import WriteConcern
try:
from collections import OrderedDict
_ORDERED_TYPES = (SON, OrderedDict)
@ -54,6 +53,19 @@ except ImportError:
_NO_OBJ_ERROR = "No matching object found"
class ReturnDocument(object):
"""An enum used with
:meth:`~pymongo.collection.Collection.find_one_and_replace` and
:meth:`~pymongo.collection.Collection.find_one_and_update`.
"""
BEFORE = False
"""Return the original document before it was updated/replaced, or
``None`` if no document matches the query.
"""
AFTER = True
"""Return the updated/replaced or inserted document."""
def _gen_index_name(keys):
"""Generate an index name from the set of fields it is over.
"""
@ -287,8 +299,13 @@ class Collection(common.BaseObject):
def bulk_write(self, requests, ordered=True):
"""Send a batch of write operations to the server.
Write operations are passed as a list using the write operation classes
from the :mod:`~pymongo.options` module::
Requests are passed as a list of write operation instances (
:class:`~pymongo.operations.InsertOne`,
:class:`~pymongo.operations.UpdateOne`,
:class:`~pymongo.operations.UpdateMany`,
:class:`~pymongo.operations.ReplaceOne`,
:class:`~pymongo.operations.DeleteOne`, or
:class:`~pymongo.operations.DeleteMany`).
>>> for doc in db.test.find({}):
... print(doc)
@ -297,7 +314,7 @@ class Collection(common.BaseObject):
{u'x': 1, u'_id': ObjectId('54f62e60fba5226811f634f0')}
>>> # DeleteMany, UpdateOne, and UpdateMany are also available.
...
>>> from pymongo.options import InsertOne, DeleteOne, ReplaceOne
>>> from pymongo import InsertOne, DeleteOne, ReplaceOne
>>> requests = [InsertOne({'y': 1}), DeleteOne({'x': 1}),
... ReplaceOne({'w': 1}, {'z': 1}, upsert=True)]
>>> result = db.test.bulk_write(requests)
@ -797,27 +814,27 @@ class Collection(common.BaseObject):
time out on the server. Care should be taken to ensure that
cursors with no_cursor_timeout turned on are properly closed.
- `cursor_type` (optional): the type of cursor to return. The valid
options are:
options are defined by :class:`~pymongo.cursor.CursorType`:
- :data:`~pymongo.cursor.NON_TAILABLE` - the result of this find
call will return a standard cursor over the result set.
- :data:`~pymongo.cursor.TAILABLE` - the result of this find call
will be a tailable cursor - tailable cursors are only for use
with capped collections. They are not closed when the last data
is retrieved but are kept open and the cursor location marks the
final document position. If more data is received iteration of
the cursor will continue from the last document received. For
details, see the `tailable cursor documentation
- :attr:`~pymongo.cursor.CursorType.NON_TAILABLE` - the result of
this find call will return a standard cursor over the result set.
- :attr:`~pymongo.cursor.CursorType.TAILABLE` - the result of this
find call will be a tailable cursor - tailable cursors are only
for use with capped collections. They are not closed when the
last data is retrieved but are kept open and the cursor location
marks the final document position. If more data is received
iteration of the cursor will continue from the last document
received. For details, see the `tailable cursor documentation
<http://www.mongodb.org/display/DOCS/Tailable+Cursors>`_.
- :data:`~pymongo.cursor.TAILABLE_AWAIT` - the result of this find
call will be a tailable cursor with the await flag set. The
server will wait for a few seconds after returning the full
result set so that it can capture and return additional data
- :attr:`~pymongo.cursor.CursorType.TAILABLE_AWAIT` - the result
of this find call will be a tailable cursor with the await flag
set. The server will wait for a few seconds after returning the
full result set so that it can capture and return additional data
added during the query.
- :data:`~pymongo.cursor.EXHAUST` - the result of this find call
will be an exhaust cursor. MongoDB will stream batched results to
the client without waiting for the client to request each batch,
reducing latency. See notes on compatibility below.
- :attr:`~pymongo.cursor.CursorType.EXHAUST` - the result of this
find call will be an exhaust cursor. MongoDB will stream batched
results to the client without waiting for the client to request
each batch, reducing latency. See notes on compatibility below.
- `sort` (optional): a list of (key, direction) pairs
specifying the sort order for this query. See
@ -833,7 +850,7 @@ class Collection(common.BaseObject):
apply any outgoing SON manipulators before returning.
.. note:: There are a number of caveats to using
:data:`~pymongo.cursor.EXHAUST` as cursor_type:
:attr:`~pymongo.cursor.CursorType.EXHAUST` as cursor_type:
1. The `limit` option can not be used with an exhaust cursor.
@ -841,8 +858,8 @@ class Collection(common.BaseObject):
used with a sharded cluster.
3. A :class:`~pymongo.cursor.Cursor` instance created with the
cursor.EXHAUST cursor_type requires an exclusive
:class:`~socket.socket` connection to MongoDB. If the
:attr:`~pymongo.cursor.CursorType.EXHAUST` cursor_type requires an
exclusive :class:`~socket.socket` connection to MongoDB. If the
:class:`~pymongo.cursor.Cursor` is discarded without being
completely iterated the underlying :class:`~socket.socket`
connection will be closed and discarded without being returned to
@ -1654,12 +1671,12 @@ class Collection(common.BaseObject):
return res.get("results")
def __find_and_modify(self, filter, projection, sort, upsert=None,
return_document=ReturnDocument.Before, **kwargs):
return_document=ReturnDocument.BEFORE, **kwargs):
"""Internal findAndModify helper."""
common.validate_is_mapping("filter", filter)
if not isinstance(return_document, bool):
raise ValueError("return_document must be "
"ReturnDocument.Before or ReturnDocument.After")
"ReturnDocument.BEFORE or ReturnDocument.AFTER")
cmd = SON([("findAndModify", self.__name),
("query", filter),
("new", return_document)])
@ -1726,13 +1743,13 @@ class Collection(common.BaseObject):
def find_one_and_replace(self, filter, replacement,
projection=None, sort=None, upsert=False,
return_document=ReturnDocument.Before, **kwargs):
return_document=ReturnDocument.BEFORE, **kwargs):
"""Finds a single document and replaces it, returning either the
original or the replaced document.
The `find_one_and_replace` method differs from `find_one_and_update`
by replacing the document matched by *filter*, rather than modifying
the existing document.
The :meth:`find_one_and_replace` method differs from
:meth:`find_one_and_update` by replacing the document matched by
*filter*, rather than modifying the existing document.
>>> for doc in db.test.find({}):
... print(doc)
@ -1763,10 +1780,10 @@ class Collection(common.BaseObject):
- `upsert` (optional): When ``True``, inserts a new document if no
document matches the query. Defaults to ``False``.
- `return_document`: If
:attr:`~pymongo.options.ReturnDocument.Before` (the default),
:attr:`ReturnDocument.BEFORE` (the default),
returns the original document before it was replaced, or ``None``
if no document matches. If
:attr:`~pymongo.options.ReturnDocument.After`, returns the replaced
:attr:`ReturnDocument.AFTER`, returns the replaced
or inserted document.
- `**kwargs` (optional): additional command arguments can be passed
as keyword arguments (for example maxTimeMS can be used with
@ -1781,7 +1798,7 @@ class Collection(common.BaseObject):
def find_one_and_update(self, filter, update,
projection=None, sort=None, upsert=False,
return_document=ReturnDocument.Before, **kwargs):
return_document=ReturnDocument.BEFORE, **kwargs):
"""Finds a single document and updates it, returning either the
original or the updated document.
@ -1789,11 +1806,11 @@ class Collection(common.BaseObject):
... {'_id': 665}, {'$inc': {'count': 1}, '$set': {'done': True}})
{u'_id': 665, u'done': False, u'count': 25}}
By default `find_one_and_update` returns the original version of the
document before the update was applied. To return the updated version
of the document instead, use the *return_document* option.
By default :meth:`find_one_and_update` returns the original version of
the document before the update was applied. To return the updated
version of the document instead, use the *return_document* option.
>>> from pymongo.options import ReturnDocument
>>> from pymongo import ReturnDocument
>>> db.example.find_one_and_update(
... {'_id': 'userid'},
... {'$inc': {'seq': 1}},
@ -1849,10 +1866,10 @@ class Collection(common.BaseObject):
- `upsert` (optional): When ``True``, inserts a new document if no
document matches the query. Defaults to ``False``.
- `return_document`: If
:attr:`~pymongo.options.ReturnDocument.Before` (the default),
:attr:`ReturnDocument.BEFORE` (the default),
returns the original document before it was updated, or ``None``
if no document matches. If
:attr:`~pymongo.options.ReturnDocument.After`, returns the updated
:attr:`ReturnDocument.AFTER`, returns the updated
or inserted document.
- `**kwargs` (optional): additional command arguments can be passed
as keyword arguments (for example maxTimeMS can be used with

View File

@ -43,32 +43,33 @@ _QUERY_OPTIONS = {
"partial": 128}
NON_TAILABLE = 0
"""The standard cursor type."""
class CursorType(object):
NON_TAILABLE = 0
"""The standard cursor type."""
TAILABLE = _QUERY_OPTIONS["tailable_cursor"]
"""The tailable cursor type.
TAILABLE = _QUERY_OPTIONS["tailable_cursor"]
"""The tailable cursor type.
Tailable cursors are only for use with capped collections. They are not closed
when the last data is retrieved but are kept open and the cursor location marks
the final document position. If more data is received iteration of the cursor
will continue from the last document received.
"""
Tailable cursors are only for use with capped collections. They are not
closed when the last data is retrieved but are kept open and the cursor
location marks the final document position. If more data is received
iteration of the cursor will continue from the last document received.
"""
TAILABLE_AWAIT = TAILABLE | _QUERY_OPTIONS["await_data"]
"""A tailable cursor with the await option set.
TAILABLE_AWAIT = TAILABLE | _QUERY_OPTIONS["await_data"]
"""A tailable cursor with the await option set.
Creates a tailable cursor that will wait for a few seconds after returning the
full result set so that it can capture and return additional data added during
the query.
"""
Creates a tailable cursor that will wait for a few seconds after returning
the full result set so that it can capture and return additional data added
during the query.
"""
EXHAUST = _QUERY_OPTIONS["exhaust"]
"""An exhaust cursor.
EXHAUST = _QUERY_OPTIONS["exhaust"]
"""An exhaust cursor.
MongoDB will stream batched results to the client without waiting for the
client to request each batch, reducing latency.
"""
MongoDB will stream batched results to the client without waiting for the
client to request each batch, reducing latency.
"""
# This has to be an old style class due to
@ -98,7 +99,8 @@ class Cursor(object):
"""
def __init__(self, collection, filter=None, projection=None, skip=0,
limit=0, no_cursor_timeout=False, cursor_type=NON_TAILABLE,
limit=0, no_cursor_timeout=False,
cursor_type=CursorType.NON_TAILABLE,
sort=None, allow_partial_results=False, oplog_replay=False,
modifiers=None, manipulate=True):
"""Create a new cursor.
@ -120,8 +122,8 @@ class Cursor(object):
if not isinstance(limit, int):
raise TypeError("limit must be an instance of int")
validate_boolean("no_cursor_timeout", no_cursor_timeout)
if cursor_type not in (NON_TAILABLE, TAILABLE,
TAILABLE_AWAIT, EXHAUST):
if cursor_type not in (CursorType.NON_TAILABLE, CursorType.TAILABLE,
CursorType.TAILABLE_AWAIT, CursorType.EXHAUST):
raise ValueError("not a valid value for cursor_type")
validate_boolean("allow_partial_results", allow_partial_results)
validate_boolean("oplog_replay", oplog_replay)
@ -153,7 +155,7 @@ class Cursor(object):
# Exhaust cursor support
self.__exhaust = False
self.__exhaust_mgr = None
if cursor_type == EXHAUST:
if cursor_type == CursorType.EXHAUST:
if self.__collection.database.client.is_mongos:
raise InvalidOperation('Exhaust cursors are '
'not supported by mongos')

View File

@ -12,22 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Option class definitions."""
"""Operation class definitions."""
from pymongo.common import validate_boolean, validate_is_mapping
class ReturnDocument(object):
"""An enum used with
:meth:`~pymongo.collection.Collection.find_one_and_replace` and
:meth:`~pymongo.collection.Collection.find_one_and_update`.
"""
Before = False
"""Return the original document before it was updated/replaced, or
``None`` if no document matches the query.
"""
After = True
"""Return the updated/replaced or inserted document."""
class _WriteOp(object):
"""Private base class for all write operations."""

View File

@ -14,7 +14,7 @@
"""Utilities for choosing which member of a replica set to read from."""
from collections import Mapping, namedtuple
from collections import Mapping
from pymongo.errors import ConfigurationError
from pymongo.server_selectors import (member_with_tags_server_selector,
@ -278,66 +278,61 @@ _MODES = (
)
ReadPreference = namedtuple("ReadPreference", _MODES)(
Primary(), PrimaryPreferred(), Secondary(), SecondaryPreferred(), Nearest())
"""An enum that defines the read preference modes supported by PyMongo.
class ReadPreference(object):
"""An enum that defines the read preference modes supported by PyMongo.
See :doc:`/examples/high_availability` for code examples.
See :doc:`/examples/high_availability` for code examples.
A read preference is used in three cases:
A read preference is used in three cases:
:class:`~pymongo.mongo_client.MongoClient` connected to a single mongod:
:class:`~pymongo.mongo_client.MongoClient` connected to a single mongod:
- ``PRIMARY``: Queries are allowed if the server is standalone or a replica
set primary.
- All other modes allow queries to standalone servers, to a replica set
primary, or to replica set secondaries.
- ``PRIMARY``: Queries are allowed if the server is standalone or a replica
set primary.
- All other modes allow queries to standalone servers, to a replica set
primary, or to replica set secondaries.
:class:`~pymongo.mongo_client.MongoClient` initialized with the
``replicaSet`` option:
:class:`~pymongo.mongo_client.MongoClient` initialized with the
``replicaSet`` option:
- ``PRIMARY``: Read from the primary. This is the default, and provides the
strongest consistency. If no primary is available, raise
:class:`~pymongo.errors.AutoReconnect`.
- ``PRIMARY``: Read from the primary. This is the default, and provides the
strongest consistency. If no primary is available, raise
:class:`~pymongo.errors.AutoReconnect`.
- ``PRIMARY_PREFERRED``: Read from the primary if available, or if there is
none, read from a secondary matching your choice of ``tag_sets`` and
``local_threshold_ms``.
- ``PRIMARY_PREFERRED``: Read from the primary if available, or if there is
none, read from a secondary.
- ``SECONDARY``: Read from a secondary matching your choice of ``tag_sets`` and
``local_threshold_ms``. If no matching secondary is available,
raise :class:`~pymongo.errors.AutoReconnect`.
- ``SECONDARY``: Read from a secondary. If no secondary is available,
raise :class:`~pymongo.errors.AutoReconnect`.
- ``SECONDARY_PREFERRED``: Read from a secondary matching your choice of
``tag_sets`` and ``local_threshold_ms`` if available, otherwise
from primary (regardless of the primary's tags and local threshold).
- ``SECONDARY_PREFERRED``: Read from a secondary if available, otherwise
from the primary.
- ``NEAREST``: Read from any member matching your choice of ``tag_sets`` and
``local_threshold_ms``.
- ``NEAREST``: Read from any member.
:class:`~pymongo.mongo_client.MongoClient` connected to a mongos, with a
sharded cluster of replica sets:
:class:`~pymongo.mongo_client.MongoClient` connected to a mongos, with a
sharded cluster of replica sets:
- ``PRIMARY``: Read from the primary of the shard, or raise
:class:`~pymongo.errors.OperationFailure` if there is none.
This is the default.
- ``PRIMARY``: Read from the primary of the shard, or raise
:class:`~pymongo.errors.OperationFailure` if there is none.
This is the default.
- ``PRIMARY_PREFERRED``: Read from the primary of the shard, or if there is
none, read from a secondary matching your choice of ``tag_sets``.
- ``PRIMARY_PREFERRED``: Read from the primary of the shard, or if there is
none, read from a secondary of the shard.
- ``SECONDARY``: Read from a secondary matching your choice of ``tag_sets``,
or raise :class:`~pymongo.errors.OperationFailure` if there is none.
- ``SECONDARY``: Read from a secondary of the shard, or raise
:class:`~pymongo.errors.OperationFailure` if there is none.
- ``SECONDARY_PREFERRED``: Read from a secondary matching your choice of
``tag_sets``, otherwise from primary.
- ``SECONDARY_PREFERRED``: Read from a secondary of the shard if available,
otherwise from the shard primary.
- ``NEAREST``: Read from any member matching your choice of ``tag_sets``.
.. note:: ``local_threshold_ms`` is ignored when talking to a
replica set *through* a mongos. The equivalent is the
`localThreshold <http://docs.mongodb.org/manual/reference/mongos/#cmdoption--localThreshold>`_
command line option.
"""
- ``NEAREST``: Read from any shard member.
"""
PRIMARY = Primary()
PRIMARY_PREFERRED = PrimaryPreferred()
SECONDARY = Secondary()
SECONDARY_PREFERRED = SecondaryPreferred()
NEAREST = Nearest()
def read_pref_mode_from_name(name):

View File

@ -38,7 +38,8 @@ class _WriteResult(object):
class InsertOneResult(_WriteResult):
"""The return type for :meth:`Collection.insert_one`."""
"""The return type for :meth:`~pymongo.collection.Collection.insert_one`.
"""
__slots__ = ("__inserted_id", "__acknowledged")
@ -75,8 +76,10 @@ class InsertManyResult(_WriteResult):
class UpdateResult(_WriteResult):
"""The return type for :meth:`~pymongo.collection.Collection.update_one`
and :meth:`~pymongo.collection.Collection.update_many`"""
"""The return type for :meth:`~pymongo.collection.Collection.update_one`,
:meth:`~pymongo.collection.Collection.update_many`, and
:meth:`~pymongo.collection.Collection.replace_one`.
"""
__slots__ = ("__raw_result", "__acknowledged")

View File

@ -22,7 +22,7 @@ from bson import InvalidDocument, SON
from bson.objectid import ObjectId
from bson.py3compat import string_type
from pymongo import MongoClient
from pymongo.options import *
from pymongo.operations import *
from pymongo.common import partition_node
from pymongo.errors import (BulkWriteError,
ConfigurationError,

View File

@ -32,7 +32,7 @@ from bson.py3compat import thread, u
from bson.son import SON
from bson.tz_util import utc
from pymongo import auth, message
from pymongo.cursor import EXHAUST
from pymongo.cursor import CursorType
from pymongo.database import Database
from pymongo.errors import (AutoReconnect,
ConfigurationError,
@ -756,7 +756,7 @@ class TestClient(IntegrationTest):
# Cause a network error.
sock_info = one(pool.sockets)
sock_info.sock.close()
cursor = collection.find(cursor_type=EXHAUST)
cursor = collection.find(cursor_type=CursorType.EXHAUST)
with self.assertRaises(ConnectionFailure):
next(cursor)
@ -848,7 +848,8 @@ class TestExhaustCursor(IntegrationTest):
# This will cause OperationFailure in all mongo versions since
# the value for $orderby must be a document.
cursor = collection.find(
SON([('$query', {}), ('$orderby', True)]), cursor_type=EXHAUST)
SON([('$query', {}), ('$orderby', True)]),
cursor_type=CursorType.EXHAUST)
self.assertRaises(OperationFailure, cursor.next)
self.assertFalse(sock_info.closed)
@ -871,7 +872,7 @@ class TestExhaustCursor(IntegrationTest):
pool._check_interval_seconds = None # Never check.
sock_info = one(pool.sockets)
cursor = collection.find(cursor_type=EXHAUST)
cursor = collection.find(cursor_type=CursorType.EXHAUST)
# Initial query succeeds.
cursor.next()
@ -907,7 +908,7 @@ class TestExhaustCursor(IntegrationTest):
sock_info = one(pool.sockets)
sock_info.sock.close()
cursor = collection.find(cursor_type=EXHAUST)
cursor = collection.find(cursor_type=CursorType.EXHAUST)
self.assertRaises(ConnectionFailure, cursor.next)
self.assertTrue(sock_info.closed)
@ -925,7 +926,7 @@ class TestExhaustCursor(IntegrationTest):
pool = get_pool(client)
pool._check_interval_seconds = None # Never check.
cursor = collection.find(cursor_type=EXHAUST)
cursor = collection.find(cursor_type=CursorType.EXHAUST)
# Initial query succeeds.
cursor.next()

View File

@ -32,15 +32,14 @@ from bson.son import SON
from pymongo import (ASCENDING, DESCENDING, GEO2D,
GEOHAYSTACK, GEOSPHERE, HASHED, TEXT)
from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.collection import Collection, ReturnDocument
from pymongo.command_cursor import CommandCursor
from pymongo.cursor import EXHAUST
from pymongo.cursor import CursorType
from pymongo.errors import (DuplicateKeyError,
InvalidDocument,
InvalidName,
InvalidOperation,
OperationFailure)
from pymongo.options import ReturnDocument
from pymongo.read_preferences import ReadPreference
from pymongo.results import (InsertOneResult,
InsertManyResult,
@ -1374,13 +1373,16 @@ class TestCollection(IntegrationTest):
def test_exhaust(self):
if is_mongos(self.db.client):
self.assertRaises(InvalidOperation,
self.db.test.find, cursor_type=EXHAUST)
self.db.test.find,
cursor_type=CursorType.EXHAUST)
return
# Limit is incompatible with exhaust.
self.assertRaises(InvalidOperation,
self.db.test.find, cursor_type=EXHAUST, limit=5)
cur = self.db.test.find(cursor_type=EXHAUST)
self.db.test.find,
cursor_type=CursorType.EXHAUST,
limit=5)
cur = self.db.test.find(cursor_type=CursorType.EXHAUST)
self.assertRaises(InvalidOperation, cur.limit, 5)
cur = self.db.test.find(limit=5)
self.assertRaises(InvalidOperation, cur.add_option, 64)
@ -1396,7 +1398,7 @@ class TestCollection(IntegrationTest):
socks = get_pool(client).sockets
# Make sure the socket is returned after exhaustion.
cur = client[self.db.name].test.find(cursor_type=EXHAUST)
cur = client[self.db.name].test.find(cursor_type=CursorType.EXHAUST)
next(cur)
self.assertEqual(0, len(socks))
for _ in cur:
@ -1404,14 +1406,14 @@ class TestCollection(IntegrationTest):
self.assertEqual(1, len(socks))
# Same as previous but don't call next()
for _ in client[self.db.name].test.find(cursor_type=EXHAUST):
for _ in client[self.db.name].test.find(cursor_type=CursorType.EXHAUST):
pass
self.assertEqual(1, len(socks))
# If the Cursor instance is discarded before being
# completely iterated we have to close and
# discard the socket.
cur = client[self.db.name].test.find(cursor_type=EXHAUST)
cur = client[self.db.name].test.find(cursor_type=CursorType.EXHAUST)
next(cur)
self.assertEqual(0, len(socks))
if sys.platform.startswith('java') or 'PyPy' in sys.version:
@ -1606,7 +1608,7 @@ class TestCollection(IntegrationTest):
self.assertEqual({'_id': 1, 'i': 3},
c.find_one_and_update(
{'_id': 1}, {'$inc': {'i': 1}},
return_document=ReturnDocument.After))
return_document=ReturnDocument.AFTER))
self.assertEqual({'_id': 1, 'i': 3},
c.find_one_and_delete({'_id': 1}))
@ -1617,23 +1619,23 @@ class TestCollection(IntegrationTest):
self.assertEqual({'_id': 1, 'i': 1},
c.find_one_and_update(
{'_id': 1}, {'$inc': {'i': 1}},
return_document=ReturnDocument.After,
return_document=ReturnDocument.AFTER,
upsert=True))
self.assertEqual({'_id': 1, 'i': 2},
c.find_one_and_update(
{'_id': 1}, {'$inc': {'i': 1}},
return_document=ReturnDocument.After))
return_document=ReturnDocument.AFTER))
self.assertEqual({'_id': 1, 'i': 3},
c.find_one_and_replace(
{'_id': 1}, {'i': 3, 'j': 1},
projection=['i'],
return_document=ReturnDocument.After))
return_document=ReturnDocument.AFTER))
self.assertEqual({'i': 4},
c.find_one_and_update(
{'_id': 1}, {'$inc': {'i': 1}},
projection={'i': 1, '_id': 0},
return_document=ReturnDocument.After))
return_document=ReturnDocument.AFTER))
c.drop()
for j in range(5):

View File

@ -30,7 +30,7 @@ from pymongo import (MongoClient,
ALL,
OFF)
from pymongo.command_cursor import CommandCursor
from pymongo.cursor import TAILABLE, TAILABLE_AWAIT, EXHAUST
from pymongo.cursor import CursorType
from pymongo.cursor_manager import CursorManager
from pymongo.errors import (InvalidOperation,
OperationFailure,
@ -68,17 +68,18 @@ class TestCursorNoConnect(unittest.TestCase):
cursor = self.db.test.find()
self.assertEqual(0, cursor._Cursor__query_flags)
cursor.add_option(2)
cursor2 = self.db.test.find(cursor_type=TAILABLE)
cursor2 = self.db.test.find(cursor_type=CursorType.TAILABLE)
self.assertEqual(2, cursor2._Cursor__query_flags)
self.assertEqual(cursor._Cursor__query_flags,
cursor2._Cursor__query_flags)
cursor.add_option(32)
cursor2 = self.db.test.find(cursor_type=TAILABLE_AWAIT)
cursor2 = self.db.test.find(cursor_type=CursorType.TAILABLE_AWAIT)
self.assertEqual(34, cursor2._Cursor__query_flags)
self.assertEqual(cursor._Cursor__query_flags,
cursor2._Cursor__query_flags)
cursor.add_option(128)
cursor2 = self.db.test.find(cursor_type=TAILABLE_AWAIT).add_option(128)
cursor2 = self.db.test.find(
cursor_type=CursorType.TAILABLE_AWAIT).add_option(128)
self.assertEqual(162, cursor2._Cursor__query_flags)
self.assertEqual(cursor._Cursor__query_flags,
cursor2._Cursor__query_flags)
@ -88,12 +89,12 @@ class TestCursorNoConnect(unittest.TestCase):
self.assertEqual(162, cursor._Cursor__query_flags)
cursor.remove_option(128)
cursor2 = self.db.test.find(cursor_type=TAILABLE_AWAIT)
cursor2 = self.db.test.find(cursor_type=CursorType.TAILABLE_AWAIT)
self.assertEqual(34, cursor2._Cursor__query_flags)
self.assertEqual(cursor._Cursor__query_flags,
cursor2._Cursor__query_flags)
cursor.remove_option(32)
cursor2 = self.db.test.find(cursor_type=TAILABLE)
cursor2 = self.db.test.find(cursor_type=CursorType.TAILABLE)
self.assertEqual(2, cursor2._Cursor__query_flags)
self.assertEqual(cursor._Cursor__query_flags,
cursor2._Cursor__query_flags)
@ -112,7 +113,7 @@ class TestCursorNoConnect(unittest.TestCase):
self.assertEqual(0, cursor._Cursor__query_flags)
# Tailable / Await data
cursor = self.db.test.find(cursor_type=TAILABLE_AWAIT)
cursor = self.db.test.find(cursor_type=CursorType.TAILABLE_AWAIT)
self.assertEqual(34, cursor._Cursor__query_flags)
cursor2 = self.db.test.find().add_option(34)
self.assertEqual(cursor._Cursor__query_flags,
@ -121,7 +122,7 @@ class TestCursorNoConnect(unittest.TestCase):
self.assertEqual(2, cursor._Cursor__query_flags)
# Exhaust - which mongos doesn't support
cursor = self.db.test.find(cursor_type=EXHAUST)
cursor = self.db.test.find(cursor_type=CursorType.EXHAUST)
self.assertEqual(64, cursor._Cursor__query_flags)
cursor2 = self.db.test.find().add_option(64)
self.assertEqual(cursor._Cursor__query_flags,
@ -723,7 +724,7 @@ class TestCursor(IntegrationTest):
cursor = self.db.test.find({"x": re.compile("^hello.*")},
skip=1,
no_cursor_timeout=True,
cursor_type=TAILABLE_AWAIT,
cursor_type=CursorType.TAILABLE_AWAIT,
allow_partial_results=True,
manipulate=False,
projection={'_id': False}).limit(2)
@ -916,7 +917,7 @@ class TestCursor(IntegrationTest):
db.drop_collection("test")
db.create_collection("test", capped=True, size=1000, max=3)
self.addCleanup(db.drop_collection, "test")
cursor = db.test.find(cursor_type=TAILABLE)
cursor = db.test.find(cursor_type=CursorType.TAILABLE)
db.test.insert_one({"x": 1})
count = 0

View File

@ -91,7 +91,11 @@ class TestReadPreferencesBase(TestReplicaSetClientBase):
class TestReadPreferences(TestReadPreferencesBase):
def test_mode_validation(self):
for mode in ReadPreference:
for mode in (ReadPreference.PRIMARY,
ReadPreference.PRIMARY_PREFERRED,
ReadPreference.SECONDARY,
ReadPreference.SECONDARY_PREFERRED,
ReadPreference.NEAREST):
self.assertEqual(
mode,
rs_client(read_preference=mode).read_preference)