(root)/
Python-3.11.7/
Lib/
test/
test_asyncio/
test_futures.py
       1  """Tests for futures.py."""
       2  
       3  import concurrent.futures
       4  import gc
       5  import re
       6  import sys
       7  import threading
       8  import unittest
       9  from unittest import mock
      10  from types import GenericAlias
      11  import asyncio
      12  from asyncio import futures
      13  from test.test_asyncio import utils as test_utils
      14  from test import support
      15  
      16  
      17  def tearDownModule():
      18      asyncio.set_event_loop_policy(None)
      19  
      20  
      21  def _fakefunc(f):
      22      return f
      23  
      24  
      25  def first_cb():
      26      pass
      27  
      28  
      29  def last_cb():
      30      pass
      31  
      32  
      33  class ESC[4;38;5;81mDuckFuture:
      34      # Class that does not inherit from Future but aims to be duck-type
      35      # compatible with it.
      36  
      37      _asyncio_future_blocking = False
      38      __cancelled = False
      39      __result = None
      40      __exception = None
      41  
      42      def cancel(self):
      43          if self.done():
      44              return False
      45          self.__cancelled = True
      46          return True
      47  
      48      def cancelled(self):
      49          return self.__cancelled
      50  
      51      def done(self):
      52          return (self.__cancelled
      53                  or self.__result is not None
      54                  or self.__exception is not None)
      55  
      56      def result(self):
      57          self.assertFalse(self.cancelled())
      58          if self.__exception is not None:
      59              raise self.__exception
      60          return self.__result
      61  
      62      def exception(self):
      63          self.assertFalse(self.cancelled())
      64          return self.__exception
      65  
      66      def set_result(self, result):
      67          self.assertFalse(self.done())
      68          self.assertIsNotNone(result)
      69          self.__result = result
      70  
      71      def set_exception(self, exception):
      72          self.assertFalse(self.done())
      73          self.assertIsNotNone(exception)
      74          self.__exception = exception
      75  
      76      def __iter__(self):
      77          if not self.done():
      78              self._asyncio_future_blocking = True
      79              yield self
      80          self.assertTrue(self.done())
      81          return self.result()
      82  
      83  
      84  class ESC[4;38;5;81mDuckTests(ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      85  
      86      def setUp(self):
      87          super().setUp()
      88          self.loop = self.new_test_loop()
      89          self.addCleanup(self.loop.close)
      90  
      91      def test_wrap_future(self):
      92          f = DuckFuture()
      93          g = asyncio.wrap_future(f)
      94          self.assertIs(g, f)
      95  
      96      def test_ensure_future(self):
      97          f = DuckFuture()
      98          g = asyncio.ensure_future(f)
      99          self.assertIs(g, f)
     100  
     101  
     102  class ESC[4;38;5;81mBaseFutureTests:
     103  
     104      def _new_future(self,  *args, **kwargs):
     105          return self.cls(*args, **kwargs)
     106  
     107      def setUp(self):
     108          super().setUp()
     109          self.loop = self.new_test_loop()
     110          self.addCleanup(self.loop.close)
     111  
     112      def test_generic_alias(self):
     113          future = self.cls[str]
     114          self.assertEqual(future.__args__, (str,))
     115          self.assertIsInstance(future, GenericAlias)
     116  
     117      def test_isfuture(self):
     118          class ESC[4;38;5;81mMyFuture:
     119              _asyncio_future_blocking = None
     120  
     121              def __init__(self):
     122                  self._asyncio_future_blocking = False
     123  
     124          self.assertFalse(asyncio.isfuture(MyFuture))
     125          self.assertTrue(asyncio.isfuture(MyFuture()))
     126          self.assertFalse(asyncio.isfuture(1))
     127  
     128          # As `isinstance(Mock(), Future)` returns `False`
     129          self.assertFalse(asyncio.isfuture(mock.Mock()))
     130  
     131          f = self._new_future(loop=self.loop)
     132          self.assertTrue(asyncio.isfuture(f))
     133          self.assertFalse(asyncio.isfuture(type(f)))
     134  
     135          # As `isinstance(Mock(Future), Future)` returns `True`
     136          self.assertTrue(asyncio.isfuture(mock.Mock(type(f))))
     137  
     138          f.cancel()
     139  
     140      def test_initial_state(self):
     141          f = self._new_future(loop=self.loop)
     142          self.assertFalse(f.cancelled())
     143          self.assertFalse(f.done())
     144          f.cancel()
     145          self.assertTrue(f.cancelled())
     146  
     147      def test_constructor_without_loop(self):
     148          with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
     149              self._new_future()
     150  
     151      def test_constructor_use_running_loop(self):
     152          async def test():
     153              return self._new_future()
     154          f = self.loop.run_until_complete(test())
     155          self.assertIs(f._loop, self.loop)
     156          self.assertIs(f.get_loop(), self.loop)
     157  
     158      def test_constructor_use_global_loop(self):
     159          # Deprecated in 3.10, undeprecated in 3.11.1
     160          asyncio.set_event_loop(self.loop)
     161          self.addCleanup(asyncio.set_event_loop, None)
     162          f = self._new_future()
     163          self.assertIs(f._loop, self.loop)
     164          self.assertIs(f.get_loop(), self.loop)
     165  
     166      def test_constructor_positional(self):
     167          # Make sure Future doesn't accept a positional argument
     168          self.assertRaises(TypeError, self._new_future, 42)
     169  
     170      def test_uninitialized(self):
     171          # Test that C Future doesn't crash when Future.__init__()
     172          # call was skipped.
     173  
     174          fut = self.cls.__new__(self.cls, loop=self.loop)
     175          self.assertRaises(asyncio.InvalidStateError, fut.result)
     176  
     177          fut = self.cls.__new__(self.cls, loop=self.loop)
     178          self.assertRaises(asyncio.InvalidStateError, fut.exception)
     179  
     180          fut = self.cls.__new__(self.cls, loop=self.loop)
     181          with self.assertRaises((RuntimeError, AttributeError)):
     182              fut.set_result(None)
     183  
     184          fut = self.cls.__new__(self.cls, loop=self.loop)
     185          with self.assertRaises((RuntimeError, AttributeError)):
     186              fut.set_exception(Exception)
     187  
     188          fut = self.cls.__new__(self.cls, loop=self.loop)
     189          with self.assertRaises((RuntimeError, AttributeError)):
     190              fut.cancel()
     191  
     192          fut = self.cls.__new__(self.cls, loop=self.loop)
     193          with self.assertRaises((RuntimeError, AttributeError)):
     194              fut.add_done_callback(lambda f: None)
     195  
     196          fut = self.cls.__new__(self.cls, loop=self.loop)
     197          with self.assertRaises((RuntimeError, AttributeError)):
     198              fut.remove_done_callback(lambda f: None)
     199  
     200          fut = self.cls.__new__(self.cls, loop=self.loop)
     201          try:
     202              repr(fut)
     203          except (RuntimeError, AttributeError):
     204              pass
     205  
     206          fut = self.cls.__new__(self.cls, loop=self.loop)
     207          try:
     208              fut.__await__()
     209          except RuntimeError:
     210              pass
     211  
     212          fut = self.cls.__new__(self.cls, loop=self.loop)
     213          try:
     214              iter(fut)
     215          except RuntimeError:
     216              pass
     217  
     218          fut = self.cls.__new__(self.cls, loop=self.loop)
     219          self.assertFalse(fut.cancelled())
     220          self.assertFalse(fut.done())
     221  
     222      def test_future_cancel_message_getter(self):
     223          f = self._new_future(loop=self.loop)
     224          self.assertTrue(hasattr(f, '_cancel_message'))
     225          self.assertEqual(f._cancel_message, None)
     226  
     227          f.cancel('my message')
     228          with self.assertRaises(asyncio.CancelledError):
     229              self.loop.run_until_complete(f)
     230          self.assertEqual(f._cancel_message, 'my message')
     231  
     232      def test_future_cancel_message_setter(self):
     233          f = self._new_future(loop=self.loop)
     234          f.cancel('my message')
     235          f._cancel_message = 'my new message'
     236          self.assertEqual(f._cancel_message, 'my new message')
     237  
     238          # Also check that the value is used for cancel().
     239          with self.assertRaises(asyncio.CancelledError):
     240              self.loop.run_until_complete(f)
     241          self.assertEqual(f._cancel_message, 'my new message')
     242  
     243      def test_cancel(self):
     244          f = self._new_future(loop=self.loop)
     245          self.assertTrue(f.cancel())
     246          self.assertTrue(f.cancelled())
     247          self.assertTrue(f.done())
     248          self.assertRaises(asyncio.CancelledError, f.result)
     249          self.assertRaises(asyncio.CancelledError, f.exception)
     250          self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
     251          self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
     252          self.assertFalse(f.cancel())
     253  
     254      def test_result(self):
     255          f = self._new_future(loop=self.loop)
     256          self.assertRaises(asyncio.InvalidStateError, f.result)
     257  
     258          f.set_result(42)
     259          self.assertFalse(f.cancelled())
     260          self.assertTrue(f.done())
     261          self.assertEqual(f.result(), 42)
     262          self.assertEqual(f.exception(), None)
     263          self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
     264          self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
     265          self.assertFalse(f.cancel())
     266  
     267      def test_exception(self):
     268          exc = RuntimeError()
     269          f = self._new_future(loop=self.loop)
     270          self.assertRaises(asyncio.InvalidStateError, f.exception)
     271  
     272          # StopIteration cannot be raised into a Future - CPython issue26221
     273          self.assertRaisesRegex(TypeError, "StopIteration .* cannot be raised",
     274                                 f.set_exception, StopIteration)
     275  
     276          f.set_exception(exc)
     277          self.assertFalse(f.cancelled())
     278          self.assertTrue(f.done())
     279          self.assertRaises(RuntimeError, f.result)
     280          self.assertEqual(f.exception(), exc)
     281          self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
     282          self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
     283          self.assertFalse(f.cancel())
     284  
     285      def test_exception_class(self):
     286          f = self._new_future(loop=self.loop)
     287          f.set_exception(RuntimeError)
     288          self.assertIsInstance(f.exception(), RuntimeError)
     289  
     290      def test_yield_from_twice(self):
     291          f = self._new_future(loop=self.loop)
     292  
     293          def fixture():
     294              yield 'A'
     295              x = yield from f
     296              yield 'B', x
     297              y = yield from f
     298              yield 'C', y
     299  
     300          g = fixture()
     301          self.assertEqual(next(g), 'A')  # yield 'A'.
     302          self.assertEqual(next(g), f)  # First yield from f.
     303          f.set_result(42)
     304          self.assertEqual(next(g), ('B', 42))  # yield 'B', x.
     305          # The second "yield from f" does not yield f.
     306          self.assertEqual(next(g), ('C', 42))  # yield 'C', y.
     307  
     308      def test_future_repr(self):
     309          self.loop.set_debug(True)
     310          f_pending_debug = self._new_future(loop=self.loop)
     311          frame = f_pending_debug._source_traceback[-1]
     312          self.assertEqual(
     313              repr(f_pending_debug),
     314              f'<{self.cls.__name__} pending created at {frame[0]}:{frame[1]}>')
     315          f_pending_debug.cancel()
     316  
     317          self.loop.set_debug(False)
     318          f_pending = self._new_future(loop=self.loop)
     319          self.assertEqual(repr(f_pending), f'<{self.cls.__name__} pending>')
     320          f_pending.cancel()
     321  
     322          f_cancelled = self._new_future(loop=self.loop)
     323          f_cancelled.cancel()
     324          self.assertEqual(repr(f_cancelled), f'<{self.cls.__name__} cancelled>')
     325  
     326          f_result = self._new_future(loop=self.loop)
     327          f_result.set_result(4)
     328          self.assertEqual(
     329              repr(f_result), f'<{self.cls.__name__} finished result=4>')
     330          self.assertEqual(f_result.result(), 4)
     331  
     332          exc = RuntimeError()
     333          f_exception = self._new_future(loop=self.loop)
     334          f_exception.set_exception(exc)
     335          self.assertEqual(
     336              repr(f_exception),
     337              f'<{self.cls.__name__} finished exception=RuntimeError()>')
     338          self.assertIs(f_exception.exception(), exc)
     339  
     340          def func_repr(func):
     341              filename, lineno = test_utils.get_function_source(func)
     342              text = '%s() at %s:%s' % (func.__qualname__, filename, lineno)
     343              return re.escape(text)
     344  
     345          f_one_callbacks = self._new_future(loop=self.loop)
     346          f_one_callbacks.add_done_callback(_fakefunc)
     347          fake_repr = func_repr(_fakefunc)
     348          self.assertRegex(
     349              repr(f_one_callbacks),
     350              r'<' + self.cls.__name__ + r' pending cb=\[%s\]>' % fake_repr)
     351          f_one_callbacks.cancel()
     352          self.assertEqual(repr(f_one_callbacks),
     353                           f'<{self.cls.__name__} cancelled>')
     354  
     355          f_two_callbacks = self._new_future(loop=self.loop)
     356          f_two_callbacks.add_done_callback(first_cb)
     357          f_two_callbacks.add_done_callback(last_cb)
     358          first_repr = func_repr(first_cb)
     359          last_repr = func_repr(last_cb)
     360          self.assertRegex(repr(f_two_callbacks),
     361                           r'<' + self.cls.__name__ + r' pending cb=\[%s, %s\]>'
     362                           % (first_repr, last_repr))
     363  
     364          f_many_callbacks = self._new_future(loop=self.loop)
     365          f_many_callbacks.add_done_callback(first_cb)
     366          for i in range(8):
     367              f_many_callbacks.add_done_callback(_fakefunc)
     368          f_many_callbacks.add_done_callback(last_cb)
     369          cb_regex = r'%s, <8 more>, %s' % (first_repr, last_repr)
     370          self.assertRegex(
     371              repr(f_many_callbacks),
     372              r'<' + self.cls.__name__ + r' pending cb=\[%s\]>' % cb_regex)
     373          f_many_callbacks.cancel()
     374          self.assertEqual(repr(f_many_callbacks),
     375                           f'<{self.cls.__name__} cancelled>')
     376  
     377      def test_copy_state(self):
     378          from asyncio.futures import _copy_future_state
     379  
     380          f = self._new_future(loop=self.loop)
     381          f.set_result(10)
     382  
     383          newf = self._new_future(loop=self.loop)
     384          _copy_future_state(f, newf)
     385          self.assertTrue(newf.done())
     386          self.assertEqual(newf.result(), 10)
     387  
     388          f_exception = self._new_future(loop=self.loop)
     389          f_exception.set_exception(RuntimeError())
     390  
     391          newf_exception = self._new_future(loop=self.loop)
     392          _copy_future_state(f_exception, newf_exception)
     393          self.assertTrue(newf_exception.done())
     394          self.assertRaises(RuntimeError, newf_exception.result)
     395  
     396          f_cancelled = self._new_future(loop=self.loop)
     397          f_cancelled.cancel()
     398  
     399          newf_cancelled = self._new_future(loop=self.loop)
     400          _copy_future_state(f_cancelled, newf_cancelled)
     401          self.assertTrue(newf_cancelled.cancelled())
     402  
     403      def test_iter(self):
     404          fut = self._new_future(loop=self.loop)
     405  
     406          def coro():
     407              yield from fut
     408  
     409          def test():
     410              arg1, arg2 = coro()
     411  
     412          with self.assertRaisesRegex(RuntimeError, "await wasn't used"):
     413              test()
     414          fut.cancel()
     415  
     416      def test_log_traceback(self):
     417          fut = self._new_future(loop=self.loop)
     418          with self.assertRaisesRegex(ValueError, 'can only be set to False'):
     419              fut._log_traceback = True
     420  
     421      @mock.patch('asyncio.base_events.logger')
     422      def test_tb_logger_abandoned(self, m_log):
     423          fut = self._new_future(loop=self.loop)
     424          del fut
     425          self.assertFalse(m_log.error.called)
     426  
     427      @mock.patch('asyncio.base_events.logger')
     428      def test_tb_logger_not_called_after_cancel(self, m_log):
     429          fut = self._new_future(loop=self.loop)
     430          fut.set_exception(Exception())
     431          fut.cancel()
     432          del fut
     433          self.assertFalse(m_log.error.called)
     434  
     435      @mock.patch('asyncio.base_events.logger')
     436      def test_tb_logger_result_unretrieved(self, m_log):
     437          fut = self._new_future(loop=self.loop)
     438          fut.set_result(42)
     439          del fut
     440          self.assertFalse(m_log.error.called)
     441  
     442      @mock.patch('asyncio.base_events.logger')
     443      def test_tb_logger_result_retrieved(self, m_log):
     444          fut = self._new_future(loop=self.loop)
     445          fut.set_result(42)
     446          fut.result()
     447          del fut
     448          self.assertFalse(m_log.error.called)
     449  
     450      @mock.patch('asyncio.base_events.logger')
     451      def test_tb_logger_exception_unretrieved(self, m_log):
     452          fut = self._new_future(loop=self.loop)
     453          fut.set_exception(RuntimeError('boom'))
     454          del fut
     455          test_utils.run_briefly(self.loop)
     456          support.gc_collect()
     457          self.assertTrue(m_log.error.called)
     458  
     459      @mock.patch('asyncio.base_events.logger')
     460      def test_tb_logger_exception_retrieved(self, m_log):
     461          fut = self._new_future(loop=self.loop)
     462          fut.set_exception(RuntimeError('boom'))
     463          fut.exception()
     464          del fut
     465          self.assertFalse(m_log.error.called)
     466  
     467      @mock.patch('asyncio.base_events.logger')
     468      def test_tb_logger_exception_result_retrieved(self, m_log):
     469          fut = self._new_future(loop=self.loop)
     470          fut.set_exception(RuntimeError('boom'))
     471          self.assertRaises(RuntimeError, fut.result)
     472          del fut
     473          self.assertFalse(m_log.error.called)
     474  
     475      def test_wrap_future(self):
     476  
     477          def run(arg):
     478              return (arg, threading.get_ident())
     479          ex = concurrent.futures.ThreadPoolExecutor(1)
     480          f1 = ex.submit(run, 'oi')
     481          f2 = asyncio.wrap_future(f1, loop=self.loop)
     482          res, ident = self.loop.run_until_complete(f2)
     483          self.assertTrue(asyncio.isfuture(f2))
     484          self.assertEqual(res, 'oi')
     485          self.assertNotEqual(ident, threading.get_ident())
     486          ex.shutdown(wait=True)
     487  
     488      def test_wrap_future_future(self):
     489          f1 = self._new_future(loop=self.loop)
     490          f2 = asyncio.wrap_future(f1)
     491          self.assertIs(f1, f2)
     492  
     493      def test_wrap_future_without_loop(self):
     494          def run(arg):
     495              return (arg, threading.get_ident())
     496          ex = concurrent.futures.ThreadPoolExecutor(1)
     497          f1 = ex.submit(run, 'oi')
     498          with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
     499              asyncio.wrap_future(f1)
     500          ex.shutdown(wait=True)
     501  
     502      def test_wrap_future_use_running_loop(self):
     503          def run(arg):
     504              return (arg, threading.get_ident())
     505          ex = concurrent.futures.ThreadPoolExecutor(1)
     506          f1 = ex.submit(run, 'oi')
     507          async def test():
     508              return asyncio.wrap_future(f1)
     509          f2 = self.loop.run_until_complete(test())
     510          self.assertIs(self.loop, f2._loop)
     511          ex.shutdown(wait=True)
     512  
     513      def test_wrap_future_use_global_loop(self):
     514          # Deprecated in 3.10, undeprecated in 3.11.1
     515          asyncio.set_event_loop(self.loop)
     516          self.addCleanup(asyncio.set_event_loop, None)
     517          def run(arg):
     518              return (arg, threading.get_ident())
     519          ex = concurrent.futures.ThreadPoolExecutor(1)
     520          f1 = ex.submit(run, 'oi')
     521          f2 = asyncio.wrap_future(f1)
     522          self.assertIs(self.loop, f2._loop)
     523          ex.shutdown(wait=True)
     524  
     525      def test_wrap_future_cancel(self):
     526          f1 = concurrent.futures.Future()
     527          f2 = asyncio.wrap_future(f1, loop=self.loop)
     528          f2.cancel()
     529          test_utils.run_briefly(self.loop)
     530          self.assertTrue(f1.cancelled())
     531          self.assertTrue(f2.cancelled())
     532  
     533      def test_wrap_future_cancel2(self):
     534          f1 = concurrent.futures.Future()
     535          f2 = asyncio.wrap_future(f1, loop=self.loop)
     536          f1.set_result(42)
     537          f2.cancel()
     538          test_utils.run_briefly(self.loop)
     539          self.assertFalse(f1.cancelled())
     540          self.assertEqual(f1.result(), 42)
     541          self.assertTrue(f2.cancelled())
     542  
     543      def test_future_source_traceback(self):
     544          self.loop.set_debug(True)
     545  
     546          future = self._new_future(loop=self.loop)
     547          lineno = sys._getframe().f_lineno - 1
     548          self.assertIsInstance(future._source_traceback, list)
     549          self.assertEqual(future._source_traceback[-2][:3],
     550                           (__file__,
     551                            lineno,
     552                            'test_future_source_traceback'))
     553  
     554      @mock.patch('asyncio.base_events.logger')
     555      def check_future_exception_never_retrieved(self, debug, m_log):
     556          self.loop.set_debug(debug)
     557  
     558          def memory_error():
     559              try:
     560                  raise MemoryError()
     561              except BaseException as exc:
     562                  return exc
     563          exc = memory_error()
     564  
     565          future = self._new_future(loop=self.loop)
     566          future.set_exception(exc)
     567          future = None
     568          test_utils.run_briefly(self.loop)
     569          support.gc_collect()
     570  
     571          regex = f'^{self.cls.__name__} exception was never retrieved\n'
     572          exc_info = (type(exc), exc, exc.__traceback__)
     573          m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info)
     574  
     575          message = m_log.error.call_args[0][0]
     576          self.assertRegex(message, re.compile(regex, re.DOTALL))
     577  
     578      def test_future_exception_never_retrieved(self):
     579          self.check_future_exception_never_retrieved(False)
     580  
     581      def test_future_exception_never_retrieved_debug(self):
     582          self.check_future_exception_never_retrieved(True)
     583  
     584      def test_set_result_unless_cancelled(self):
     585          fut = self._new_future(loop=self.loop)
     586          fut.cancel()
     587          futures._set_result_unless_cancelled(fut, 2)
     588          self.assertTrue(fut.cancelled())
     589  
     590      def test_future_stop_iteration_args(self):
     591          fut = self._new_future(loop=self.loop)
     592          fut.set_result((1, 2))
     593          fi = fut.__iter__()
     594          result = None
     595          try:
     596              fi.send(None)
     597          except StopIteration as ex:
     598              result = ex.args[0]
     599          else:
     600              self.fail('StopIteration was expected')
     601          self.assertEqual(result, (1, 2))
     602  
     603      def test_future_iter_throw(self):
     604          fut = self._new_future(loop=self.loop)
     605          fi = iter(fut)
     606          self.assertRaises(TypeError, fi.throw,
     607                            Exception, Exception("elephant"), 32)
     608          self.assertRaises(TypeError, fi.throw,
     609                            Exception("elephant"), Exception("elephant"))
     610          # https://github.com/python/cpython/issues/101326
     611          self.assertRaises(ValueError, fi.throw, ValueError, None, None)
     612          self.assertRaises(TypeError, fi.throw, list)
     613  
     614      def test_future_del_collect(self):
     615          class ESC[4;38;5;81mEvil:
     616              def __del__(self):
     617                  gc.collect()
     618  
     619          for i in range(100):
     620              fut = self._new_future(loop=self.loop)
     621              fut.set_result(Evil())
     622  
     623  
     624  @unittest.skipUnless(hasattr(futures, '_CFuture'),
     625                       'requires the C _asyncio module')
     626  class ESC[4;38;5;81mCFutureTests(ESC[4;38;5;149mBaseFutureTests, ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     627      try:
     628          cls = futures._CFuture
     629      except AttributeError:
     630          cls = None
     631  
     632      def test_future_del_segfault(self):
     633          fut = self._new_future(loop=self.loop)
     634          with self.assertRaises(AttributeError):
     635              del fut._asyncio_future_blocking
     636          with self.assertRaises(AttributeError):
     637              del fut._log_traceback
     638  
     639  
     640  @unittest.skipUnless(hasattr(futures, '_CFuture'),
     641                       'requires the C _asyncio module')
     642  class ESC[4;38;5;81mCSubFutureTests(ESC[4;38;5;149mBaseFutureTests, ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     643      try:
     644          class ESC[4;38;5;81mCSubFuture(ESC[4;38;5;149mfuturesESC[4;38;5;149m.ESC[4;38;5;149m_CFuture):
     645              pass
     646  
     647          cls = CSubFuture
     648      except AttributeError:
     649          cls = None
     650  
     651  
     652  class ESC[4;38;5;81mPyFutureTests(ESC[4;38;5;149mBaseFutureTests, ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     653      cls = futures._PyFuture
     654  
     655  
     656  class ESC[4;38;5;81mBaseFutureDoneCallbackTests():
     657  
     658      def setUp(self):
     659          super().setUp()
     660          self.loop = self.new_test_loop()
     661  
     662      def run_briefly(self):
     663          test_utils.run_briefly(self.loop)
     664  
     665      def _make_callback(self, bag, thing):
     666          # Create a callback function that appends thing to bag.
     667          def bag_appender(future):
     668              bag.append(thing)
     669          return bag_appender
     670  
     671      def _new_future(self):
     672          raise NotImplementedError
     673  
     674      def test_callbacks_remove_first_callback(self):
     675          bag = []
     676          f = self._new_future()
     677  
     678          cb1 = self._make_callback(bag, 42)
     679          cb2 = self._make_callback(bag, 17)
     680          cb3 = self._make_callback(bag, 100)
     681  
     682          f.add_done_callback(cb1)
     683          f.add_done_callback(cb2)
     684          f.add_done_callback(cb3)
     685  
     686          f.remove_done_callback(cb1)
     687          f.remove_done_callback(cb1)
     688  
     689          self.assertEqual(bag, [])
     690          f.set_result('foo')
     691  
     692          self.run_briefly()
     693  
     694          self.assertEqual(bag, [17, 100])
     695          self.assertEqual(f.result(), 'foo')
     696  
     697      def test_callbacks_remove_first_and_second_callback(self):
     698          bag = []
     699          f = self._new_future()
     700  
     701          cb1 = self._make_callback(bag, 42)
     702          cb2 = self._make_callback(bag, 17)
     703          cb3 = self._make_callback(bag, 100)
     704  
     705          f.add_done_callback(cb1)
     706          f.add_done_callback(cb2)
     707          f.add_done_callback(cb3)
     708  
     709          f.remove_done_callback(cb1)
     710          f.remove_done_callback(cb2)
     711          f.remove_done_callback(cb1)
     712  
     713          self.assertEqual(bag, [])
     714          f.set_result('foo')
     715  
     716          self.run_briefly()
     717  
     718          self.assertEqual(bag, [100])
     719          self.assertEqual(f.result(), 'foo')
     720  
     721      def test_callbacks_remove_third_callback(self):
     722          bag = []
     723          f = self._new_future()
     724  
     725          cb1 = self._make_callback(bag, 42)
     726          cb2 = self._make_callback(bag, 17)
     727          cb3 = self._make_callback(bag, 100)
     728  
     729          f.add_done_callback(cb1)
     730          f.add_done_callback(cb2)
     731          f.add_done_callback(cb3)
     732  
     733          f.remove_done_callback(cb3)
     734          f.remove_done_callback(cb3)
     735  
     736          self.assertEqual(bag, [])
     737          f.set_result('foo')
     738  
     739          self.run_briefly()
     740  
     741          self.assertEqual(bag, [42, 17])
     742          self.assertEqual(f.result(), 'foo')
     743  
     744      def test_callbacks_invoked_on_set_result(self):
     745          bag = []
     746          f = self._new_future()
     747          f.add_done_callback(self._make_callback(bag, 42))
     748          f.add_done_callback(self._make_callback(bag, 17))
     749  
     750          self.assertEqual(bag, [])
     751          f.set_result('foo')
     752  
     753          self.run_briefly()
     754  
     755          self.assertEqual(bag, [42, 17])
     756          self.assertEqual(f.result(), 'foo')
     757  
     758      def test_callbacks_invoked_on_set_exception(self):
     759          bag = []
     760          f = self._new_future()
     761          f.add_done_callback(self._make_callback(bag, 100))
     762  
     763          self.assertEqual(bag, [])
     764          exc = RuntimeError()
     765          f.set_exception(exc)
     766  
     767          self.run_briefly()
     768  
     769          self.assertEqual(bag, [100])
     770          self.assertEqual(f.exception(), exc)
     771  
     772      def test_remove_done_callback(self):
     773          bag = []
     774          f = self._new_future()
     775          cb1 = self._make_callback(bag, 1)
     776          cb2 = self._make_callback(bag, 2)
     777          cb3 = self._make_callback(bag, 3)
     778  
     779          # Add one cb1 and one cb2.
     780          f.add_done_callback(cb1)
     781          f.add_done_callback(cb2)
     782  
     783          # One instance of cb2 removed. Now there's only one cb1.
     784          self.assertEqual(f.remove_done_callback(cb2), 1)
     785  
     786          # Never had any cb3 in there.
     787          self.assertEqual(f.remove_done_callback(cb3), 0)
     788  
     789          # After this there will be 6 instances of cb1 and one of cb2.
     790          f.add_done_callback(cb2)
     791          for i in range(5):
     792              f.add_done_callback(cb1)
     793  
     794          # Remove all instances of cb1. One cb2 remains.
     795          self.assertEqual(f.remove_done_callback(cb1), 6)
     796  
     797          self.assertEqual(bag, [])
     798          f.set_result('foo')
     799  
     800          self.run_briefly()
     801  
     802          self.assertEqual(bag, [2])
     803          self.assertEqual(f.result(), 'foo')
     804  
     805      def test_remove_done_callbacks_list_mutation(self):
     806          # see http://bugs.python.org/issue28963 for details
     807  
     808          fut = self._new_future()
     809          fut.add_done_callback(str)
     810  
     811          for _ in range(63):
     812              fut.add_done_callback(id)
     813  
     814          class ESC[4;38;5;81mevil:
     815              def __eq__(self, other):
     816                  fut.remove_done_callback(id)
     817                  return False
     818  
     819          fut.remove_done_callback(evil())
     820  
     821      def test_remove_done_callbacks_list_clear(self):
     822          # see https://github.com/python/cpython/issues/97592 for details
     823  
     824          fut = self._new_future()
     825          fut.add_done_callback(str)
     826  
     827          for _ in range(63):
     828              fut.add_done_callback(id)
     829  
     830          class ESC[4;38;5;81mevil:
     831              def __eq__(self, other):
     832                  fut.remove_done_callback(other)
     833  
     834          fut.remove_done_callback(evil())
     835  
     836      def test_schedule_callbacks_list_mutation_1(self):
     837          # see http://bugs.python.org/issue28963 for details
     838  
     839          def mut(f):
     840              f.remove_done_callback(str)
     841  
     842          fut = self._new_future()
     843          fut.add_done_callback(mut)
     844          fut.add_done_callback(str)
     845          fut.add_done_callback(str)
     846          fut.set_result(1)
     847          test_utils.run_briefly(self.loop)
     848  
     849      def test_schedule_callbacks_list_mutation_2(self):
     850          # see http://bugs.python.org/issue30828 for details
     851  
     852          fut = self._new_future()
     853          fut.add_done_callback(str)
     854  
     855          for _ in range(63):
     856              fut.add_done_callback(id)
     857  
     858          max_extra_cbs = 100
     859          extra_cbs = 0
     860  
     861          class ESC[4;38;5;81mevil:
     862              def __eq__(self, other):
     863                  nonlocal extra_cbs
     864                  extra_cbs += 1
     865                  if extra_cbs < max_extra_cbs:
     866                      fut.add_done_callback(id)
     867                  return False
     868  
     869          fut.remove_done_callback(evil())
     870  
     871  
     872  @unittest.skipUnless(hasattr(futures, '_CFuture'),
     873                       'requires the C _asyncio module')
     874  class ESC[4;38;5;81mCFutureDoneCallbackTests(ESC[4;38;5;149mBaseFutureDoneCallbackTests,
     875                                 ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     876  
     877      def _new_future(self):
     878          return futures._CFuture(loop=self.loop)
     879  
     880  
     881  @unittest.skipUnless(hasattr(futures, '_CFuture'),
     882                       'requires the C _asyncio module')
     883  class ESC[4;38;5;81mCSubFutureDoneCallbackTests(ESC[4;38;5;149mBaseFutureDoneCallbackTests,
     884                                    ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     885  
     886      def _new_future(self):
     887          class ESC[4;38;5;81mCSubFuture(ESC[4;38;5;149mfuturesESC[4;38;5;149m.ESC[4;38;5;149m_CFuture):
     888              pass
     889          return CSubFuture(loop=self.loop)
     890  
     891  
     892  class ESC[4;38;5;81mPyFutureDoneCallbackTests(ESC[4;38;5;149mBaseFutureDoneCallbackTests,
     893                                  ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     894  
     895      def _new_future(self):
     896          return futures._PyFuture(loop=self.loop)
     897  
     898  
     899  class ESC[4;38;5;81mBaseFutureInheritanceTests:
     900  
     901      def _get_future_cls(self):
     902          raise NotImplementedError
     903  
     904      def setUp(self):
     905          super().setUp()
     906          self.loop = self.new_test_loop()
     907          self.addCleanup(self.loop.close)
     908  
     909      def test_inherit_without_calling_super_init(self):
     910          # See https://bugs.python.org/issue38785 for the context
     911          cls = self._get_future_cls()
     912  
     913          class ESC[4;38;5;81mMyFut(ESC[4;38;5;149mcls):
     914              def __init__(self, *args, **kwargs):
     915                  # don't call super().__init__()
     916                  pass
     917  
     918          fut = MyFut(loop=self.loop)
     919          with self.assertRaisesRegex(
     920              RuntimeError,
     921              "Future object is not initialized."
     922          ):
     923              fut.get_loop()
     924  
     925  
     926  class ESC[4;38;5;81mPyFutureInheritanceTests(ESC[4;38;5;149mBaseFutureInheritanceTests,
     927                                 ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     928      def _get_future_cls(self):
     929          return futures._PyFuture
     930  
     931  
     932  @unittest.skipUnless(hasattr(futures, '_CFuture'),
     933                       'requires the C _asyncio module')
     934  class ESC[4;38;5;81mCFutureInheritanceTests(ESC[4;38;5;149mBaseFutureInheritanceTests,
     935                                ESC[4;38;5;149mtest_utilsESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     936      def _get_future_cls(self):
     937          return futures._CFuture
     938  
     939  
     940  if __name__ == '__main__':
     941      unittest.main()