summaryrefslogtreecommitdiff
path: root/pypers/meta/testsafetype.py
blob: b3c63369a562f39d8c78a35587cd2c72a3d41278 (plain)
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