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

Side by Side Diff: third_party/twisted_8_1/twisted/manhole/explorer.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 # -*- test-case-name: twisted.test.test_explorer -*-
2 # $Id: explorer.py,v 1.6 2003/02/18 21:15:30 acapnotic Exp $
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6
7 """Support for python object introspection and exploration.
8
9 Note that Explorers, what with their list of attributes, are much like
10 manhole.coil.Configurables. Someone should investigate this further. (TODO)
11
12 Also TODO: Determine how much code in here (particularly the function
13 signature stuff) can be replaced with functions available in the
14 L{inspect} module available in Python 2.1.
15 """
16
17 # System Imports
18 import inspect, new, string, sys, types
19 import UserDict
20
21 # Twisted Imports
22 from twisted.spread import pb
23 from twisted.python import reflect
24
25
26 True=(1==1)
27 False=not True
28
29 class Pool(UserDict.UserDict):
30 def getExplorer(self, object, identifier):
31 oid = id(object)
32 if self.data.has_key(oid):
33 # XXX: This potentially returns something with
34 # 'identifier' set to a different value.
35 return self.data[oid]
36 else:
37 klass = typeTable.get(type(object), ExplorerGeneric)
38 e = new.instance(klass, {})
39 self.data[oid] = e
40 klass.__init__(e, object, identifier)
41 return e
42
43 explorerPool = Pool()
44
45 class Explorer(pb.Cacheable):
46 properties = ["id", "identifier"]
47 attributeGroups = []
48 accessors = ["get_refcount"]
49
50 id = None
51 identifier = None
52
53 def __init__(self, object, identifier):
54 self.object = object
55 self.identifier = identifier
56 self.id = id(object)
57
58 self.properties = []
59 reflect.accumulateClassList(self.__class__, 'properties',
60 self.properties)
61
62 self.attributeGroups = []
63 reflect.accumulateClassList(self.__class__, 'attributeGroups',
64 self.attributeGroups)
65
66 self.accessors = []
67 reflect.accumulateClassList(self.__class__, 'accessors',
68 self.accessors)
69
70 def getStateToCopyFor(self, perspective):
71 all = ["properties", "attributeGroups", "accessors"]
72 all.extend(self.properties)
73 all.extend(self.attributeGroups)
74
75 state = {}
76 for key in all:
77 state[key] = getattr(self, key)
78
79 state['view'] = pb.ViewPoint(perspective, self)
80 state['explorerClass'] = self.__class__.__name__
81 return state
82
83 def view_get_refcount(self, perspective):
84 return sys.getrefcount(self)
85
86 class ExplorerGeneric(Explorer):
87 properties = ["str", "repr", "typename"]
88
89 def __init__(self, object, identifier):
90 Explorer.__init__(self, object, identifier)
91 self.str = str(object)
92 self.repr = repr(object)
93 self.typename = type(object).__name__
94
95
96 class ExplorerImmutable(Explorer):
97 properties = ["value"]
98
99 def __init__(self, object, identifier):
100 Explorer.__init__(self, object, identifier)
101 self.value = object
102
103
104 class ExplorerSequence(Explorer):
105 properties = ["len"]
106 attributeGroups = ["elements"]
107 accessors = ["get_elements"]
108
109 def __init__(self, seq, identifier):
110 Explorer.__init__(self, seq, identifier)
111 self.seq = seq
112 self.len = len(seq)
113
114 # Use accessor method to fill me in.
115 self.elements = []
116
117 def get_elements(self):
118 self.len = len(self.seq)
119 l = []
120 for i in xrange(self.len):
121 identifier = "%s[%s]" % (self.identifier, i)
122
123 # GLOBAL: using global explorerPool
124 l.append(explorerPool.getExplorer(self.seq[i], identifier))
125
126 return l
127
128 def view_get_elements(self, perspective):
129 # XXX: set the .elements member of all my remoteCaches
130 return self.get_elements()
131
132
133 class ExplorerMapping(Explorer):
134 properties = ["len"]
135 attributeGroups = ["keys"]
136 accessors = ["get_keys", "get_item"]
137
138 def __init__(self, dct, identifier):
139 Explorer.__init__(self, dct, identifier)
140
141 self.dct = dct
142 self.len = len(dct)
143
144 # Use accessor method to fill me in.
145 self.keys = []
146
147 def get_keys(self):
148 keys = self.dct.keys()
149 self.len = len(keys)
150 l = []
151 for i in xrange(self.len):
152 identifier = "%s.keys()[%s]" % (self.identifier, i)
153
154 # GLOBAL: using global explorerPool
155 l.append(explorerPool.getExplorer(keys[i], identifier))
156
157 return l
158
159 def view_get_keys(self, perspective):
160 # XXX: set the .keys member of all my remoteCaches
161 return self.get_keys()
162
163 def view_get_item(self, perspective, key):
164 if type(key) is types.InstanceType:
165 key = key.object
166
167 item = self.dct[key]
168
169 identifier = "%s[%s]" % (self.identifier, repr(key))
170 # GLOBAL: using global explorerPool
171 item = explorerPool.getExplorer(item, identifier)
172 return item
173
174
175 class ExplorerBuiltin(Explorer):
176 """
177 @ivar name: the name the function was defined as
178 @ivar doc: function's docstring, or C{None} if unavailable
179 @ivar self: if not C{None}, the function is a method of this object.
180 """
181 properties = ["doc", "name", "self"]
182 def __init__(self, function, identifier):
183 Explorer.__init__(self, function, identifier)
184 self.doc = function.__doc__
185 self.name = function.__name__
186 self.self = function.__self__
187
188
189 class ExplorerInstance(Explorer):
190 """
191 Attribute groups:
192 - B{methods} -- dictionary of methods
193 - B{data} -- dictionary of data members
194
195 Note these are only the *instance* methods and members --
196 if you want the class methods, you'll have to look up the class.
197
198 TODO: Detail levels (me, me & class, me & class ancestory)
199
200 @ivar klass: the class this is an instance of.
201 """
202 properties = ["klass"]
203 attributeGroups = ["methods", "data"]
204
205 def __init__(self, instance, identifier):
206 Explorer.__init__(self, instance, identifier)
207 members = {}
208 methods = {}
209 for i in dir(instance):
210 # TODO: Make screening of private attributes configurable.
211 if i[0] == '_':
212 continue
213 mIdentifier = string.join([identifier, i], ".")
214 member = getattr(instance, i)
215 mType = type(member)
216
217 if mType is types.MethodType:
218 methods[i] = explorerPool.getExplorer(member, mIdentifier)
219 else:
220 members[i] = explorerPool.getExplorer(member, mIdentifier)
221
222 self.klass = explorerPool.getExplorer(instance.__class__,
223 self.identifier +
224 '.__class__')
225 self.data = members
226 self.methods = methods
227
228
229 class ExplorerClass(Explorer):
230 """
231 @ivar name: the name the class was defined with
232 @ivar doc: the class's docstring
233 @ivar bases: a list of this class's base classes.
234 @ivar module: the module the class is defined in
235
236 Attribute groups:
237 - B{methods} -- class methods
238 - B{data} -- other members of the class
239 """
240 properties = ["name", "doc", "bases", "module"]
241 attributeGroups = ["methods", "data"]
242 def __init__(self, theClass, identifier):
243 Explorer.__init__(self, theClass, identifier)
244 if not identifier:
245 identifier = theClass.__name__
246 members = {}
247 methods = {}
248 for i in dir(theClass):
249 if (i[0] == '_') and (i != '__init__'):
250 continue
251
252 mIdentifier = string.join([identifier, i], ".")
253 member = getattr(theClass, i)
254 mType = type(member)
255
256 if mType is types.MethodType:
257 methods[i] = explorerPool.getExplorer(member, mIdentifier)
258 else:
259 members[i] = explorerPool.getExplorer(member, mIdentifier)
260
261 self.name = theClass.__name__
262 self.doc = inspect.getdoc(theClass)
263 self.data = members
264 self.methods = methods
265 self.bases = explorerPool.getExplorer(theClass.__bases__,
266 identifier + ".__bases__")
267 self.module = getattr(theClass, '__module__', None)
268
269
270 class ExplorerFunction(Explorer):
271 properties = ["name", "doc", "file", "line","signature"]
272 """
273 name -- the name the function was defined as
274 signature -- the function's calling signature (Signature instance)
275 doc -- the function's docstring
276 file -- the file the function is defined in
277 line -- the line in the file the function begins on
278 """
279 def __init__(self, function, identifier):
280 Explorer.__init__(self, function, identifier)
281 code = function.func_code
282 argcount = code.co_argcount
283 takesList = (code.co_flags & 0x04) and 1
284 takesKeywords = (code.co_flags & 0x08) and 1
285
286 n = (argcount + takesList + takesKeywords)
287 signature = Signature(code.co_varnames[:n])
288
289 if function.func_defaults:
290 i_d = 0
291 for i in xrange(argcount - len(function.func_defaults),
292 argcount):
293 default = function.func_defaults[i_d]
294 default = explorerPool.getExplorer(
295 default, '%s.func_defaults[%d]' % (identifier, i_d))
296 signature.set_default(i, default)
297
298 i_d = i_d + 1
299
300 if takesKeywords:
301 signature.set_keyword(n - 1)
302
303 if takesList:
304 signature.set_varlist(n - 1 - takesKeywords)
305
306 # maybe also: function.func_globals,
307 # or at least func_globals.__name__?
308 # maybe the bytecode, for disassembly-view?
309
310 self.name = function.__name__
311 self.signature = signature
312 self.doc = inspect.getdoc(function)
313 self.file = code.co_filename
314 self.line = code.co_firstlineno
315
316
317 class ExplorerMethod(ExplorerFunction):
318 properties = ["self", "klass"]
319 """
320 In addition to ExplorerFunction properties:
321 self -- the object I am bound to, or None if unbound
322 klass -- the class I am a method of
323 """
324 def __init__(self, method, identifier):
325
326 function = method.im_func
327 if type(function) is types.InstanceType:
328 function = function.__call__.im_func
329
330 ExplorerFunction.__init__(self, function, identifier)
331 self.id = id(method)
332 self.klass = explorerPool.getExplorer(method.im_class,
333 identifier + '.im_class')
334 self.self = explorerPool.getExplorer(method.im_self,
335 identifier + '.im_self')
336
337 if method.im_self:
338 # I'm a bound method -- eat the 'self' arg.
339 self.signature.discardSelf()
340
341
342 class ExplorerModule(Explorer):
343 """
344 @ivar name: the name the module was defined as
345 @ivar doc: documentation string for the module
346 @ivar file: the file the module is defined in
347
348 Attribute groups:
349 - B{classes} -- the public classes provided by the module
350 - B{functions} -- the public functions provided by the module
351 - B{data} -- the public data members provided by the module
352
353 (\"Public\" is taken to be \"anything that doesn't start with _\")
354 """
355 properties = ["name","doc","file"]
356 attributeGroups = ["classes", "functions", "data"]
357
358 def __init__(self, module, identifier):
359 Explorer.__init__(self, module, identifier)
360 functions = {}
361 classes = {}
362 data = {}
363 for key, value in module.__dict__.items():
364 if key[0] == '_':
365 continue
366
367 mIdentifier = "%s.%s" % (identifier, key)
368
369 if type(value) is types.ClassType:
370 classes[key] = explorerPool.getExplorer(value,
371 mIdentifier)
372 elif type(value) is types.FunctionType:
373 functions[key] = explorerPool.getExplorer(value,
374 mIdentifier)
375 elif type(value) is types.ModuleType:
376 pass # pass on imported modules
377 else:
378 data[key] = explorerPool.getExplorer(value, mIdentifier)
379
380 self.name = module.__name__
381 self.doc = inspect.getdoc(module)
382 self.file = getattr(module, '__file__', None)
383 self.classes = classes
384 self.functions = functions
385 self.data = data
386
387 typeTable = {types.InstanceType: ExplorerInstance,
388 types.ClassType: ExplorerClass,
389 types.MethodType: ExplorerMethod,
390 types.FunctionType: ExplorerFunction,
391 types.ModuleType: ExplorerModule,
392 types.BuiltinFunctionType: ExplorerBuiltin,
393 types.ListType: ExplorerSequence,
394 types.TupleType: ExplorerSequence,
395 types.DictType: ExplorerMapping,
396 types.StringType: ExplorerImmutable,
397 types.NoneType: ExplorerImmutable,
398 types.IntType: ExplorerImmutable,
399 types.FloatType: ExplorerImmutable,
400 types.LongType: ExplorerImmutable,
401 types.ComplexType: ExplorerImmutable,
402 }
403
404 class Signature(pb.Copyable):
405 """I represent the signature of a callable.
406
407 Signatures are immutable, so don't expect my contents to change once
408 they've been set.
409 """
410 _FLAVOURLESS = None
411 _HAS_DEFAULT = 2
412 _VAR_LIST = 4
413 _KEYWORD_DICT = 8
414
415 def __init__(self, argNames):
416 self.name = argNames
417 self.default = [None] * len(argNames)
418 self.flavour = [None] * len(argNames)
419
420 def get_name(self, arg):
421 return self.name[arg]
422
423 def get_default(self, arg):
424 if arg is types.StringType:
425 arg = self.name.index(arg)
426
427 # Wouldn't it be nice if we just returned "None" when there
428 # wasn't a default? Well, yes, but often times "None" *is*
429 # the default, so return a tuple instead.
430 if self.flavour[arg] == self._HAS_DEFAULT:
431 return (True, self.default[arg])
432 else:
433 return (False, None)
434
435 def set_default(self, arg, value):
436 if arg is types.StringType:
437 arg = self.name.index(arg)
438
439 self.flavour[arg] = self._HAS_DEFAULT
440 self.default[arg] = value
441
442 def set_varlist(self, arg):
443 if arg is types.StringType:
444 arg = self.name.index(arg)
445
446 self.flavour[arg] = self._VAR_LIST
447
448 def set_keyword(self, arg):
449 if arg is types.StringType:
450 arg = self.name.index(arg)
451
452 self.flavour[arg] = self._KEYWORD_DICT
453
454 def is_varlist(self, arg):
455 if arg is types.StringType:
456 arg = self.name.index(arg)
457
458 return (self.flavour[arg] == self._VAR_LIST)
459
460 def is_keyword(self, arg):
461 if arg is types.StringType:
462 arg = self.name.index(arg)
463
464 return (self.flavour[arg] == self._KEYWORD_DICT)
465
466 def discardSelf(self):
467 """Invoke me to discard the first argument if this is a bound method.
468 """
469 ## if self.name[0] != 'self':
470 ## log.msg("Warning: Told to discard self, but name is %s" %
471 ## self.name[0])
472 self.name = self.name[1:]
473 self.default.pop(0)
474 self.flavour.pop(0)
475
476 def getStateToCopy(self):
477 return {'name': tuple(self.name),
478 'flavour': tuple(self.flavour),
479 'default': tuple(self.default)}
480
481 def __len__(self):
482 return len(self.name)
483
484 def __str__(self):
485 arglist = []
486 for arg in xrange(len(self)):
487 name = self.get_name(arg)
488 hasDefault, default = self.get_default(arg)
489 if hasDefault:
490 a = "%s=%s" % (name, default)
491 elif self.is_varlist(arg):
492 a = "*%s" % (name,)
493 elif self.is_keyword(arg):
494 a = "**%s" % (name,)
495 else:
496 a = name
497 arglist.append(a)
498
499 return string.join(arglist,", ")
500
501
502
503
504
505 class CRUFT_WatchyThingie:
506 # TODO:
507 #
508 # * an exclude mechanism for the watcher's browser, to avoid
509 # sending back large and uninteresting data structures.
510 #
511 # * an exclude mechanism for the watcher's trigger, to avoid
512 # triggering on some frequently-called-method-that-doesn't-
513 # actually-change-anything.
514 #
515 # * XXX! need removeWatch()
516
517 def watchIdentifier(self, identifier, callback):
518 """Watch the object returned by evaluating the identifier.
519
520 Whenever I think the object might have changed, I'll send an
521 ObjectLink of it to the callback.
522
523 WARNING: This calls eval() on its argument!
524 """
525 object = eval(identifier,
526 self.globalNamespace,
527 self.localNamespace)
528 return self.watchObject(object, identifier, callback)
529
530 def watchObject(self, object, identifier, callback):
531 """Watch the given object.
532
533 Whenever I think the object might have changed, I'll send an
534 ObjectLink of it to the callback.
535
536 The identifier argument is used to generate identifiers for
537 objects which are members of this one.
538 """
539 if type(object) is not types.InstanceType:
540 raise TypeError, "Sorry, can only place a watch on Instances."
541
542 # uninstallers = []
543
544 dct = {}
545 reflect.addMethodNamesToDict(object.__class__, dct, '')
546 for k in object.__dict__.keys():
547 dct[k] = 1
548
549 members = dct.keys()
550
551 clazzNS = {}
552 clazz = new.classobj('Watching%s%X' %
553 (object.__class__.__name__, id(object)),
554 (_MonkeysSetattrMixin, object.__class__,),
555 clazzNS)
556
557 clazzNS['_watchEmitChanged'] = new.instancemethod(
558 lambda slf, i=identifier, b=self, cb=callback:
559 cb(b.browseObject(slf, i)),
560 None, clazz)
561
562 # orig_class = object.__class__
563 object.__class__ = clazz
564
565 for name in members:
566 m = getattr(object, name)
567 # Only hook bound methods.
568 if ((type(m) is types.MethodType)
569 and (m.im_self is not None)):
570 # What's the use of putting watch monkeys on methods
571 # in addition to __setattr__? Well, um, uh, if the
572 # methods modify their attributes (i.e. add a key to
573 # a dictionary) instead of [re]setting them, then
574 # we wouldn't know about it unless we did this.
575 # (Is that convincing?)
576
577 monkey = _WatchMonkey(object)
578 monkey.install(name)
579 # uninstallers.append(monkey.uninstall)
580
581 # XXX: This probably prevents these objects from ever having a
582 # zero refcount. Leak, Leak!
583 ## self.watchUninstallers[object] = uninstallers
584
585
586 class _WatchMonkey:
587 """I hang on a method and tell you what I see.
588
589 TODO: Aya! Now I just do browseObject all the time, but I could
590 tell you what got called with what when and returning what.
591 """
592 oldMethod = None
593
594 def __init__(self, instance):
595 """Make a monkey to hang on this instance object.
596 """
597 self.instance = instance
598
599 def install(self, methodIdentifier):
600 """Install myself on my instance in place of this method.
601 """
602 oldMethod = getattr(self.instance, methodIdentifier, None)
603
604 # XXX: this conditional probably isn't effective.
605 if oldMethod is not self:
606 # avoid triggering __setattr__
607 self.instance.__dict__[methodIdentifier] = (
608 new.instancemethod(self, self.instance,
609 self.instance.__class__))
610 self.oldMethod = (methodIdentifier, oldMethod)
611
612 def uninstall(self):
613 """Remove myself from this instance and restore the original method.
614
615 (I hope.)
616 """
617 if self.oldMethod is None:
618 return
619
620 # XXX: This probably doesn't work if multiple monkies are hanging
621 # on a method and they're not removed in order.
622 if self.oldMethod[1] is None:
623 delattr(self.instance, self.oldMethod[0])
624 else:
625 setattr(self.instance, self.oldMethod[0], self.oldMethod[1])
626
627 def __call__(self, instance, *a, **kw):
628 """Pretend to be the method I replaced, and ring the bell.
629 """
630 if self.oldMethod[1]:
631 rval = apply(self.oldMethod[1], a, kw)
632 else:
633 rval = None
634
635 instance._watchEmitChanged()
636 return rval
637
638
639 class _MonkeysSetattrMixin:
640 """A mix-in class providing __setattr__ for objects being watched.
641 """
642 def __setattr__(self, k, v):
643 """Set the attribute and ring the bell.
644 """
645 if hasattr(self.__class__.__bases__[1], '__setattr__'):
646 # Hack! Using __bases__[1] is Bad, but since we created
647 # this class, we can be reasonably sure it'll work.
648 self.__class__.__bases__[1].__setattr__(self, k, v)
649 else:
650 self.__dict__[k] = v
651
652 # XXX: Hey, waitasec, did someone just hang a new method on me?
653 # Do I need to put a monkey on it?
654
655 self._watchEmitChanged()
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/manhole/_inspectro.py ('k') | third_party/twisted_8_1/twisted/manhole/gladereactor.glade » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698