Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(332)

Side by Side Diff: third_party/twisted_8_1/twisted/manhole/service.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """L{twisted.manhole} L{PB<twisted.spread.pb>} service implementation.
7 """
8
9 # twisted imports
10 from twisted import copyright
11 from twisted.spread import pb
12 from twisted.python import log, failure
13 from twisted.cred import portal
14 from twisted.application import service
15 from zope.interface import implements, Interface
16
17 # sibling imports
18 import explorer
19
20 # system imports
21 from cStringIO import StringIO
22
23 import string
24 import sys
25 import traceback
26 import types
27
28
29 class FakeStdIO:
30 def __init__(self, type_, list):
31 self.type = type_
32 self.list = list
33
34 def write(self, text):
35 log.msg("%s: %s" % (self.type, string.strip(str(text))))
36 self.list.append((self.type, text))
37
38 def flush(self):
39 pass
40
41 def consolidate(self):
42 """Concatenate adjacent messages of same type into one.
43
44 Greatly cuts down on the number of elements, increasing
45 network transport friendliness considerably.
46 """
47 if not self.list:
48 return
49
50 inlist = self.list
51 outlist = []
52 last_type = inlist[0]
53 block_begin = 0
54 for i in xrange(1, len(self.list)):
55 (mtype, message) = inlist[i]
56 if mtype == last_type:
57 continue
58 else:
59 if (i - block_begin) == 1:
60 outlist.append(inlist[block_begin])
61 else:
62 messages = map(lambda l: l[1],
63 inlist[block_begin:i])
64 message = string.join(messages, '')
65 outlist.append((last_type, message))
66 last_type = mtype
67 block_begin = i
68
69
70 class IManholeClient(Interface):
71 def console(list_of_messages):
72 """Takes a list of (type, message) pairs to display.
73
74 Types include:
75 - \"stdout\" -- string sent to sys.stdout
76
77 - \"stderr\" -- string sent to sys.stderr
78
79 - \"result\" -- string repr of the resulting value
80 of the expression
81
82 - \"exception\" -- a L{failure.Failure}
83 """
84
85 def receiveExplorer(xplorer):
86 """Receives an explorer.Explorer
87 """
88
89 def listCapabilities():
90 """List what manholey things I am capable of doing.
91
92 i.e. C{\"Explorer\"}, C{\"Failure\"}
93 """
94
95 def runInConsole(command, console, globalNS=None, localNS=None,
96 filename=None, args=None, kw=None, unsafeTracebacks=False):
97 """Run this, directing all output to the specified console.
98
99 If command is callable, it will be called with the args and keywords
100 provided. Otherwise, command will be compiled and eval'd.
101 (Wouldn't you like a macro?)
102
103 Returns the command's return value.
104
105 The console is called with a list of (type, message) pairs for
106 display, see L{IManholeClient.console}.
107 """
108 output = []
109 fakeout = FakeStdIO("stdout", output)
110 fakeerr = FakeStdIO("stderr", output)
111 errfile = FakeStdIO("exception", output)
112 code = None
113 val = None
114 if filename is None:
115 filename = str(console)
116 if args is None:
117 args = ()
118 if kw is None:
119 kw = {}
120 if localNS is None:
121 localNS = globalNS
122 if (globalNS is None) and (not callable(command)):
123 raise ValueError("Need a namespace to evaluate the command in.")
124
125 try:
126 out = sys.stdout
127 err = sys.stderr
128 sys.stdout = fakeout
129 sys.stderr = fakeerr
130 try:
131 if callable(command):
132 val = apply(command, args, kw)
133 else:
134 try:
135 code = compile(command, filename, 'eval')
136 except:
137 code = compile(command, filename, 'single')
138
139 if code:
140 val = eval(code, globalNS, localNS)
141 finally:
142 sys.stdout = out
143 sys.stderr = err
144 except:
145 (eType, eVal, tb) = sys.exc_info()
146 fail = failure.Failure(eVal, eType, tb)
147 del tb
148 # In CVS reversion 1.35, there was some code here to fill in the
149 # source lines in the traceback for frames in the local command
150 # buffer. But I can't figure out when that's triggered, so it's
151 # going away in the conversion to Failure, until you bring it back.
152 errfile.write(pb.failure2Copyable(fail, unsafeTracebacks))
153
154 if console:
155 fakeout.consolidate()
156 console(output)
157
158 return val
159
160 def _failureOldStyle(fail):
161 """Pre-Failure manhole representation of exceptions.
162
163 For compatibility with manhole clients without the \"Failure\"
164 capability.
165
166 A dictionary with two members:
167 - \'traceback\' -- traceback.extract_tb output; a list of tuples
168 (filename, line number, function name, text) suitable for
169 feeding to traceback.format_list.
170
171 - \'exception\' -- a list of one or more strings, each
172 ending in a newline. (traceback.format_exception_only output)
173 """
174 import linecache
175 tb = []
176 for f in fail.frames:
177 # (filename, line number, function name, text)
178 tb.append((f[1], f[2], f[0], linecache.getline(f[1], f[2])))
179
180 return {
181 'traceback': tb,
182 'exception': traceback.format_exception_only(fail.type, fail.value)
183 }
184
185 # Capabilities clients are likely to have before they knew how to answer a
186 # "listCapabilities" query.
187 _defaultCapabilities = {
188 "Explorer": 'Set'
189 }
190
191 class Perspective(pb.Avatar):
192 lastDeferred = 0
193 def __init__(self, service):
194 self.localNamespace = {
195 "service": service,
196 "avatar": self,
197 "_": None,
198 }
199 self.clients = {}
200 self.service = service
201
202 def __getstate__(self):
203 state = self.__dict__.copy()
204 state['clients'] = {}
205 if state['localNamespace'].has_key("__builtins__"):
206 del state['localNamespace']['__builtins__']
207 return state
208
209 def attached(self, client, identity):
210 """A client has attached -- welcome them and add them to the list.
211 """
212 self.clients[client] = identity
213
214 host = ':'.join(map(str, client.broker.transport.getHost()[1:]))
215
216 msg = self.service.welcomeMessage % {
217 'you': getattr(identity, 'name', str(identity)),
218 'host': host,
219 'longversion': copyright.longversion,
220 }
221
222 client.callRemote('console', [("stdout", msg)])
223
224 client.capabilities = _defaultCapabilities
225 client.callRemote('listCapabilities').addCallbacks(
226 self._cbClientCapable, self._ebClientCapable,
227 callbackArgs=(client,),errbackArgs=(client,))
228
229 def detached(self, client, identity):
230 try:
231 del self.clients[client]
232 except KeyError:
233 pass
234
235 def runInConsole(self, command, *args, **kw):
236 """Convience method to \"runInConsole with my stuff\".
237 """
238 return runInConsole(command,
239 self.console,
240 self.service.namespace,
241 self.localNamespace,
242 str(self.service),
243 args=args,
244 kw=kw,
245 unsafeTracebacks=self.service.unsafeTracebacks)
246
247
248 ### Methods for communicating to my clients.
249
250 def console(self, message):
251 """Pass a message to my clients' console.
252 """
253 clients = self.clients.keys()
254 origMessage = message
255 compatMessage = None
256 for client in clients:
257 try:
258 if not client.capabilities.has_key("Failure"):
259 if compatMessage is None:
260 compatMessage = origMessage[:]
261 for i in xrange(len(message)):
262 if ((message[i][0] == "exception") and
263 isinstance(message[i][1], failure.Failure)):
264 compatMessage[i] = (
265 message[i][0],
266 _failureOldStyle(message[i][1]))
267 client.callRemote('console', compatMessage)
268 else:
269 client.callRemote('console', message)
270 except pb.ProtocolError:
271 # Stale broker.
272 self.detached(client, None)
273
274 def receiveExplorer(self, objectLink):
275 """Pass an Explorer on to my clients.
276 """
277 clients = self.clients.keys()
278 for client in clients:
279 try:
280 client.callRemote('receiveExplorer', objectLink)
281 except pb.ProtocolError:
282 # Stale broker.
283 self.detached(client, None)
284
285
286 def _cbResult(self, val, dnum):
287 self.console([('result', "Deferred #%s Result: %r\n" %(dnum, val))])
288 return val
289
290 def _cbClientCapable(self, capabilities, client):
291 log.msg("client %x has %s" % (id(client), capabilities))
292 client.capabilities = capabilities
293
294 def _ebClientCapable(self, reason, client):
295 reason.trap(AttributeError)
296 log.msg("Couldn't get capabilities from %s, assuming defaults." %
297 (client,))
298
299 ### perspective_ methods, commands used by the client.
300
301 def perspective_do(self, expr):
302 """Evaluate the given expression, with output to the console.
303
304 The result is stored in the local variable '_', and its repr()
305 string is sent to the console as a \"result\" message.
306 """
307 log.msg(">>> %s" % expr)
308 val = self.runInConsole(expr)
309 if val is not None:
310 self.localNamespace["_"] = val
311 from twisted.internet.defer import Deferred
312 # TODO: client support for Deferred.
313 if isinstance(val, Deferred):
314 self.lastDeferred += 1
315 self.console([('result', "Waiting for Deferred #%s...\n" % self. lastDeferred)])
316 val.addBoth(self._cbResult, self.lastDeferred)
317 else:
318 self.console([("result", repr(val) + '\n')])
319 log.msg("<<<")
320
321 def perspective_explore(self, identifier):
322 """Browse the object obtained by evaluating the identifier.
323
324 The resulting ObjectLink is passed back through the client's
325 receiveBrowserObject method.
326 """
327 object = self.runInConsole(identifier)
328 if object:
329 expl = explorer.explorerPool.getExplorer(object, identifier)
330 self.receiveExplorer(expl)
331
332 def perspective_watch(self, identifier):
333 """Watch the object obtained by evaluating the identifier.
334
335 Whenever I think this object might have changed, I will pass
336 an ObjectLink of it back to the client's receiveBrowserObject
337 method.
338 """
339 raise NotImplementedError
340 object = self.runInConsole(identifier)
341 if object:
342 # Return an ObjectLink of this right away, before the watch.
343 oLink = self.runInConsole(self.browser.browseObject,
344 object, identifier)
345 self.receiveExplorer(oLink)
346
347 self.runInConsole(self.browser.watchObject,
348 object, identifier,
349 self.receiveExplorer)
350
351
352 class Realm:
353
354 implements(portal.IRealm)
355
356 def __init__(self, service):
357 self.service = service
358 self._cache = {}
359
360 def requestAvatar(self, avatarId, mind, *interfaces):
361 if pb.IPerspective not in interfaces:
362 raise NotImplementedError("no interface")
363 if avatarId in self._cache:
364 p = self._cache[avatarId]
365 else:
366 p = Perspective(self.service)
367 p.attached(mind, avatarId)
368 def detached():
369 p.detached(mind, avatarId)
370 return (pb.IPerspective, p, detached)
371
372
373 class Service(service.Service):
374
375 welcomeMessage = (
376 "\nHello %(you)s, welcome to Manhole "
377 "on %(host)s.\n"
378 "%(longversion)s.\n\n")
379
380 def __init__(self, unsafeTracebacks=False, namespace=None):
381 self.unsafeTracebacks = unsafeTracebacks
382 self.namespace = {
383 '__name__': '__manhole%x__' % (id(self),),
384 'sys': sys
385 }
386 if namespace:
387 self.namespace.update(namespace)
388
389 def __getstate__(self):
390 """This returns the persistent state of this shell factory.
391 """
392 # TODO -- refactor this and twisted.reality.author.Author to
393 # use common functionality (perhaps the 'code' module?)
394 dict = self.__dict__.copy()
395 ns = dict['namespace'].copy()
396 dict['namespace'] = ns
397 if ns.has_key('__builtins__'):
398 del ns['__builtins__']
399 return dict
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/manhole/logview.glade ('k') | third_party/twisted_8_1/twisted/manhole/telnet.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698