~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/python/reflect.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_reflect -*-
 
2
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
"""
 
6
Standardized versions of various cool and/or strange things that you can do
 
7
with Python's reflection capabilities.
 
8
"""
 
9
 
 
10
import sys
 
11
import os
 
12
import types
 
13
import pickle
 
14
import traceback
 
15
import weakref
 
16
import re
 
17
import warnings
 
18
import new
 
19
try:
 
20
    from collections import deque
 
21
except ImportError:
 
22
    deque = list
 
23
 
 
24
RegexType = type(re.compile(""))
 
25
 
 
26
 
 
27
try:
 
28
    from cStringIO import StringIO
 
29
except ImportError:
 
30
    from StringIO import StringIO
 
31
 
 
32
from twisted.python.util import unsignedID
 
33
from twisted.python.deprecate import deprecated
 
34
from twisted.python.deprecate import _fullyQualifiedName as fullyQualifiedName
 
35
from twisted.python.versions import Version
 
36
 
 
37
 
 
38
 
 
39
class Settable:
 
40
    """
 
41
    A mixin class for syntactic sugar.  Lets you assign attributes by
 
42
    calling with keyword arguments; for example, C{x(a=b,c=d,y=z)} is the
 
43
    same as C{x.a=b;x.c=d;x.y=z}.  The most useful place for this is
 
44
    where you don't want to name a variable, but you do want to set
 
45
    some attributes; for example, C{X()(y=z,a=b)}.
 
46
    """
 
47
    def __init__(self, **kw):
 
48
        self(**kw)
 
49
 
 
50
    def __call__(self,**kw):
 
51
        for key,val in kw.items():
 
52
            setattr(self,key,val)
 
53
        return self
 
54
 
 
55
 
 
56
class AccessorType(type):
 
57
    """Metaclass that generates properties automatically.
 
58
 
 
59
    This is for Python 2.2 and up.
 
60
 
 
61
    Using this metaclass for your class will give you explicit accessor
 
62
    methods; a method called set_foo, will automatically create a property
 
63
    'foo' that uses set_foo as a setter method. Same for get_foo and del_foo.
 
64
 
 
65
    Note that this will only work on methods that are present on class
 
66
    creation. If you add methods after the class is defined they will not
 
67
    automatically become properties. Likewise, class attributes will only
 
68
    be used if they are present upon class creation, and no getter function
 
69
    was set - if a getter is present, the class attribute will be ignored.
 
70
 
 
71
    This is a 2.2-only alternative to the Accessor mixin - just set in your
 
72
    class definition::
 
73
 
 
74
        __metaclass__ = AccessorType
 
75
 
 
76
    """
 
77
 
 
78
    def __init__(self, name, bases, d):
 
79
        type.__init__(self, name, bases, d)
 
80
        accessors = {}
 
81
        prefixs = ["get_", "set_", "del_"]
 
82
        for k in d.keys():
 
83
            v = getattr(self, k)
 
84
            for i in range(3):
 
85
                if k.startswith(prefixs[i]):
 
86
                    accessors.setdefault(k[4:], [None, None, None])[i] = v
 
87
        for name, (getter, setter, deler) in accessors.items():
 
88
            # create default behaviours for the property - if we leave
 
89
            # the getter as None we won't be able to getattr, etc..
 
90
            if getter is None:
 
91
                if hasattr(self, name):
 
92
                    value = getattr(self, name)
 
93
                    def getter(this, value=value, name=name):
 
94
                        if name in this.__dict__:
 
95
                            return this.__dict__[name]
 
96
                        else:
 
97
                            return value
 
98
                else:
 
99
                    def getter(this, name=name):
 
100
                        if name in this.__dict__:
 
101
                            return this.__dict__[name]
 
102
                        else:
 
103
                            raise AttributeError("no such attribute %r" % name)
 
104
            if setter is None:
 
105
                def setter(this, value, name=name):
 
106
                    this.__dict__[name] = value
 
107
            if deler is None:
 
108
                def deler(this, name=name):
 
109
                    del this.__dict__[name]
 
110
            setattr(self, name, property(getter, setter, deler, ""))
 
