Skip to content

Commit 31dd718

Browse files
Kentzoasvetlov
authored andcommitted
Add the remaining property #20 (#21)
- If timeout is not started yet or started unconstrained: remaining is None - If timeout is expired: remaining is 0.0 - All other: roughly amount of time before TimeoutError is triggered
1 parent cc315ee commit 31dd718

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

async_timeout/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def __init__(self, timeout, *, loop=None):
2828
self._task = None
2929
self._cancelled = False
3030
self._cancel_handler = None
31+
self._cancel_at = None
3132

3233
def __enter__(self):
3334
return self._do_enter()
@@ -47,14 +48,21 @@ def __aexit__(self, exc_type, exc_val, exc_tb):
4748
def expired(self):
4849
return self._cancelled
4950

51+
@property
52+
def remaining(self):
53+
if self._cancel_at is not None:
54+
return max(self._cancel_at - self._loop.time(), 0.0)
55+
else:
56+
return None
57+
5058
def _do_enter(self):
5159
if self._timeout is not None:
5260
self._task = current_task(self._loop)
5361
if self._task is None:
5462
raise RuntimeError('Timeout context manager should be used '
5563
'inside a task')
56-
self._cancel_handler = self._loop.call_later(
57-
self._timeout, self._cancel_task)
64+
self._cancel_at = self._loop.time() + self._timeout
65+
self._cancel_handler = self._loop.call_at(self._cancel_at, self._cancel_task)
5866
return self
5967

6068
def _do_exit(self, exc_type):

tests/test_timeout.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,21 @@ def test_timeout_inner_other_error(loop):
227227
with timeout(0.01, loop=loop) as cm:
228228
raise RuntimeError
229229
assert not cm.expired
230+
231+
@asyncio.coroutine
232+
def test_timeout_remaining(loop):
233+
with timeout(None, loop=loop) as cm:
234+
assert cm.remaining is None
235+
236+
t = timeout(1.0, loop=loop)
237+
assert t.remaining is None
238+
239+
with timeout(1.0, loop=loop) as cm:
240+
yield from asyncio.sleep(0.1, loop=loop)
241+
assert cm.remaining < 1.0
242+
243+
with pytest.raises(asyncio.TimeoutError):
244+
with timeout(0.1, loop=loop) as cm:
245+
yield from asyncio.sleep(0.5, loop=loop)
246+
247+
assert cm.remaining == 0.0

0 commit comments

Comments
 (0)