diff --git a/gridfs/grid_file.py b/gridfs/grid_file.py index ea1037d30..e5df5e42b 100644 --- a/gridfs/grid_file.py +++ b/gridfs/grid_file.py @@ -30,6 +30,7 @@ from pymongo import ASCENDING from pymongo.collection import Collection from pymongo.cursor import Cursor from pymongo.errors import DuplicateKeyError +from pymongo.read_preferences import ReadPreference try: _SEEK_SET = os.SEEK_SET @@ -258,7 +259,8 @@ class GridIn(object): db.error() md5 = db.command( - "filemd5", self._id, root=self._coll.name)["md5"] + "filemd5", self._id, root=self._coll.name, + read_preference=ReadPreference.PRIMARY)["md5"] self._file["md5"] = md5 self._file["length"] = self._position diff --git a/pymongo/collection.py b/pymongo/collection.py index 870d67f55..24d09205c 100644 --- a/pymongo/collection.py +++ b/pymongo/collection.py @@ -28,6 +28,7 @@ from pymongo.cursor import Cursor from pymongo.errors import InvalidName, OperationFailure from pymongo.helpers import _check_write_command_response from pymongo.message import _INSERT, _UPDATE, _DELETE +from pymongo.read_preferences import ReadPreference try: @@ -125,9 +126,12 @@ class Collection(common.BaseObject): if options: if "size" in options: options["size"] = float(options["size"]) - self.__database.command("create", self.__name, **options) + self.__database.command("create", self.__name, + read_preference=ReadPreference.PRIMARY, + **options) else: - self.__database.command("create", self.__name) + self.__database.command("create", self.__name, + read_preference=ReadPreference.PRIMARY) def __getattr__(self, name): """Get a sub-collection of this collection by name. @@ -1037,7 +1041,9 @@ class Collection(common.BaseObject): index.update(kwargs) try: - self.__database.command('createIndexes', self.name, indexes=[index]) + self.__database.command('createIndexes', self.name, + read_preference=ReadPreference.PRIMARY, + indexes=[index]) except OperationFailure, exc: if exc.code in (59, None): index["ns"] = self.__full_name @@ -1183,7 +1189,9 @@ class Collection(common.BaseObject): self.__database.connection._purge_index(self.__database.name, self.__name, name) - self.__database.command("dropIndexes", self.__name, index=name, + self.__database.command("dropIndexes", self.__name, + read_preference=ReadPreference.PRIMARY, + index=name, allowable_errors=["ns not found"]) def reindex(self): @@ -1195,7 +1203,8 @@ class Collection(common.BaseObject): .. versionadded:: 1.11+ """ - return self.__database.command("reIndex", self.__name) + return self.__database.command("reIndex", self.__name, + read_preference=ReadPreference.PRIMARY) def index_information(self): """Get information on this collection's indexes. @@ -1416,9 +1425,10 @@ class Collection(common.BaseObject): raise InvalidName("collection names must not contain '$'") new_name = "%s.%s" % (self.__database.name, new_name) - self.__database.connection.admin.command("renameCollection", - self.__full_name, - to=new_name, **kwargs) + client = self.__database.connection + client.admin.command("renameCollection", self.__full_name, + read_preference=ReadPreference.PRIMARY, + to=new_name, **kwargs) def distinct(self, key): """Get a list of distinct values for `key` among all documents @@ -1645,6 +1655,7 @@ class Collection(common.BaseObject): out = self.__database.command("findAndModify", self.__name, allowable_errors=[no_obj_error], + read_preference=ReadPreference.PRIMARY, uuid_subtype=self.uuid_subtype, **kwargs) diff --git a/pymongo/database.py b/pymongo/database.py index 646c0a97a..f565b7260 100644 --- a/pymongo/database.py +++ b/pymongo/database.py @@ -26,7 +26,9 @@ from pymongo.errors import (CollectionInvalid, ConfigurationError, InvalidName, OperationFailure) -from pymongo import read_preferences as rp +from pymongo.read_preferences import (modes, + secondary_ok_commands, + ReadPreference) def _check_name(name): @@ -282,7 +284,7 @@ class Database(common.BaseObject): command_name = command.keys()[0].lower() must_use_master = kwargs.pop('_use_master', False) - if command_name not in rp.secondary_ok_commands: + if command_name not in secondary_ok_commands: must_use_master = True # Special-case: mapreduce can go to secondaries only if inline @@ -323,13 +325,13 @@ class Database(common.BaseObject): command.update(kwargs) # Warn if must_use_master will override read_preference. - if (extra_opts['read_preference'] != rp.ReadPreference.PRIMARY and + if (extra_opts['read_preference'] != ReadPreference.PRIMARY and extra_opts['_must_use_master']): warnings.warn("%s does not support %s read preference " "and will be routed to the primary instead." % (command_name, - rp.modes[extra_opts['read_preference']]), - UserWarning) + modes[extra_opts['read_preference']]), + UserWarning, stacklevel=3) cursor = self["$cmd"].find(command, **extra_opts).limit(-1) for doc in cursor: @@ -466,7 +468,8 @@ class Database(common.BaseObject): self.__connection._purge_index(self.__name, name) - self.command("drop", unicode(name), allowable_errors=["ns not found"]) + self.command("drop", unicode(name), allowable_errors=["ns not found"], + read_preference=ReadPreference.PRIMARY) def validate_collection(self, name_or_collection, scandata=False, full=False): @@ -504,7 +507,8 @@ class Database(common.BaseObject): "%s or Collection" % (basestring.__name__,)) result = self.command("validate", unicode(name), - scandata=scandata, full=full) + scandata=scandata, full=full, + read_preference=ReadPreference.PRIMARY) valid = True # Pre 1.9 results @@ -553,7 +557,8 @@ class Database(common.BaseObject): .. mongodoc:: profiling """ - result = self.command("profile", -1) + result = self.command("profile", -1, + read_preference=ReadPreference.PRIMARY) assert result["was"] >= 0 and result["was"] <= 2 return result["was"] @@ -593,9 +598,11 @@ class Database(common.BaseObject): raise TypeError("slow_ms must be an integer") if slow_ms is not None: - self.command("profile", level, slowms=slow_ms) + self.command("profile", level, slowms=slow_ms, + read_preference=ReadPreference.PRIMARY) else: - self.command("profile", level) + self.command("profile", level, + read_preference=ReadPreference.PRIMARY) def profiling_info(self): """Returns a list containing current profiling information. @@ -610,7 +617,8 @@ class Database(common.BaseObject): Return None if the last operation was error-free. Otherwise return the error that occurred. """ - error = self.command("getlasterror") + error = self.command("getlasterror", + read_preference=ReadPreference.PRIMARY) error_msg = error.get("err", "") if error_msg is None: return None @@ -623,7 +631,8 @@ class Database(common.BaseObject): Returns a SON object with status information. """ - return self.command("getlasterror") + return self.command("getlasterror", + read_preference=ReadPreference.PRIMARY) def previous_error(self): """Get the most recent error to have occurred on this database. @@ -632,7 +641,8 @@ class Database(common.BaseObject): `Database.reset_error_history`. Returns None if no such errors have occurred. """ - error = self.command("getpreverror") + error = self.command("getpreverror", + read_preference=ReadPreference.PRIMARY) if error.get("err", 0) is None: return None return error @@ -643,7 +653,8 @@ class Database(common.BaseObject): Calls to `Database.previous_error` will only return errors that have occurred since the most recent call to this method. """ - self.command("reseterror") + self.command("reseterror", + read_preference=ReadPreference.PRIMARY) def __iter__(self): return self @@ -697,7 +708,8 @@ class Database(common.BaseObject): else: command_name = "updateUser" - self.command(command_name, name, **opts) + self.command(command_name, name, + read_preference=ReadPreference.PRIMARY, **opts) def _legacy_add_user(self, name, password, read_only, **kwargs): """Uses v1 system to add users, i.e. saving to system.users. @@ -763,7 +775,8 @@ class Database(common.BaseObject): "read_only and roles together") try: - uinfo = self.command("usersInfo", name) + uinfo = self.command("usersInfo", name, + read_preference=ReadPreference.PRIMARY) except OperationFailure, exc: # MongoDB >= 2.5.3 requires the use of commands to manage # users. "No such command" error didn't return an error @@ -793,6 +806,7 @@ class Database(common.BaseObject): try: self.command("dropUser", name, + read_preference=ReadPreference.PRIMARY, writeConcern=self._get_wc_override()) except OperationFailure, exc: # See comment in add_user try / except above. @@ -930,7 +944,9 @@ class Database(common.BaseObject): if not isinstance(code, Code): code = Code(code) - result = self.command("$eval", code, args=args) + result = self.command("$eval", code, + read_preference=ReadPreference.PRIMARY, + args=args) return result.get("retval", None) def __call__(self, *args, **kwargs): diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 0d15dc121..c26103fdb 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -61,6 +61,9 @@ from pymongo.errors import (AutoReconnect, InvalidURI, OperationFailure) from pymongo.member import Member +from pymongo.read_preferences import ReadPreference + + EMPTY = b("") @@ -1337,13 +1340,15 @@ class MongoClient(common.BaseObject): def server_info(self): """Get information about the MongoDB server we're connected to. """ - return self.admin.command("buildinfo") + return self.admin.command("buildinfo", + read_preference=ReadPreference.PRIMARY) def database_names(self): """Get a list of the names of all databases on the connected server. """ return [db["name"] for db in - self.admin.command("listDatabases")["databases"]] + self.admin.command("listDatabases", + read_preference=ReadPreference.PRIMARY)["databases"]] def drop_database(self, name_or_database): """Drop a database. @@ -1365,7 +1370,8 @@ class MongoClient(common.BaseObject): "%s or Database" % (basestring.__name__,)) self._purge_index(name) - self[name].command("dropDatabase") + self[name].command("dropDatabase", + read_preference=ReadPreference.PRIMARY) def copy_database(self, from_name, to_name, from_host=None, username=None, password=None): @@ -1413,12 +1419,15 @@ class MongoClient(common.BaseObject): if username is not None: nonce = self.admin.command("copydbgetnonce", - fromhost=from_host)["nonce"] + read_preference=ReadPreference.PRIMARY, + fromhost=from_host)["nonce"] command["username"] = username command["nonce"] = nonce command["key"] = auth._auth_key(nonce, username, password) - return self.admin.command("copydb", **command) + return self.admin.command("copydb", + read_preference=ReadPreference.PRIMARY, + **command) finally: self.end_request() @@ -1467,7 +1476,8 @@ class MongoClient(common.BaseObject): .. versionadded:: 2.0 """ - self.admin.command("fsync", **kwargs) + self.admin.command("fsync", + read_preference=ReadPreference.PRIMARY, **kwargs) def unlock(self): """Unlock a previously locked server. diff --git a/pymongo/mongo_replica_set_client.py b/pymongo/mongo_replica_set_client.py index 0f501ffd0..bd7deaa12 100644 --- a/pymongo/mongo_replica_set_client.py +++ b/pymongo/mongo_replica_set_client.py @@ -59,6 +59,7 @@ from pymongo.errors import (AutoReconnect, DuplicateKeyError, OperationFailure, InvalidOperation) +from pymongo.read_preferences import ReadPreference from pymongo.thread_util import DummyLock EMPTY = b("") @@ -1832,13 +1833,15 @@ class MongoReplicaSetClient(common.BaseObject): def server_info(self): """Get information about the MongoDB primary we're connected to. """ - return self.admin.command("buildinfo") + return self.admin.command("buildinfo", + read_preference=ReadPreference.PRIMARY) def database_names(self): """Get a list of the names of all databases on the connected server. """ return [db["name"] for db in - self.admin.command("listDatabases")["databases"]] + self.admin.command("listDatabases", + read_preference=ReadPreference.PRIMARY)["databases"]] def drop_database(self, name_or_database): """Drop a database. @@ -1860,7 +1863,8 @@ class MongoReplicaSetClient(common.BaseObject): "%s or Database" % (basestring.__name__,)) self._purge_index(name) - self[name].command("dropDatabase") + self[name].command("dropDatabase", + read_preference=ReadPreference.PRIMARY) def copy_database(self, from_name, to_name, from_host=None, username=None, password=None): @@ -1906,12 +1910,15 @@ class MongoReplicaSetClient(common.BaseObject): if username is not None: nonce = self.admin.command("copydbgetnonce", - fromhost=from_host)["nonce"] + read_preference=ReadPreference.PRIMARY, + fromhost=from_host)["nonce"] command["username"] = username command["nonce"] = nonce command["key"] = auth._auth_key(nonce, username, password) - return self.admin.command("copydb", **command) + return self.admin.command("copydb", + read_preference=ReadPreference.PRIMARY, + **command) finally: self.end_request() diff --git a/test/test_client.py b/test/test_client.py index bd3cbe8dd..b5a95a1db 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -22,6 +22,7 @@ import sys import time import thread import unittest +import warnings sys.path[0:0] = [""] @@ -43,6 +44,7 @@ from pymongo.errors import (AutoReconnect, from test import version, host, port, pair from test.pymongo_mocks import MockClient from test.utils import (assertRaisesExactly, + catch_warnings, delay, is_mongos, remove_all_users, @@ -315,11 +317,16 @@ class TestClient(unittest.TestCase, TestRequestMixin): def test_from_uri(self): c = MongoClient(host, port) - self.assertEqual(c, MongoClient("mongodb://%s:%d" % (host, port))) - self.assertTrue(MongoClient( - "mongodb://%s:%d" % (host, port), slave_okay=True).slave_okay) - self.assertTrue(MongoClient( - "mongodb://%s:%d/?slaveok=true;w=2" % (host, port)).slave_okay) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + self.assertEqual(c, MongoClient("mongodb://%s:%d" % (host, port))) + self.assertTrue(MongoClient( + "mongodb://%s:%d" % (host, port), slave_okay=True).slave_okay) + self.assertTrue(MongoClient( + "mongodb://%s:%d/?slaveok=true;w=2" % (host, port)).slave_okay) + finally: + ctx.exit() def test_get_default_database(self): c = MongoClient("mongodb://%s:%d/foo" % (host, port), _connect=False) diff --git a/test/test_collection.py b/test/test_collection.py index 433cc5b78..9387d665f 100644 --- a/test/test_collection.py +++ b/test/test_collection.py @@ -51,8 +51,8 @@ from pymongo.errors import (DocumentTooLarge, OperationFailure, WTimeoutError) from test.test_client import get_client -from test.utils import (is_mongos, joinall, enable_text_search, get_pool, - oid_generated_on_client) +from test.utils import (catch_warnings, enable_text_search, + get_pool, is_mongos, joinall, oid_generated_on_client) from test import (qcheck, version) @@ -226,19 +226,21 @@ class TestCollection(unittest.TestCase): def test_deprecated_ttl_index_kwarg(self): db = self.db - # In Python 2.6+ we could use the catch_warnings context - # manager to test this warning nicely. As we can't do that - # we must test raising errors before the ignore filter is applied. - warnings.simplefilter("error", DeprecationWarning) + ctx = catch_warnings() try: + warnings.simplefilter("error", DeprecationWarning) self.assertRaises(DeprecationWarning, lambda: db.test.ensure_index("goodbye", ttl=10)) finally: - warnings.resetwarnings() - warnings.simplefilter("ignore") + ctx.exit() - self.assertEqual("goodbye_1", - db.test.ensure_index("goodbye", ttl=10)) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + self.assertEqual("goodbye_1", + db.test.ensure_index("goodbye", ttl=10)) + finally: + ctx.exit() self.assertEqual(None, db.test.ensure_index("goodbye")) def test_ensure_unique_index_threaded(self): @@ -853,10 +855,15 @@ class TestCollection(unittest.TestCase): ) # Misconfigured value for safe - self.assertRaises( - TypeError, - lambda: db.test.insert([{'i': 2}] * 2, safe=1), - ) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + self.assertRaises( + TypeError, + lambda: db.test.insert([{'i': 2}] * 2, safe=1), + ) + finally: + ctx.exit() def test_insert_iterables(self): db = self.db @@ -979,10 +986,16 @@ class TestCollection(unittest.TestCase): db.test.insert({"_id": 2, "x": 2}) # No error - db.test.insert({"_id": 1, "x": 1}, safe=False) - db.test.save({"_id": 1, "x": 1}, safe=False) - db.test.insert({"_id": 2, "x": 2}, safe=False) - db.test.save({"_id": 2, "x": 2}, safe=False) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + db.test.insert({"_id": 1, "x": 1}, safe=False) + db.test.save({"_id": 1, "x": 1}, safe=False) + db.test.insert({"_id": 2, "x": 2}, safe=False) + db.test.save({"_id": 2, "x": 2}, safe=False) + finally: + ctx.exit() + db.test.insert({"_id": 1, "x": 1}, w=0) db.test.save({"_id": 1, "x": 1}, w=0) db.test.insert({"_id": 2, "x": 2}, w=0) @@ -2200,47 +2213,51 @@ class TestCollection(unittest.TestCase): for j in xrange(5): c.insert({'j': j, 'i': 0}) - sort={'j': DESCENDING} - self.assertEqual(4, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) - sort={'j': ASCENDING} - self.assertEqual(0, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) - sort=[('j', DESCENDING)] - self.assertEqual(4, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) - sort=[('j', ASCENDING)] - self.assertEqual(0, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) - sort=SON([('j', DESCENDING)]) - self.assertEqual(4, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) - sort=SON([('j', ASCENDING)]) - self.assertEqual(0, c.find_and_modify({}, - {'$inc': {'i': 1}}, - sort=sort)['j']) + ctx = catch_warnings() try: - from collections import OrderedDict - sort=OrderedDict([('j', DESCENDING)]) + warnings.simplefilter("ignore", DeprecationWarning) + sort={'j': DESCENDING} self.assertEqual(4, c.find_and_modify({}, {'$inc': {'i': 1}}, sort=sort)['j']) - sort=OrderedDict([('j', ASCENDING)]) + sort={'j': ASCENDING} self.assertEqual(0, c.find_and_modify({}, {'$inc': {'i': 1}}, sort=sort)['j']) - except ImportError: - pass - # Test that a standard dict with two keys is rejected. - sort={'j': DESCENDING, 'foo': DESCENDING} - self.assertRaises(TypeError, c.find_and_modify, {}, - {'$inc': {'i': 1}}, - sort=sort) + sort=[('j', DESCENDING)] + self.assertEqual(4, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + sort=[('j', ASCENDING)] + self.assertEqual(0, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + sort=SON([('j', DESCENDING)]) + self.assertEqual(4, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + sort=SON([('j', ASCENDING)]) + self.assertEqual(0, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + try: + from collections import OrderedDict + sort=OrderedDict([('j', DESCENDING)]) + self.assertEqual(4, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + sort=OrderedDict([('j', ASCENDING)]) + self.assertEqual(0, c.find_and_modify({}, + {'$inc': {'i': 1}}, + sort=sort)['j']) + except ImportError: + pass + # Test that a standard dict with two keys is rejected. + sort={'j': DESCENDING, 'foo': DESCENDING} + self.assertRaises(TypeError, c.find_and_modify, + {}, {'$inc': {'i': 1}}, sort=sort) + finally: + ctx.exit() def test_find_with_nested(self): if not version.at_least(self.db.connection, (2, 0, 0)): diff --git a/test/test_common.py b/test/test_common.py index f05e406cc..462a19526 100644 --- a/test/test_common.py +++ b/test/test_common.py @@ -31,7 +31,7 @@ from pymongo.mongo_client import MongoClient from pymongo.mongo_replica_set_client import MongoReplicaSetClient from pymongo.errors import ConfigurationError, OperationFailure from test import host, port, pair, version -from test.utils import drop_collections +from test.utils import catch_warnings, drop_collections have_uuid = True try: @@ -44,11 +44,9 @@ class TestCommon(unittest.TestCase): def test_baseobject(self): - # In Python 2.6+ we could use the catch_warnings context - # manager to test this warning nicely. As we can't do that - # we must test raising errors before the ignore filter is applied. - warnings.simplefilter("error", UserWarning) + ctx = catch_warnings() try: + warnings.simplefilter("error", UserWarning) self.assertRaises(UserWarning, lambda: MongoClient(host, port, wtimeout=1000, w=0)) try: @@ -61,191 +59,195 @@ class TestCommon(unittest.TestCase): except UserWarning: self.fail() finally: - warnings.resetwarnings() - warnings.simplefilter("ignore") + ctx.exit() # Connection tests - c = Connection(pair) - self.assertFalse(c.slave_okay) - self.assertFalse(c.safe) - self.assertEqual({}, c.get_lasterror_options()) - db = c.pymongo_test - db.drop_collection("test") - self.assertFalse(db.slave_okay) - self.assertFalse(db.safe) - self.assertEqual({}, db.get_lasterror_options()) - coll = db.test - self.assertFalse(coll.slave_okay) - self.assertFalse(coll.safe) - self.assertEqual({}, coll.get_lasterror_options()) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + c = Connection(pair) + self.assertFalse(c.slave_okay) + self.assertFalse(c.safe) + self.assertEqual({}, c.get_lasterror_options()) + db = c.pymongo_test + db.drop_collection("test") + self.assertFalse(db.slave_okay) + self.assertFalse(db.safe) + self.assertEqual({}, db.get_lasterror_options()) + coll = db.test + self.assertFalse(coll.slave_okay) + self.assertFalse(coll.safe) + self.assertEqual({}, coll.get_lasterror_options()) - self.assertEqual((False, {}), coll._get_write_mode()) - coll.safe = False - coll.write_concern.update(w=1) - self.assertEqual((True, {}), coll._get_write_mode()) - coll.write_concern.update(w=3) - self.assertEqual((True, {'w': 3}), coll._get_write_mode()) + self.assertEqual((False, {}), coll._get_write_mode()) + coll.safe = False + coll.write_concern.update(w=1) + self.assertEqual((True, {}), coll._get_write_mode()) + coll.write_concern.update(w=3) + self.assertEqual((True, {'w': 3}), coll._get_write_mode()) - coll.safe = True - coll.write_concern.update(w=0) - self.assertEqual((False, {}), coll._get_write_mode()) + coll.safe = True + coll.write_concern.update(w=0) + self.assertEqual((False, {}), coll._get_write_mode()) - coll = db.test - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - cursor = coll.find(slave_okay=True) - self.assertTrue(cursor._Cursor__slave_okay) + coll = db.test + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + cursor = coll.find(slave_okay=True) + self.assertTrue(cursor._Cursor__slave_okay) - # MongoClient test - c = MongoClient(pair) - self.assertFalse(c.slave_okay) - self.assertTrue(c.safe) - self.assertEqual({}, c.get_lasterror_options()) - db = c.pymongo_test - db.drop_collection("test") - self.assertFalse(db.slave_okay) - self.assertTrue(db.safe) - self.assertEqual({}, db.get_lasterror_options()) - coll = db.test - self.assertFalse(coll.slave_okay) - self.assertTrue(coll.safe) - self.assertEqual({}, coll.get_lasterror_options()) + # MongoClient test + c = MongoClient(pair) + self.assertFalse(c.slave_okay) + self.assertTrue(c.safe) + self.assertEqual({}, c.get_lasterror_options()) + db = c.pymongo_test + db.drop_collection("test") + self.assertFalse(db.slave_okay) + self.assertTrue(db.safe) + self.assertEqual({}, db.get_lasterror_options()) + coll = db.test + self.assertFalse(coll.slave_okay) + self.assertTrue(coll.safe) + self.assertEqual({}, coll.get_lasterror_options()) - self.assertEqual((True, {}), coll._get_write_mode()) - coll.safe = False - coll.write_concern.update(w=1) - self.assertEqual((True, {}), coll._get_write_mode()) - coll.write_concern.update(w=3) - self.assertEqual((True, {'w': 3}), coll._get_write_mode()) + self.assertEqual((True, {}), coll._get_write_mode()) + coll.safe = False + coll.write_concern.update(w=1) + self.assertEqual((True, {}), coll._get_write_mode()) + coll.write_concern.update(w=3) + self.assertEqual((True, {'w': 3}), coll._get_write_mode()) - coll.safe = True - coll.write_concern.update(w=0) - self.assertEqual((False, {}), coll._get_write_mode()) + coll.safe = True + coll.write_concern.update(w=0) + self.assertEqual((False, {}), coll._get_write_mode()) - coll = db.test - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - cursor = coll.find(slave_okay=True) - self.assertTrue(cursor._Cursor__slave_okay) + coll = db.test + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + cursor = coll.find(slave_okay=True) + self.assertTrue(cursor._Cursor__slave_okay) - # Setting any safe operations overrides explicit safe - self.assertTrue(MongoClient(host, port, wtimeout=1000, safe=False).safe) + # Setting any safe operations overrides explicit safe + self.assertTrue(MongoClient(host, port, wtimeout=1000, safe=False).safe) - c = MongoClient(pair, slaveok=True, w='majority', - wtimeout=300, fsync=True, j=True) - self.assertTrue(c.slave_okay) - self.assertTrue(c.safe) - d = {'w': 'majority', 'wtimeout': 300, 'fsync': True, 'j': True} - self.assertEqual(d, c.get_lasterror_options()) - db = c.pymongo_test - self.assertTrue(db.slave_okay) - self.assertTrue(db.safe) - self.assertEqual(d, db.get_lasterror_options()) - coll = db.test - self.assertTrue(coll.slave_okay) - self.assertTrue(coll.safe) - self.assertEqual(d, coll.get_lasterror_options()) - cursor = coll.find() - self.assertTrue(cursor._Cursor__slave_okay) - cursor = coll.find(slave_okay=False) - self.assertFalse(cursor._Cursor__slave_okay) + c = MongoClient(pair, slaveok=True, w='majority', + wtimeout=300, fsync=True, j=True) + self.assertTrue(c.slave_okay) + self.assertTrue(c.safe) + d = {'w': 'majority', 'wtimeout': 300, 'fsync': True, 'j': True} + self.assertEqual(d, c.get_lasterror_options()) + db = c.pymongo_test + self.assertTrue(db.slave_okay) + self.assertTrue(db.safe) + self.assertEqual(d, db.get_lasterror_options()) + coll = db.test + self.assertTrue(coll.slave_okay) + self.assertTrue(coll.safe) + self.assertEqual(d, coll.get_lasterror_options()) + cursor = coll.find() + self.assertTrue(cursor._Cursor__slave_okay) + cursor = coll.find(slave_okay=False) + self.assertFalse(cursor._Cursor__slave_okay) - c = MongoClient('mongodb://%s/?' - 'w=2;wtimeoutMS=300;fsync=true;' - 'journal=true' % (pair,)) - self.assertTrue(c.safe) - d = {'w': 2, 'wtimeout': 300, 'fsync': True, 'j': True} - self.assertEqual(d, c.get_lasterror_options()) + c = MongoClient('mongodb://%s/?' + 'w=2;wtimeoutMS=300;fsync=true;' + 'journal=true' % (pair,)) + self.assertTrue(c.safe) + d = {'w': 2, 'wtimeout': 300, 'fsync': True, 'j': True} + self.assertEqual(d, c.get_lasterror_options()) - c = MongoClient('mongodb://%s/?' - 'slaveok=true;w=1;wtimeout=300;' - 'fsync=true;j=true' % (pair,)) - self.assertTrue(c.slave_okay) - self.assertTrue(c.safe) - d = {'w': 1, 'wtimeout': 300, 'fsync': True, 'j': True} - self.assertEqual(d, c.get_lasterror_options()) - self.assertEqual(d, c.write_concern) - db = c.pymongo_test - self.assertTrue(db.slave_okay) - self.assertTrue(db.safe) - self.assertEqual(d, db.get_lasterror_options()) - self.assertEqual(d, db.write_concern) - coll = db.test - self.assertTrue(coll.slave_okay) - self.assertTrue(coll.safe) - self.assertEqual(d, coll.get_lasterror_options()) - self.assertEqual(d, coll.write_concern) - cursor = coll.find() - self.assertTrue(cursor._Cursor__slave_okay) - cursor = coll.find(slave_okay=False) - self.assertFalse(cursor._Cursor__slave_okay) + c = MongoClient('mongodb://%s/?' + 'slaveok=true;w=1;wtimeout=300;' + 'fsync=true;j=true' % (pair,)) + self.assertTrue(c.slave_okay) + self.assertTrue(c.safe) + d = {'w': 1, 'wtimeout': 300, 'fsync': True, 'j': True} + self.assertEqual(d, c.get_lasterror_options()) + self.assertEqual(d, c.write_concern) + db = c.pymongo_test + self.assertTrue(db.slave_okay) + self.assertTrue(db.safe) + self.assertEqual(d, db.get_lasterror_options()) + self.assertEqual(d, db.write_concern) + coll = db.test + self.assertTrue(coll.slave_okay) + self.assertTrue(coll.safe) + self.assertEqual(d, coll.get_lasterror_options()) + self.assertEqual(d, coll.write_concern) + cursor = coll.find() + self.assertTrue(cursor._Cursor__slave_okay) + cursor = coll.find(slave_okay=False) + self.assertFalse(cursor._Cursor__slave_okay) - c.unset_lasterror_options() - self.assertTrue(c.slave_okay) - self.assertTrue(c.safe) - c.safe = False - self.assertFalse(c.safe) - c.slave_okay = False - self.assertFalse(c.slave_okay) - self.assertEqual({}, c.get_lasterror_options()) - self.assertEqual({}, c.write_concern) - db = c.pymongo_test - self.assertFalse(db.slave_okay) - self.assertFalse(db.safe) - self.assertEqual({}, db.get_lasterror_options()) - self.assertEqual({}, db.write_concern) - coll = db.test - self.assertFalse(coll.slave_okay) - self.assertFalse(coll.safe) - self.assertEqual({}, coll.get_lasterror_options()) - self.assertEqual({}, coll.write_concern) - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - cursor = coll.find(slave_okay=True) - self.assertTrue(cursor._Cursor__slave_okay) + c.unset_lasterror_options() + self.assertTrue(c.slave_okay) + self.assertTrue(c.safe) + c.safe = False + self.assertFalse(c.safe) + c.slave_okay = False + self.assertFalse(c.slave_okay) + self.assertEqual({}, c.get_lasterror_options()) + self.assertEqual({}, c.write_concern) + db = c.pymongo_test + self.assertFalse(db.slave_okay) + self.assertFalse(db.safe) + self.assertEqual({}, db.get_lasterror_options()) + self.assertEqual({}, db.write_concern) + coll = db.test + self.assertFalse(coll.slave_okay) + self.assertFalse(coll.safe) + self.assertEqual({}, coll.get_lasterror_options()) + self.assertEqual({}, coll.write_concern) + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + cursor = coll.find(slave_okay=True) + self.assertTrue(cursor._Cursor__slave_okay) - coll.set_lasterror_options(fsync=True) - self.assertEqual({'fsync': True}, coll.get_lasterror_options()) - self.assertEqual({'fsync': True}, coll.write_concern) - self.assertEqual({}, db.get_lasterror_options()) - self.assertEqual({}, db.write_concern) - self.assertFalse(db.safe) - self.assertEqual({}, c.get_lasterror_options()) - self.assertEqual({}, c.write_concern) - self.assertFalse(c.safe) + coll.set_lasterror_options(fsync=True) + self.assertEqual({'fsync': True}, coll.get_lasterror_options()) + self.assertEqual({'fsync': True}, coll.write_concern) + self.assertEqual({}, db.get_lasterror_options()) + self.assertEqual({}, db.write_concern) + self.assertFalse(db.safe) + self.assertEqual({}, c.get_lasterror_options()) + self.assertEqual({}, c.write_concern) + self.assertFalse(c.safe) - db.set_lasterror_options(w='majority') - self.assertEqual({'fsync': True}, coll.get_lasterror_options()) - self.assertEqual({'fsync': True}, coll.write_concern) - self.assertEqual({'w': 'majority'}, db.get_lasterror_options()) - self.assertEqual({'w': 'majority'}, db.write_concern) - self.assertEqual({}, c.get_lasterror_options()) - self.assertEqual({}, c.write_concern) - self.assertFalse(c.safe) - db.slave_okay = True - self.assertTrue(db.slave_okay) - self.assertFalse(c.slave_okay) - self.assertFalse(coll.slave_okay) - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - cursor = db.coll2.find() - self.assertTrue(cursor._Cursor__slave_okay) - cursor = db.coll2.find(slave_okay=False) - self.assertFalse(cursor._Cursor__slave_okay) + db.set_lasterror_options(w='majority') + self.assertEqual({'fsync': True}, coll.get_lasterror_options()) + self.assertEqual({'fsync': True}, coll.write_concern) + self.assertEqual({'w': 'majority'}, db.get_lasterror_options()) + self.assertEqual({'w': 'majority'}, db.write_concern) + self.assertEqual({}, c.get_lasterror_options()) + self.assertEqual({}, c.write_concern) + self.assertFalse(c.safe) + db.slave_okay = True + self.assertTrue(db.slave_okay) + self.assertFalse(c.slave_okay) + self.assertFalse(coll.slave_okay) + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + cursor = db.coll2.find() + self.assertTrue(cursor._Cursor__slave_okay) + cursor = db.coll2.find(slave_okay=False) + self.assertFalse(cursor._Cursor__slave_okay) - self.assertRaises(ConfigurationError, coll.set_lasterror_options, foo=20) - self.assertRaises(TypeError, coll._BaseObject__set_slave_okay, 20) - self.assertRaises(TypeError, coll._BaseObject__set_safe, 20) + self.assertRaises(ConfigurationError, coll.set_lasterror_options, foo=20) + self.assertRaises(TypeError, coll._BaseObject__set_slave_okay, 20) + self.assertRaises(TypeError, coll._BaseObject__set_safe, 20) - coll.remove() - self.assertEqual(None, coll.find_one(slave_okay=True)) - coll.unset_lasterror_options() - coll.set_lasterror_options(w=4, wtimeout=10) - # Fails if we don't have 4 active nodes or we don't have replication... - self.assertRaises(OperationFailure, coll.insert, {'foo': 'bar'}) - # Succeeds since we override the lasterror settings per query. - self.assertTrue(coll.insert({'foo': 'bar'}, fsync=True)) - drop_collections(db) + coll.remove() + self.assertEqual(None, coll.find_one(slave_okay=True)) + coll.unset_lasterror_options() + coll.set_lasterror_options(w=4, wtimeout=10) + # Fails if we don't have 4 active nodes or we don't have replication... + self.assertRaises(OperationFailure, coll.insert, {'foo': 'bar'}) + # Succeeds since we override the lasterror settings per query. + self.assertTrue(coll.insert({'foo': 'bar'}, fsync=True)) + drop_collections(db) + finally: + ctx.exit() def test_uuid_subtype(self): if not have_uuid: @@ -439,30 +441,36 @@ class TestCommon(unittest.TestCase): m = MongoClient(pair, w=0) coll = m.pymongo_test.write_concern_test coll.drop() - doc = {"_id": ObjectId()} - coll.insert(doc) - self.assertTrue(coll.insert(doc, safe=False)) - self.assertTrue(coll.insert(doc, w=0)) - self.assertTrue(coll.insert(doc)) - self.assertRaises(OperationFailure, coll.insert, doc, safe=True) - self.assertRaises(OperationFailure, coll.insert, doc, w=1) - m = MongoClient(pair) - coll = m.pymongo_test.write_concern_test - self.assertTrue(coll.insert(doc, safe=False)) - self.assertTrue(coll.insert(doc, w=0)) - self.assertRaises(OperationFailure, coll.insert, doc) - self.assertRaises(OperationFailure, coll.insert, doc, safe=True) - self.assertRaises(OperationFailure, coll.insert, doc, w=1) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + doc = {"_id": ObjectId()} + coll.insert(doc) + self.assertTrue(coll.insert(doc, safe=False)) + self.assertTrue(coll.insert(doc, w=0)) + self.assertTrue(coll.insert(doc)) + self.assertRaises(OperationFailure, coll.insert, doc, safe=True) + self.assertRaises(OperationFailure, coll.insert, doc, w=1) - m = MongoClient("mongodb://%s/" % (pair,)) - self.assertTrue(m.safe) - coll = m.pymongo_test.write_concern_test - self.assertRaises(OperationFailure, coll.insert, doc) - m = MongoClient("mongodb://%s/?w=0" % (pair,)) - self.assertFalse(m.safe) - coll = m.pymongo_test.write_concern_test - self.assertTrue(coll.insert(doc)) + m = MongoClient(pair) + coll = m.pymongo_test.write_concern_test + self.assertTrue(coll.insert(doc, safe=False)) + self.assertTrue(coll.insert(doc, w=0)) + self.assertRaises(OperationFailure, coll.insert, doc) + self.assertRaises(OperationFailure, coll.insert, doc, safe=True) + self.assertRaises(OperationFailure, coll.insert, doc, w=1) + + m = MongoClient("mongodb://%s/" % (pair,)) + self.assertTrue(m.safe) + coll = m.pymongo_test.write_concern_test + self.assertRaises(OperationFailure, coll.insert, doc) + m = MongoClient("mongodb://%s/?w=0" % (pair,)) + self.assertFalse(m.safe) + coll = m.pymongo_test.write_concern_test + self.assertTrue(coll.insert(doc)) + finally: + ctx.exit() # Equality tests self.assertEqual(m, MongoClient("mongodb://%s/?w=0" % (pair,))) @@ -478,30 +486,36 @@ class TestCommon(unittest.TestCase): m = MongoReplicaSetClient(pair, replicaSet=setname, w=0) coll = m.pymongo_test.write_concern_test coll.drop() - doc = {"_id": ObjectId()} - coll.insert(doc) - self.assertTrue(coll.insert(doc, safe=False)) - self.assertTrue(coll.insert(doc, w=0)) - self.assertTrue(coll.insert(doc)) - self.assertRaises(OperationFailure, coll.insert, doc, safe=True) - self.assertRaises(OperationFailure, coll.insert, doc, w=1) - m = MongoReplicaSetClient(pair, replicaSet=setname) - coll = m.pymongo_test.write_concern_test - self.assertTrue(coll.insert(doc, safe=False)) - self.assertTrue(coll.insert(doc, w=0)) - self.assertRaises(OperationFailure, coll.insert, doc) - self.assertRaises(OperationFailure, coll.insert, doc, safe=True) - self.assertRaises(OperationFailure, coll.insert, doc, w=1) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + doc = {"_id": ObjectId()} + coll.insert(doc) + self.assertTrue(coll.insert(doc, safe=False)) + self.assertTrue(coll.insert(doc, w=0)) + self.assertTrue(coll.insert(doc)) + self.assertRaises(OperationFailure, coll.insert, doc, safe=True) + self.assertRaises(OperationFailure, coll.insert, doc, w=1) - m = MongoReplicaSetClient("mongodb://%s/?replicaSet=%s" % (pair, setname)) - self.assertTrue(m.safe) - coll = m.pymongo_test.write_concern_test - self.assertRaises(OperationFailure, coll.insert, doc) - m = MongoReplicaSetClient("mongodb://%s/?replicaSet=%s;w=0" % (pair, setname)) - self.assertFalse(m.safe) - coll = m.pymongo_test.write_concern_test - self.assertTrue(coll.insert(doc)) + m = MongoReplicaSetClient(pair, replicaSet=setname) + coll = m.pymongo_test.write_concern_test + self.assertTrue(coll.insert(doc, safe=False)) + self.assertTrue(coll.insert(doc, w=0)) + self.assertRaises(OperationFailure, coll.insert, doc) + self.assertRaises(OperationFailure, coll.insert, doc, safe=True) + self.assertRaises(OperationFailure, coll.insert, doc, w=1) + + m = MongoReplicaSetClient("mongodb://%s/?replicaSet=%s" % (pair, setname)) + self.assertTrue(m.safe) + coll = m.pymongo_test.write_concern_test + self.assertRaises(OperationFailure, coll.insert, doc) + m = MongoReplicaSetClient("mongodb://%s/?replicaSet=%s;w=0" % (pair, setname)) + self.assertFalse(m.safe) + coll = m.pymongo_test.write_concern_test + self.assertTrue(coll.insert(doc)) + finally: + ctx.exit() if __name__ == "__main__": diff --git a/test/test_cursor.py b/test/test_cursor.py index efad94d79..ead450275 100644 --- a/test/test_cursor.py +++ b/test/test_cursor.py @@ -19,6 +19,8 @@ import random import re import sys import unittest +import warnings + sys.path[0:0] = [""] from nose.plugins.skip import SkipTest @@ -37,7 +39,8 @@ from pymongo.errors import (InvalidOperation, ExecutionTimeout) from test import version from test.test_client import get_client -from test.utils import is_mongos, get_command_line, server_started_with_auth +from test.utils import (catch_warnings, is_mongos, + get_command_line, server_started_with_auth) class TestCursor(unittest.TestCase): @@ -1100,8 +1103,11 @@ self.assertFalse(c2.alive) pass client = self.db.connection + ctx = catch_warnings() try: + warnings.simplefilter("ignore", DeprecationWarning) client.set_cursor_manager(CManager) + docs = [] cursor = self.db.test.find().batch_size(10) docs.append(cursor.next()) @@ -1115,6 +1121,7 @@ self.assertFalse(c2.alive) self.assertEqual(len(docs), 200) finally: client.set_cursor_manager(CursorManager) + ctx.exit() if __name__ == "__main__": unittest.main() diff --git a/test/test_database.py b/test/test_database.py index b2e0efbb7..0756eb8d5 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -47,8 +47,8 @@ from pymongo.son_manipulator import (AutoReference, NamespaceInjector, ObjectIdShuffler) from test import version -from test.utils import (get_command_line, is_mongos, - remove_all_users, server_started_with_auth) +from test.utils import (catch_warnings, get_command_line, + is_mongos, remove_all_users, server_started_with_auth) from test.test_client import get_client @@ -368,15 +368,15 @@ class TestDatabase(unittest.TestCase): "user", 'password', True, roles=['read']) if version.at_least(self.client, (2, 5, 3, -1)): - warnings.simplefilter("error", DeprecationWarning) + ctx = catch_warnings() try: + warnings.simplefilter("error", DeprecationWarning) self.assertRaises(DeprecationWarning, db.add_user, "user", "password") self.assertRaises(DeprecationWarning, db.add_user, "user", "password", True) finally: - warnings.resetwarnings() - warnings.simplefilter("ignore") + ctx.exit() self.assertRaises(ConfigurationError, db.add_user, "user", "password", digestPassword=True) @@ -947,8 +947,9 @@ class TestDatabase(unittest.TestCase): self.fail("_check_command_response didn't raise OperationFailure") def test_command_read_pref_warning(self): - warnings.simplefilter("error", UserWarning) + ctx = catch_warnings() try: + warnings.simplefilter("error", UserWarning) self.assertRaises(UserWarning, self.client.pymongo_test.command, 'ping', read_preference=ReadPreference.SECONDARY) try: @@ -957,8 +958,7 @@ class TestDatabase(unittest.TestCase): except UserWarning: self.fail("Shouldn't have raised UserWarning.") finally: - warnings.resetwarnings() - warnings.simplefilter("ignore") + ctx.exit() def test_command_max_time_ms(self): if not version.at_least(self.client, (2, 5, 3, -1)): diff --git a/test/test_gridfs.py b/test/test_gridfs.py index d8834c7ef..c3afe7d32 100644 --- a/test/test_gridfs.py +++ b/test/test_gridfs.py @@ -16,25 +16,25 @@ """Tests for the gridfs package. """ -import sys -sys.path[0:0] = [""] - -from pymongo.mongo_client import MongoClient -from pymongo.errors import ConnectionFailure -from pymongo.read_preferences import ReadPreference -from test.test_replica_set_client import TestReplicaSetClientBase - import datetime -import unittest +import sys import threading import time +import unittest +import warnings + +sys.path[0:0] = [""] + import gridfs from bson.py3compat import b, StringIO -from gridfs.errors import (FileExists, - NoFile) +from gridfs.errors import (FileExists, NoFile) +from pymongo.errors import ConnectionFailure +from pymongo.mongo_client import MongoClient +from pymongo.read_preferences import ReadPreference from test.test_client import get_client -from test.utils import joinall +from test.test_replica_set_client import TestReplicaSetClientBase +from test.utils import catch_warnings, joinall class JustWrite(threading.Thread): @@ -416,20 +416,25 @@ class TestGridfsReplicaSet(TestReplicaSetClientBase): primary_connection = MongoClient(primary_host, primary_port) secondary_host, secondary_port = self.secondaries[0] - for secondary_connection in [ - MongoClient(secondary_host, secondary_port, slave_okay=True), - MongoClient(secondary_host, secondary_port, - read_preference=ReadPreference.SECONDARY), - ]: - primary_connection.pymongo_test.drop_collection("fs.files") - primary_connection.pymongo_test.drop_collection("fs.chunks") + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + for secondary_connection in [ + MongoClient(secondary_host, secondary_port, slave_okay=True), + MongoClient(secondary_host, secondary_port, + read_preference=ReadPreference.SECONDARY), + ]: + primary_connection.pymongo_test.drop_collection("fs.files") + primary_connection.pymongo_test.drop_collection("fs.chunks") - # Should detect it's connected to secondary and not attempt to - # create index - fs = gridfs.GridFS(secondary_connection.pymongo_test) + # Should detect it's connected to secondary and not attempt to + # create index + fs = gridfs.GridFS(secondary_connection.pymongo_test) - # This won't detect secondary, raises error - self.assertRaises(ConnectionFailure, fs.put, b('foo')) + # This won't detect secondary, raises error + self.assertRaises(ConnectionFailure, fs.put, b('foo')) + finally: + ctx.exit() def test_gridfs_secondary_lazy(self): # Should detect it's connected to secondary and not attempt to diff --git a/test/test_legacy_connections.py b/test/test_legacy_connections.py index 83b475dc0..0308f8141 100644 --- a/test/test_legacy_connections.py +++ b/test/test_legacy_connections.py @@ -17,6 +17,7 @@ import sys import unittest +import warnings sys.path[0:0] = [""] @@ -28,27 +29,33 @@ from pymongo.replica_set_connection import ReplicaSetConnection from pymongo.errors import ConfigurationError from test import host, port, pair from test.test_replica_set_client import TestReplicaSetClientBase -from test.utils import get_pool +from test.utils import catch_warnings, get_pool class TestConnection(unittest.TestCase): def test_connection(self): c = Connection(host, port) - self.assertTrue(c.auto_start_request) - self.assertEqual(None, c.max_pool_size) - self.assertFalse(c.slave_okay) - self.assertFalse(c.safe) - self.assertEqual({}, c.get_lasterror_options()) - # Connection's writes are unacknowledged by default - doc = {"_id": ObjectId()} - coll = c.pymongo_test.write_concern_test - coll.drop() - coll.insert(doc) - coll.insert(doc) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + self.assertTrue(c.auto_start_request) + self.assertEqual(None, c.max_pool_size) + self.assertFalse(c.slave_okay) + self.assertFalse(c.safe) + self.assertEqual({}, c.get_lasterror_options()) - c = Connection("mongodb://%s:%s/?safe=true" % (host, port)) - self.assertTrue(c.safe) + # Connection's writes are unacknowledged by default + doc = {"_id": ObjectId()} + coll = c.pymongo_test.write_concern_test + coll.drop() + coll.insert(doc) + coll.insert(doc) + + c = Connection("mongodb://%s:%s/?safe=true" % (host, port)) + self.assertTrue(c.safe) + finally: + ctx.exit() # To preserve legacy Connection's behavior, max_size should be None. # Pool should handle this without error. @@ -73,23 +80,29 @@ class TestConnection(unittest.TestCase): class TestReplicaSetConnection(TestReplicaSetClientBase): def test_replica_set_connection(self): c = ReplicaSetConnection(pair, replicaSet=self.name) - self.assertTrue(c.auto_start_request) - self.assertEqual(None, c.max_pool_size) - self.assertFalse(c.slave_okay) - self.assertFalse(c.safe) - self.assertEqual({}, c.get_lasterror_options()) - # ReplicaSetConnection's writes are unacknowledged by default - doc = {"_id": ObjectId()} - coll = c.pymongo_test.write_concern_test - coll.drop() - coll.insert(doc) - coll.insert(doc) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + self.assertTrue(c.auto_start_request) + self.assertEqual(None, c.max_pool_size) + self.assertFalse(c.slave_okay) + self.assertFalse(c.safe) + self.assertEqual({}, c.get_lasterror_options()) - c = ReplicaSetConnection("mongodb://%s:%s/?replicaSet=%s&safe=true" % ( - host, port, self.name)) + # ReplicaSetConnection's writes are unacknowledged by default + doc = {"_id": ObjectId()} + coll = c.pymongo_test.write_concern_test + coll.drop() + coll.insert(doc) + coll.insert(doc) - self.assertTrue(c.safe) + c = ReplicaSetConnection("mongodb://%s:%s/?replicaSet=%s&safe=true" % ( + host, port, self.name)) + + self.assertTrue(c.safe) + finally: + ctx.exit() # To preserve legacy ReplicaSetConnection's behavior, max_size should # be None. Pool should handle this without error. diff --git a/test/test_master_slave_connection.py b/test/test_master_slave_connection.py index 5af88a3c2..28c38069e 100644 --- a/test/test_master_slave_connection.py +++ b/test/test_master_slave_connection.py @@ -20,6 +20,8 @@ import sys import threading import time import unittest +import warnings + sys.path[0:0] = [""] from nose.plugins.skip import SkipTest @@ -35,7 +37,7 @@ from pymongo.mongo_client import MongoClient from pymongo.collection import Collection from pymongo.master_slave_connection import MasterSlaveConnection from test import host, port, host2, port2, host3, port3 -from test.utils import TestRequestMixin, get_pool +from test.utils import TestRequestMixin, catch_warnings, get_pool class TestMasterSlaveConnection(unittest.TestCase, TestRequestMixin): @@ -363,7 +365,7 @@ class TestMasterSlaveConnection(unittest.TestCase, TestRequestMixin): def test_kill_cursor_explicit(self): c = self.client - c.slave_okay = True + c.read_preference = ReadPreference.SECONDARY_PREFERRED db = c.pymongo_test test = db.master_slave_test_kill_cursor_explicit @@ -412,60 +414,65 @@ class TestMasterSlaveConnection(unittest.TestCase, TestRequestMixin): self.assertRaises(OperationFailure, lambda: list(cursor2)) def test_base_object(self): - c = self.client - self.assertFalse(c.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(c.safe) - self.assertEqual({}, c.get_lasterror_options()) - db = c.pymongo_test - self.assertFalse(db.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(db.safe) - self.assertEqual({}, db.get_lasterror_options()) - coll = db.test - coll.drop() - self.assertFalse(coll.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(coll.safe) - self.assertEqual({}, coll.get_lasterror_options()) - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - self.assertTrue(bool(cursor._Cursor__read_preference)) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + c = self.client + self.assertFalse(c.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(c.safe) + self.assertEqual({}, c.get_lasterror_options()) + db = c.pymongo_test + self.assertFalse(db.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(db.safe) + self.assertEqual({}, db.get_lasterror_options()) + coll = db.test + coll.drop() + self.assertFalse(coll.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(coll.safe) + self.assertEqual({}, coll.get_lasterror_options()) + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + self.assertTrue(bool(cursor._Cursor__read_preference)) - w = 1 + len(self.slaves) - wtimeout=10000 # Wait 10 seconds for replication to complete - c.set_lasterror_options(w=w, wtimeout=wtimeout) - self.assertFalse(c.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(c.safe) - self.assertEqual({'w': w, 'wtimeout': wtimeout}, c.get_lasterror_options()) - db = c.pymongo_test - self.assertFalse(db.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(db.safe) - self.assertEqual({'w': w, 'wtimeout': wtimeout}, db.get_lasterror_options()) - coll = db.test - self.assertFalse(coll.slave_okay) - self.assertTrue(bool(c.read_preference)) - self.assertTrue(coll.safe) - self.assertEqual({'w': w, 'wtimeout': wtimeout}, - coll.get_lasterror_options()) - cursor = coll.find() - self.assertFalse(cursor._Cursor__slave_okay) - self.assertTrue(bool(cursor._Cursor__read_preference)) + w = 1 + len(self.slaves) + wtimeout=10000 # Wait 10 seconds for replication to complete + c.set_lasterror_options(w=w, wtimeout=wtimeout) + self.assertFalse(c.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(c.safe) + self.assertEqual({'w': w, 'wtimeout': wtimeout}, c.get_lasterror_options()) + db = c.pymongo_test + self.assertFalse(db.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(db.safe) + self.assertEqual({'w': w, 'wtimeout': wtimeout}, db.get_lasterror_options()) + coll = db.test + self.assertFalse(coll.slave_okay) + self.assertTrue(bool(c.read_preference)) + self.assertTrue(coll.safe) + self.assertEqual({'w': w, 'wtimeout': wtimeout}, + coll.get_lasterror_options()) + cursor = coll.find() + self.assertFalse(cursor._Cursor__slave_okay) + self.assertTrue(bool(cursor._Cursor__read_preference)) - coll.insert({'foo': 'bar'}) - self.assertEqual(1, coll.find({'foo': 'bar'}).count()) - self.assertTrue(coll.find({'foo': 'bar'})) - coll.remove({'foo': 'bar'}) - self.assertEqual(0, coll.find({'foo': 'bar'}).count()) + coll.insert({'foo': 'bar'}) + self.assertEqual(1, coll.find({'foo': 'bar'}).count()) + self.assertTrue(coll.find({'foo': 'bar'})) + coll.remove({'foo': 'bar'}) + self.assertEqual(0, coll.find({'foo': 'bar'}).count()) - c.safe = False - c.unset_lasterror_options() - self.assertFalse(self.client.slave_okay) - self.assertTrue(bool(self.client.read_preference)) - self.assertFalse(self.client.safe) - self.assertEqual({}, self.client.get_lasterror_options()) + c.safe = False + c.unset_lasterror_options() + self.assertFalse(self.client.slave_okay) + self.assertTrue(bool(self.client.read_preference)) + self.assertFalse(self.client.safe) + self.assertEqual({}, self.client.get_lasterror_options()) + finally: + ctx.exit() def test_document_class(self): c = MasterSlaveConnection(self.master, self.slaves) diff --git a/test/test_read_preferences.py b/test/test_read_preferences.py index 457ea6b51..8b61a0069 100644 --- a/test/test_read_preferences.py +++ b/test/test_read_preferences.py @@ -14,9 +14,9 @@ """Test the replica_set_connection module.""" import random - import sys import unittest +import warnings from nose.plugins.skip import SkipTest @@ -32,6 +32,7 @@ from pymongo.errors import ConfigurationError from test.test_replica_set_client import TestReplicaSetClientBase from test.test_client import get_client from test import version, utils, host, port +from test.utils import catch_warnings class TestReadPreferencesBase(TestReplicaSetClientBase): @@ -278,8 +279,13 @@ class TestCommandAndReadPreference(TestReplicaSetClientBase): # Test generic 'command' method. Some commands obey read preference, # most don't. # Disobedient commands, always go to primary - self._test_fn(False, lambda: self.c.pymongo_test.command('ping')) - self._test_fn(False, lambda: self.c.admin.command('buildinfo')) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.command('ping')) + self._test_fn(False, lambda: self.c.admin.command('buildinfo')) + finally: + ctx.exit() # Obedient commands. self._test_fn(True, lambda: self.c.pymongo_test.command('group', { @@ -342,7 +348,12 @@ class TestCommandAndReadPreference(TestReplicaSetClientBase): # Text search. if version.at_least(self.c, (2, 3, 2)): - utils.enable_text_search(self.c) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + utils.enable_text_search(self.c) + finally: + ctx.exit() db = self.c.pymongo_test # Only way to create an index and wait for all members to build it. @@ -366,20 +377,25 @@ class TestCommandAndReadPreference(TestReplicaSetClientBase): # Non-inline mapreduce always goes to primary, doesn't obey read prefs. # Test with command in a SON and with kwargs - self._test_fn(False, lambda: self.c.pymongo_test.command(SON([ - ('mapreduce', 'test'), - ('map', 'function() { }'), - ('reduce', 'function() { }'), - ('out', 'mr_out') - ]))) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.command(SON([ + ('mapreduce', 'test'), + ('map', 'function() { }'), + ('reduce', 'function() { }'), + ('out', 'mr_out') + ]))) - self._test_fn(False, lambda: self.c.pymongo_test.command( - 'mapreduce', 'test', map='function() { }', - reduce='function() { }', out='mr_out')) + self._test_fn(False, lambda: self.c.pymongo_test.command( + 'mapreduce', 'test', map='function() { }', + reduce='function() { }', out='mr_out')) - self._test_fn(False, lambda: self.c.pymongo_test.command( - 'mapreduce', 'test', map='function() { }', - reduce='function() { }', out={'replace': 'some_collection'})) + self._test_fn(False, lambda: self.c.pymongo_test.command( + 'mapreduce', 'test', map='function() { }', + reduce='function() { }', out={'replace': 'some_collection'})) + finally: + ctx.exit() # Inline mapreduce obeys read prefs self._test_fn(True, lambda: self.c.pymongo_test.command( @@ -405,32 +421,47 @@ class TestCommandAndReadPreference(TestReplicaSetClientBase): # Aggregate with $out always goes to primary, doesn't obey read prefs. # Test aggregate command sent directly to db.command. - self._test_fn(False, lambda: self.c.pymongo_test.command( - "aggregate", "test", - pipeline=[{"$match": {"x": 1}}, {"$out": "agg_out"}] - )) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.command( + "aggregate", "test", + pipeline=[{"$match": {"x": 1}}, {"$out": "agg_out"}] + )) - # Test aggregate when sent through the collection aggregate function. - self._test_fn(False, lambda: self.c.pymongo_test.test.aggregate( - [{"$match": {"x": 2}}, {"$out": "agg_out"}] - )) + # Test aggregate when sent through the collection aggregate function. + self._test_fn(False, lambda: self.c.pymongo_test.test.aggregate( + [{"$match": {"x": 2}}, {"$out": "agg_out"}] + )) + finally: + ctx.exit() self.c.pymongo_test.drop_collection("test") self.c.pymongo_test.drop_collection("agg_out") def test_create_collection(self): # Collections should be created on primary, obviously - self._test_fn(False, lambda: self.c.pymongo_test.command( - 'create', 'some_collection%s' % random.randint(0, sys.maxint))) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.command( + 'create', 'some_collection%s' % random.randint(0, sys.maxint))) - self._test_fn(False, lambda: self.c.pymongo_test.create_collection( - 'some_collection%s' % random.randint(0, sys.maxint))) + self._test_fn(False, lambda: self.c.pymongo_test.create_collection( + 'some_collection%s' % random.randint(0, sys.maxint))) + finally: + ctx.exit() def test_drop_collection(self): - self._test_fn(False, lambda: self.c.pymongo_test.drop_collection( - 'some_collection')) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.drop_collection( + 'some_collection')) - self._test_fn(False, lambda: self.c.pymongo_test.some_collection.drop()) + self._test_fn(False, lambda: self.c.pymongo_test.some_collection.drop()) + finally: + ctx.exit() def test_group(self): self._test_fn(True, lambda: self.c.pymongo_test.test.group( @@ -440,8 +471,13 @@ class TestCommandAndReadPreference(TestReplicaSetClientBase): # mapreduce fails if no collection self.c.pymongo_test.test.insert({}, w=self.w) - self._test_fn(False, lambda: self.c.pymongo_test.test.map_reduce( - 'function() { }', 'function() { }', 'mr_out')) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + self._test_fn(False, lambda: self.c.pymongo_test.test.map_reduce( + 'function() { }', 'function() { }', 'mr_out')) + finally: + ctx.exit() self._test_fn(True, lambda: self.c.pymongo_test.test.map_reduce( 'function() { }', 'function() { }', {'inline': 1})) @@ -517,83 +553,93 @@ class TestMongosConnection(unittest.TestCase): NEAREST = ReadPreference.NEAREST SLAVE_OKAY = _QUERY_OPTIONS['slave_okay'] - # Test non-PRIMARY modes which can be combined with tags - for kwarg, value, mongos_mode in ( - ('read_preference', PRIMARY_PREFERRED, 'primaryPreferred'), - ('read_preference', SECONDARY, 'secondary'), - ('read_preference', SECONDARY_PREFERRED, 'secondaryPreferred'), - ('read_preference', NEAREST, 'nearest'), - ('slave_okay', True, 'secondaryPreferred'), - ('slave_okay', False, 'primary') - ): - for tag_sets in ( - None, [{}] + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", DeprecationWarning) + # Test non-PRIMARY modes which can be combined with tags + for kwarg, value, mongos_mode in ( + ('read_preference', PRIMARY_PREFERRED, 'primaryPreferred'), + ('read_preference', SECONDARY, 'secondary'), + ('read_preference', SECONDARY_PREFERRED, 'secondaryPreferred'), + ('read_preference', NEAREST, 'nearest'), + ('slave_okay', True, 'secondaryPreferred'), + ('slave_okay', False, 'primary') ): - # Create a client e.g. with read_preference=NEAREST or - # slave_okay=True - c = get_client(tag_sets=tag_sets, **{kwarg: value}) + for tag_sets in ( + None, [{}] + ): + # Create a client e.g. with read_preference=NEAREST or + # slave_okay=True + c = get_client(tag_sets=tag_sets, **{kwarg: value}) - self.assertEqual(is_mongos, c.is_mongos) - cursor = c.pymongo_test.test.find() - if is_mongos: - # We don't set $readPreference for SECONDARY_PREFERRED - # unless tags are in use. slaveOkay has the same effect. - if mongos_mode == 'secondaryPreferred': - self.assertEqual( - None, - cursor._Cursor__query_spec().get('$readPreference')) + self.assertEqual(is_mongos, c.is_mongos) + cursor = c.pymongo_test.test.find() + if is_mongos: + # We don't set $readPreference for SECONDARY_PREFERRED + # unless tags are in use. slaveOkay has the same effect. + if mongos_mode == 'secondaryPreferred': + self.assertEqual( + None, + cursor._Cursor__query_spec().get('$readPreference')) - self.assertTrue( - cursor._Cursor__query_options() & SLAVE_OKAY) + self.assertTrue( + cursor._Cursor__query_options() & SLAVE_OKAY) - # Don't send $readPreference for PRIMARY either - elif mongos_mode == 'primary': - self.assertEqual( - None, - cursor._Cursor__query_spec().get('$readPreference')) + # Don't send $readPreference for PRIMARY either + elif mongos_mode == 'primary': + self.assertEqual( + None, + cursor._Cursor__query_spec().get('$readPreference')) - self.assertFalse( - cursor._Cursor__query_options() & SLAVE_OKAY) + self.assertFalse( + cursor._Cursor__query_options() & SLAVE_OKAY) + else: + self.assertEqual( + {'mode': mongos_mode}, + cursor._Cursor__query_spec().get('$readPreference')) + + self.assertTrue( + cursor._Cursor__query_options() & SLAVE_OKAY) else: + self.assertFalse( + '$readPreference' in cursor._Cursor__query_spec()) + + for tag_sets in ( + [{'dc': 'la'}], + [{'dc': 'la'}, {'dc': 'sf'}], + [{'dc': 'la'}, {'dc': 'sf'}, {}], + ): + if kwarg == 'slave_okay': + # Can't use tags with slave_okay True or False, need a + # real read preference + self.assertRaises( + ConfigurationError, + get_client, tag_sets=tag_sets, **{kwarg: value}) + + continue + + c = get_client(tag_sets=tag_sets, **{kwarg: value}) + + self.assertEqual(is_mongos, c.is_mongos) + cursor = c.pymongo_test.test.find() + if is_mongos: self.assertEqual( - {'mode': mongos_mode}, + {'mode': mongos_mode, 'tags': tag_sets}, cursor._Cursor__query_spec().get('$readPreference')) - - self.assertTrue( - cursor._Cursor__query_options() & SLAVE_OKAY) - else: - self.assertFalse( - '$readPreference' in cursor._Cursor__query_spec()) - - for tag_sets in ( - [{'dc': 'la'}], - [{'dc': 'la'}, {'dc': 'sf'}], - [{'dc': 'la'}, {'dc': 'sf'}, {}], - ): - if kwarg == 'slave_okay': - # Can't use tags with slave_okay True or False, need a - # real read preference - self.assertRaises( - ConfigurationError, - get_client, tag_sets=tag_sets, **{kwarg: value}) - - continue - - c = get_client(tag_sets=tag_sets, **{kwarg: value}) - - self.assertEqual(is_mongos, c.is_mongos) - cursor = c.pymongo_test.test.find() - if is_mongos: - self.assertEqual( - {'mode': mongos_mode, 'tags': tag_sets}, - cursor._Cursor__query_spec().get('$readPreference')) - else: - self.assertFalse( - '$readPreference' in cursor._Cursor__query_spec()) + else: + self.assertFalse( + '$readPreference' in cursor._Cursor__query_spec()) + finally: + ctx.exit() def test_only_secondary_ok_commands_have_read_prefs(self): c = get_client(read_preference=ReadPreference.SECONDARY) - is_mongos = utils.is_mongos(c) + ctx = catch_warnings() + try: + warnings.simplefilter("ignore", UserWarning) + is_mongos = utils.is_mongos(c) + finally: + ctx.exit() if not is_mongos: raise SkipTest("Only mongos have read_prefs added to the spec") diff --git a/test/test_replica_set_client.py b/test/test_replica_set_client.py index cf1bfee6b..803e5949c 100644 --- a/test/test_replica_set_client.py +++ b/test/test_replica_set_client.py @@ -260,7 +260,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin): read_preference=ReadPreference.SECONDARY, tag_sets=copy.deepcopy(tag_sets), secondary_acceptable_latency_ms=77) - c.admin.command('ping') self.assertEqual(c.primary, self.primary) self.assertEqual(c.hosts, self.hosts) self.assertEqual(c.arbiters, self.arbiters) diff --git a/test/utils.py b/test/utils.py index 76cb90a50..b13cccbff 100644 --- a/test/utils.py +++ b/test/utils.py @@ -584,3 +584,83 @@ class _TestLazyConnectMixin(object): self.assertEqual( ismaster['maxMessageSizeBytes'], c.max_message_size) + + +# Backport of WarningMessage from python 2.6, with fixed syntax for python 2.4. +class WarningMessage(object): + + """Holds the result of a single showwarning() call.""" + + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + + def __init__(self, message, category, + filename, lineno, file=None, line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + self._category_name = None + if category: + self._category_name = category.__name__ + + def __str__(self): + return ("{message : %r, category : %r, filename : %r, lineno : %s, " + "line : %r}" % (self.message, self._category_name, + self.filename, self.lineno, self.line)) + + +# Rough backport of warnings.catch_warnings from python 2.6, +# with changes to support python 2.4. +class CatchWarnings(object): + """A non-context manager version of warnings.catch_warnings. + + The 'record' argument specifies whether warnings should be captured by a + custom implementation of warnings.showwarning() and be appended to a list + accessed through the `log` property. The objects appended to the list are + arguments whose attributes mirror the arguments to showwarning(). + + The 'module' argument is to specify an alternative module to the module + named 'warnings' and imported under that name. This argument is only useful + when testing the warnings module itself. + """ + + def __init__(self, record=False, module=None): + self._record = record + if module is None: + self._module = sys.modules['warnings'] + else: + self._module = module + + # No __enter__ so do that work here + self._filters = self._module.filters + self._module.filters = self._filters[:] + self._showwarning = self._module.showwarning + self._log = [] + if self._record: + def showwarning(*args, **kwargs): + self._log.append(WarningMessage(*args, **kwargs)) + self._module.showwarning = showwarning + + @property + def log(self): + """A list of any warnings recorded when using record=True.""" + return self._log + + def __repr__(self): + args = [] + if self._record: + args.append("record=True") + if self._module is not sys.modules['warnings']: + args.append("module=%r" % self._module) + name = type(self).__name__ + return "%s(%s)" % (name, ", ".join(args)) + + def exit(self): + """Revert changes to the warnings module.""" + self._module.filters = self._filters + self._module.showwarning = self._showwarning + + +def catch_warnings(record=False, module=None): + """Helper for use with CatchWarnings.""" + return CatchWarnings(record, module)