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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
# testnoconflict.py
from safetype import safetype as type
errormsg23 = "multiple bases have instance lay-out conflict"
errormsg24 = """Error when calling the metaclass bases
multiple bases have instance lay-out conflict"""
try:
set
except NameError: # we are using Python 2.3
errormsg = errormsg23
else: # we are using Python 2.4
errormsg = errormsg24
# the simplest non-trivial case (M_A and M_B)
class M_A(type): pass
class M_B(type): pass
class A: __metaclass__ = M_A
class B: __metaclass__ = M_B
class C(A,B):
pass
# here needed_metas = (M_A, M_B)
assert C.__class__.__name__ == "_M_AM_B"
# injecting M_A from left
class C(B):
__metaclass__ = M_A
# here needed_metas = (M_A, M_B)
assert C.__class__.__name__ == "_M_AM_B"
# injecting M_B from left
class C(A):
__metaclass__ = M_B
# here needed_metas = (M_A, M_B)
assert C.__class__.__name__ == "_M_BM_A"
# composing an old-style class and a metaclass
class O: pass
try:
class C(O, M_A):
pass
except TypeError, e:
# here needed_metas = (type, )
assert str(e) == errormsg
# the other way around
try:
class C(M_A, O):
pass
except TypeError, e:
# here needed_metas = (type, )
assert str(e) == errormsg
# composing an new-style class and a metaclass
class N(object): pass
try:
class C(N, M_A):
pass
except TypeError, e:
# here needed_metas = (type, )
assert str(e) == errormsg
# the other way around
try:
class C(M_A, N):
pass
except TypeError, e:
# here needed_metas = (type, )
assert str(e) == errormsg
# composing a non-trivial class and a metaclass
class C(B, M_A):
pass
# here needed_metas = (M_B,)
assert C.__class__ is M_B
# the other way around
class C(M_A, B):
pass
# here needed_metas = (M_B,)
assert C.__class__ is M_B
# a more bizarre hierarchy
class C(B, M_B):
pass
# here needed_metas = (M_B,)
assert C.__class__ is M_B
# C.__mro__ == [C, B, M_B, type, object]
# changing the order
class C(M_B, B):
pass
# here needed_metas = (M_B,)
assert C.__class__ is M_B
# C.__mro__ == [C, M_B, type, B, object]
# meta-metaclasses
class MM_X(type): pass
class MM_Y(type): pass
class M_X(type): __metaclass__ = MM_X
class M_Y(type): __metaclass__ = MM_Y
class X(type): __metaclass__ = M_X
class Y(type): __metaclass__ = M_Y
class Z(X,Y): pass
# here needed_metas = (M_X, M_Y)
assert Z.__class__.__name__ == "_M_XM_Y"
# in order to construct _M_XM_Y classmaker has to
# construct _MM_XMM_Y first:
assert Z.__class__.__class__.__name__ == "_MM_XMM_Y"
class C(Z, B): pass
# here needed_metas = (_M_XM_Y, M_B)
# composition of many metaclasses
class M_A(type): pass
class M_B(type): pass
class M_C(M_B): pass
class A: __metaclass__ = M_A
class B: __metaclass__ = M_B
class C: __metaclass__ = M_C
class D: __metaclass__ = M_B
class E(A, B):
pass
# here needed_metas = (M_A, M_B)
assert E.__class__.__name__ == "_M_AM_B"
class F(C):
pass
# here needed_metas = (M_A, M_B)
assert F.__class__.__name__ == "M_C"
class G(E, F):
pass
# here needed_metas = (_M_AM_B, M_C)
assert G.__class__.__name__ == "__M_AM_BM_C"
## Test for C-coded metaclasses, i.e. Zope ExtensionClass
try: # is Zope installed?
from OFS.Folder import Folder # an instance of Zope ExtensionClass
class C(Folder): # no problem here
pass
assert C.__class__.__name__ == "ExtensionClass"
try:
class C(Folder):
__metaclass__ = M_A
except TypeError, e:
e[1] == 'Incompatible root metatypes'
except ImportError:
pass # will skip the ExtensionClass test
|