Skip to content

Commit 463d759

Browse files
committed
PYTHON-2116 Add __repr__ to monitoring events and description classes
1 parent 8256af6 commit 463d759

File tree

8 files changed

+177
-11
lines changed

8 files changed

+177
-11
lines changed

pymongo/monitoring.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,11 @@ def database_name(self):
561561
"""The name of the database this command was run against."""
562562
return self.__db
563563

564+
def __repr__(self):
565+
return "<%s %s db: %r, command: %r, operation_id: %s>" % (
566+
self.__class__.__name__, self.connection_id, self.database_name,
567+
self.command_name, self.operation_id)
568+
564569

565570
class CommandSucceededEvent(_CommandEvent):
566571
"""Event published when a command succeeds.
@@ -596,6 +601,11 @@ def reply(self):
596601
"""The server failure document for this operation."""
597602
return self.__reply
598603

604+
def __repr__(self):
605+
return "<%s %s command: %r, operation_id: %s, duration_micros: %s>" % (
606+
self.__class__.__name__, self.connection_id,
607+
self.command_name, self.operation_id, self.duration_micros)
608+
599609

600610
class CommandFailedEvent(_CommandEvent):
601611
"""Event published when a command fails.
@@ -626,6 +636,13 @@ def failure(self):
626636
"""The server failure document for this operation."""
627637
return self.__failure
628638

639+
def __repr__(self):
640+
return (
641+
"<%s %s command: %r, operation_id: %s, duration_micros: %s, "
642+
"failure: %r>" % (
643+
self.__class__.__name__, self.connection_id, self.command_name,
644+
self.operation_id, self.duration_micros, self.failure))
645+
629646

630647
class _PoolEvent(object):
631648
"""Base class for pool events."""
@@ -928,6 +945,10 @@ def topology_id(self):
928945
"""A unique identifier for the topology this server is a part of."""
929946
return self.__topology_id
930947

948+
def __repr__(self):
949+
return "<%s %s topology_id: %s>" % (
950+
self.__class__.__name__, self.server_address, self.topology_id)
951+
931952

932953
class ServerDescriptionChangedEvent(_ServerEvent):
933954
"""Published when server description changes.
@@ -954,6 +975,11 @@ def new_description(self):
954975
:class:`~pymongo.server_description.ServerDescription`."""
955976
return self.__new_description
956977

978+
def __repr__(self):
979+
return "<%s %s changed from: %s, to: %s>" % (
980+
self.__class__.__name__, self.server_address,
981+
self.previous_description, self.new_description)
982+
957983

958984
class ServerOpeningEvent(_ServerEvent):
959985
"""Published when server is initialized.
@@ -986,6 +1012,10 @@ def topology_id(self):
9861012
"""A unique identifier for the topology this server is a part of."""
9871013
return self.__topology_id
9881014

1015+
def __repr__(self):
1016+
return "<%s topology_id: %s>" % (
1017+
self.__class__.__name__, self.topology_id)
1018+
9891019

9901020
class TopologyDescriptionChangedEvent(TopologyEvent):
9911021
"""Published when the topology description changes.
@@ -1012,6 +1042,11 @@ def new_description(self):
10121042
:class:`~pymongo.topology_description.TopologyDescription`."""
10131043
return self.__new_description
10141044

1045+
def __repr__(self):
1046+
return "<%s topology_id: %s changed from: %s, to: %s>" % (
1047+
self.__class__.__name__, self.topology_id,
1048+
self.previous_description, self.new_description)
1049+
10151050

10161051
class TopologyOpenedEvent(TopologyEvent):
10171052
"""Published when the topology is initialized.
@@ -1045,6 +1080,9 @@ def connection_id(self):
10451080
to."""
10461081
return self.__connection_id
10471082

1083+
def __repr__(self):
1084+
return "<%s %s>" % (self.__class__.__name__, self.connection_id)
1085+
10481086

10491087
class ServerHeartbeatStartedEvent(_ServerHeartbeatEvent):
10501088
"""Published when a heartbeat is started.
@@ -1078,6 +1116,11 @@ def reply(self):
10781116
"""An instance of :class:`~pymongo.ismaster.IsMaster`."""
10791117
return self.__reply
10801118

1119+
def __repr__(self):
1120+
return "<%s %s duration: %s, reply: %s>" % (
1121+
self.__class__.__name__, self.connection_id,
1122+
self.duration, self.reply)
1123+
10811124

