diff --git a/bson/codec_options.py b/bson/codec_options.py index 6ea5708c1..deeff0cc3 100644 --- a/bson/codec_options.py +++ b/bson/codec_options.py @@ -43,7 +43,7 @@ class CodecOptions(_options_base): def __new__(cls, as_class=dict, tz_aware=False, uuid_representation=PYTHON_LEGACY): if not issubclass(as_class, MutableMapping): - raise TypeError("document_class must be dict, bson.son.SON, or " + raise TypeError("as_class must be dict, bson.son.SON, or " "another subclass of collections.MutableMapping") if not isinstance(tz_aware, bool): raise TypeError("tz_aware must be True or False") diff --git a/doc/api/pymongo/mongo_client.rst b/doc/api/pymongo/mongo_client.rst index 189ac1677..07a99d007 100644 --- a/doc/api/pymongo/mongo_client.rst +++ b/doc/api/pymongo/mongo_client.rst @@ -15,14 +15,10 @@ Raises :class:`~pymongo.errors.InvalidName` if an invalid database name is used. .. autoattribute:: address - .. autoattribute:: host - .. autoattribute:: port .. autoattribute:: is_primary .. autoattribute:: is_mongos .. autoattribute:: max_pool_size .. autoattribute:: nodes - .. autoattribute:: document_class - .. autoattribute:: tz_aware .. autoattribute:: max_bson_size .. autoattribute:: max_message_size .. autoattribute:: min_wire_version diff --git a/doc/api/pymongo/mongo_replica_set_client.rst b/doc/api/pymongo/mongo_replica_set_client.rst index 22c7887f0..386442e40 100644 --- a/doc/api/pymongo/mongo_replica_set_client.rst +++ b/doc/api/pymongo/mongo_replica_set_client.rst @@ -17,10 +17,7 @@ .. autoattribute:: primary .. autoattribute:: secondaries .. autoattribute:: arbiters - .. autoattribute:: is_mongos .. autoattribute:: max_pool_size - .. autoattribute:: document_class - .. autoattribute:: tz_aware .. autoattribute:: max_bson_size .. autoattribute:: max_message_size .. autoattribute:: min_wire_version @@ -32,4 +29,7 @@ .. automethod:: database_names .. automethod:: drop_database .. automethod:: get_default_database + .. automethod:: get_database .. automethod:: close_cursor + .. automethod:: kill_cursors + .. automethod:: set_cursor_manager diff --git a/doc/changelog.rst b/doc/changelog.rst index 57c436821..011da6f29 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -87,6 +87,9 @@ The ``copy_database`` method is removed, see the The ``disconnect`` method is removed. Use :meth:`~pymongo.mongo_client.MongoClient.close` instead. +The ``get_document_class`` method is removed. Use +:attr:`~pymongo.mongo_client.MongoClient.codec_options` instead. + The ``get_lasterror_options``, ``set_lasterror_options``, and ``unset_lasterror_options`` methods are removed. Write concern options can be passed to :class:`~pymongo.mongo_client.MongoClient` as keyword @@ -96,7 +99,7 @@ The :meth:`~pymongo.mongo_client.MongoClient.get_database` method is added for getting a Database instance with its options configured differently than the MongoClient's. -The following attributes have been added: +The following read-only attributes have been added: - :attr:`~pymongo.mongo_client.MongoClient.codec_options` @@ -107,9 +110,17 @@ The following attributes are now read-only: The following attributes have been removed: +- :attr:`~pymongo.mongo_client.MongoClient.document_class` + (use :attr:`~pymongo.mongo_client.MongoClient.codec_options` instead) +- :attr:`~pymongo.mongo_client.MongoClient.host` + (use :attr:`~pymongo.mongo_client.MongoClient.address` instead) +- :attr:`~pymongo.mongo_client.MongoClient.port` + (use :attr:`~pymongo.mongo_client.MongoClient.address` instead) - :attr:`~pymongo.mongo_client.MongoClient.safe` - :attr:`~pymongo.mongo_client.MongoClient.slave_okay` - :attr:`~pymongo.mongo_client.MongoClient.tag_sets` +- :attr:`~pymongo.mongo_client.MongoClient.tz_aware` + (use :attr:`~pymongo.mongo_client.MongoClient.codec_options` instead) The following attributes have been renamed: @@ -143,7 +154,7 @@ parameter. The ``connection`` property is renamed to :attr:`~pymongo.database.Database.client`. -The following attributes have been added: +The following read-only attributes have been added: - :attr:`~pymongo.database.Database.codec_options` @@ -192,7 +203,7 @@ The ``get_lasterror_options``, ``set_lasterror_options``, and :class:`~pymongo.collection.Collection` changes ............................................... -The following attributes have been added: +The following read-only attributes have been added: - :attr:`~pymongo.collection.Collection.codec_options` diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 428a0d4a1..add8c88d9 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -264,7 +264,7 @@ class MongoClient(common.BaseObject): client['__my_database__'] - Not: + Not:: client.__my_database__ """ @@ -462,28 +462,6 @@ class MongoClient(common.BaseObject): except ConnectionFailure: return default - @property - def host(self): - """Hostname of the standalone, primary, or mongos currently in use. - - .. warning:: An application that accesses :attr:`host` and :attr:`port` - is vulnerable to a race condition, if the client switches to a - new primary or mongos in between. Use :attr:`address` instead. - """ - address = self.address - return address[0] if address else None - - @property - def port(self): - """Port of the standalone, primary, or mongos currently in use. - - .. warning:: An application that accesses :attr:`host` and :attr:`port` - is vulnerable to a race condition, if the client switches to a - new primary or mongos in between. Use :attr:`address` instead. - """ - address = self.address - return address[1] if address else None - @property def address(self): """(host, port) of the current standalone, primary, or mongos, or None. @@ -506,7 +484,9 @@ class MongoClient(common.BaseObject): def primary(self): """The (host, port) of the current primary of the replica set. - Returns None if there is no primary. + Returns ``None`` if this client is not connected to a replica set, + there is no primary, or this client was created without the + `replicaSet` option. .. versionadded:: 3.0 MongoClient gained this property in version 3.0 when @@ -518,7 +498,9 @@ class MongoClient(common.BaseObject): def secondaries(self): """The secondary members known to this client. - A sequence of (host, port) pairs. + A sequence of (host, port) pairs. Empty if this client is not + connected to a replica set, there are no visible secondaries, or this + client was created without the `replicaSet` option. .. versionadded:: 3.0 MongoClient gained this property in version 3.0 when @@ -531,13 +513,14 @@ class MongoClient(common.BaseObject): """Arbiters in the replica set. A sequence of (host, port) pairs. Empty if this client is not - connected to a replica set. + connected to a replica set, there are no arbiters, or this client was + created without the `replicaSet` option. """ return self._topology.get_arbiters() @property def is_primary(self): - """If the current server can accept writes. + """If this client if connected to a server that can accept writes. True if the current server is a standalone, mongos, or the primary of a replica set. @@ -571,32 +554,6 @@ class MongoClient(common.BaseObject): description = self._topology.description return frozenset(s.address for s in description.known_servers) - @property - def document_class(self): - """Default class to use for documents returned from this client. - - .. versionchanged:: 3.0 - Now read-only. - """ - return self.__options.codec_options.as_class - - def get_document_class(self): - """Default class to use for documents returned from this client. - - Deprecated; use the document_class property instead. - """ - warnings.warn('get_document_class() is deprecated, use the' - ' document_class property', - DeprecationWarning, stacklevel=2) - - return self.__options.codec_options.as_class - - @property - def tz_aware(self): - """Does this client return timezone-aware datetimes? - """ - return self.__options.codec_options.tz_aware - @property def max_bson_size(self): """The largest BSON object the connected server accepts in bytes. diff --git a/pymongo/topology.py b/pymongo/topology.py index 9b5659a4e..274946db5 100644 --- a/pymongo/topology.py +++ b/pymongo/topology.py @@ -178,7 +178,7 @@ class Topology(object): topology_type = self._description.topology_type if topology_type not in (TOPOLOGY_TYPE.ReplicaSetWithPrimary, TOPOLOGY_TYPE.ReplicaSetNoPrimary): - return [] + return set() descriptions = selector(self._description.known_servers) return set([d.address for d in descriptions]) diff --git a/test/test_client.py b/test/test_client.py index 3a36063e0..c91a7ab55 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -206,16 +206,11 @@ class TestClient(IntegrationTest): self.assertIsInstance(c.max_pool_size, int) self.assertIsInstance(c.nodes, frozenset) - with ignore_deprecations(): - self.assertEqual(dict, c.get_document_class()) - - self.assertIsInstance(c.tz_aware, bool) + self.assertEqual(c.codec_options, CodecOptions()) self.assertIsInstance(c.max_bson_size, int) self.assertIsInstance(c.min_wire_version, int) self.assertIsInstance(c.max_wire_version, int) self.assertIsInstance(c.max_write_batch_size, int) - self.assertEqual(None, c.host) - self.assertEqual(None, c.port) self.assertFalse(c.primary) self.assertFalse(c.secondaries) @@ -272,8 +267,7 @@ class TestClient(IntegrationTest): self.assertIn("%s:%d" % node, repr(self.client)) def test_getters(self): - self.assertEqual(client_context.client.host, host) - self.assertEqual(client_context.client.port, port) + self.assertEqual(client_context.client.address, (host, port)) self.assertEqual(client_context.nodes, self.client.nodes) def test_database_names(self): @@ -470,23 +464,16 @@ class TestClient(IntegrationTest): db = c.pymongo_test db.test.insert_one({"x": 1}) - self.assertEqual(dict, c.document_class) + self.assertEqual(dict, c.codec_options.as_class) self.assertTrue(isinstance(db.test.find_one(), dict)) self.assertFalse(isinstance(db.test.find_one(), SON)) c = rs_or_single_client(document_class=SON) db = c.pymongo_test - self.assertEqual(SON, c.document_class) + self.assertEqual(SON, c.codec_options.as_class) self.assertTrue(isinstance(db.test.find_one(), SON)) - # document_class is read-only in PyMongo 3.0. - with self.assertRaises(AttributeError): - c.document_class = dict - - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - self.assertRaises(DeprecationWarning, c.get_document_class) def test_timeouts(self): client = rs_or_single_client(connectTimeoutMS=10500) @@ -1070,8 +1057,7 @@ class TestMongoClientFailover(MockClientTest): replicaSet='rs') wait_until(lambda: len(c.nodes) == 3, 'connect') - self.assertEqual('a', c.host) - self.assertEqual(1, c.port) + self.assertEqual(c.address, ('a', 1)) # Fail over. c.kill_host('a:1') @@ -1082,8 +1068,7 @@ class TestMongoClientFailover(MockClientTest): t = c._get_topology() t.select_servers(writable_server_selector) # Reconnect. - self.assertEqual('b', c.host) - self.assertEqual(2, c.port) + self.assertEqual(c.address, ('b', 2)) # a:1 not longer in nodes. self.assertLess(len(c.nodes), 3) @@ -1113,8 +1098,7 @@ class TestMongoClientFailover(MockClientTest): # But it can reconnect. c.revive_host('a:1') c._get_topology().select_servers(writable_server_selector) - self.assertEqual('a', c.host) - self.assertEqual(1, c.port) + self.assertEqual(c.address, ('a', 1)) def test_network_error_on_operation(self): # Verify only the disconnected server is reset by a network failure. diff --git a/test/test_replica_set_client.py b/test/test_replica_set_client.py index 67222665e..87dcf7ca0 100644 --- a/test/test_replica_set_client.py +++ b/test/test_replica_set_client.py @@ -21,6 +21,7 @@ import time sys.path[0:0] = [""] +from bson.codec_options import CodecOptions from bson.py3compat import u from bson.son import SON from pymongo.common import partition_node @@ -124,12 +125,11 @@ class TestReplicaSetClient(TestReplicaSetClientBase): self.assertEqual(c.secondaries, self.secondaries) self.assertEqual(c.arbiters, self.arbiters) self.assertEqual(c.max_pool_size, 100) - self.assertEqual(c.document_class, dict) - self.assertEqual(c.tz_aware, False) # Make sure MongoClient's properties are copied to Database and # Collection. for obj in c, c.pymongo_test, c.pymongo_test.test: + self.assertEqual(obj.codec_options, CodecOptions()) self.assertEqual(obj.read_preference, ReadPreference.PRIMARY) self.assertEqual(obj.write_concern, WriteConcern()) @@ -143,14 +143,14 @@ class TestReplicaSetClient(TestReplicaSetClientBase): pair, replicaSet=self.name, max_pool_size=25, document_class=SON, tz_aware=True, read_preference=secondary, - localThresholdMS=77) + localThresholdMS=77, j=True) self.assertEqual(c.max_pool_size, 25) - self.assertEqual(c.document_class, SON) - self.assertEqual(c.tz_aware, True) for obj in c, c.pymongo_test, c.pymongo_test.test: + self.assertEqual(obj.codec_options, CodecOptions(SON, True)) self.assertEqual(obj.read_preference, secondary) + self.assertEqual(obj.write_concern, WriteConcern(j=True)) cursor = c.pymongo_test.test.find() self.assertEqual( diff --git a/test/test_replica_set_reconfig.py b/test/test_replica_set_reconfig.py index e1b5e9e3d..ffff2634d 100644 --- a/test/test_replica_set_reconfig.py +++ b/test/test_replica_set_reconfig.py @@ -43,8 +43,8 @@ class TestSecondaryBecomesStandalone(MockClientTest): replicaSet='rs') # MongoClient connects to primary by default. - wait_until(lambda: c.host == 'a', 'connect to primary') - self.assertEqual(1, c.port) + wait_until(lambda: c.address is not None, 'connect to primary') + self.assertEqual(c.address, ('a', 1)) # C is brought up as a standalone. c.mock_members.remove('c:3') @@ -60,8 +60,7 @@ class TestSecondaryBecomesStandalone(MockClientTest): with self.assertRaises(AutoReconnect): c.db.command('ismaster') - self.assertEqual(None, c.host) - self.assertEqual(None, c.port) + self.assertEqual(c.address, None) def test_replica_set_client(self): c = MockClient( @@ -144,8 +143,7 @@ class TestSecondaryAdded(MockClientTest): wait_until(lambda: len(c.nodes) == 2, 'discover both nodes') # MongoClient connects to primary by default. - self.assertEqual('a', c.host) - self.assertEqual(1, c.port) + self.assertEqual(c.address, ('a', 1)) self.assertEqual(set([('a', 1), ('b', 2)]), c.nodes) # C is added. @@ -155,8 +153,7 @@ class TestSecondaryAdded(MockClientTest): c.close() c.db.command('ismaster') - self.assertEqual('a', c.host) - self.assertEqual(1, c.port) + self.assertEqual(c.address, ('a', 1)) wait_until(lambda: set([('a', 1), ('b', 2), ('c', 3)]) == c.nodes, 'reconnect to both secondaries')