Index: third_party/twisted_8_1/twisted/manhole/explorer.py |
diff --git a/third_party/twisted_8_1/twisted/manhole/explorer.py b/third_party/twisted_8_1/twisted/manhole/explorer.py |
deleted file mode 100644 |
index e1b8dc5954fdf0b9e05dc731cffbce71554cf33f..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/manhole/explorer.py |
+++ /dev/null |
@@ -1,655 +0,0 @@ |
-# -*- test-case-name: twisted.test.test_explorer -*- |
-# $Id: explorer.py,v 1.6 2003/02/18 21:15:30 acapnotic Exp $ |
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories. |
-# See LICENSE for details. |
- |
- |
-"""Support for python object introspection and exploration. |
- |
-Note that Explorers, what with their list of attributes, are much like |
-manhole.coil.Configurables. Someone should investigate this further. (TODO) |
- |
-Also TODO: Determine how much code in here (particularly the function |
-signature stuff) can be replaced with functions available in the |
-L{inspect} module available in Python 2.1. |
-""" |
- |
-# System Imports |
-import inspect, new, string, sys, types |
-import UserDict |
- |
-# Twisted Imports |
-from twisted.spread import pb |
-from twisted.python import reflect |
- |
- |
-True=(1==1) |
-False=not True |
- |
-class Pool(UserDict.UserDict): |
- def getExplorer(self, object, identifier): |
- oid = id(object) |
- if self.data.has_key(oid): |
- # XXX: This potentially returns something with |
- # 'identifier' set to a different value. |
- return self.data[oid] |
- else: |
- klass = typeTable.get(type(object), ExplorerGeneric) |
- e = new.instance(klass, {}) |
- self.data[oid] = e |
- klass.__init__(e, object, identifier) |
- return e |
- |
-explorerPool = Pool() |
- |
-class Explorer(pb.Cacheable): |
- properties = ["id", "identifier"] |
- attributeGroups = [] |
- accessors = ["get_refcount"] |
- |
- id = None |
- identifier = None |
- |
- def __init__(self, object, identifier): |
- self.object = object |
- self.identifier = identifier |
- self.id = id(object) |
- |
- self.properties = [] |
- reflect.accumulateClassList(self.__class__, 'properties', |
- self.properties) |
- |
- self.attributeGroups = [] |
- reflect.accumulateClassList(self.__class__, 'attributeGroups', |
- self.attributeGroups) |
- |
- self.accessors = [] |
- reflect.accumulateClassList(self.__class__, 'accessors', |
- self.accessors) |
- |
- def getStateToCopyFor(self, perspective): |
- all = ["properties", "attributeGroups", "accessors"] |
- all.extend(self.properties) |
- all.extend(self.attributeGroups) |
- |
- state = {} |
- for key in all: |
- state[key] = getattr(self, key) |
- |
- state['view'] = pb.ViewPoint(perspective, self) |
- state['explorerClass'] = self.__class__.__name__ |
- return state |
- |
- def view_get_refcount(self, perspective): |
- return sys.getrefcount(self) |
- |
-class ExplorerGeneric(Explorer): |
- properties = ["str", "repr", "typename"] |
- |
- def __init__(self, object, identifier): |
- Explorer.__init__(self, object, identifier) |
- self.str = str(object) |
- self.repr = repr(object) |
- self.typename = type(object).__name__ |
- |
- |
-class ExplorerImmutable(Explorer): |
- properties = ["value"] |
- |
- def __init__(self, object, identifier): |
- Explorer.__init__(self, object, identifier) |
- self.value = object |
- |
- |
-class ExplorerSequence(Explorer): |
- properties = ["len"] |
- attributeGroups = ["elements"] |
- accessors = ["get_elements"] |
- |
- def __init__(self, seq, identifier): |
- Explorer.__init__(self, seq, identifier) |
- self.seq = seq |
- self.len = len(seq) |
- |
- # Use accessor method to fill me in. |
- self.elements = [] |
- |
- def get_elements(self): |
- self.len = len(self.seq) |
- l = [] |
- for i in xrange(self.len): |
- identifier = "%s[%s]" % (self.identifier, i) |
- |
- # GLOBAL: using global explorerPool |
- l.append(explorerPool.getExplorer(self.seq[i], identifier)) |
- |
- return l |
- |
- def view_get_elements(self, perspective): |
- # XXX: set the .elements member of all my remoteCaches |
- return self.get_elements() |
- |
- |
-class ExplorerMapping(Explorer): |
- properties = ["len"] |
- attributeGroups = ["keys"] |
- accessors = ["get_keys", "get_item"] |
- |
- def __init__(self, dct, identifier): |
- Explorer.__init__(self, dct, identifier) |
- |
- self.dct = dct |
- self.len = len(dct) |
- |
- # Use accessor method to fill me in. |
- self.keys = [] |
- |
- def get_keys(self): |
- keys = self.dct.keys() |
- self.len = len(keys) |
- l = [] |
- for i in xrange(self.len): |
- identifier = "%s.keys()[%s]" % (self.identifier, i) |
- |
- # GLOBAL: using global explorerPool |
- l.append(explorerPool.getExplorer(keys[i], identifier)) |
- |
- return l |
- |
- def view_get_keys(self, perspective): |
- # XXX: set the .keys member of all my remoteCaches |
- return self.get_keys() |
- |
- def view_get_item(self, perspective, key): |
- if type(key) is types.InstanceType: |
- key = key.object |
- |
- item = self.dct[key] |
- |
- identifier = "%s[%s]" % (self.identifier, repr(key)) |
- # GLOBAL: using global explorerPool |
- item = explorerPool.getExplorer(item, identifier) |
- return item |
- |
- |
-class ExplorerBuiltin(Explorer): |
- """ |
- @ivar name: the name the function was defined as |
- @ivar doc: function's docstring, or C{None} if unavailable |
- @ivar self: if not C{None}, the function is a method of this object. |
- """ |
- properties = ["doc", "name", "self"] |
- def __init__(self, function, identifier): |
- Explorer.__init__(self, function, identifier) |
- self.doc = function.__doc__ |
- self.name = function.__name__ |
- self.self = function.__self__ |
- |
- |
-class ExplorerInstance(Explorer): |
- """ |
- Attribute groups: |
- - B{methods} -- dictionary of methods |
- - B{data} -- dictionary of data members |
- |
- Note these are only the *instance* methods and members -- |
- if you want the class methods, you'll have to look up the class. |
- |
- TODO: Detail levels (me, me & class, me & class ancestory) |
- |
- @ivar klass: the class this is an instance of. |
- """ |
- properties = ["klass"] |
- attributeGroups = ["methods", "data"] |
- |
- def __init__(self, instance, identifier): |
- Explorer.__init__(self, instance, identifier) |
- members = {} |
- methods = {} |
- for i in dir(instance): |
- # TODO: Make screening of private attributes configurable. |
- if i[0] == '_': |
- continue |
- mIdentifier = string.join([identifier, i], ".") |
- member = getattr(instance, i) |
- mType = type(member) |
- |
- if mType is types.MethodType: |
- methods[i] = explorerPool.getExplorer(member, mIdentifier) |
- else: |
- members[i] = explorerPool.getExplorer(member, mIdentifier) |
- |
- self.klass = explorerPool.getExplorer(instance.__class__, |
- self.identifier + |
- '.__class__') |
- self.data = members |
- self.methods = methods |
- |
- |
-class ExplorerClass(Explorer): |
- """ |
- @ivar name: the name the class was defined with |
- @ivar doc: the class's docstring |
- @ivar bases: a list of this class's base classes. |
- @ivar module: the module the class is defined in |
- |
- Attribute groups: |
- - B{methods} -- class methods |
- - B{data} -- other members of the class |
- """ |
- properties = ["name", "doc", "bases", "module"] |
- attributeGroups = ["methods", "data"] |
- def __init__(self, theClass, identifier): |
- Explorer.__init__(self, theClass, identifier) |
- if not identifier: |
- identifier = theClass.__name__ |
- members = {} |
- methods = {} |
- for i in dir(theClass): |
- if (i[0] == '_') and (i != '__init__'): |
- continue |
- |
- mIdentifier = string.join([identifier, i], ".") |
- member = getattr(theClass, i) |
- mType = type(member) |
- |
- if mType is types.MethodType: |
- methods[i] = explorerPool.getExplorer(member, mIdentifier) |
- else: |
- members[i] = explorerPool.getExplorer(member, mIdentifier) |
- |
- self.name = theClass.__name__ |
- self.doc = inspect.getdoc(theClass) |
- self.data = members |
- self.methods = methods |
- self.bases = explorerPool.getExplorer(theClass.__bases__, |
- identifier + ".__bases__") |
- self.module = getattr(theClass, '__module__', None) |
- |
- |
-class ExplorerFunction(Explorer): |
- properties = ["name", "doc", "file", "line","signature"] |
- """ |
- name -- the name the function was defined as |
- signature -- the function's calling signature (Signature instance) |
- doc -- the function's docstring |
- file -- the file the function is defined in |
- line -- the line in the file the function begins on |
- """ |
- def __init__(self, function, identifier): |
- Explorer.__init__(self, function, identifier) |
- code = function.func_code |
- argcount = code.co_argcount |
- takesList = (code.co_flags & 0x04) and 1 |
- takesKeywords = (code.co_flags & 0x08) and 1 |
- |
- n = (argcount + takesList + takesKeywords) |
- signature = Signature(code.co_varnames[:n]) |
- |
- if function.func_defaults: |
- i_d = 0 |
- for i in xrange(argcount - len(function.func_defaults), |
- argcount): |
- default = function.func_defaults[i_d] |
- default = explorerPool.getExplorer( |
- default, '%s.func_defaults[%d]' % (identifier, i_d)) |
- signature.set_default(i, default) |
- |
- i_d = i_d + 1 |
- |
- if takesKeywords: |
- signature.set_keyword(n - 1) |
- |
- if takesList: |
- signature.set_varlist(n - 1 - takesKeywords) |
- |
- # maybe also: function.func_globals, |
- # or at least func_globals.__name__? |
- # maybe the bytecode, for disassembly-view? |
- |
- self.name = function.__name__ |
- self.signature = signature |
- self.doc = inspect.getdoc(function) |
- self.file = code.co_filename |
- self.line = code.co_firstlineno |
- |
- |
-class ExplorerMethod(ExplorerFunction): |
- properties = ["self", "klass"] |
- """ |
- In addition to ExplorerFunction properties: |
- self -- the object I am bound to, or None if unbound |
- klass -- the class I am a method of |
- """ |
- def __init__(self, method, identifier): |
- |
- function = method.im_func |
- if type(function) is types.InstanceType: |
- function = function.__call__.im_func |
- |
- ExplorerFunction.__init__(self, function, identifier) |
- self.id = id(method) |
- self.klass = explorerPool.getExplorer(method.im_class, |
- identifier + '.im_class') |
- self.self = explorerPool.getExplorer(method.im_self, |
- identifier + '.im_self') |
- |
- if method.im_self: |
- # I'm a bound method -- eat the 'self' arg. |
- self.signature.discardSelf() |
- |
- |
-class ExplorerModule(Explorer): |
- """ |
- @ivar name: the name the module was defined as |
- @ivar doc: documentation string for the module |
- @ivar file: the file the module is defined in |
- |
- Attribute groups: |
- - B{classes} -- the public classes provided by the module |
- - B{functions} -- the public functions provided by the module |
- - B{data} -- the public data members provided by the module |
- |
- (\"Public\" is taken to be \"anything that doesn't start with _\") |
- """ |
- properties = ["name","doc","file"] |
- attributeGroups = ["classes", "functions", "data"] |
- |
- def __init__(self, module, identifier): |
- Explorer.__init__(self, module, identifier) |
- functions = {} |
- classes = {} |
- data = {} |
- for key, value in module.__dict__.items(): |
- if key[0] == '_': |
- continue |
- |
- mIdentifier = "%s.%s" % (identifier, key) |
- |
- if type(value) is types.ClassType: |
- classes[key] = explorerPool.getExplorer(value, |
- mIdentifier) |
- elif type(value) is types.FunctionType: |
- functions[key] = explorerPool.getExplorer(value, |
- mIdentifier) |
- elif type(value) is types.ModuleType: |
- pass # pass on imported modules |
- else: |
- data[key] = explorerPool.getExplorer(value, mIdentifier) |
- |
- self.name = module.__name__ |
- self.doc = inspect.getdoc(module) |
- self.file = getattr(module, '__file__', None) |
- self.classes = classes |
- self.functions = functions |
- self.data = data |
- |
-typeTable = {types.InstanceType: ExplorerInstance, |
- types.ClassType: ExplorerClass, |
- types.MethodType: ExplorerMethod, |
- types.FunctionType: ExplorerFunction, |
- types.ModuleType: ExplorerModule, |
- types.BuiltinFunctionType: ExplorerBuiltin, |
- types.ListType: ExplorerSequence, |
- types.TupleType: ExplorerSequence, |
- types.DictType: ExplorerMapping, |
- types.StringType: ExplorerImmutable, |
- types.NoneType: ExplorerImmutable, |
- types.IntType: ExplorerImmutable, |
- types.FloatType: ExplorerImmutable, |
- types.LongType: ExplorerImmutable, |
- types.ComplexType: ExplorerImmutable, |
- } |
- |
-class Signature(pb.Copyable): |
- """I represent the signature of a callable. |
- |
- Signatures are immutable, so don't expect my contents to change once |
- they've been set. |
- """ |
- _FLAVOURLESS = None |
- _HAS_DEFAULT = 2 |
- _VAR_LIST = 4 |
- _KEYWORD_DICT = 8 |
- |
- def __init__(self, argNames): |
- self.name = argNames |
- self.default = [None] * len(argNames) |
- self.flavour = [None] * len(argNames) |
- |
- def get_name(self, arg): |
- return self.name[arg] |
- |
- def get_default(self, arg): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- # Wouldn't it be nice if we just returned "None" when there |
- # wasn't a default? Well, yes, but often times "None" *is* |
- # the default, so return a tuple instead. |
- if self.flavour[arg] == self._HAS_DEFAULT: |
- return (True, self.default[arg]) |
- else: |
- return (False, None) |
- |
- def set_default(self, arg, value): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- self.flavour[arg] = self._HAS_DEFAULT |
- self.default[arg] = value |
- |
- def set_varlist(self, arg): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- self.flavour[arg] = self._VAR_LIST |
- |
- def set_keyword(self, arg): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- self.flavour[arg] = self._KEYWORD_DICT |
- |
- def is_varlist(self, arg): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- return (self.flavour[arg] == self._VAR_LIST) |
- |
- def is_keyword(self, arg): |
- if arg is types.StringType: |
- arg = self.name.index(arg) |
- |
- return (self.flavour[arg] == self._KEYWORD_DICT) |
- |
- def discardSelf(self): |
- """Invoke me to discard the first argument if this is a bound method. |
- """ |
- ## if self.name[0] != 'self': |
- ## log.msg("Warning: Told to discard self, but name is %s" % |
- ## self.name[0]) |
- self.name = self.name[1:] |
- self.default.pop(0) |
- self.flavour.pop(0) |
- |
- def getStateToCopy(self): |
- return {'name': tuple(self.name), |
- 'flavour': tuple(self.flavour), |
- 'default': tuple(self.default)} |
- |
- def __len__(self): |
- return len(self.name) |
- |
- def __str__(self): |
- arglist = [] |
- for arg in xrange(len(self)): |
- name = self.get_name(arg) |
- hasDefault, default = self.get_default(arg) |
- if hasDefault: |
- a = "%s=%s" % (name, default) |
- elif self.is_varlist(arg): |
- a = "*%s" % (name,) |
- elif self.is_keyword(arg): |
- a = "**%s" % (name,) |
- else: |
- a = name |
- arglist.append(a) |
- |
- return string.join(arglist,", ") |
- |
- |
- |
- |
- |
-class CRUFT_WatchyThingie: |
- # TODO: |
- # |
- # * an exclude mechanism for the watcher's browser, to avoid |
- # sending back large and uninteresting data structures. |
- # |
- # * an exclude mechanism for the watcher's trigger, to avoid |
- # triggering on some frequently-called-method-that-doesn't- |
- # actually-change-anything. |
- # |
- # * XXX! need removeWatch() |
- |
- def watchIdentifier(self, identifier, callback): |
- """Watch the object returned by evaluating the identifier. |
- |
- Whenever I think the object might have changed, I'll send an |
- ObjectLink of it to the callback. |
- |
- WARNING: This calls eval() on its argument! |
- """ |
- object = eval(identifier, |
- self.globalNamespace, |
- self.localNamespace) |
- return self.watchObject(object, identifier, callback) |
- |
- def watchObject(self, object, identifier, callback): |
- """Watch the given object. |
- |
- Whenever I think the object might have changed, I'll send an |
- ObjectLink of it to the callback. |
- |
- The identifier argument is used to generate identifiers for |
- objects which are members of this one. |
- """ |
- if type(object) is not types.InstanceType: |
- raise TypeError, "Sorry, can only place a watch on Instances." |
- |
- # uninstallers = [] |
- |
- dct = {} |
- reflect.addMethodNamesToDict(object.__class__, dct, '') |
- for k in object.__dict__.keys(): |
- dct[k] = 1 |
- |
- members = dct.keys() |
- |
- clazzNS = {} |
- clazz = new.classobj('Watching%s%X' % |
- (object.__class__.__name__, id(object)), |
- (_MonkeysSetattrMixin, object.__class__,), |
- clazzNS) |
- |
- clazzNS['_watchEmitChanged'] = new.instancemethod( |
- lambda slf, i=identifier, b=self, cb=callback: |
- cb(b.browseObject(slf, i)), |
- None, clazz) |
- |
- # orig_class = object.__class__ |
- object.__class__ = clazz |
- |
- for name in members: |
- m = getattr(object, name) |
- # Only hook bound methods. |
- if ((type(m) is types.MethodType) |
- and (m.im_self is not None)): |
- # What's the use of putting watch monkeys on methods |
- # in addition to __setattr__? Well, um, uh, if the |
- # methods modify their attributes (i.e. add a key to |
- # a dictionary) instead of [re]setting them, then |
- # we wouldn't know about it unless we did this. |
- # (Is that convincing?) |
- |
- monkey = _WatchMonkey(object) |
- monkey.install(name) |
- # uninstallers.append(monkey.uninstall) |
- |
- # XXX: This probably prevents these objects from ever having a |
- # zero refcount. Leak, Leak! |
- ## self.watchUninstallers[object] = uninstallers |
- |
- |
-class _WatchMonkey: |
- """I hang on a method and tell you what I see. |
- |
- TODO: Aya! Now I just do browseObject all the time, but I could |
- tell you what got called with what when and returning what. |
- """ |
- oldMethod = None |
- |
- def __init__(self, instance): |
- """Make a monkey to hang on this instance object. |
- """ |
- self.instance = instance |
- |
- def install(self, methodIdentifier): |
- """Install myself on my instance in place of this method. |
- """ |
- oldMethod = getattr(self.instance, methodIdentifier, None) |
- |
- # XXX: this conditional probably isn't effective. |
- if oldMethod is not self: |
- # avoid triggering __setattr__ |
- self.instance.__dict__[methodIdentifier] = ( |
- new.instancemethod(self, self.instance, |
- self.instance.__class__)) |
- self.oldMethod = (methodIdentifier, oldMethod) |
- |
- def uninstall(self): |
- """Remove myself from this instance and restore the original method. |
- |
- (I hope.) |
- """ |
- if self.oldMethod is None: |
- return |
- |
- # XXX: This probably doesn't work if multiple monkies are hanging |
- # on a method and they're not removed in order. |
- if self.oldMethod[1] is None: |
- delattr(self.instance, self.oldMethod[0]) |
- else: |
- setattr(self.instance, self.oldMethod[0], self.oldMethod[1]) |
- |
- def __call__(self, instance, *a, **kw): |
- """Pretend to be the method I replaced, and ring the bell. |
- """ |
- if self.oldMethod[1]: |
- rval = apply(self.oldMethod[1], a, kw) |
- else: |
- rval = None |
- |
- instance._watchEmitChanged() |
- return rval |
- |
- |
-class _MonkeysSetattrMixin: |
- """A mix-in class providing __setattr__ for objects being watched. |
- """ |
- def __setattr__(self, k, v): |
- """Set the attribute and ring the bell. |
- """ |
- if hasattr(self.__class__.__bases__[1], '__setattr__'): |
- # Hack! Using __bases__[1] is Bad, but since we created |
- # this class, we can be reasonably sure it'll work. |
- self.__class__.__bases__[1].__setattr__(self, k, v) |
- else: |
- self.__dict__[k] = v |
- |
- # XXX: Hey, waitasec, did someone just hang a new method on me? |
- # Do I need to put a monkey on it? |
- |
- self._watchEmitChanged() |