(root)/
Python-3.12.0/
Lib/
test/
test_super.py
       1  """Unit tests for zero-argument super() & related machinery."""
       2  
       3  import unittest
       4  from unittest.mock import patch
       5  from test import shadowed_super
       6  
       7  
       8  ADAPTIVE_WARMUP_DELAY = 2
       9  
      10  
      11  class ESC[4;38;5;81mA:
      12      def f(self):
      13          return 'A'
      14      @classmethod
      15      def cm(cls):
      16          return (cls, 'A')
      17  
      18  class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
      19      def f(self):
      20          return super().f() + 'B'
      21      @classmethod
      22      def cm(cls):
      23          return (cls, super().cm(), 'B')
      24  
      25  class ESC[4;38;5;81mC(ESC[4;38;5;149mA):
      26      def f(self):
      27          return super().f() + 'C'
      28      @classmethod
      29      def cm(cls):
      30          return (cls, super().cm(), 'C')
      31  
      32  class ESC[4;38;5;81mD(ESC[4;38;5;149mC, ESC[4;38;5;149mB):
      33      def f(self):
      34          return super().f() + 'D'
      35      def cm(cls):
      36          return (cls, super().cm(), 'D')
      37  
      38  class ESC[4;38;5;81mE(ESC[4;38;5;149mD):
      39      pass
      40  
      41  class ESC[4;38;5;81mF(ESC[4;38;5;149mE):
      42      f = E.f
      43  
      44  class ESC[4;38;5;81mG(ESC[4;38;5;149mA):
      45      pass
      46  
      47  
      48  class ESC[4;38;5;81mTestSuper(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      49  
      50      def tearDown(self):
      51          # This fixes the damage that test_various___class___pathologies does.
      52          nonlocal __class__
      53          __class__ = TestSuper
      54  
      55      def test_basics_working(self):
      56          self.assertEqual(D().f(), 'ABCD')
      57  
      58      def test_class_getattr_working(self):
      59          self.assertEqual(D.f(D()), 'ABCD')
      60  
      61      def test_subclass_no_override_working(self):
      62          self.assertEqual(E().f(), 'ABCD')
      63          self.assertEqual(E.f(E()), 'ABCD')
      64  
      65      def test_unbound_method_transfer_working(self):
      66          self.assertEqual(F().f(), 'ABCD')
      67          self.assertEqual(F.f(F()), 'ABCD')
      68  
      69      def test_class_methods_still_working(self):
      70          self.assertEqual(A.cm(), (A, 'A'))
      71          self.assertEqual(A().cm(), (A, 'A'))
      72          self.assertEqual(G.cm(), (G, 'A'))
      73          self.assertEqual(G().cm(), (G, 'A'))
      74  
      75      def test_super_in_class_methods_working(self):
      76          d = D()
      77          self.assertEqual(d.cm(), (d, (D, (D, (D, 'A'), 'B'), 'C'), 'D'))
      78          e = E()
      79          self.assertEqual(e.cm(), (e, (E, (E, (E, 'A'), 'B'), 'C'), 'D'))
      80  
      81      def test_super_with_closure(self):
      82          # Issue4360: super() did not work in a function that
      83          # contains a closure
      84          class ESC[4;38;5;81mE(ESC[4;38;5;149mA):
      85              def f(self):
      86                  def nested():
      87                      self
      88                  return super().f() + 'E'
      89  
      90          self.assertEqual(E().f(), 'AE')
      91  
      92      def test_various___class___pathologies(self):
      93          # See issue #12370
      94          class ESC[4;38;5;81mX(ESC[4;38;5;149mA):
      95              def f(self):
      96                  return super().f()
      97              __class__ = 413
      98          x = X()
      99          self.assertEqual(x.f(), 'A')
     100          self.assertEqual(x.__class__, 413)
     101          class ESC[4;38;5;81mX:
     102              x = __class__
     103              def f():
     104                  __class__
     105          self.assertIs(X.x, type(self))
     106          with self.assertRaises(NameError) as e:
     107              exec("""class X:
     108                  __class__
     109                  def f():
     110                      __class__""", globals(), {})
     111          self.assertIs(type(e.exception), NameError) # Not UnboundLocalError
     112          class ESC[4;38;5;81mX:
     113              global __class__
     114              __class__ = 42
     115              def f():
     116                  __class__
     117          self.assertEqual(globals()["__class__"], 42)
     118          del globals()["__class__"]
     119          self.assertNotIn("__class__", X.__dict__)
     120          class ESC[4;38;5;81mX:
     121              nonlocal __class__
     122              __class__ = 42
     123              def f():
     124                  __class__
     125          self.assertEqual(__class__, 42)
     126  
     127      def test___class___instancemethod(self):
     128          # See issue #14857
     129          class ESC[4;38;5;81mX:
     130              def f(self):
     131                  return __class__
     132          self.assertIs(X().f(), X)
     133  
     134      def test___class___classmethod(self):
     135          # See issue #14857
     136          class ESC[4;38;5;81mX:
     137              @classmethod
     138              def f(cls):
     139                  return __class__
     140          self.assertIs(X.f(), X)
     141  
     142      def test___class___staticmethod(self):
     143          # See issue #14857
     144          class ESC[4;38;5;81mX:
     145              @staticmethod
     146              def f():
     147                  return __class__
     148          self.assertIs(X.f(), X)
     149  
     150      def test___class___new(self):
     151          # See issue #23722
     152          # Ensure zero-arg super() works as soon as type.__new__() is completed
     153          test_class = None
     154  
     155          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     156              def __new__(cls, name, bases, namespace):
     157                  nonlocal test_class
     158                  self = super().__new__(cls, name, bases, namespace)
     159                  test_class = self.f()
     160                  return self
     161  
     162          class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
     163              @staticmethod
     164              def f():
     165                  return __class__
     166  
     167          self.assertIs(test_class, A)
     168  
     169      def test___class___delayed(self):
     170          # See issue #23722
     171          test_namespace = None
     172  
     173          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     174              def __new__(cls, name, bases, namespace):
     175                  nonlocal test_namespace
     176                  test_namespace = namespace
     177                  return None
     178  
     179          class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
     180              @staticmethod
     181              def f():
     182                  return __class__
     183  
     184          self.assertIs(A, None)
     185  
     186          B = type("B", (), test_namespace)
     187          self.assertIs(B.f(), B)
     188  
     189      def test___class___mro(self):
     190          # See issue #23722
     191          test_class = None
     192  
     193          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     194              def mro(self):
     195                  # self.f() doesn't work yet...
     196                  self.__dict__["f"]()
     197                  return super().mro()
     198  
     199          class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
     200              def f():
     201                  nonlocal test_class
     202                  test_class = __class__
     203  
     204          self.assertIs(test_class, A)
     205  
     206      def test___classcell___expected_behaviour(self):
     207          # See issue #23722
     208          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     209              def __new__(cls, name, bases, namespace):
     210                  nonlocal namespace_snapshot
     211                  namespace_snapshot = namespace.copy()
     212                  return super().__new__(cls, name, bases, namespace)
     213  
     214          # __classcell__ is injected into the class namespace by the compiler
     215          # when at least one method needs it, and should be omitted otherwise
     216          namespace_snapshot = None
     217          class ESC[4;38;5;81mWithoutClassRef(metaclass=ESC[4;38;5;149mMeta):
     218              pass
     219          self.assertNotIn("__classcell__", namespace_snapshot)
     220  
     221          # With zero-arg super() or an explicit __class__ reference,
     222          # __classcell__ is the exact cell reference to be populated by
     223          # type.__new__
     224          namespace_snapshot = None
     225          class ESC[4;38;5;81mWithClassRef(metaclass=ESC[4;38;5;149mMeta):
     226              def f(self):
     227                  return __class__
     228  
     229          class_cell = namespace_snapshot["__classcell__"]
     230          method_closure = WithClassRef.f.__closure__
     231          self.assertEqual(len(method_closure), 1)
     232          self.assertIs(class_cell, method_closure[0])
     233          # Ensure the cell reference *doesn't* get turned into an attribute
     234          with self.assertRaises(AttributeError):
     235              WithClassRef.__classcell__
     236  
     237      def test___classcell___missing(self):
     238          # See issue #23722
     239          # Some metaclasses may not pass the original namespace to type.__new__
     240          # We test that case here by forcibly deleting __classcell__
     241          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     242              def __new__(cls, name, bases, namespace):
     243                  namespace.pop('__classcell__', None)
     244                  return super().__new__(cls, name, bases, namespace)
     245  
     246          # The default case should continue to work without any errors
     247          class ESC[4;38;5;81mWithoutClassRef(metaclass=ESC[4;38;5;149mMeta):
     248              pass
     249  
     250          # With zero-arg super() or an explicit __class__ reference, we expect
     251          # __build_class__ to raise a RuntimeError complaining that
     252          # __class__ was not set, and asking if __classcell__ was propagated
     253          # to type.__new__.
     254          expected_error = '__class__ not set.*__classcell__ propagated'
     255          with self.assertRaisesRegex(RuntimeError, expected_error):
     256              class ESC[4;38;5;81mWithClassRef(metaclass=ESC[4;38;5;149mMeta):
     257                  def f(self):
     258                      return __class__
     259  
     260      def test___classcell___overwrite(self):
     261          # See issue #23722
     262          # Overwriting __classcell__ with nonsense is explicitly prohibited
     263          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     264              def __new__(cls, name, bases, namespace, cell):
     265                  namespace['__classcell__'] = cell
     266                  return super().__new__(cls, name, bases, namespace)
     267  
     268          for bad_cell in (None, 0, "", object()):
     269              with self.subTest(bad_cell=bad_cell):
     270                  with self.assertRaises(TypeError):
     271                      class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta, cell=ESC[4;38;5;149mbad_cell):
     272                          pass
     273  
     274      def test___classcell___wrong_cell(self):
     275          # See issue #23722
     276          # Pointing the cell reference at the wrong class is also prohibited
     277          class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
     278              def __new__(cls, name, bases, namespace):
     279                  cls = super().__new__(cls, name, bases, namespace)
     280                  B = type("B", (), namespace)
     281                  return cls
     282  
     283          with self.assertRaises(TypeError):
     284              class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
     285                  def f(self):
     286                      return __class__
     287  
     288      def test_obscure_super_errors(self):
     289          def f():
     290              super()
     291          with self.assertRaisesRegex(RuntimeError, r"no arguments"):
     292              f()
     293  
     294          class ESC[4;38;5;81mC:
     295              def f():
     296                  super()
     297          with self.assertRaisesRegex(RuntimeError, r"no arguments"):
     298              C.f()
     299  
     300          def f(x):
     301              del x
     302              super()
     303          with self.assertRaisesRegex(RuntimeError, r"arg\[0\] deleted"):
     304              f(None)
     305  
     306          class ESC[4;38;5;81mX:
     307              def f(x):
     308                  nonlocal __class__
     309                  del __class__
     310                  super()
     311          with self.assertRaisesRegex(RuntimeError, r"empty __class__ cell"):
     312              X().f()
     313  
     314      def test_cell_as_self(self):
     315          class ESC[4;38;5;81mX:
     316              def meth(self):
     317                  super()
     318  
     319          def f():
     320              k = X()
     321              def g():
     322                  return k
     323              return g
     324          c = f().__closure__[0]
     325          self.assertRaises(TypeError, X.meth, c)
     326  
     327      def test_super_init_leaks(self):
     328          # Issue #26718: super.__init__ leaked memory if called multiple times.
     329          # This will be caught by regrtest.py -R if this leak.
     330          # NOTE: Despite the use in the test a direct call of super.__init__
     331          # is not endorsed.
     332          sp = super(float, 1.0)
     333          for i in range(1000):
     334              super.__init__(sp, int, i)
     335  
     336      def test_super_argcount(self):
     337          with self.assertRaisesRegex(TypeError, "expected at most"):
     338              super(int, int, int)
     339  
     340      def test_super_argtype(self):
     341          with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
     342              super(1, int)
     343  
     344      def test_shadowed_global(self):
     345          self.assertEqual(shadowed_super.C().method(), "truly super")
     346  
     347      def test_shadowed_local(self):
     348          class ESC[4;38;5;81msuper:
     349              msg = "quite super"
     350  
     351          class ESC[4;38;5;81mC:
     352              def method(self):
     353                  return super().msg
     354  
     355          self.assertEqual(C().method(), "quite super")
     356  
     357      def test_shadowed_dynamic(self):
     358          class ESC[4;38;5;81mMySuper:
     359              msg = "super super"
     360  
     361          class ESC[4;38;5;81mC:
     362              def method(self):
     363                  return super().msg
     364  
     365          with patch(f"{__name__}.super", MySuper) as m:
     366              self.assertEqual(C().method(), "super super")
     367  
     368      def test_shadowed_dynamic_two_arg(self):
     369          call_args = []
     370          class ESC[4;38;5;81mMySuper:
     371              def __init__(self, *args):
     372                  call_args.append(args)
     373              msg = "super super"
     374  
     375          class ESC[4;38;5;81mC:
     376              def method(self):
     377                  return super(1, 2).msg
     378  
     379          with patch(f"{__name__}.super", MySuper) as m:
     380              self.assertEqual(C().method(), "super super")
     381              self.assertEqual(call_args, [(1, 2)])
     382  
     383      def test_attribute_error(self):
     384          class ESC[4;38;5;81mC:
     385              def method(self):
     386                  return super().msg
     387  
     388          with self.assertRaisesRegex(AttributeError, "'super' object has no attribute 'msg'"):
     389              C().method()
     390  
     391      def test_bad_first_arg(self):
     392          class ESC[4;38;5;81mC:
     393              def method(self):
     394                  return super(1, self).method()
     395  
     396          with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
     397              C().method()
     398  
     399      def test_super___class__(self):
     400          class ESC[4;38;5;81mC:
     401              def method(self):
     402                  return super().__class__
     403  
     404          self.assertEqual(C().method(), super)
     405  
     406      def test_super_subclass___class__(self):
     407          class ESC[4;38;5;81mmysuper(ESC[4;38;5;149msuper):
     408              pass
     409  
     410          class ESC[4;38;5;81mC:
     411              def method(self):
     412                  return mysuper(C, self).__class__
     413  
     414          self.assertEqual(C().method(), mysuper)
     415  
     416      def test_unusual_getattro(self):
     417          class ESC[4;38;5;81mMyType(ESC[4;38;5;149mtype):
     418              pass
     419  
     420          def test(name):
     421              mytype = MyType(name, (MyType,), {})
     422              super(MyType, type(mytype)).__setattr__(mytype, "bar", 1)
     423              self.assertEqual(mytype.bar, 1)
     424  
     425          for _ in range(ADAPTIVE_WARMUP_DELAY):
     426              test("foo1")
     427  
     428      def test_reassigned_new(self):
     429          class ESC[4;38;5;81mA:
     430              def __new__(cls):
     431                  pass
     432  
     433              def __init_subclass__(cls):
     434                  if "__new__" not in cls.__dict__:
     435                      cls.__new__ = cls.__new__
     436  
     437          class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
     438              pass
     439  
     440          class ESC[4;38;5;81mC(ESC[4;38;5;149mB):
     441              def __new__(cls):
     442                  return super().__new__(cls)
     443  
     444          for _ in range(ADAPTIVE_WARMUP_DELAY):
     445              C()
     446  
     447      def test_mixed_staticmethod_hierarchy(self):
     448          # This test is just a desugared version of `test_reassigned_new`
     449          class ESC[4;38;5;81mA:
     450              @staticmethod
     451              def some(cls, *args, **kwargs):
     452                  self.assertFalse(args)
     453                  self.assertFalse(kwargs)
     454  
     455          class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
     456              def some(cls, *args, **kwargs):
     457                  return super().some(cls, *args, **kwargs)
     458  
     459          class ESC[4;38;5;81mC(ESC[4;38;5;149mB):
     460              @staticmethod
     461              def some(cls):
     462                  return super().some(cls)
     463  
     464          for _ in range(ADAPTIVE_WARMUP_DELAY):
     465              C.some(C)
     466  
     467  
     468  if __name__ == "__main__":
     469      unittest.main()