From 6a74edce6bb34e1a51eca762045a9ffa004370be Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sat, 24 Mar 2018 18:54:59 +0545 Subject: [PATCH] issue #155: parent: move master.Context into parent. The Context and Router APIs for constructing children and making function calls should be available in every parent context, as user code wants to have access to the same API. --- docs/api.rst | 10 +++++----- docs/howitworks.rst | 8 ++++---- mitogen/fakessh.py | 8 ++++---- mitogen/master.py | 26 -------------------------- mitogen/parent.py | 28 +++++++++++++++++++++++++++- mitogen/unix.py | 4 ++-- preamble_size.py | 2 +- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 5f8db01c..45241afe 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -732,12 +732,12 @@ Context Class No message was received and `deadline` passed. -.. currentmodule:: mitogen.master +.. currentmodule:: mitogen.parent .. class:: Context Extend :py:class:`mitogen.core.Router` with functionality useful to - masters, and child contexts who later become masters. Currently when this + masters, and child contexts who later become parents. Currently when this class is required, the target context's router is upgraded at runtime. .. method:: call_async (fn, \*args, \*\*kwargs) @@ -820,7 +820,7 @@ Receiver Class Receivers are used to wait for pickled responses from another context to be sent to a handle registered in this context. A receiver may be single-use - (as in the case of :py:meth:`mitogen.master.Context.call_async`) or + (as in the case of :py:meth:`mitogen.parent.Context.call_async`) or multiple use. :param mitogen.core.Router router: @@ -1057,7 +1057,7 @@ A random assortment of utility functions useful on masters and children. functionality, such as annotating the safety of a Unicode string, or adding additional methods to a dict. However, cPickle loves to preserve those subtypes during serialization, resulting in CallError during :py:meth:`call - ` in the target when it tries to deserialize + ` in the target when it tries to deserialize the data. This function walks the object graph `obj`, producing a copy with any @@ -1139,7 +1139,7 @@ Exceptions .. class:: CallError (e) - Raised when :py:meth:`Context.call() ` fails. + Raised when :py:meth:`Context.call() ` fails. A copy of the traceback from the external context is appended to the exception message. diff --git a/docs/howitworks.rst b/docs/howitworks.rst index 67947675..dd7c299f 100644 --- a/docs/howitworks.rst +++ b/docs/howitworks.rst @@ -206,8 +206,8 @@ After all initialization is complete, the child's main thread sits in a loop reading from a :py:class:`Channel ` connected to the :py:data:`CALL_FUNCTION ` handle. This handle is written to by -:py:meth:`call() ` -and :py:meth:`call_async() `. +:py:meth:`call() ` +and :py:meth:`call_async() `. :py:data:`CALL_FUNCTION ` only accepts requests from the context IDs listed in :py:data:`mitogen.parent_ids`, forming a chain @@ -369,7 +369,7 @@ Children listen on the following handles: Receives `(mod_name, class_name, func_name, args, kwargs)` 5-tuples from - :py:meth:`call_async() `, + :py:meth:`call_async() `, imports ``mod_name``, then attempts to execute `class_name.func_name(\*args, \**kwargs)`. @@ -430,7 +430,7 @@ also listen on the following handles: Additional handles are created to receive the result of every function call -triggered by :py:meth:`call_async() `. +triggered by :py:meth:`call_async() `. Sentinel Value diff --git a/mitogen/fakessh.py b/mitogen/fakessh.py index be3a2539..13abfcfe 100644 --- a/mitogen/fakessh.py +++ b/mitogen/fakessh.py @@ -287,7 +287,7 @@ def _fakessh_main(dest_context_id, econtext): if not args: die('fakessh: login mode not supported and no command specified') - dest = mitogen.master.Context(econtext.router, dest_context_id) + dest = mitogen.parent.Context(econtext.router, dest_context_id) # Even though SSH receives an argument vector, it still cats the vector # together before sending to the server, the server just uses /bin/sh -c to @@ -318,7 +318,7 @@ def run(dest, router, args, deadline=None, econtext=None): mitogen.parent.upgrade_router(econtext) context_id = router.allocate_id() - fakessh = mitogen.master.Context(router, context_id) + fakessh = mitogen.parent.Context(router, context_id) fakessh.name = 'fakessh.%d' % (context_id,) sock1, sock2 = socket.socketpair() @@ -345,8 +345,8 @@ def run(dest, router, args, deadline=None, econtext=None): fp.write('ExternalContext().main(**%r)\n' % ({ 'parent_ids': parent_ids, 'context_id': context_id, - 'debug': router.debug, - 'profiling': router.profiling, + 'debug': getattr(router, 'debug', False), + 'profiling': getattr(router, 'profiling', False), 'log_level': mitogen.parent.get_log_level(), 'in_fd': sock2.fileno(), 'out_fd': sock2.fileno(), diff --git a/mitogen/master.py b/mitogen/master.py index fbc338ef..d0c8eb8a 100644 --- a/mitogen/master.py +++ b/mitogen/master.py @@ -641,33 +641,7 @@ class Broker(mitogen.core.Broker): self._watcher.remove() -class Context(mitogen.core.Context): - via = None - - def call_async(self, fn, *args, **kwargs): - LOG.debug('%r.call_async(%r, *%r, **%r)', - self, fn, args, kwargs) - - if isinstance(fn, types.MethodType) and \ - isinstance(fn.im_self, (type, types.ClassType)): - klass = fn.im_self.__name__ - else: - klass = None - - return self.send_async( - mitogen.core.Message.pickled( - (fn.__module__, klass, fn.__name__, args, kwargs), - handle=mitogen.core.CALL_FUNCTION, - ) - ) - - def call(self, fn, *args, **kwargs): - receiver = self.call_async(fn, *args, **kwargs) - return receiver.get().unpickle(throw_dead=False) - - class Router(mitogen.parent.Router): - context_class = Context broker_class = Broker debug = False profiling = False diff --git a/mitogen/parent.py b/mitogen/parent.py index f81c6e92..08081031 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -39,6 +39,7 @@ import termios import textwrap import threading import time +import types import zlib import mitogen.core @@ -467,6 +468,31 @@ class ChildIdAllocator(object): return self.allocate() +class Context(mitogen.core.Context): + via = None + + def call_async(self, fn, *args, **kwargs): + LOG.debug('%r.call_async(%r, *%r, **%r)', + self, fn, args, kwargs) + + if isinstance(fn, types.MethodType) and \ + isinstance(fn.im_self, (type, types.ClassType)): + klass = fn.im_self.__name__ + else: + klass = None + + return self.send_async( + mitogen.core.Message.pickled( + (fn.__module__, klass, fn.__name__, args, kwargs), + handle=mitogen.core.CALL_FUNCTION, + ) + ) + + def call(self, fn, *args, **kwargs): + receiver = self.call_async(fn, *args, **kwargs) + return receiver.get().unpickle(throw_dead=False) + + class RouteMonitor(object): def __init__(self, router, parent=None): self.router = router @@ -556,7 +582,7 @@ class RouteMonitor(object): class Router(mitogen.core.Router): - context_class = mitogen.core.Context + context_class = Context id_allocator = None responder = None diff --git a/mitogen/unix.py b/mitogen/unix.py index dad71ff9..3cfcbf1d 100644 --- a/mitogen/unix.py +++ b/mitogen/unix.py @@ -83,7 +83,7 @@ class Listener(mitogen.core.BasicStream): pid, = struct.unpack('>L', sock.recv(4)) context_id = self._router.id_allocator.allocate() - context = mitogen.master.Context(self._router, context_id) + context = mitogen.parent.Context(self._router, context_id) stream = mitogen.core.Stream(self._router, context_id) stream.accept(sock.fileno(), sock.fileno()) stream.name = 'unix_client.%d' % (pid,) @@ -111,7 +111,7 @@ def connect(path, broker=None): stream.accept(sock.fileno(), sock.fileno()) stream.name = 'unix_listener.%d' % (pid,) - context = mitogen.master.Context(router, remote_id) + context = mitogen.parent.Context(router, remote_id) router.register(context, stream) mitogen.core.listen(router.broker, 'shutdown', diff --git a/preamble_size.py b/preamble_size.py index 358abed7..9af20795 100644 --- a/preamble_size.py +++ b/preamble_size.py @@ -13,7 +13,7 @@ import mitogen.ssh import mitogen.sudo router = mitogen.master.Router() -context = mitogen.master.Context(router, 0) +context = mitogen.parent.Context(router, 0) stream = mitogen.ssh.Stream(router, 0, hostname='foo') print 'SSH command size: %s' % (len(' '.join(stream.get_boot_command())),)