111
 
 
112
 
 
113
class PropertyAccessor(object):
 
114
    """A mixin class for Python 2.2 that uses AccessorType.
 
115
 
 
116
    This provides compatability with the pre-2.2 Accessor mixin, up
 
117
    to a point.
 
118
 
 
119
    Extending this class will give you explicit accessor methods; a
 
120
    method called set_foo, for example, is the same as an if statement
 
121
    in __setattr__ looking for 'foo'.  Same for get_foo and del_foo.
 
122
 
 
123
    There are also reallyDel and reallySet methods, so you can
 
124
    override specifics in subclasses without clobbering __setattr__
 
125
    and __getattr__, or using non-2.1 compatible code.
 
126
 
 
127
    There is are incompatibilities with Accessor - accessor
 
128
    methods added after class creation will *not* be detected. OTOH,
 
129
    this method is probably way faster.
 
130
 
 
131
    In addition, class attributes will only be used if no getter
 
132
    was defined, and instance attributes will not override getter methods
 
133
    whereas in original Accessor the class attribute or instance attribute
 
134
    would override the getter method.
 
135
    """
 
136
    # addendum to above:
 
137
    # The behaviour of Accessor is wrong IMHO, and I've found bugs
 
138
    # caused by it.
 
139
    #  -- itamar
 
140
 
 
141
    __metaclass__ = AccessorType
 
142
 
 
143
    def reallySet(self, k, v):
 
144
        self.__dict__[k] = v
 
145
 
 
146
    def reallyDel(self, k):
 
147
        del self.__dict__[k]
 
148
 
 
149
 
 
150
class Accessor:
 
151
    """
 
152
    Extending this class will give you explicit accessor methods; a
 
153
    method called C{set_foo}, for example, is the same as an if statement
 
154
    in L{__setattr__} looking for C{'foo'}.  Same for C{get_foo} and
 
155
    C{del_foo}.  There are also L{reallyDel} and L{reallySet} methods,
 
156
    so you can override specifics in subclasses without clobbering
 
157
    L{__setattr__} and L{__getattr__}.
 
158
 
 
159
    This implementation is for Python 2.1.
 
160
    """
 
161
 
 
162
    def __setattr__(self, k,v):
 
163
        kstring='set_%s'%k
 
164
        if hasattr(self.__class__,kstring):
 
165
            return getattr(self,kstring)(v)
 
166
        else:
 
167
            self.reallySet(k,v)
 
168
 
 
169
    def __getattr__(self, k):
 
170
        kstring='get_%s'%k
 
171
        if hasattr(self.__class__,kstring):
 
172
            return getattr(self,kstring)()
 
173
        raise AttributeError("%s instance has no accessor for: %s" % (qual(self.__class__),k))
 
174
 
 
175
    def __delattr__(self, k):
 
176
        kstring='del_%s'%k
 
177
        if hasattr(self.__class__,kstring):
 
178
            getattr(self,kstring)()
 
179
            return
 
180
        self.reallyDel(k)
 
181
 
 
182
    def reallySet(self, k,v):
 
183
        """
 
184
        *actually* set self.k to v without incurring side-effects.
 
185
        This is a hook to be overridden by subclasses.
 
186
        """
 
187
        if k == "__dict__":
 
188
            self.__dict__.clear()
 
189
            self.__dict__.update(v)
 
190
        else:
 
191
            self.__dict__[k]=v
 
192
 
 
193
    def reallyDel(self, k):
 
194
        """
 
195
        *actually* del self.k without incurring side-effects.  This is a
 
196
        hook to be overridden by subclasses.
 
197
        """
 
198
        del self.__dict__[k]
 
199
 
 
200
# just in case
 
201
OriginalAccessor = Accessor
 
202
 
 
203
 
 
204
class Summer(Accessor):
 
205
    """
 
206
    Extend from this class to get the capability to maintain 'related
 
207
    sums'.  Have a tuple in your class like the following::
 
208
 
 
209
        sums=(('amount','credit','credit_total'),
 
210
              ('amount','debit','debit_total'))
 
211
 
 
212
    and the 'credit_total' member of the 'credit' member of self will
 
213
    always be incremented when the 'amount' member of self is
 
214
    incremented, similiarly for the debit versions.
 
215
    """
 
