From 418960607df669f40d1c5b6fddd2e17b6a519f55 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 4 Jul 2023 16:56:09 +0100 Subject: [PATCH] Fully qualify class names in repr(), add selected state information This is intended to disambiguate objects in log and debug output. --- ansible_mitogen/planner.py | 5 +++- ansible_mitogen/runner.py | 2 +- mitogen/core.py | 59 ++++++++++++++++++++++++------------- mitogen/fakessh.py | 11 ++++--- mitogen/master.py | 10 +++---- mitogen/parent.py | 25 +++++++++++----- mitogen/service.py | 9 ++++-- tests/importer_test.py | 5 ++++ tests/message_test.py | 18 +++++++++-- tests/module_finder_test.py | 4 +-- 10 files changed, 102 insertions(+), 46 deletions(-) diff --git a/ansible_mitogen/planner.py b/ansible_mitogen/planner.py index 0b1b7aab..051506b5 100644 --- a/ansible_mitogen/planner.py +++ b/ansible_mitogen/planner.py @@ -113,7 +113,10 @@ class Invocation(object): return self._module_source def __repr__(self): - return 'Invocation(module_name=%s)' % (self.module_name,) + return '%s.%s(module_name=%r)' % ( + __name__, self.__class__.__name__, + self.module_name, + ) class Planner(object): diff --git a/ansible_mitogen/runner.py b/ansible_mitogen/runner.py index c4cb71ff..900a2461 100644 --- a/ansible_mitogen/runner.py +++ b/ansible_mitogen/runner.py @@ -185,7 +185,7 @@ class EnvironmentFileWatcher(object): LOG.debug('%r installed; existing keys: %r', self, self._keys) def __repr__(self): - return 'EnvironmentFileWatcher(%r)' % (self.path,) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.path) def _stat(self): try: diff --git a/mitogen/core.py b/mitogen/core.py index bee722e6..67f895d6 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -294,7 +294,7 @@ class Kwargs(dict): self[k] = v def __repr__(self): - return 'Kwargs(%s)' % (dict.__repr__(self),) + return '%s(%s)' % (self.__class__.__name__, dict.__repr__(self),) def __reduce__(self): return (Kwargs, (dict(self),)) @@ -979,7 +979,8 @@ class Message(object): return obj def __repr__(self): - return 'Message(%r, %r, %r, %r, %r, %r..%d)' % ( + return '%s.%s(dst_id=%r, src_id=%r, auth_id=%r, handle=%r, reply_to=%r, data=%r..%d)' % ( + __name__, self.__class__.__name__, self.dst_id, self.src_id, self.auth_id, self.handle, self.reply_to, (self.data or '')[:50], len(self.data) ) @@ -1025,7 +1026,10 @@ class Sender(object): ) def __repr__(self): - return 'Sender(%r, %r)' % (self.context, self.dst_handle) + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.context, self.dst_handle, + ) def __reduce__(self): return _unpickle_sender, (self.context.context_id, self.dst_handle) @@ -1087,7 +1091,10 @@ class Receiver(object): ) def __repr__(self): - return 'Receiver(%r, %r)' % (self.router, self.handle) + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.router, self.handle, + ) def __enter__(self): return self @@ -1237,7 +1244,8 @@ class Channel(Sender, Receiver): Sender.close(self) def __repr__(self): - return 'Channel(%s, %s)' % ( + return '%s.%s(%s, %s)' % ( + __name__, self.__class__.__name__, Sender.__repr__(self), Receiver.__repr__(self) ) @@ -1351,7 +1359,7 @@ class Importer(object): ) def __repr__(self): - return 'Importer' + return '%s.%s()' % (__name__, self.__class__.__name__) def builtin_find_module(self, fullname): # imp.find_module() will always succeed for __main__, because it is a @@ -1719,7 +1727,10 @@ class Stream(object): self.transmit_side = Side(self, wfp) def __repr__(self): - return "" % (self.name, id(self) & 0xffff,) + return "<%s.%s %r #%04x>" % ( + __name__, self.__class__.__name__, + self.name, id(self) & 0xffff, + ) def on_receive(self, broker): """ @@ -1812,8 +1823,8 @@ class Protocol(object): return stream def __repr__(self): - return '%s(%s)' % ( - self.__class__.__name__, + return '%s.%s(%r)' % ( + __name__, self.__class__.__name__, self.stream and self.stream.name, ) @@ -2008,8 +2019,9 @@ class Side(object): set_nonblock(self.fd) def __repr__(self): - return '' % ( - self.stream.name or repr(self.stream), + return '<%s.%s of %r fd %r>' % ( + __name__, self.__class__.__name__, + self.stream.name or self.stream, self.fd ) @@ -2334,7 +2346,10 @@ class Context(object): return data def __repr__(self): - return 'Context(%s, %r)' % (self.context_id, self.name) + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.context_id, self.name, + ) def _unpickle_context(context_id, name, router=None): @@ -2397,7 +2412,10 @@ class Poller(object): self._wfds = {} def __repr__(self): - return '%s' % (type(self).__name__,) + return '<%s.%s with %d readers %d writers>' % ( + __name__, self.__class__.__name__, + len(self._rfds), len(self._wfds), + ) def _update(self, fd): """ @@ -2769,7 +2787,8 @@ class Latch(object): assert written == len(cookie) and not disconnected def __repr__(self): - return 'Latch(%#x, size=%d, t=%r)' % ( + return '%s.%s(%#x, size=%d, thread=%r)' % ( + __name__, self.__class__.__name__, id(self), len(self._queue), threading__thread_name(threading__current_thread()), @@ -2798,9 +2817,9 @@ class Waker(Protocol): self._deferred = collections.deque() def __repr__(self): - return 'Waker(fd=%r/%r)' % ( - self.stream.receive_side and self.stream.receive_side.fd, - self.stream.transmit_side and self.stream.transmit_side.fd, + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.stream.receive_side, self.stream.transmit_side, ) @property @@ -2990,7 +3009,7 @@ class Router(object): self.add_handler(self._on_del_route, DEL_ROUTE) def __repr__(self): - return 'Router(%r)' % (self.broker,) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.broker) def _setup_logging(self): """ @@ -3626,7 +3645,7 @@ class Broker(object): self._thread.join() def __repr__(self): - return 'Broker(%04x)' % (id(self) & 0xffff,) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.poller) class Dispatcher(object): @@ -3643,7 +3662,7 @@ class Dispatcher(object): _service_recv = None def __repr__(self): - return 'Dispatcher' + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.econtext) def __init__(self, econtext): self.econtext = econtext diff --git a/mitogen/fakessh.py b/mitogen/fakessh.py index 2d660248..66bed85a 100644 --- a/mitogen/fakessh.py +++ b/mitogen/fakessh.py @@ -159,9 +159,9 @@ class IoPump(mitogen.core.Protocol): self.on_disconnect(broker) def __repr__(self): - return 'IoPump(%r, %r)' % ( - self.receive_side.fp.fileno(), - self.transmit_side.fp.fileno(), + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.receive_side, self.transmit_side, ) @@ -191,7 +191,10 @@ class Process(object): pmon.add(proc.pid, self._on_proc_exit) def __repr__(self): - return 'Process(%r, %r)' % (self.stdin, self.stdout) + return '%s.%s(%r, %r, %r)' % ( + __name__, self.__class__.__name__, + self.router, self.stdin, self.stdout, + ) def _on_proc_exit(self, status): LOG.debug('%r._on_proc_exit(%r)', self, status) diff --git a/mitogen/master.py b/mitogen/master.py index 4fb535f0..1141c190 100644 --- a/mitogen/master.py +++ b/mitogen/master.py @@ -451,7 +451,7 @@ class LogForwarder(object): logger.handle(record) def __repr__(self): - return 'LogForwarder(%r)' % (self._router,) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self._router) class FinderMethod(object): @@ -461,7 +461,7 @@ class FinderMethod(object): simple task, right? Naive young fellow, welcome to the real world. """ def __repr__(self): - return '%s()' % (type(self).__name__,) + return '%s.%s()' % (__name__, self.__class__.__name__) def find(self, fullname): """ @@ -813,7 +813,7 @@ class ModuleFinder(object): self._related_cache = {} def __repr__(self): - return 'ModuleFinder()' + return '%s.%s()' % (__name__, self.__class__.__name__) def add_source_override(self, fullname, path, source, is_pkg): """ @@ -995,7 +995,7 @@ class ModuleResponder(object): ) def __repr__(self): - return 'ModuleResponder' + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self._router) def add_source_override(self, fullname, path, source, is_pkg): """ @@ -1412,7 +1412,7 @@ class IdAllocator(object): ) def __repr__(self): - return 'IdAllocator(%r)' % (self.router,) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.router) def allocate(self): """ diff --git a/mitogen/parent.py b/mitogen/parent.py index 32aa3cb6..2e4f1488 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -592,7 +592,10 @@ class Timer(object): self.func = func def __repr__(self): - return 'Timer(%r, %r)' % (self.when, self.func) + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.when, self.func, + ) def __eq__(self, other): return self.when == other.when @@ -1399,7 +1402,9 @@ class Connection(object): self._router = router def __repr__(self): - return 'Connection(%r)' % (self.stdio_stream,) + return '%s.%s(stdio_stream=%r)' % ( + __name__, self.__class__.__name__, self.stdio_stream, + ) # Minimised, gzipped, base64'd and passed to 'python -c'. It forks, dups # file descriptor 0 as 100, creates a pipe, then execs a new interpreter @@ -1832,7 +1837,7 @@ class CallChain(object): ) def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, self.context) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.context) def __enter__(self): return self @@ -2112,7 +2117,10 @@ class RouteMonitor(object): ) def __repr__(self): - return 'RouteMonitor()' + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, + self.router, self.parent, + ) def _send_one(self, stream, handle, target_id, name): """ @@ -2653,8 +2661,8 @@ class Process(object): self.stderr = stderr def __repr__(self): - return '%s %s pid %d' % ( - type(self).__name__, + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, self.name, self.pid, ) @@ -2711,7 +2719,10 @@ class ModuleForwarder(object): ) def __repr__(self): - return 'ModuleForwarder' + return '%s.%s(%r, %r, %r)' % ( + __name__, self.__class__.__name__, + self.router, self.parent_context, self.importer, + ) def _on_forward_module(self, msg): if msg.is_dead: diff --git a/mitogen/service.py b/mitogen/service.py index 0e5f6419..81bd5a56 100644 --- a/mitogen/service.py +++ b/mitogen/service.py @@ -262,7 +262,7 @@ class Invoker(object): self.service = service def __repr__(self): - return '%s(%s)' % (type(self).__name__, self.service) + return '%s.%s(%r)' % (__name__, self.__class__.__name__, self.service) unauthorized_msg = ( 'Caller is not authorized to invoke %r of service %r' @@ -448,7 +448,9 @@ class Service(object): self.select = mitogen.select.Select() def __repr__(self): - return '%s()' % (self.__class__.__name__,) + return '%s.%s(%r, %r)' % ( + __name__, self.__class__.__name__, self.router, self.select, + ) def on_message(self, event): """ @@ -661,7 +663,8 @@ class Pool(object): raise def __repr__(self): - return 'Pool(%04x, size=%d, th=%r)' % ( + return '%s.%s(%04x, size=%d, th=%r)' % ( + __name__, self.__class__.__name__, id(self) & 0xffff, len(self._threads), get_thread_name(), diff --git a/tests/importer_test.py b/tests/importer_test.py index e48c02a4..1cff5fa7 100644 --- a/tests/importer_test.py +++ b/tests/importer_test.py @@ -42,6 +42,11 @@ class ImporterMixin(testlib.RouterMixin): super(ImporterMixin, self).tearDown() +class ReprTest(ImporterMixin, testlib.TestCase): + def test_repr(self): + self.assertEqual('mitogen.core.Importer()', repr(self.importer)) + + class LoadModuleTest(ImporterMixin, testlib.TestCase): data = zlib.compress(b("data = 1\n\n")) path = 'fake_module.py' diff --git a/tests/message_test.py b/tests/message_test.py index 2d2299d1..05a1e39e 100644 --- a/tests/message_test.py +++ b/tests/message_test.py @@ -535,6 +535,18 @@ class UnpickleCompatTest(testlib.TestCase): class ReprTest(testlib.TestCase): klass = mitogen.core.Message - def test_repr(self): - # doesn't crash - repr(self.klass.pickled('test')) + def test_repr_data(self): + msg = self.klass(dst_id=1, src_id=2, auth_id=3, handle=4, reply_to=5, data=b'abcdef') + if mitogen.core.PY3: + expected = "mitogen.core.Message(dst_id=1, src_id=2, auth_id=3, handle=4, reply_to=5, data=b'abcdef'..6)" + else: + expected = "mitogen.core.Message(dst_id=1, src_id=2, auth_id=3, handle=4, reply_to=5, data='abcdef'..6)" + self.assertEqual(expected, repr(msg)) + + def test_repr_pickled(self): + msg = self.klass.pickled(u'test') + if mitogen.core.PY3: + expected = r"mitogen.core.Message(dst_id=None, src_id=0, auth_id=0, handle=None, reply_to=None, data=b'\x80\x02X\x04\x00\x00\x00testq\x00.'..14)" + else: + expected = r"mitogen.core.Message(dst_id=None, src_id=0, auth_id=0, handle=None, reply_to=None, data='\x80\x02X\x04\x00\x00\x00testq\x01.'..14)" + self.assertEqual(expected, repr(msg)) diff --git a/tests/module_finder_test.py b/tests/module_finder_test.py index ff18bbc5..bf80cf0d 100644 --- a/tests/module_finder_test.py +++ b/tests/module_finder_test.py @@ -19,8 +19,8 @@ class ConstructorTest(testlib.TestCase): class ReprTest(testlib.TestCase): klass = mitogen.master.ModuleFinder - def test_simple(self): - self.assertEqual('ModuleFinder()', repr(self.klass())) + def test_repr(self): + self.assertEqual('mitogen.master.ModuleFinder()', repr(self.klass())) class IsStdlibNameTest(testlib.TestCase):