1doctests = """ 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 ... def __init__(cls, *args, **kwds): 67 ... pass 68 ... 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', (<class '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', (<class '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'>, <class '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 SyntaxError: keyword argument repeated: 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['__qualname__'] = 'C' 163 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 () 181 ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] 182 kw: [] 183 >>> type(C) is dict 184 True 185 >>> print(sorted(C.items())) 186 [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] 187 >>> 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' 203 d['__qualname__'] = 'C' 204 d['a'] = 1 205 d['a'] = 2 206 d['b'] = 3 207 meta: C () 208 ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)] 209 kw: [('other', 'booh')] 210 >>> 211 212The default metaclass must define a __prepare__() method. 213 214 >>> type.__prepare__() 215 {} 216 >>> 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 235Test 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 249""" 250 251import 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} 258 259def test_main(verbose=False): 260 from test import support 261 from test import test_metaclass 262 support.run_doctest(test_metaclass, verbose) 263 264if __name__ == "__main__": 265 test_main(verbose=True) 266