Home | History | Annotate | Download | only in test
      1 import sys
      2 import types
      3 import unittest
      4 
      5 
      6 class Test(unittest.TestCase):
      7     def test_init_subclass(self):
      8         class A:
      9             initialized = False
     10 
     11             def __init_subclass__(cls):
     12                 super().__init_subclass__()
     13                 cls.initialized = True
     14 
     15         class B(A):
     16             pass
     17 
     18         self.assertFalse(A.initialized)
     19         self.assertTrue(B.initialized)
     20 
     21     def test_init_subclass_dict(self):
     22         class A(dict):
     23             initialized = False
     24 
     25             def __init_subclass__(cls):
     26                 super().__init_subclass__()
     27                 cls.initialized = True
     28 
     29         class B(A):
     30             pass
     31 
     32         self.assertFalse(A.initialized)
     33         self.assertTrue(B.initialized)
     34 
     35     def test_init_subclass_kwargs(self):
     36         class A:
     37             def __init_subclass__(cls, **kwargs):
     38                 cls.kwargs = kwargs
     39 
     40         class B(A, x=3):
     41             pass
     42 
     43         self.assertEqual(B.kwargs, dict(x=3))
     44 
     45     def test_init_subclass_error(self):
     46         class A:
     47             def __init_subclass__(cls):
     48                 raise RuntimeError
     49 
     50         with self.assertRaises(RuntimeError):
     51             class B(A):
     52                 pass
     53 
     54     def test_init_subclass_wrong(self):
     55         class A:
     56             def __init_subclass__(cls, whatever):
     57                 pass
     58 
     59         with self.assertRaises(TypeError):
     60             class B(A):
     61                 pass
     62 
     63     def test_init_subclass_skipped(self):
     64         class BaseWithInit:
     65             def __init_subclass__(cls, **kwargs):
     66                 super().__init_subclass__(**kwargs)
     67                 cls.initialized = cls
     68 
     69         class BaseWithoutInit(BaseWithInit):
     70             pass
     71 
     72         class A(BaseWithoutInit):
     73             pass
     74 
     75         self.assertIs(A.initialized, A)
     76         self.assertIs(BaseWithoutInit.initialized, BaseWithoutInit)
     77 
     78     def test_init_subclass_diamond(self):
     79         class Base:
     80             def __init_subclass__(cls, **kwargs):
     81                 super().__init_subclass__(**kwargs)
     82                 cls.calls = []
     83 
     84         class Left(Base):
     85             pass
     86 
     87         class Middle:
     88             def __init_subclass__(cls, middle, **kwargs):
     89                 super().__init_subclass__(**kwargs)
     90                 cls.calls += [middle]
     91 
     92         class Right(Base):
     93             def __init_subclass__(cls, right="right", **kwargs):
     94                 super().__init_subclass__(**kwargs)
     95                 cls.calls += [right]
     96 
     97         class A(Left, Middle, Right, middle="middle"):
     98             pass
     99 
    100         self.assertEqual(A.calls, ["right", "middle"])
    101         self.assertEqual(Left.calls, [])
    102         self.assertEqual(Right.calls, [])
    103 
    104     def test_set_name(self):
    105         class Descriptor:
    106             def __set_name__(self, owner, name):
    107                 self.owner = owner
    108                 self.name = name
    109 
    110         class A:
    111             d = Descriptor()
    112 
    113         self.assertEqual(A.d.name, "d")
    114         self.assertIs(A.d.owner, A)
    115 
    116     def test_set_name_metaclass(self):
    117         class Meta(type):
    118             def __new__(cls, name, bases, ns):
    119                 ret = super().__new__(cls, name, bases, ns)
    120                 self.assertEqual(ret.d.name, "d")
    121                 self.assertIs(ret.d.owner, ret)
    122                 return 0
    123 
    124         class Descriptor:
    125             def __set_name__(self, owner, name):
    126                 self.owner = owner
    127                 self.name = name
    128 
    129         class A(metaclass=Meta):
    130             d = Descriptor()
    131         self.assertEqual(A, 0)
    132 
    133     def test_set_name_error(self):
    134         class Descriptor:
    135             def __set_name__(self, owner, name):
    136                 1/0
    137 
    138         with self.assertRaises(RuntimeError) as cm:
    139             class NotGoingToWork:
    140                 attr = Descriptor()
    141 
    142         exc = cm.exception
    143         self.assertRegex(str(exc), r'\bNotGoingToWork\b')
    144         self.assertRegex(str(exc), r'\battr\b')
    145         self.assertRegex(str(exc), r'\bDescriptor\b')
    146         self.assertIsInstance(exc.__cause__, ZeroDivisionError)
    147 
    148     def test_set_name_wrong(self):
    149         class Descriptor:
    150             def __set_name__(self):
    151                 pass
    152 
    153         with self.assertRaises(RuntimeError) as cm:
    154             class NotGoingToWork:
    155                 attr = Descriptor()
    156 
    157         exc = cm.exception
    158         self.assertRegex(str(exc), r'\bNotGoingToWork\b')
    159         self.assertRegex(str(exc), r'\battr\b')
    160         self.assertRegex(str(exc), r'\bDescriptor\b')
    161         self.assertIsInstance(exc.__cause__, TypeError)
    162 
    163     def test_set_name_lookup(self):
    164         resolved = []
    165         class NonDescriptor:
    166             def __getattr__(self, name):
    167                 resolved.append(name)
    168 
    169         class A:
    170             d = NonDescriptor()
    171 
    172         self.assertNotIn('__set_name__', resolved,
    173                          '__set_name__ is looked up in instance dict')
    174 
    175     def test_set_name_init_subclass(self):
    176         class Descriptor:
    177             def __set_name__(self, owner, name):
    178                 self.owner = owner
    179                 self.name = name
    180 
    181         class Meta(type):
    182             def __new__(cls, name, bases, ns):
    183                 self = super().__new__(cls, name, bases, ns)
    184                 self.meta_owner = self.owner
    185                 self.meta_name = self.name
    186                 return self
    187 
    188         class A:
    189             def __init_subclass__(cls):
    190                 cls.owner = cls.d.owner
    191                 cls.name = cls.d.name
    192 
    193         class B(A, metaclass=Meta):
    194             d = Descriptor()
    195 
    196         self.assertIs(B.owner, B)
    197         self.assertEqual(B.name, 'd')
    198         self.assertIs(B.meta_owner, B)
    199         self.assertEqual(B.name, 'd')
    200 
    201     def test_set_name_modifying_dict(self):
    202         notified = []
    203         class Descriptor:
    204             def __set_name__(self, owner, name):
    205                 setattr(owner, name + 'x', None)
    206                 notified.append(name)
    207 
    208         class A:
    209             a = Descriptor()
    210             b = Descriptor()
    211             c = Descriptor()
    212             d = Descriptor()
    213             e = Descriptor()
    214 
    215         self.assertCountEqual(notified, ['a', 'b', 'c', 'd', 'e'])
    216 
    217     def test_errors(self):
    218         class MyMeta(type):
    219             pass
    220 
    221         with self.assertRaises(TypeError):
    222             class MyClass(metaclass=MyMeta, otherarg=1):
    223                 pass
    224 
    225         with self.assertRaises(TypeError):
    226             types.new_class("MyClass", (object,),
    227                             dict(metaclass=MyMeta, otherarg=1))
    228         types.prepare_class("MyClass", (object,),
    229                             dict(metaclass=MyMeta, otherarg=1))
    230 
    231         class MyMeta(type):
    232             def __init__(self, name, bases, namespace, otherarg):
    233                 super().__init__(name, bases, namespace)
    234 
    235         with self.assertRaises(TypeError):
    236             class MyClass(metaclass=MyMeta, otherarg=1):
    237                 pass
    238 
    239         class MyMeta(type):
    240             def __new__(cls, name, bases, namespace, otherarg):
    241                 return super().__new__(cls, name, bases, namespace)
    242 
    243             def __init__(self, name, bases, namespace, otherarg):
    244                 super().__init__(name, bases, namespace)
    245                 self.otherarg = otherarg
    246 
    247         class MyClass(metaclass=MyMeta, otherarg=1):
    248             pass
    249 
    250         self.assertEqual(MyClass.otherarg, 1)
    251 
    252     def test_errors_changed_pep487(self):
    253         # These tests failed before Python 3.6, PEP 487
    254         class MyMeta(type):
    255             def __new__(cls, name, bases, namespace):
    256                 return super().__new__(cls, name=name, bases=bases,
    257                                        dict=namespace)
    258 
    259         with self.assertRaises(TypeError):
    260             class MyClass(metaclass=MyMeta):
    261                 pass
    262 
    263         class MyMeta(type):
    264             def __new__(cls, name, bases, namespace, otherarg):
    265                 self = super().__new__(cls, name, bases, namespace)
    266                 self.otherarg = otherarg
    267                 return self
    268 
    269         class MyClass(metaclass=MyMeta, otherarg=1):
    270             pass
    271 
    272         self.assertEqual(MyClass.otherarg, 1)
    273 
    274     def test_type(self):
    275         t = type('NewClass', (object,), {})
    276         self.assertIsInstance(t, type)
    277         self.assertEqual(t.__name__, 'NewClass')
    278 
    279         with self.assertRaises(TypeError):
    280             type(name='NewClass', bases=(object,), dict={})
    281 
    282 
    283 if __name__ == "__main__":
    284     unittest.main()
    285