216
 
 
217
    def reallySet(self, k,v):
 
218
        "This method does the work."
 
219
        for sum in self.sums:
 
220
            attr=sum[0]
 
221
            obj=sum[1]
 
222
            objattr=sum[2]
 
223
            if k == attr:
 
224
                try:
 
225
                    oldval=getattr(self, attr)
 
226
                except:
 
227
                    oldval=0
 
228
                diff=v-oldval
 
229
                if hasattr(self, obj):
 
230
                    ob=getattr(self,obj)
 
231
                    if ob is not None:
 
232
                        try:oldobjval=getattr(ob, objattr)
 
233
                        except:oldobjval=0.0
 
234
                        setattr(ob,objattr,oldobjval+diff)
 
235
 
 
236
            elif k == obj:
 
237
                if hasattr(self, attr):
 
238
                    x=getattr(self,attr)
 
239
                    setattr(self,attr,0)
 
240
                    y=getattr(self,k)
 
241
                    Accessor.reallySet(self,k,v)
 
242
                    setattr(self,attr,x)
 
243
                    Accessor.reallySet(self,y,v)
 
244
        Accessor.reallySet(self,k,v)
 
245
 
 
246
 
 
247
class QueueMethod:
 
248
    """ I represent a method that doesn't exist yet."""
 
249
    def __init__(self, name, calls):
 
250
        self.name = name
 
251
        self.calls = calls
 
252
    def __call__(self, *args):
 
253
        self.calls.append((self.name, args))
 
254
 
 
255
 
 
256
def funcinfo(function):
 
257
    """
 
258
    this is more documentation for myself than useful code.
 
259
    """
 
260
    warnings.warn(
 
261
        "[v2.5] Use inspect.getargspec instead of twisted.python.reflect.funcinfo",
 
262
        DeprecationWarning,
 
263
        stacklevel=2)
 
264
    code=function.func_code
 
265
    name=function.func_name
 
266
    argc=code.co_argcount
 
267
    argv=code.co_varnames[:argc]
 
268
    defaults=function.func_defaults
 
269
 
 
270
    out = []
 
271
 
 
272
    out.append('The function %s accepts %s arguments' % (name ,argc))
 
273
    if defaults:
 
274
        required=argc-len(defaults)
 
275
        out.append('It requires %s arguments' % required)
 
276
        out.append('The arguments required are: %s' % argv[:required])
 
277
        out.append('additional arguments are:')
 
278
        for i in range(argc-required):
 
279
            j=i+required
 
280
            out.append('%s which has a default of' % (argv[j], defaults[i]))
 
281
    return out
 
282
 
 
283
 
 
284
ISNT=0
 
285
WAS=1
 
286
IS=2
 
287
 
 
288
 
 
289
def fullFuncName(func):
 
290
    qualName = (str(pickle.whichmodule(func, func.__name__)) + '.' + func.__name__)
 
291
    if namedObject(qualName) is not func:
 
292
        raise Exception("Couldn't find %s as %s." % (func, qualName))
 
293
    return qualName
 
294
 
 
295
 
 
296
def qual(clazz):
 
297
    """Return full import path of a class."""
 
298
    return clazz.__module__ + '.' + clazz.__name__
 
299
 
 
300
 
 
301
def getcurrent(clazz):
 
302
    assert type(clazz) == types.ClassType, 'must be a class...'
 
303
    module = namedModule(clazz.__module__)
 
304
    currclass = getattr(module, clazz.__name__, None)
 
305
    if currclass is None:
 
306
        return clazz
 
307
    return currclass
 
308
 
 
309
 
 
310
def getClass(obj):
 
311
    """Return the class or type of object 'obj'.
 
312
    Returns sensible result for oldstyle and newstyle instances and types."""
 
313
    if hasattr(obj, '__class__'):
 
314
        return obj.__class__
 
315
    else:
 
316
        return type(obj)
 
317
 
 
318
# class graph nonsense
 
319
 
 
320
# I should really have a better name for this...
 
321
def isinst(inst,clazz):
 
