blob: e6fe20a107c239a64fc1e8bedfda2b159134f56f [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 ...
Benjamin Petersonab078e92016-07-13 21:13:29 -070081 Prepare called: ('C', (<class 'object'>,)) {'other': 'haha'}
Guido van Rossum52cc1d82007-03-18 15:41:51 +000082 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 ...
Benjamin Petersonab078e92016-07-13 21:13:29 -0700107 Prepare called: ('C', (<class 'object'>,)) {'other': 'haha'}
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000108 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 ...
Benjamin Petersonab078e92016-07-13 21:13:29 -0700117 Prepare called: ('C', (<class 'test.test_metaclass.B'>, <class 'object'>)) {'other': 'haha'}
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000118 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 [...]
Benjamin Peterson13b6d0d2008-07-01 20:26:36 +0000131 SyntaxError: keyword argument repeated
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000132 >>>
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'
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100162 d['__qualname__'] = 'C'
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000163 d['foo'] = 4
164 d['foo'] = 42
165 d['bar'] = 123
166 >>>
167
168Use a metaclass that doesn't derive from type.
169
170 >>> def meta(name, bases, namespace, **kwds):
171 ... print("meta:", name, bases)
172 ... print("ns:", sorted(namespace.items()))
173 ... print("kw:", sorted(kwds.items()))
174 ... return namespace
175 ...
176 >>> class C(metaclass=meta):
177 ... a = 42
178 ... b = 24
179 ...
180 meta: C ()
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100181 ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000182 kw: []
Eric Snow4f29e752016-09-08 15:11:11 -0700183 >>> type(C) is dict
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000184 True
185 >>> print(sorted(C.items()))
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100186 [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000187 >>>
188
189And again, with a __prepare__ attribute.
190
191 >>> def prepare(name, bases, **kwds):
192 ... print("prepare:", name, bases, sorted(kwds.items()))
193 ... return LoggingDict()
194 ...
195 >>> meta.__prepare__ = prepare
196 >>> class C(metaclass=meta, other="booh"):
197 ... a = 1
198 ... a = 2
199 ... b = 3
200 ...
201 prepare: C () [('other', 'booh')]
202 d['__module__'] = 'test.test_metaclass'
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100203 d['__qualname__'] = 'C'
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000204 d['a'] = 1
205 d['a'] = 2
206 d['b'] = 3
207 meta: C ()
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100208 ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)]
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000209 kw: [('other', 'booh')]
210 >>>
211
Guido van Rossum47374822007-08-02 16:48:17 +0000212The default metaclass must define a __prepare__() method.
213
Eric Snow4f29e752016-09-08 15:11:11 -0700214 >>> type.__prepare__()
215 {}
Guido van Rossum47374822007-08-02 16:48:17 +0000216 >>>
217
218Make sure it works with subclassing.
219
220 >>> class M(type):
221 ... @classmethod
222 ... def __prepare__(cls, *args, **kwds):
223 ... d = super().__prepare__(*args, **kwds)
224 ... d["hello"] = 42
225 ... return d
226 ...
227 >>> class C(metaclass=M):
228 ... print(hello)
229 ...
230 42
231 >>> print(C.hello)
232 42
233 >>>
234
Benjamin Peterson23e018a2010-02-27 17:40:01 +0000235Test failures in looking up the __prepare__ method work.
236 >>> class ObscureException(Exception):
237 ... pass
238 >>> class FailDescr:
239 ... def __get__(self, instance, owner):
240 ... raise ObscureException
241 >>> class Meta(type):
242 ... __prepare__ = FailDescr()
243 >>> class X(metaclass=Meta):
244 ... pass
245 Traceback (most recent call last):
246 [...]
247 test.test_metaclass.ObscureException
248
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000249"""
250
Brett Cannon7a540732011-02-22 03:04:06 +0000251import sys
252
253# Trace function introduces __locals__ which causes various tests to fail.
254if hasattr(sys, 'gettrace') and sys.gettrace():
255 __test__ = {}
256else:
257 __test__ = {'doctests' : doctests}
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000258
259def test_main(verbose=False):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000260 from test import support
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000261 from test import test_metaclass
Benjamin Petersonab078e92016-07-13 21:13:29 -0700262 support.run_doctest(test_metaclass, verbose)
Guido van Rossum52cc1d82007-03-18 15:41:51 +0000263
264if __name__ == "__main__":
265 test_main(verbose=True)