zvoase (owner)

Revisions

  • 118488 Tue Feb 10 09:55:07 -0800 2009
gist: 61496 Download_button fork
public
Public Clone URL: git://gist.github.com/61496.git
Embed All Files: show embed
callsuper.py #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class CallSuper(Exception): pass
 
 
def callsuper(method):
    """
Decorator for calling the super method automagically.
In the submethod, if a ``CallSuper`` exception is raised at any point, then
the wrapper will look up the class's MRO (method resolution order) for a
method of the same name. If none is found, the exception is allowed to
permeate. If one is found, it too is wrapped with the ``callsuper``
decorator and called with the arguments passed to ``CallSuper.__init__()``.
"""
    def callsuper_wrapper(self, *args):
        try:
            return method(self, *args)
        except CallSuper, exc:
            supermethod, name = None, method.__name__
            for base in self.__class__.mro()[1:]:
                if (hasattr(base, name) and
                    hasattr(getattr(base, name), '__call__')):
                    supermethod = callsuper(getattr(base, name))
                    break
            if not supermethod:
                raise
            return supermethod(self, *exc.args)
    callsuper_wrapper.__name__ = method.__name__
    callsuper_wrapper.__doc__ = method.__doc__
    return callsuper_wrapper
 
# Test it out
 
global COUNTER
COUNTER = 0
 
class SuperClass(object):
    
    def method(self):
        global COUNTER
        COUNTER += 1 # Increment counter.
 
class SubClass(SuperClass):
    
    @callsuper
    def method(self):
        global COUNTER
        COUNTER += 1 # Increment counter.
        raise CallSuper
 
SubClass().method()
assert COUNTER == 2