322
    if type(inst) != types.InstanceType or type(clazz)!= types.ClassType:
 
323
        return isinstance(inst,clazz)
 
324
    cl = inst.__class__
 
325
    cl2 = getcurrent(cl)
 
326
    clazz = getcurrent(clazz)
 
327
    if issubclass(cl2,clazz):
 
328
        if cl == cl2:
 
329
            return WAS
 
330
        else:
 
331
            inst.__class__ = cl2
 
332
            return IS
 
333
    else:
 
334
        return ISNT
 
335
 
 
336
 
 
337
def namedModule(name):
 
338
    """Return a module given its name."""
 
339
    topLevel = __import__(name)
 
340
    packages = name.split(".")[1:]
 
341
    m = topLevel
 
342
    for p in packages:
 
343
        m = getattr(m, p)
 
344
    return m
 
345
 
 
346
 
 
347
def namedObject(name):
 
348
    """Get a fully named module-global object.
 
349
    """
 
350
    classSplit = name.split('.')
 
351
    module = namedModule('.'.join(classSplit[:-1]))
 
352
    return getattr(module, classSplit[-1])
 
353
 
 
354
namedClass = namedObject # backwards compat
 
355
 
 
356
 
 
357
 
 
358
class _NoModuleFound(Exception):
 
359
    """
 
360
    No module was found because none exists.
 
361
    """
 
362
 
 
363
 
 
364
class InvalidName(ValueError):
 
365
    """
 
366
    The given name is not a dot-separated list of Python objects.
 
367
    """
 
368
 
 
369
 
 
370
class ModuleNotFound(InvalidName):
 
371
    """
 
372
    The module associated with the given name doesn't exist and it can't be
 
373
    imported.
 
374
    """
 
375
 
 
376
 
 
377
class ObjectNotFound(InvalidName):
 
378
    """
 
379
    The object associated with the given name doesn't exist and it can't be
 
380
    imported.
 
381
    """
 
382
 
 
383
 
 
384
def _importAndCheckStack(importName):
 
385
    """
 
386
    Import the given name as a module, then walk the stack to determine whether
 
387
    the failure was the module not existing, or some code in the module (for
 
388
    example a dependent import) failing.  This can be helpful to determine
 
389
    whether any actual application code was run.  For example, to distiguish
 
390
    administrative error (entering the wrong module name), from programmer
 
391
    error (writing buggy code in a module that fails to import).
 
392
 
 
393
    @raise Exception: if something bad happens.  This can be any type of
 
394
    exception, since nobody knows what loading some arbitrary code might do.
 
395
 
 
396
    @raise _NoModuleFound: if no module was found.
 
397
    """
 
398
    try:
 
399
        try:
 
400
            return __import__(importName)
 
401
        except ImportError:
 
402
            excType, excValue, excTraceback = sys.exc_info()
 
403
            while excTraceback:
 
404
                execName = excTraceback.tb_frame.f_globals["__name__"]
 
405
                if (execName is None or # python 2.4+, post-cleanup
 
406
                    execName == importName): # python 2.3, no cleanup
 
407
                    raise excType, excValue, excTraceback
 
408
                excTraceback = excTraceback.tb_next
 
409
            raise _NoModuleFound()
 
410
    except:
 
411
        # Necessary for cleaning up modules in 2.3.
 
412
        sys.modules.pop(importName, None)
 
413
        raise
 
414
 
 
415
 
 
416
 
 
417
def namedAny(name):
 
418
    """
 
419
    Retrieve a Python object by its fully qualified name from the global Python
 
420
    module namespace.  The first part of the name, that describes a module,
 
421
    will be discovered and imported.  Each subsequent part of the name is
 
422
    treated as the name of an attribute of the object specified by all of the
 
423
    name which came before it.  For example, the fully-qualified name of this
 
424
    object is 'twisted.python.reflect.namedAny'.
 
425
 
 
426
    @type name: L{str}
 
427
    @param name: The name of the object to return.
 
428
 
 
429
    @raise InvalidName: If the name is an empty string, starts or ends with
 
430
        a '.', or is otherwise syntactically incorrect.
 
431
 
 
432
    @raise ModuleNotFound: If the name is syntactically correct but the
 
433
        module it specifies cannot be imported because it does not appear to
 
434
        exist.
 
435
 
 
436
    @raise ObjectNotFound: If the name is syntactically correct, includes at
 
437
        least one '.', but the module it specifies cannot be imported because
 
438
        it does not appear to exist.
 
439
 
 
440
    @raise AttributeError: If an attribute of an object along the way cannot be
 
441
        accessed, or a module along the way is not found.
 
442
 
 
443
    @return: the Python object identified by 'name'.
 
444
    """
 
