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())),)