|  | doctests = """ | 
|  |  | 
|  | Basic class construction. | 
|  |  | 
|  | >>> class C: | 
|  | ...     def meth(self): print("Hello") | 
|  | ... | 
|  | >>> C.__class__ is type | 
|  | True | 
|  | >>> a = C() | 
|  | >>> a.__class__ is C | 
|  | True | 
|  | >>> a.meth() | 
|  | Hello | 
|  | >>> | 
|  |  | 
|  | Use *args notation for the bases. | 
|  |  | 
|  | >>> class A: pass | 
|  | >>> class B: pass | 
|  | >>> bases = (A, B) | 
|  | >>> class C(*bases): pass | 
|  | >>> C.__bases__ == bases | 
|  | True | 
|  | >>> | 
|  |  | 
|  | Use a trivial metaclass. | 
|  |  | 
|  | >>> class M(type): | 
|  | ...     pass | 
|  | ... | 
|  | >>> class C(metaclass=M): | 
|  | ...    def meth(self): print("Hello") | 
|  | ... | 
|  | >>> C.__class__ is M | 
|  | True | 
|  | >>> a = C() | 
|  | >>> a.__class__ is C | 
|  | True | 
|  | >>> a.meth() | 
|  | Hello | 
|  | >>> | 
|  |  | 
|  | Use **kwds notation for the metaclass keyword. | 
|  |  | 
|  | >>> kwds = {'metaclass': M} | 
|  | >>> class C(**kwds): pass | 
|  | ... | 
|  | >>> C.__class__ is M | 
|  | True | 
|  | >>> a = C() | 
|  | >>> a.__class__ is C | 
|  | True | 
|  | >>> | 
|  |  | 
|  | Use a metaclass with a __prepare__ static method. | 
|  |  | 
|  | >>> class M(type): | 
|  | ...    @staticmethod | 
|  | ...    def __prepare__(*args, **kwds): | 
|  | ...        print("Prepare called:", args, kwds) | 
|  | ...        return dict() | 
|  | ...    def __new__(cls, name, bases, namespace, **kwds): | 
|  | ...        print("New called:", kwds) | 
|  | ...        return type.__new__(cls, name, bases, namespace) | 
|  | ...    def __init__(cls, *args, **kwds): | 
|  | ...        pass | 
|  | ... | 
|  | >>> class C(metaclass=M): | 
|  | ...     def meth(self): print("Hello") | 
|  | ... | 
|  | Prepare called: ('C', ()) {} | 
|  | New called: {} | 
|  | >>> | 
|  |  | 
|  | Also pass another keyword. | 
|  |  | 
|  | >>> class C(object, metaclass=M, other="haha"): | 
|  | ...     pass | 
|  | ... | 
|  | Prepare called: ('C', (<class 'object'>,)) {'other': 'haha'} | 
|  | New called: {'other': 'haha'} | 
|  | >>> C.__class__ is M | 
|  | True | 
|  | >>> C.__bases__ == (object,) | 
|  | True | 
|  | >>> a = C() | 
|  | >>> a.__class__ is C | 
|  | True | 
|  | >>> | 
|  |  | 
|  | Check that build_class doesn't mutate the kwds dict. | 
|  |  | 
|  | >>> kwds = {'metaclass': type} | 
|  | >>> class C(**kwds): pass | 
|  | ... | 
|  | >>> kwds == {'metaclass': type} | 
|  | True | 
|  | >>> | 
|  |  | 
|  | Use various combinations of explicit keywords and **kwds. | 
|  |  | 
|  | >>> bases = (object,) | 
|  | >>> kwds = {'metaclass': M, 'other': 'haha'} | 
|  | >>> class C(*bases, **kwds): pass | 
|  | ... | 
|  | Prepare called: ('C', (<class 'object'>,)) {'other': 'haha'} | 
|  | New called: {'other': 'haha'} | 
|  | >>> C.__class__ is M | 
|  | True | 
|  | >>> C.__bases__ == (object,) | 
|  | True | 
|  | >>> class B: pass | 
|  | >>> kwds = {'other': 'haha'} | 
|  | >>> class C(B, metaclass=M, *bases, **kwds): pass | 
|  | ... | 
|  | Prepare called: ('C', (<class 'test.test_metaclass.B'>, <class 'object'>)) {'other': 'haha'} | 
|  | New called: {'other': 'haha'} | 
|  | >>> C.__class__ is M | 
|  | True | 
|  | >>> C.__bases__ == (B, object) | 
|  | True | 
|  | >>> | 
|  |  | 
|  | Check for duplicate keywords. | 
|  |  | 
|  | >>> class C(metaclass=type, metaclass=type): pass | 
|  | ... | 
|  | Traceback (most recent call last): | 
|  | [...] | 
|  | SyntaxError: keyword argument repeated: metaclass | 
|  | >>> | 
|  |  | 
|  | Another way. | 
|  |  | 
|  | >>> kwds = {'metaclass': type} | 
|  | >>> class C(metaclass=type, **kwds): pass | 
|  | ... | 
|  | Traceback (most recent call last): | 
|  | [...] | 
|  | TypeError: __build_class__() got multiple values for keyword argument 'metaclass' | 
|  | >>> | 
|  |  | 
|  | Use a __prepare__ method that returns an instrumented dict. | 
|  |  | 
|  | >>> class LoggingDict(dict): | 
|  | ...     def __setitem__(self, key, value): | 
|  | ...         print("d[%r] = %r" % (key, value)) | 
|  | ...         dict.__setitem__(self, key, value) | 
|  | ... | 
|  | >>> class Meta(type): | 
|  | ...    @staticmethod | 
|  | ...    def __prepare__(name, bases): | 
|  | ...        return LoggingDict() | 
|  | ... | 
|  | >>> class C(metaclass=Meta): | 
|  | ...     foo = 2+2 | 
|  | ...     foo = 42 | 
|  | ...     bar = 123 | 
|  | ... | 
|  | d['__module__'] = 'test.test_metaclass' | 
|  | d['__qualname__'] = 'C' | 
|  | d['foo'] = 4 | 
|  | d['foo'] = 42 | 
|  | d['bar'] = 123 | 
|  | >>> | 
|  |  | 
|  | Use a metaclass that doesn't derive from type. | 
|  |  | 
|  | >>> def meta(name, bases, namespace, **kwds): | 
|  | ...     print("meta:", name, bases) | 
|  | ...     print("ns:", sorted(namespace.items())) | 
|  | ...     print("kw:", sorted(kwds.items())) | 
|  | ...     return namespace | 
|  | ... | 
|  | >>> class C(metaclass=meta): | 
|  | ...     a = 42 | 
|  | ...     b = 24 | 
|  | ... | 
|  | meta: C () | 
|  | ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] | 
|  | kw: [] | 
|  | >>> type(C) is dict | 
|  | True | 
|  | >>> print(sorted(C.items())) | 
|  | [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] | 
|  | >>> | 
|  |  | 
|  | And again, with a __prepare__ attribute. | 
|  |  | 
|  | >>> def prepare(name, bases, **kwds): | 
|  | ...     print("prepare:", name, bases, sorted(kwds.items())) | 
|  | ...     return LoggingDict() | 
|  | ... | 
|  | >>> meta.__prepare__ = prepare | 
|  | >>> class C(metaclass=meta, other="booh"): | 
|  | ...    a = 1 | 
|  | ...    a = 2 | 
|  | ...    b = 3 | 
|  | ... | 
|  | prepare: C () [('other', 'booh')] | 
|  | d['__module__'] = 'test.test_metaclass' | 
|  | d['__qualname__'] = 'C' | 
|  | d['a'] = 1 | 
|  | d['a'] = 2 | 
|  | d['b'] = 3 | 
|  | meta: C () | 
|  | ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)] | 
|  | kw: [('other', 'booh')] | 
|  | >>> | 
|  |  | 
|  | The default metaclass must define a __prepare__() method. | 
|  |  | 
|  | >>> type.__prepare__() | 
|  | {} | 
|  | >>> | 
|  |  | 
|  | Make sure it works with subclassing. | 
|  |  | 
|  | >>> class M(type): | 
|  | ...     @classmethod | 
|  | ...     def __prepare__(cls, *args, **kwds): | 
|  | ...         d = super().__prepare__(*args, **kwds) | 
|  | ...         d["hello"] = 42 | 
|  | ...         return d | 
|  | ... | 
|  | >>> class C(metaclass=M): | 
|  | ...     print(hello) | 
|  | ... | 
|  | 42 | 
|  | >>> print(C.hello) | 
|  | 42 | 
|  | >>> | 
|  |  | 
|  | Test failures in looking up the __prepare__ method work. | 
|  | >>> class ObscureException(Exception): | 
|  | ...     pass | 
|  | >>> class FailDescr: | 
|  | ...     def __get__(self, instance, owner): | 
|  | ...        raise ObscureException | 
|  | >>> class Meta(type): | 
|  | ...     __prepare__ = FailDescr() | 
|  | >>> class X(metaclass=Meta): | 
|  | ...     pass | 
|  | Traceback (most recent call last): | 
|  | [...] | 
|  | test.test_metaclass.ObscureException | 
|  |  | 
|  | """ | 
|  |  | 
|  | import sys | 
|  |  | 
|  | # Trace function introduces __locals__ which causes various tests to fail. | 
|  | if hasattr(sys, 'gettrace') and sys.gettrace(): | 
|  | __test__ = {} | 
|  | else: | 
|  | __test__ = {'doctests' : doctests} | 
|  |  | 
|  | def test_main(verbose=False): | 
|  | from test import support | 
|  | from test import test_metaclass | 
|  | support.run_doctest(test_metaclass, verbose) | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | test_main(verbose=True) |