445
    if not name:
 
446
        raise InvalidName('Empty module name')
 
447
 
 
448
    names = name.split('.')
 
449
 
 
450
    # if the name starts or ends with a '.' or contains '..', the __import__
 
451
    # will raise an 'Empty module name' error. This will provide a better error
 
452
    # message.
 
453
    if '' in names:
 
454
        raise InvalidName(
 
455
            "name must be a string giving a '.'-separated list of Python "
 
456
            "identifiers, not %r" % (name,))
 
457
 
 
458
    topLevelPackage = None
 
459
    moduleNames = names[:]
 
460
    while not topLevelPackage:
 
461
        if moduleNames:
 
462
            trialname = '.'.join(moduleNames)
 
463
            try:
 
464
                topLevelPackage = _importAndCheckStack(trialname)
 
465
            except _NoModuleFound:
 
466
                moduleNames.pop()
 
467
        else:
 
468
            if len(names) == 1:
 
469
                raise ModuleNotFound("No module named %r" % (name,))
 
470
            else:
 
471
                raise ObjectNotFound('%r does not name an object' % (name,))
 
472
 
 
473
    obj = topLevelPackage
 
474
    for n in names[1:]:
 
475
        obj = getattr(obj, n)
 
476
 
 
477
    return obj
 
478
 
 
479
 
 
480
 
 
481
def macro(name, filename, source, **identifiers):
 
482
    """macro(name, source, **identifiers)
 
483
 
 
484
    This allows you to create macro-like behaviors in python.
 
485
    """
 
486
    if not identifiers.has_key('name'):
 
487
        identifiers['name'] = name
 
488
    source = source % identifiers
 
489
    codeplace = "<%s (macro)>" % filename
 
490
    code = compile(source, codeplace, 'exec')
 
491
 
 
492
    # shield your eyes!
 
493
    sm = sys.modules
 
494
    tprm = "twisted.python.reflect.macros"
 
495
    if not sm.has_key(tprm):
 
496
        macros = new.module(tprm)
 
497
        sm[tprm] = macros
 
498
        macros.count = 0
 
499
    macros = sm[tprm]
 
500
    macros.count += 1
 
501
    macroname = 'macro_' + str(macros.count)
 
502
    tprmm = tprm + '.' + macroname
 
503
    mymod = new.module(tprmm)
 
504
    sys.modules[tprmm] = mymod
 
505
    setattr(macros, macroname, mymod)
 
506
    dict = mymod.__dict__
 
507
 
 
508
    # Before we go on, I guess I should explain why I just did that.  Basically
 
509
    # it's a gross hack to get epydoc to work right, but the general idea is
 
510
    # that it will be a useful aid in debugging in _any_ app which expects
 
511
    # sys.modules to have the same globals as some function.  For example, it
 
512
    # would be useful if you were foolishly trying to pickle a wrapped function
 
513
    # directly from a class that had been hooked.
 
514
 
 
515
    exec code in dict, dict
 
516
    return dict[name]
 
517
macro = deprecated(Version("Twisted", 8, 2, 0))(macro)
 
518
 
 
519
 
 
520
 
 
521
def _determineClass(x):
 
522
    try:
 
523
        return x.__class__
 
524
    except:
 
525
        return type(x)
 
526
 
 
527
 
 
528
 
 
529
def _determineClassName(x):
 
530
    c = _determineClass(x)
 
531
    try:
 
532
        return c.__name__
 
533
    except:
 
534
        try:
 
535
            return str(c)
 
536
        except:
 
537
            return '<BROKEN CLASS AT 0x%x>' % unsignedID(c)
 
538
 
 
539
 
 
540
 
 
541
def _safeFormat(formatter, o):
 
542
    """
 
543
    Helper function for L{safe_repr} and L{safe_str}.
 
544
    """
 
545
    try:
 
546
        return formatter(o)
 
547
    except:
 
548
        io = StringIO()
 
549
        traceback.print_exc(file=io)
 
550
        className = _determineClassName(o)
 
551
        tbValue = io.getvalue()
 
552
        return "<%s instance at 0x%x with %s error:\n %s>" % (
 
553
            className, unsignedID(o), formatter.__name__, tbValue)
 
554
 
 
555
 
 
556
 
 
557
def safe_repr(o):
 
558
    """
 
559
    safe_repr(anything) -> string
 
560
 
 
561
    Returns a string representation of an object, or a string containing a
 
562
    traceback, if that object's __repr__ raised an exception.
 
563
    """
 
564
    return _safeFormat(repr, o)
 
565
 
 
566
 
 
567
 
 
568
def safe_str(o):
 
569
    """
 
570
    safe_str(anything) -> string
 
571
 
 
572
    Returns a string representation of an object, or a string containing a
 
573
    traceback, if that object's __str__ raised an exception.
 
574
    """
 
575
    return _safeFormat(str, o)
 
576
 
 
577
 
 
578
 
 
579
##the following were factored out of usage
 
580
 
 
581
def allYourBase(classObj, baseClass=None):
 
582
    """allYourBase(classObj, baseClass=None) -> list of all base
 
583
    classes that are subclasses of baseClass, unless it is None,
 
584
    in which case all bases will be added.
 
585
    """
 
586
    l = []
 
587
    accumulateBases(classObj, l, baseClass)
 
588
    return l
 
589
 
 
590
 
 
591
def accumulateBases(classObj, l, baseClass=None):
 
592
    for base in classObj.__bases__:
 
593
        if baseClass is None or issubclass(base, baseClass):
 
594
            l.append(base)
 
595
        accumulateBases(base, l, baseClass)
 
596
 
 
597
 
 
598
def prefixedMethodNames(classObj, prefix):
 
599
    """A list of method names with a given prefix in a given class.
 
600
    """
 
601
    dct = {}
 
602
    addMethodNamesToDict(classObj, dct, prefix)
 
603
    return dct.keys()
 
604
 
 
605
 
 
606
def addMethodNamesToDict(classObj, dict, prefix, baseClass=None):
 
607
    """
 
608
    addMethodNamesToDict(classObj, dict, prefix, baseClass=None) -> dict
 
609
    this goes through 'classObj' (and its bases) and puts method names
 
610
    starting with 'prefix' in 'dict' with a value of 1. if baseClass isn't
 
611
    None, methods will only be added if classObj is-a baseClass
 
612
 
 
613
    If the class in question has the methods 'prefix_methodname' and
 
614
    'prefix_methodname2', the resulting dict should look something like:
 
615
    {"methodname": 1, "methodname2": 1}.
 
616
    """
 
617
    for base in classObj.__bases__:
 
618
        addMethodNamesToDict(base, dict, prefix, baseClass)
 
619
 
 
620
    if baseClass is None or baseClass in classObj.__bases__:
 
621
        for name, method in classObj.__dict__.items():
 
622
            optName = name[len(prefix):]
 
623
            if ((type(method) is types.FunctionType)
 
624
                and (name[:len(prefix)] == prefix)
 
625
                and (len(optName))):
 
626
                dict[optName] = 1
 
627
 
 
628
 
 
629
def prefixedMethods(obj, prefix=''):
 
630
    """A list of methods with a given prefix on a given instance.
 
631
    """
 
632
    dct = {}
 
633
    accumulateMethods(obj, dct, prefix)
 
634
    return dct.values()
 
635
 
 
636
 
 
637
def accumulateMethods(obj, dict, prefix='', curClass=None):
 
638
    """accumulateMethods(instance, dict, prefix)
 
639
    I recurse through the bases of instance.__class__, and add methods
 
640
    beginning with 'prefix' to 'dict', in the form of
 
641
    {'methodname':*instance*method_object}.
 
642
    """
 