10821125
class ServerHeartbeatFailedEvent(_ServerHeartbeatEvent):
10831126
"""Fired when the server heartbeat fails, either with an "ok: 0"
@@ -1103,6 +1146,11 @@ def reply(self):
11031146
"""A subclass of :exc:`Exception`."""
11041147
return self.__reply
11051148

1149+
def __repr__(self):
1150+
return "<%s %s duration: %s, reply: %r>" % (
1151+
self.__class__.__name__, self.connection_id,
1152+
self.duration, self.reply)
1153+
11061154

11071155
class _EventListeners(object):
11081156
"""Configure event listeners for a client instance.

pymongo/server.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,5 @@ def _split_message(self, message):
225225
request_id, data = message
226226
return request_id, data, 0
227227

228-
def __str__(self):
229-
d = self._description
230-
return '<Server "%s:%s" %s>' % (
231-
d.address[0], d.address[1],
232-
SERVER_TYPE._fields[d.server_type])
228+
def __repr__(self):
229+
return '<%s %r>' % (self.__class__.__name__, self._description)

pymongo/server_description.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,5 +228,13 @@ def __eq__(self, other):
228228
def __ne__(self, other):
229229
return not self == other
230230

231+
def __repr__(self):
232+
errmsg = ''
233+
if self.error:
234+
errmsg = ', error=%r' % (self.error,)
235+
return "<%s %s server_type: %s, rtt: %s%s>" % (
236+
self.__class__.__name__, self.address, self.server_type_name,
237+
self.round_trip_time, errmsg)
238+
231239
# For unittesting only. Use under no circumstances!
232240
_host_to_round_trip_time = {}

pymongo/topology.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,3 +686,9 @@ def _error_message(self, selector):
686686
else:
687687
return ','.join(str(server.error) for server in servers
688688
if server.error)
689+
690+
def __repr__(self):
691+
msg = ''
692+
if not self._opened:
693+
msg = 'CLOSED '
694+
return '<%s %s%r>' % (self.__class__.__name__, msg, self._description)

