Kaydet (Commit) 0a28c0d1 authored tarafından jhaydaman's avatar jhaydaman Kaydeden (comit) Andrew Svetlov

bpo-33238: Add InvalidStateError to concurrent.futures. (GH-7056)

Future.set_result and Future.set_exception now raise InvalidStateError
if the futures are not pending or running. This mirrors the behavior
of asyncio.Future, and prevents AssertionErrors in asyncio.wrap_future
when set_result is called multiple times.
üst bb9474f1
......@@ -380,6 +380,11 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable.
This method should only be used by :class:`Executor` implementations and
unit tests.
.. versionchanged:: 3.8
This method raises
:exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is
already done.
.. method:: set_exception(exception)
Sets the result of the work associated with the :class:`Future` to the
......@@ -388,6 +393,10 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable.
This method should only be used by :class:`Executor` implementations and
unit tests.
.. versionchanged:: 3.8
This method raises
:exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is
already done.
Module Functions
----------------
......@@ -466,6 +475,13 @@ Exception classes
.. versionadded:: 3.7
.. exception:: InvalidStateError
Raised when an operation is performed on a future that is not allowed
in the current state.
.. versionadded:: 3.8
.. currentmodule:: concurrent.futures.thread
.. exception:: BrokenThreadPool
......
__all__ = ()
import concurrent.futures._base
import concurrent.futures
import reprlib
from . import format_helpers
Error = concurrent.futures._base.Error
CancelledError = concurrent.futures.CancelledError
TimeoutError = concurrent.futures.TimeoutError
class InvalidStateError(Error):
"""The operation is not allowed in this state."""
InvalidStateError = concurrent.futures.InvalidStateError
# States for Future.
......
......@@ -10,6 +10,7 @@ from concurrent.futures._base import (FIRST_COMPLETED,
ALL_COMPLETED,
CancelledError,
TimeoutError,
InvalidStateError,
BrokenExecutor,
Future,
Executor,
......
......@@ -53,6 +53,10 @@ class TimeoutError(Error):
"""The operation exceeded the given deadline."""
pass
class InvalidStateError(Error):
"""The operation is not allowed in this state."""
pass
class _Waiter(object):
"""Provides the event that wait() and as_completed() block on."""
def __init__(self):
......@@ -513,6 +517,8 @@ class Future(object):
Should only be used by Executor implementations and unit tests.
"""
with self._condition:
if self._state in {CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED}:
raise InvalidStateError('{}: {!r}'.format(self._state, self))
self._result = result
self._state = FINISHED
for waiter in self._waiters:
......@@ -526,6 +532,8 @@ class Future(object):
Should only be used by Executor implementations and unit tests.
"""
with self._condition:
if self._state in {CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED}:
raise InvalidStateError('{}: {!r}'.format(self._state, self))
self._exception = exception
self._state = FINISHED
for waiter in self._waiters:
......
......@@ -1206,6 +1206,34 @@ class FutureTests(BaseTestCase):
self.assertTrue(isinstance(f1.exception(timeout=5), OSError))
t.join()
def test_multiple_set_result(self):
f = create_future(state=PENDING)
f.set_result(1)
with self.assertRaisesRegex(
futures.InvalidStateError,
'FINISHED: <Future at 0x[0-9a-f]+ '
'state=finished returned int>'
):
f.set_result(2)
self.assertTrue(f.done())
self.assertEqual(f.result(), 1)
def test_multiple_set_exception(self):
f = create_future(state=PENDING)
e = ValueError()
f.set_exception(e)
with self.assertRaisesRegex(
futures.InvalidStateError,
'FINISHED: <Future at 0x[0-9a-f]+ '
'state=finished raised ValueError>'
):
f.set_exception(Exception())
self.assertEqual(f.exception(), e)
@test.support.reap_threads
def test_main():
......
Add ``InvalidStateError`` to :mod:`concurrent.futures`.
``Future.set_result`` and ``Future.set_exception`` now raise
``InvalidStateError`` if the futures are not pending or running. Patch by
Jason Haydaman.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment