• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Generic metaclass.
2
3XXX This is very much a work in progress.
4
5"""
6
7import types
8
9class MetaMethodWrapper:
10
11    def __init__(self, func, inst):
12        self.func = func
13        self.inst = inst
14        self.__name__ = self.func.__name__
15
16    def __call__(self, *args, **kw):
17        return apply(self.func, (self.inst,) + args, kw)
18
19class MetaHelper:
20
21    __methodwrapper__ = MetaMethodWrapper # For derived helpers to override
22
23    def __helperinit__(self, formalclass):
24        self.__formalclass__ = formalclass
25
26    def __getattr__(self, name):
27        # Invoked for any attr not in the instance's __dict__
28        try:
29            raw = self.__formalclass__.__getattr__(name)
30        except AttributeError:
31            try:
32                ga = self.__formalclass__.__getattr__('__usergetattr__')
33            except (KeyError, AttributeError):
34                raise AttributeError, name
35            return ga(self, name)
36        if type(raw) != types.FunctionType:
37            return raw
38        return self.__methodwrapper__(raw, self)
39
40class MetaClass:
41
42    """A generic metaclass.
43
44    This can be subclassed to implement various kinds of meta-behavior.
45
46    """
47
48    __helper__ = MetaHelper             # For derived metaclasses to override
49
50    __inited = 0
51
52    def __init__(self, name, bases, dict):
53        try:
54            ga = dict['__getattr__']
55        except KeyError:
56            pass
57        else:
58            dict['__usergetattr__'] = ga
59            del dict['__getattr__']
60        self.__name__ = name
61        self.__bases__ = bases
62        self.__realdict__ = dict
63        self.__inited = 1
64
65    def __getattr__(self, name):
66        try:
67            return self.__realdict__[name]
68        except KeyError:
69            for base in self.__bases__:
70                try:
71                    return base.__getattr__(name)
72                except AttributeError:
73                    pass
74            raise AttributeError, name
75
76    def __setattr__(self, name, value):
77        if not self.__inited:
78            self.__dict__[name] = value
79        else:
80            self.__realdict__[name] = value
81
82    def __call__(self, *args, **kw):
83        inst = self.__helper__()
84        inst.__helperinit__(self)
85        try:
86            init = inst.__getattr__('__init__')
87        except AttributeError:
88            init = lambda: None
89        apply(init, args, kw)
90        return inst
91
92
93Meta = MetaClass('Meta', (), {})
94
95
96def _test():
97    class C(Meta):
98        def __init__(self, *args):
99            print "__init__, args =", args
100        def m1(self, x):
101            print "m1(x=%r)" % (x,)
102    print C
103    x = C()
104    print x
105    x.m1(12)
106    class D(C):
107        def __getattr__(self, name):
108            if name[:2] == '__': raise AttributeError, name
109            return "getattr:%s" % name
110    x = D()
111    print x.foo
112    print x._foo
113##     print x.__foo
114##     print x.__foo__
115
116
117if __name__ == '__main__':
118    _test()
119