python (3.12.0)

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