| Index: third_party/twisted_8_1/twisted/manhole/service.py
|
| diff --git a/third_party/twisted_8_1/twisted/manhole/service.py b/third_party/twisted_8_1/twisted/manhole/service.py
|
| deleted file mode 100644
|
| index 28572ad0229869df39f92bed959d50022eed3ce7..0000000000000000000000000000000000000000
|
| --- a/third_party/twisted_8_1/twisted/manhole/service.py
|
| +++ /dev/null
|
| @@ -1,399 +0,0 @@
|
| -
|
| -# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
|
| -# See LICENSE for details.
|
| -
|
| -
|
| -"""L{twisted.manhole} L{PB<twisted.spread.pb>} service implementation.
|
| -"""
|
| -
|
| -# twisted imports
|
| -from twisted import copyright
|
| -from twisted.spread import pb
|
| -from twisted.python import log, failure
|
| -from twisted.cred import portal
|
| -from twisted.application import service
|
| -from zope.interface import implements, Interface
|
| -
|
| -# sibling imports
|
| -import explorer
|
| -
|
| -# system imports
|
| -from cStringIO import StringIO
|
| -
|
| -import string
|
| -import sys
|
| -import traceback
|
| -import types
|
| -
|
| -
|
| -class FakeStdIO:
|
| - def __init__(self, type_, list):
|
| - self.type = type_
|
| - self.list = list
|
| -
|
| - def write(self, text):
|
| - log.msg("%s: %s" % (self.type, string.strip(str(text))))
|
| - self.list.append((self.type, text))
|
| -
|
| - def flush(self):
|
| - pass
|
| -
|
| - def consolidate(self):
|
| - """Concatenate adjacent messages of same type into one.
|
| -
|
| - Greatly cuts down on the number of elements, increasing
|
| - network transport friendliness considerably.
|
| - """
|
| - if not self.list:
|
| - return
|
| -
|
| - inlist = self.list
|
| - outlist = []
|
| - last_type = inlist[0]
|
| - block_begin = 0
|
| - for i in xrange(1, len(self.list)):
|
| - (mtype, message) = inlist[i]
|
| - if mtype == last_type:
|
| - continue
|
| - else:
|
| - if (i - block_begin) == 1:
|
| - outlist.append(inlist[block_begin])
|
| - else:
|
| - messages = map(lambda l: l[1],
|
| - inlist[block_begin:i])
|
| - message = string.join(messages, '')
|
| - outlist.append((last_type, message))
|
| - last_type = mtype
|
| - block_begin = i
|
| -
|
| -
|
| -class IManholeClient(Interface):
|
| - def console(list_of_messages):
|
| - """Takes a list of (type, message) pairs to display.
|
| -
|
| - Types include:
|
| - - \"stdout\" -- string sent to sys.stdout
|
| -
|
| - - \"stderr\" -- string sent to sys.stderr
|
| -
|
| - - \"result\" -- string repr of the resulting value
|
| - of the expression
|
| -
|
| - - \"exception\" -- a L{failure.Failure}
|
| - """
|
| -
|
| - def receiveExplorer(xplorer):
|
| - """Receives an explorer.Explorer
|
| - """
|
| -
|
| - def listCapabilities():
|
| - """List what manholey things I am capable of doing.
|
| -
|
| - i.e. C{\"Explorer\"}, C{\"Failure\"}
|
| - """
|
| -
|
| -def runInConsole(command, console, globalNS=None, localNS=None,
|
| - filename=None, args=None, kw=None, unsafeTracebacks=False):
|
| - """Run this, directing all output to the specified console.
|
| -
|
| - If command is callable, it will be called with the args and keywords
|
| - provided. Otherwise, command will be compiled and eval'd.
|
| - (Wouldn't you like a macro?)
|
| -
|
| - Returns the command's return value.
|
| -
|
| - The console is called with a list of (type, message) pairs for
|
| - display, see L{IManholeClient.console}.
|
| - """
|
| - output = []
|
| - fakeout = FakeStdIO("stdout", output)
|
| - fakeerr = FakeStdIO("stderr", output)
|
| - errfile = FakeStdIO("exception", output)
|
| - code = None
|
| - val = None
|
| - if filename is None:
|
| - filename = str(console)
|
| - if args is None:
|
| - args = ()
|
| - if kw is None:
|
| - kw = {}
|
| - if localNS is None:
|
| - localNS = globalNS
|
| - if (globalNS is None) and (not callable(command)):
|
| - raise ValueError("Need a namespace to evaluate the command in.")
|
| -
|
| - try:
|
| - out = sys.stdout
|
| - err = sys.stderr
|
| - sys.stdout = fakeout
|
| - sys.stderr = fakeerr
|
| - try:
|
| - if callable(command):
|
| - val = apply(command, args, kw)
|
| - else:
|
| - try:
|
| - code = compile(command, filename, 'eval')
|
| - except:
|
| - code = compile(command, filename, 'single')
|
| -
|
| - if code:
|
| - val = eval(code, globalNS, localNS)
|
| - finally:
|
| - sys.stdout = out
|
| - sys.stderr = err
|
| - except:
|
| - (eType, eVal, tb) = sys.exc_info()
|
| - fail = failure.Failure(eVal, eType, tb)
|
| - del tb
|
| - # In CVS reversion 1.35, there was some code here to fill in the
|
| - # source lines in the traceback for frames in the local command
|
| - # buffer. But I can't figure out when that's triggered, so it's
|
| - # going away in the conversion to Failure, until you bring it back.
|
| - errfile.write(pb.failure2Copyable(fail, unsafeTracebacks))
|
| -
|
| - if console:
|
| - fakeout.consolidate()
|
| - console(output)
|
| -
|
| - return val
|
| -
|
| -def _failureOldStyle(fail):
|
| - """Pre-Failure manhole representation of exceptions.
|
| -
|
| - For compatibility with manhole clients without the \"Failure\"
|
| - capability.
|
| -
|
| - A dictionary with two members:
|
| - - \'traceback\' -- traceback.extract_tb output; a list of tuples
|
| - (filename, line number, function name, text) suitable for
|
| - feeding to traceback.format_list.
|
| -
|
| - - \'exception\' -- a list of one or more strings, each
|
| - ending in a newline. (traceback.format_exception_only output)
|
| - """
|
| - import linecache
|
| - tb = []
|
| - for f in fail.frames:
|
| - # (filename, line number, function name, text)
|
| - tb.append((f[1], f[2], f[0], linecache.getline(f[1], f[2])))
|
| -
|
| - return {
|
| - 'traceback': tb,
|
| - 'exception': traceback.format_exception_only(fail.type, fail.value)
|
| - }
|
| -
|
| -# Capabilities clients are likely to have before they knew how to answer a
|
| -# "listCapabilities" query.
|
| -_defaultCapabilities = {
|
| - "Explorer": 'Set'
|
| - }
|
| -
|
| -class Perspective(pb.Avatar):
|
| - lastDeferred = 0
|
| - def __init__(self, service):
|
| - self.localNamespace = {
|
| - "service": service,
|
| - "avatar": self,
|
| - "_": None,
|
| - }
|
| - self.clients = {}
|
| - self.service = service
|
| -
|
| - def __getstate__(self):
|
| - state = self.__dict__.copy()
|
| - state['clients'] = {}
|
| - if state['localNamespace'].has_key("__builtins__"):
|
| - del state['localNamespace']['__builtins__']
|
| - return state
|
| -
|
| - def attached(self, client, identity):
|
| - """A client has attached -- welcome them and add them to the list.
|
| - """
|
| - self.clients[client] = identity
|
| -
|
| - host = ':'.join(map(str, client.broker.transport.getHost()[1:]))
|
| -
|
| - msg = self.service.welcomeMessage % {
|
| - 'you': getattr(identity, 'name', str(identity)),
|
| - 'host': host,
|
| - 'longversion': copyright.longversion,
|
| - }
|
| -
|
| - client.callRemote('console', [("stdout", msg)])
|
| -
|
| - client.capabilities = _defaultCapabilities
|
| - client.callRemote('listCapabilities').addCallbacks(
|
| - self._cbClientCapable, self._ebClientCapable,
|
| - callbackArgs=(client,),errbackArgs=(client,))
|
| -
|
| - def detached(self, client, identity):
|
| - try:
|
| - del self.clients[client]
|
| - except KeyError:
|
| - pass
|
| -
|
| - def runInConsole(self, command, *args, **kw):
|
| - """Convience method to \"runInConsole with my stuff\".
|
| - """
|
| - return runInConsole(command,
|
| - self.console,
|
| - self.service.namespace,
|
| - self.localNamespace,
|
| - str(self.service),
|
| - args=args,
|
| - kw=kw,
|
| - unsafeTracebacks=self.service.unsafeTracebacks)
|
| -
|
| -
|
| - ### Methods for communicating to my clients.
|
| -
|
| - def console(self, message):
|
| - """Pass a message to my clients' console.
|
| - """
|
| - clients = self.clients.keys()
|
| - origMessage = message
|
| - compatMessage = None
|
| - for client in clients:
|
| - try:
|
| - if not client.capabilities.has_key("Failure"):
|
| - if compatMessage is None:
|
| - compatMessage = origMessage[:]
|
| - for i in xrange(len(message)):
|
| - if ((message[i][0] == "exception") and
|
| - isinstance(message[i][1], failure.Failure)):
|
| - compatMessage[i] = (
|
| - message[i][0],
|
| - _failureOldStyle(message[i][1]))
|
| - client.callRemote('console', compatMessage)
|
| - else:
|
| - client.callRemote('console', message)
|
| - except pb.ProtocolError:
|
| - # Stale broker.
|
| - self.detached(client, None)
|
| -
|
| - def receiveExplorer(self, objectLink):
|
| - """Pass an Explorer on to my clients.
|
| - """
|
| - clients = self.clients.keys()
|
| - for client in clients:
|
| - try:
|
| - client.callRemote('receiveExplorer', objectLink)
|
| - except pb.ProtocolError:
|
| - # Stale broker.
|
| - self.detached(client, None)
|
| -
|
| -
|
| - def _cbResult(self, val, dnum):
|
| - self.console([('result', "Deferred #%s Result: %r\n" %(dnum, val))])
|
| - return val
|
| -
|
| - def _cbClientCapable(self, capabilities, client):
|
| - log.msg("client %x has %s" % (id(client), capabilities))
|
| - client.capabilities = capabilities
|
| -
|
| - def _ebClientCapable(self, reason, client):
|
| - reason.trap(AttributeError)
|
| - log.msg("Couldn't get capabilities from %s, assuming defaults." %
|
| - (client,))
|
| -
|
| - ### perspective_ methods, commands used by the client.
|
| -
|
| - def perspective_do(self, expr):
|
| - """Evaluate the given expression, with output to the console.
|
| -
|
| - The result is stored in the local variable '_', and its repr()
|
| - string is sent to the console as a \"result\" message.
|
| - """
|
| - log.msg(">>> %s" % expr)
|
| - val = self.runInConsole(expr)
|
| - if val is not None:
|
| - self.localNamespace["_"] = val
|
| - from twisted.internet.defer import Deferred
|
| - # TODO: client support for Deferred.
|
| - if isinstance(val, Deferred):
|
| - self.lastDeferred += 1
|
| - self.console([('result', "Waiting for Deferred #%s...\n" % self.lastDeferred)])
|
| - val.addBoth(self._cbResult, self.lastDeferred)
|
| - else:
|
| - self.console([("result", repr(val) + '\n')])
|
| - log.msg("<<<")
|
| -
|
| - def perspective_explore(self, identifier):
|
| - """Browse the object obtained by evaluating the identifier.
|
| -
|
| - The resulting ObjectLink is passed back through the client's
|
| - receiveBrowserObject method.
|
| - """
|
| - object = self.runInConsole(identifier)
|
| - if object:
|
| - expl = explorer.explorerPool.getExplorer(object, identifier)
|
| - self.receiveExplorer(expl)
|
| -
|
| - def perspective_watch(self, identifier):
|
| - """Watch the object obtained by evaluating the identifier.
|
| -
|
| - Whenever I think this object might have changed, I will pass
|
| - an ObjectLink of it back to the client's receiveBrowserObject
|
| - method.
|
| - """
|
| - raise NotImplementedError
|
| - object = self.runInConsole(identifier)
|
| - if object:
|
| - # Return an ObjectLink of this right away, before the watch.
|
| - oLink = self.runInConsole(self.browser.browseObject,
|
| - object, identifier)
|
| - self.receiveExplorer(oLink)
|
| -
|
| - self.runInConsole(self.browser.watchObject,
|
| - object, identifier,
|
| - self.receiveExplorer)
|
| -
|
| -
|
| -class Realm:
|
| -
|
| - implements(portal.IRealm)
|
| -
|
| - def __init__(self, service):
|
| - self.service = service
|
| - self._cache = {}
|
| -
|
| - def requestAvatar(self, avatarId, mind, *interfaces):
|
| - if pb.IPerspective not in interfaces:
|
| - raise NotImplementedError("no interface")
|
| - if avatarId in self._cache:
|
| - p = self._cache[avatarId]
|
| - else:
|
| - p = Perspective(self.service)
|
| - p.attached(mind, avatarId)
|
| - def detached():
|
| - p.detached(mind, avatarId)
|
| - return (pb.IPerspective, p, detached)
|
| -
|
| -
|
| -class Service(service.Service):
|
| -
|
| - welcomeMessage = (
|
| - "\nHello %(you)s, welcome to Manhole "
|
| - "on %(host)s.\n"
|
| - "%(longversion)s.\n\n")
|
| -
|
| - def __init__(self, unsafeTracebacks=False, namespace=None):
|
| - self.unsafeTracebacks = unsafeTracebacks
|
| - self.namespace = {
|
| - '__name__': '__manhole%x__' % (id(self),),
|
| - 'sys': sys
|
| - }
|
| - if namespace:
|
| - self.namespace.update(namespace)
|
| -
|
| - def __getstate__(self):
|
| - """This returns the persistent state of this shell factory.
|
| - """
|
| - # TODO -- refactor this and twisted.reality.author.Author to
|
| - # use common functionality (perhaps the 'code' module?)
|
| - dict = self.__dict__.copy()
|
| - ns = dict['namespace'].copy()
|
| - dict['namespace'] = ns
|
| - if ns.has_key('__builtins__'):
|
| - del ns['__builtins__']
|
| - return dict
|
|
|