643
    if not curClass:
 
644
        curClass = obj.__class__
 
645
    for base in curClass.__bases__:
 
646
        accumulateMethods(obj, dict, prefix, base)
 
647
 
 
648
    for name, method in curClass.__dict__.items():
 
649
        optName = name[len(prefix):]
 
650
        if ((type(method) is types.FunctionType)
 
651
            and (name[:len(prefix)] == prefix)
 
652
            and (len(optName))):
 
653
            dict[optName] = getattr(obj, name)
 
654
 
 
655
 
 
656
def accumulateClassDict(classObj, attr, adict, baseClass=None):
 
657
    """Accumulate all attributes of a given name in a class heirarchy into a single dictionary.
 
658
 
 
659
    Assuming all class attributes of this name are dictionaries.
 
660
    If any of the dictionaries being accumulated have the same key, the
 
661
    one highest in the class heirarchy wins.
 
662
    (XXX: If \"higest\" means \"closest to the starting class\".)
 
663
 
 
664
    Ex::
 
665
 
 
666
    | class Soy:
 
667
    |   properties = {\"taste\": \"bland\"}
 
668
    |
 
669
    | class Plant:
 
670
    |   properties = {\"colour\": \"green\"}
 
671
    |
 
672
    | class Seaweed(Plant):
 
673
    |   pass
 
674
    |
 
675
    | class Lunch(Soy, Seaweed):
 
676
    |   properties = {\"vegan\": 1 }
 
677
    |
 
678
    | dct = {}
 
679
    |
 
680
    | accumulateClassDict(Lunch, \"properties\", dct)
 
681
    |
 
682
    | print dct
 
683
 
 
684
    {\"taste\": \"bland\", \"colour\": \"green\", \"vegan\": 1}
 
685
    """
 
686
    for base in classObj.__bases__:
 
687
        accumulateClassDict(base, attr, adict)
 
688
    if baseClass is None or baseClass in classObj.__bases__:
 
689
        adict.update(classObj.__dict__.get(attr, {}))
 
690
 
 
691
 
 
692
def accumulateClassList(classObj, attr, listObj, baseClass=None):
 
693
    """Accumulate all attributes of a given name in a class heirarchy into a single list.
 
694
 
 
695
    Assuming all class attributes of this name are lists.
 
696
    """
 
697
    for base in classObj.__bases__:
 
698
        accumulateClassList(base, attr, listObj)
 
699
    if baseClass is None or baseClass in classObj.__bases__:
 
700
        listObj.extend(classObj.__dict__.get(attr, []))
 
701
 
 
702
 
 
703
def isSame(a, b):
 
704
    return (a is b)
 
705
 
 
706
 
 
707
def isLike(a, b):
 
708
    return (a == b)
 
709
 
 
710
 
 
711
def modgrep(goal):
 
712
    return objgrep(sys.modules, goal, isLike, 'sys.modules')
 
713
 
 
714
 
 
715
def isOfType(start, goal):
 
716
    return ((type(start) is goal) or
 
717
            (isinstance(start, types.InstanceType) and
 
718
             start.__class__ is goal))
 
719
 
 
720
 
 
721
def findInstances(start, t):
 
722
    return objgrep(start, t, isOfType)
 
723
 
 
724
 
 
725
def objgrep(start, goal, eq=isLike, path='', paths=None, seen=None, showUnknowns=0, maxDepth=None):
 
726
    '''An insanely CPU-intensive process for finding stuff.
 
727
    '''
 
728
    if paths is None:
 
729
        paths = []
 
730
    if seen is None:
 
731
        seen = {}
 
732
    if eq(start, goal):
 
733
        paths.append(path)
 
734
    if id(start) in seen:
 
735
        if seen[id(start)] is start:
 
736
            return
 
737
    if maxDepth is not None:
 
738
        if maxDepth == 0:
 
739
            return
 
740
        maxDepth -= 1
 
741
    seen[id(start)] = start
 
742
    if isinstance(start, types.DictionaryType):
 
743
        for k, v in start.items():
 
744
            objgrep(k, goal, eq, path+'{'+repr(v)+'}', paths, seen, showUnknowns, maxDepth)
 
