From a297930774a048e4e2606886f6b2f62ed5decdd0 Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Mon, 10 Jun 2019 00:26:30 -0700 Subject: [PATCH] Deprecate Event.clear() Closes: gh-637 --- newsfragments/637.removal.rst | 1 + trio/_signals.py | 12 ++++++------ trio/_sync.py | 16 +++++++++++++--- trio/tests/test_sync.py | 13 +++++++++++-- 4 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 newsfragments/637.removal.rst diff --git a/newsfragments/637.removal.rst b/newsfragments/637.removal.rst new file mode 100644 index 0000000000..f426c28158 --- /dev/null +++ b/newsfragments/637.removal.rst @@ -0,0 +1 @@ +The ``clear`` method on `trio.Event` has been deprecated. diff --git a/trio/_signals.py b/trio/_signals.py index 09dbedecc4..2ebb4a0a5a 100644 --- a/trio/_signals.py +++ b/trio/_signals.py @@ -3,7 +3,6 @@ from collections import OrderedDict import trio -from ._sync import Event from ._util import ( signal_raise, aiter_compat, is_main_thread, ConflictDetector ) @@ -62,7 +61,7 @@ class SignalReceiver: def __init__(self): # {signal num: None} self._pending = OrderedDict() - self._have_pending = Event() + self._lot = trio.hazmat.ParkingLot() self._conflict_detector = ConflictDetector( "only one task can iterate on a signal receiver at a time" ) @@ -73,7 +72,7 @@ def _add(self, signum): signal_raise(signum) else: self._pending[signum] = None - self._have_pending.set() + self._lot.unpark() def _redeliver_remaining(self): # First make sure that any signals still in the delivery pipeline will @@ -108,10 +107,11 @@ async def __anext__(self): # calls to __anext__, but doing it without race conditions is quite # tricky, and there doesn't seem to be any point in trying. with self._conflict_detector: - await self._have_pending.wait() - signum, _ = self._pending.popitem(last=False) if not self._pending: - self._have_pending.clear() + await self._lot.park() + else: + await trio.hazmat.checkpoint() + signum, _ = self._pending.popitem(last=False) return signum diff --git a/trio/_sync.py b/trio/_sync.py index 67518a5219..1d5a7888f4 100644 --- a/trio/_sync.py +++ b/trio/_sync.py @@ -7,6 +7,7 @@ from ._util import aiter_compat from ._core import enable_ki_protection, ParkingLot +from ._deprecate import deprecated __all__ = [ "Event", @@ -36,6 +37,13 @@ class Event: primitive that doesn't have this protection, consider :class:`Condition` or :class:`trio.hazmat.ParkingLot`. + .. note:: Unlike `threading.Event`, `trio.Event` has no + `~threading.Event.clear` method. In Trio, once an `Event` has happened, + it cannot un-happen. If you need to represent a series of events, + consider creating a new `Event` object for each one (they're cheap!), + or other synchronization methods like :ref:`channels ` or + `trio.hazmat.ParkingLot`. + """ _lot = attr.ib(default=attr.Factory(ParkingLot), init=False) @@ -55,10 +63,12 @@ def set(self): self._flag = True self._lot.unpark_all() + @deprecated( + "0.12.0", + issue=637, + instead="multiple Event objects or other synchronization primitives" + ) def clear(self): - """Set the internal flag value to False. - - """ self._flag = False async def wait(self): diff --git a/trio/tests/test_sync.py b/trio/tests/test_sync.py index c29d0f71c4..ab5b26d06e 100644 --- a/trio/tests/test_sync.py +++ b/trio/tests/test_sync.py @@ -20,8 +20,7 @@ async def test_Event(): with assert_checkpoints(): await e.wait() - e.clear() - assert not e.is_set() + e = Event() record = [] @@ -41,6 +40,16 @@ async def child(): assert record == ["sleeping", "sleeping", "woken", "woken"] +# When we remove clear() then this test can be removed too +def test_Event_clear(recwarn): + e = Event() + assert not e.is_set() + e.set() + assert e.is_set() + e.clear() + assert not e.is_set() + + async def test_CapacityLimiter(): with pytest.raises(TypeError): CapacityLimiter(1.0)