Home | History | Annotate | Download | only in test
      1 doctests = """
      2 
      3 Basic 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 
     17 Use *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 
     27 Use 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 
     44 Use **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 
     56 Use 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 
     76 Also 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 
     92 Check 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 
    101 Use 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 
    125 Check 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
    132     >>>
    133 
    134 Another 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 
    144 Use 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 
    168 Use 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 
    189 And 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 
    212 The default metaclass must define a __prepare__() method.
    213 
    214     >>> type.__prepare__()
    215     {}
    216     >>>
    217 
    218 Make 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 
    235 Test 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 
    251 import sys
    252 
    253 # Trace function introduces __locals__ which causes various tests to fail.
    254 if hasattr(sys, 'gettrace') and sys.gettrace():
    255     __test__ = {}
    256 else:
    257     __test__ = {'doctests' : doctests}
    258 
    259 def test_main(verbose=False):
    260     from test import support
    261     from test import test_metaclass
    262     support.run_doctest(test_metaclass, verbose)
    263 
    264 if __name__ == "__main__":
    265     test_main(verbose=True)
    266