745
            objgrep(v, goal, eq, path+'['+repr(k)+']', paths, seen, showUnknowns, maxDepth)
 
746
    elif isinstance(start, (list, tuple, deque)):
 
747
        for idx in xrange(len(start)):
 
748
            objgrep(start[idx], goal, eq, path+'['+str(idx)+']', paths, seen, showUnknowns, maxDepth)
 
749
    elif isinstance(start, types.MethodType):
 
750
        objgrep(start.im_self, goal, eq, path+'.im_self', paths, seen, showUnknowns, maxDepth)
 
751
        objgrep(start.im_func, goal, eq, path+'.im_func', paths, seen, showUnknowns, maxDepth)
 
752
        objgrep(start.im_class, goal, eq, path+'.im_class', paths, seen, showUnknowns, maxDepth)
 
753
    elif hasattr(start, '__dict__'):
 
754
        for k, v in start.__dict__.items():
 
755
            objgrep(v, goal, eq, path+'.'+k, paths, seen, showUnknowns, maxDepth)
 
756
        if isinstance(start, types.InstanceType):
 
757
            objgrep(start.__class__, goal, eq, path+'.__class__', paths, seen, showUnknowns, maxDepth)
 
758
    elif isinstance(start, weakref.ReferenceType):
 
759
        objgrep(start(), goal, eq, path+'()', paths, seen, showUnknowns, maxDepth)
 
760
    elif (isinstance(start, types.StringTypes+
 
761
                    (types.IntType, types.FunctionType,
 
762
                     types.BuiltinMethodType, RegexType, types.FloatType,
 
763
                     types.NoneType, types.FileType)) or
 
764
          type(start).__name__ in ('wrapper_descriptor', 'method_descriptor',
 
765
                                   'member_descriptor', 'getset_descriptor')):
 
766
        pass
 
767
    elif showUnknowns:
 
768
        print 'unknown type', type(start), start
 
769
    return paths
 
770
 
 
771
 
 
772
def filenameToModuleName(fn):
 
773
    """
 
774
    Convert a name in the filesystem to the name of the Python module it is.
 
775
 
 
776
    This is agressive about getting a module name back from a file; it will
 
777
    always return a string.  Agressive means 'sometimes wrong'; it won't look
 
778
    at the Python path or try to do any error checking: don't use this method
 
779
    unless you already know that the filename you're talking about is a Python
 
780
    module.
 
781
    """
 
782
    fullName = os.path.abspath(fn)
 
783
    base = os.path.basename(fn)
 
784
    if not base:
 
785
        # this happens when fn ends with a path separator, just skit it
 
786
        base = os.path.basename(fn[:-1])
 
787
    modName = os.path.splitext(base)[0]
 
788
    while 1:
 
789
        fullName = os.path.dirname(fullName)
 
790
        if os.path.exists(os.path.join(fullName, "__init__.py")):
 
791
            modName = "%s.%s" % (os.path.basename(fullName), modName)
 
792
        else:
 
793
            break
 
794
    return modName
 
795
 
 
796
 
 
797
 
 
798
__all__ = [
 
799
    'InvalidName', 'ModuleNotFound', 'ObjectNotFound',
 
800
 
 
801
    'ISNT', 'WAS', 'IS',
 
802
 
 
803
    'Settable', 'AccessorType', 'PropertyAccessor', 'Accessor', 'Summer',
 
804
    'QueueMethod', 'OriginalAccessor',
 
805
 
 
806
    'funcinfo', 'fullFuncName', 'qual', 'getcurrent', 'getClass', 'isinst',
 
807
    'namedModule', 'namedObject', 'namedClass', 'namedAny', 'macro',
 
808
    'safe_repr', 'safe_str', 'allYourBase', 'accumulateBases',
 
809
    'prefixedMethodNames', 'addMethodNamesToDict', 'prefixedMethods',
 
810
    'accumulateClassDict', 'accumulateClassList', 'isSame', 'isLike',
 
811
    'modgrep', 'isOfType', 'findInstances', 'objgrep', 'filenameToModuleName',
 
812
    'fullyQualifiedName']