]> git.phdru.name Git - m_lib.git/blob - m_lib/metaclasses.py
Use int() instead of atoi() for Py3 compatibility
[m_lib.git] / m_lib / metaclasses.py
1 #! /usr/bin/env python
2
3
4 # From: Michele Simionato (mis6@pitt.edu)
5 # http://groups.google.com/groups?selm=2259b0e2.0304250413.4be8ee45%40posting.google.com
6 # To solve "TypeError: metatype conflict among bases"
7
8
9 def _generatemetaclass(bases, metas):
10    "Internal function called by child"
11
12    if metas == (type,): # trivial metaclass
13        metabases = (); metaname = "_"
14    else: # non-trivial metaclass
15        metabases = metas
16        metaname = "_"+''.join([m.__name__ for m in metas])
17    trivial = lambda m: m in metabases or m is type
18
19    for b in bases:
20        meta_b = type(b)
21        if not trivial(meta_b):
22            metabases += (meta_b,)
23            metaname += meta_b.__name__
24
25    if not metabases: # trivial metabase
26        return type
27    elif len(metabases) == 1: # single metabase
28        return metabases[0]
29    else: # multiple metabases
30        return type(metaname, metabases, {}) # creates a new metaclass
31       #shifting the possible conflict to meta-metaclasses
32
33
34 def child(*bases, **options):
35    """Class factory avoiding metatype conflicts: if the base classes have
36    metaclasses conflicting within themselves or with the given metaclass,
37    it automatically generates a compatible metaclass and instantiate the
38    child class from it. The recognized keywords in the option dictionary
39    are name, dic and meta."""
40    name = options.get('name', ''.join([b.__name__ for b in bases])+'_')
41    dic = options.get('dic', {})
42    metas = options.get('metas', (type,))
43    return _generatemetaclass(bases, metas)(name, bases, dic)
44
45
46
47 def test():
48     class M_A(type): pass
49     class M_B(type): pass
50     A = M_A('A', (), {})
51     B = M_B('B', (), {})
52
53     try:
54        class C(A, B): pass
55     except TypeError:
56        pass
57     else:
58        raise RuntimeError
59
60     C = child(A, B, name='C')
61
62
63 if __name__ == "__main__":
64     test()