blob: 9126cf6524ca47a3120fc9d512b4110e61b1b451 [file] [log] [blame]
Guido van Rossum52cc1d82007-03-18 15:41:51 +00001doctests = """
2
3Basic class construction.
4
5 >>> class C:
6 ... def meth(self): print("Hello")
7 ...
8 >>> C.__class__ is type
9 True
10 >>> a = C()
11 >>> a.__class__ is C
12 True
13 >>> a.meth()
14 Hello
15 >>>
16
17Use *args notation for the bases.
18
19 >>> class A: pass
20 >>> class B: pass
21 >>> bases = (A, B)
22 >>> class C(*bases): pass
23 >>> C.__bases__ == bases
24 True
25 >>>
26
27Use a trivial metaclass.
28
29 >>> class M(type):
30 ... pass
31 ...
32 >>> class C(metaclass=M):
33 ... def meth(self): print("Hello")
34 ...
35 >>> C.__class__ is M
36 True
37 >>> a = C()
38 >>> a.__class__ is C
39 True
40 >>> a.meth()
41 Hello
42 >>>
43
44Use **kwds notation for the metaclass keyword.
45
46 >>> kwds = {'metaclass': M}
47 >>> class C(**kwds): pass
48 ...
49 >>> C.__class__ is M
50 True
51 >>> a = C()
52 >>> a.__class__ is C
53 True
54 >>>
55
56Use a metaclass with a __prepare__ static method.
57
58 >>> class M(type):
59 ... @staticmethod
60 ... def __prepare__(*args, **kwds):
61 ... print("Prepare called:", args, kwds)
62 ... return dict()
63 ... def __new__(cls, name, bases, namespace, **kwds):
64 ... print("New called:", kwds)
65 ... return type.__new__(cls, name, bases, namespace)
Guido van Rossumd8faa362007-04-27 19:54:29 +000066 ... def __init__(cls, *args, **kwds):
67 ... pass
Guido van Rossum52cc1d82007-03-18 15:41:51 +000068 ...
69 >>> class C(metaclass=M):
70 ... def meth(self): print("Hello")
71 ...
72 Prepare called: ('C', ()) {}
73 New called: {}
74 >>>
75
76Also pass another keyword.
77
78 >>> class C(object, metaclass=M, other="haha"):
79 ... pass
80 ...
81 Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
82 New called: {'other': 'haha'}
83 >>> C.__class__ is M
84 True
85 >>> C.__bases__ == (object,)
86 True
87 >>> a = C()
88 >>> a.__class__ is C
89 True
90 >>>
91
92Check that build_class doesn't mutate the kwds dict.
93
94 >>> kwds = {'metaclass': type}
95 >>> class C(**kwds): pass
96 ...
97 >>> kwds == {'metaclass': type}
98 True
99 >>>
100
101Use various combinations of explicit keywords and **kwds.
102
103 >>> bases = (object,)
104 >>> kwds = {'metaclass': M, 'other': 'haha'}
105 >>> class C(*bases, **kwds): pass
106 ...
107 Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
108 New called: {'other': 'haha'}
109 >>> C.__class__ is M
110 True
111 >>> C.__bases__ == (object,)
112 True
113 >>> class B: pass
114 >>> kwds = {'other': 'haha'}
115 >>> class C(B, metaclass=M, *bases, **kwds): pass
116 ...
117 Prepare called: ('C', (<class 'test.test_metaclass.B'>, <type 'object'>)) {'other': 'haha'}
118 New called: {'other': 'haha'}
119 >>> C.__class__ is M
120 True
121 >>> C.__bases__ == (B, object)
122 True
123 >>>
124
125Check for duplicate keywords.
126
127 >>> class C(metaclass=type, metaclass=type): pass
128 ...
129 Traceback (most recent call last):
130 [...]
131 TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
132 >>>
133
134Another way.
135
136 >>> kwds = {'metaclass': type}
137 >>> class C(metaclass=type, **kwds): pass
138 ...
139 Traceback (most recent call last):
140 [...]
141 TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
142 >>>
143
144Use a __prepare__ method that returns an instrumented dict.
145
146 >>> class LoggingDict(dict):
147 ... def __setitem__(self, key, value):
148 ... print("d[%r] = %r" % (key, value))
149 ... dict.__setitem__(self, key, value)
150 ...
151 >>> class Meta(type):
152 ... @staticmethod
153 ... def __prepare__(name, bases):
154 ... return LoggingDict()
155 ...
156 >>> class C(metaclass=Meta):
157 ... foo = 2+2
158 ... foo = 42
159 ... bar = 123
160 ...
161 d['__module__'] = 'test.test_metaclass'
162 d['foo'] = 4
163 d['foo'] = 42
164 d['bar'] = 123
165 >>>
166
167Use a metaclass that doesn't derive from type.
168
169 >>> def meta(name, bases, namespace, **kwds):
170 ... print("meta:", name, bases)
171 ... print("ns:", sorted(namespace.items()))
172 ... print("kw:", sorted(kwds.items()))
173 ... return namespace
174 ...
175 >>> class C(metaclass=meta):
176 ... a = 42
177 ... b = 24
178 ...
179 meta: C ()
180 ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
181 kw: []
182 >>> type(C) is dict
183 True
184 >>> print(sorted(C.items()))
185 [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
186 >>>
187
188And again, with a __prepare__ attribute.
189
190 >>> def prepare(name, bases, **kwds):
191 ... print("prepare:", name, bases, sorted(kwds.items()))
192 ... return LoggingDict()
193 ...
194 >>> meta.__prepare__ = prepare
195 >>> class C(metaclass=meta, other="booh"):
196 ... a = 1
197 ... a = 2
198 ... b = 3
199 ...
200 prepare: C () [('other', 'booh')]
201 d['__module__'] = 'test.test_metaclass'
202 d['a'] = 1
203 d['a'] = 2
204 d['b'] = 3
205 meta: C ()
206 ns: [('__module__', 'test.test_metaclass'), ('a', 2), ('b', 3)]
207 kw: [('other', 'booh')]
208 >>>
209
210"""
211
212__test__ = {'doctests' : doctests}
213
214def test_main(verbose=False):
215 from test import test_support
216 from test import test_metaclass
217 test_support.run_doctest(test_metaclass, verbose)
218
219if __name__ == "__main__":
220 test_main(verbose=True)