pymongo/topology_description.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ def has_writable_server(self):
288288
"""
289289
return self.has_readable_server(ReadPreference.PRIMARY)
290290

291+
def __repr__(self):
292+
return "<%s id: %s, topology_type: %s, servers: %r>" % (
293+
self.__class__.__name__, self._topology_settings._topology_id,
294+
self.topology_type_name, list(self._server_descriptions.values()))
295+
291296

292297
# If topology type is Unknown and we receive an ismaster response, what should
293298
# the new topology type be?

test/test_monitoring.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,5 +1347,91 @@ def test_simple(self):
13471347
self.assertTrue(isinstance(started.request_id, int))
13481348

13491349

1350+
class TestEventClasses(PyMongoTestCase):
1351+
1352+
def test_command_event_repr(self):
1353+
request_id, connection_id, operation_id = 1, ('localhost', 27017), 2
1354+
event = monitoring.CommandStartedEvent(
1355+
{'isMaster': 1}, 'admin', request_id, connection_id, operation_id)
1356+
self.assertEqual(
1357+
repr(event),
1358+
"<CommandStartedEvent ('localhost', 27017) db: 'admin', "
1359+
"command: 'isMaster', operation_id: 2>")
1360+
delta = datetime.timedelta(milliseconds=100)
1361+
event = monitoring.CommandSucceededEvent(
1362+
delta, {'ok': 1}, 'isMaster', request_id, connection_id,
1363+
operation_id)
1364+
self.assertEqual(
1365+
repr(event),
1366+
"<CommandSucceededEvent ('localhost', 27017) "
1367+
"command: 'isMaster', operation_id: 2, duration_micros: 100000>")
1368+
event = monitoring.CommandFailedEvent(
1369+
delta, {'ok': 0}, 'isMaster', request_id, connection_id,
1370+
operation_id)
1371+
self.assertEqual(
1372+
repr(event),
1373+
"<CommandFailedEvent ('localhost', 27017) "
1374+
"command: 'isMaster', operation_id: 2, duration_micros: 100000, "
1375+
"failure: {'ok': 0}>")
1376+
1377+
def test_server_heartbeat_event_repr(self):
1378+
connection_id = ('localhost', 27017)
1379+
event = monitoring.ServerHeartbeatStartedEvent(connection_id)
1380+
self.assertEqual(
1381+
repr(event),
1382+
"<ServerHeartbeatStartedEvent ('localhost', 27017)>")
1383+
delta = 0.1
1384+
event = monitoring.ServerHeartbeatSucceededEvent(
1385+
delta, {'ok': 1}, connection_id)
1386+
self.assertEqual(
1387+
repr(event),
1388+
"<ServerHeartbeatSucceededEvent ('localhost', 27017) "
1389+
"duration: 0.1, reply: {'ok': 1}>")
1390+
event = monitoring.ServerHeartbeatFailedEvent(
1391+
delta, 'ERROR', connection_id)
1392+
self.assertEqual(
1393+
repr(event),
1394+
"<ServerHeartbeatFailedEvent ('localhost', 27017) "
1395+
"duration: 0.1, reply: 'ERROR'>")
1396+
1397+
def test_server_event_repr(self):
1398+
server_address = ('localhost', 27017)
1399+
topology_id = ObjectId('000000000000000000000001')
1400+
event = monitoring.ServerOpeningEvent(server_address, topology_id)
1401+
self.assertEqual(
1402+
repr(event),
1403+
"<ServerOpeningEvent ('localhost', 27017) "
1404+
"topology_id: 000000000000000000000001>")
1405+
event = monitoring.ServerDescriptionChangedEvent(
1406+
'PREV', 'NEW', server_address, topology_id)
1407+
self.assertEqual(
1408+
repr(event),
1409+
"<ServerDescriptionChangedEvent ('localhost', 27017) "
1410+
"changed from: PREV, to: NEW>")
1411+
event = monitoring.ServerClosedEvent(server_address, topology_id)
1412+
self.assertEqual(
1413+
repr(event),
1414+
"<ServerClosedEvent ('localhost', 27017) "
1415+
"topology_id: 000000000000000000000001>")
1416+
1417+
def test_topology_event_repr(self):
1418+
topology_id = ObjectId('000000000000000000000001')
1419+
event = monitoring.TopologyOpenedEvent(topology_id)
1420+
self.assertEqual(
1421+
repr(event),
1422+
"<TopologyOpenedEvent topology_id: 000000000000000000000001>")
1423+
event = monitoring.TopologyDescriptionChangedEvent(
1424+
'PREV', 'NEW', topology_id)
1425+
self.assertEqual(
1426+
repr(event),
1427+
"<TopologyDescriptionChangedEvent "
1428+
"topology_id: 000000000000000000000001 "
1429+
"changed from: PREV, to: NEW>")
1430+
event = monitoring.TopologyClosedEvent(topology_id)
1431+
self.assertEqual(
1432+
repr(event),
1433+
"<TopologyClosedEvent topology_id: 000000000000000000000001>")
1434+
1435+
13501436
if __name__ == "__main__":
13511437
unittest.main()

test/test_server_description.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ def test_all_hosts(self):
160160
[('a', 27017), ('b', 27018), ('c', 27017)],
161161
sorted(s.all_hosts))
162162

163+
def test_repr(self):
164+
s = parse_ismaster_response({'ok': 1, 'msg': 'isdbgrid'})
165+
self.assertEqual(repr(s),
166+
"<ServerDescription ('localhost', 27017)"
167+
" server_type: Mongos, rtt: None>")
168+
163169

164170
if __name__ == "__main__":
165171
unittest.main()

test/test_topology.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,6 @@ def setUp(self):
114114
self.addCleanup(self.client_knobs.disable)
115115

116116

117-
# Use assertRaisesRegex if available, otherwise use Python 2.7's
118-
# deprecated assertRaisesRegexp, with a 'p'.
119-
if not hasattr(unittest.TestCase, 'assertRaisesRegex'):
120-
TopologyTest.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
121-
122-
123117
class TestTopologyConfiguration(TopologyTest):
124118
def test_timeout_configuration(self):
125119
pool_options = PoolOptions(connect_timeout=1, socket_timeout=2)
@@ -623,6 +617,22 @@ def write_batch_size():
623617

624618
self.assertEqual(2, write_batch_size())
625619

620+
def test_topology_repr(self):
621+
t = create_mock_topology(replica_set_name='rs')
622+
self.addCleanup(t.close)
623+
got_ismaster(t, ('a', 27017), {
624+
'ok': 1,
625+
'ismaster': True,
626+
'setName': 'rs',
627+
'hosts': ['a', 'b']})
628+
self.assertEqual(
629+
repr(t.description),
630+
"<TopologyDescription id: %s, "
631+
"topology_type: ReplicaSetWithPrimary, servers: ["
632+
"<ServerDescription ('a', 27017) server_type: RSPrimary, rtt: 0>, "
633+
"<ServerDescription ('b', 27017) server_type: Unknown,"
634+
" rtt: None>]>" % (t._topology_id,))
635+
626636

627637
def wait_for_master(topology):
628638
"""Wait for a Topology to discover a writable server.

0 commit comments

Comments
 (0)