blob: df81079d1b974b138b84926a042aec64d0ada769 [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)
66 ...
67 >>> class C(metaclass=M):
68 ... def meth(self): print("Hello")
69 ...
70 Prepare called: ('C', ()) {}
71 New called: {}
72 >>>
73
74Also pass another keyword.
75
76 >>> class C(object, metaclass=M, other="haha"):
77 ... pass
78 ...
79 Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
80 New called: {'other': 'haha'}
81 >>> C.__class__ is M
82 True
83 >>> C.__bases__ == (object,)
84 True
85 >>> a = C()
86 >>> a.__class__ is C
87 True
88 >>>
89
90Check that build_class doesn't mutate the kwds dict.
91
92 >>> kwds = {'metaclass': type}
93 >>> class C(**kwds): pass
94 ...
95 >>> kwds == {'metaclass': type}
96 True
97 >>>
98
99Use various combinations of explicit keywords and **kwds.
100
101 >>> bases = (object,)
102 >>> kwds = {'metaclass': M, 'other': 'haha'}
103 >>> class C(*bases, **kwds): pass
104 ...
105 Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
106 New called: {'other': 'haha'}
107 >>> C.__class__ is M
108 True
109 >>> C.__bases__ == (object,)
110 True
111 >>> class B: pass
112 >>> kwds = {'other': 'haha'}
113 >>> class C(B, metaclass=M, *bases, **kwds): pass
114 ...
115 Prepare called: ('C', (<class 'test.test_metaclass.B'>, <type 'object'>)) {'other': 'haha'}
116 New called: {'other': 'haha'}
117 >>> C.__class__ is M
118 True
119 >>> C.__bases__ == (B, object)
120 True
121 >>>
122
123Check for duplicate keywords.
124
125 >>> class C(metaclass=type, metaclass=type): pass
126 ...
127 Traceback (most recent call last):
128 [...]
129 TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
130 >>>
131
132Another way.
133
134 >>> kwds = {'metaclass': type}
135 >>> class C(metaclass=type, **kwds): pass
136 ...
137 Traceback (most recent call last):
138 [...]
139 TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
140 >>>
141
142Use a __prepare__ method that returns an instrumented dict.
143
144 >>> class LoggingDict(dict):
145 ... def __setitem__(self, key, value):
146 ... print("d[%r] = %r" % (key, value))
147 ... dict.__setitem__(self, key, value)
148 ...
149 >>> class Meta(type):
150 ... @staticmethod
151 ... def __prepare__(name, bases):
152 ... return LoggingDict()
153 ...
154 >>> class C(metaclass=Meta):
155 ... foo = 2+2
156 ... foo = 42
157 ... bar = 123
158 ...
159 d['__module__'] = 'test.test_metaclass'
160 d['foo'] = 4
161 d['foo'] = 42
162 d['bar'] = 123
163 >>>
164
165Use a metaclass that doesn't derive from type.
166
167 >>> def meta(name, bases, namespace, **kwds):
168 ... print("meta:", name, bases)
169 ... print("ns:", sorted(namespace.items()))
170 ... print("kw:", sorted(kwds.items()))
171 ... return namespace
172 ...
173 >>> class C(metaclass=meta):
174 ... a = 42
175 ... b = 24
176 ...
177 meta: C ()
178 ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
179 kw: []
180 >>> type(C) is dict
181 True
182 >>> print(sorted(C.items()))
183 [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
184 >>>
185
186And again, with a __prepare__ attribute.
187
188 >>> def prepare(name, bases, **kwds):
189 ... print("prepare:", name, bases, sorted(kwds.items()))
190 ... return LoggingDict()
191 ...
192 >>> meta.__prepare__ = prepare
193 >>> class C(metaclass=meta, other="booh"):
194 ... a = 1
195 ... a = 2
196 ... b = 3
197 ...
198 prepare: C () [('other', 'booh')]
199 d['__module__'] = 'test.test_metaclass'
200 d['a'] = 1
201 d['a'] = 2
202 d['b'] = 3
203 meta: C ()
204 ns: [('__module__', 'test.test_metaclass'), ('a', 2), ('b', 3)]
205 kw: [('other', 'booh')]
206 >>>
207
208"""
209
210__test__ = {'doctests' : doctests}
211
212def test_main(verbose=False):
213 from test import test_support
214 from test import test_metaclass
215 test_support.run_doctest(test_metaclass, verbose)
216
217if __name__ == "__main__":
218 test_main(verbose=True)