-
Notifications
You must be signed in to change notification settings - Fork 181
/
Copy pathtimer.py
129 lines (101 loc) · 3.95 KB
/
timer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""
A generic timer class suitable for use as the DICOM UL's ARTIM timer.
"""
import logging
import time
from typing import Optional
LOGGER = logging.getLogger(__name__)
class Timer:
"""A generic timer.
Implementation of the DICOM Upper Layer's ARTIM timer. The ARTIM timer is
used by the state machine to monitor connection and response timeouts.
This class may also be used as a general purpose expiry timer.
A :attr:`~Timer.timeout` of ``None`` implies that :attr:`~Timer.expired`
always returns ``False`` and :attr:`~Timer.remaining` always returns ``1``.
A :attr:`~Timer.timeout` of :class:`float` implies that:
- If not yet started, :attr:`~Timer.expired` returns ``False`` and
:attr:`~Timer.remaining` returns :attr:`~Timer.timeout`
- If started then :attr:`~Timer.expired` returns ``False`` until the time
since starting is greater than :attr:`~Timer.timeout` after which it
returns ``True``. :attr:`~Timer.remaining` returns the number of seconds
until :attr:`~Timer.expired` returns ``True`` (will return negative
value after expiry)
- If started then stopped before the timeout then :attr:`~Timer.expired`
returns ``False``, if stopped after the time since starting is greater
than :attr:`~Timer.timeout` then returns ``True``.
:attr:`~Timer.remaining` always returns the number of seconds until
:attr:`~Timer.expired` returns ``True``.
References
----------
* DICOM Standard, Part 8,
:dcm:`Section 9.1.5<part08/chapter_9.html#sect_9.1.5>`.
"""
def __init__(self, timeout: Optional[float]) -> None:
"""Create a new :class:`Timer`.
Parameters
---------
timeout : numeric or None
The number of seconds before the timer expires. A value of ``None``
means the timer never expires.
"""
self._start_time: Optional[float] = None
self._end_time: Optional[float] = None
self._timeout = timeout
@property
def expired(self) -> bool:
"""Check if the timer has expired.
Returns
-------
bool
``True`` if the timer has expired, ``False`` otherwise
"""
# Timer never expires
if self.timeout is None:
return False
# Timer hasn't started
if self._start_time is None:
return False
# Timer has started
if self.remaining < 0:
return True
return False
@property
def remaining(self) -> float:
"""Return the number of seconds remaining until timeout.
Returns ``1`` if the timer is set to never expire.
"""
# Timer never expires
if self.timeout is None:
return 1
# Timer hasn't started
if self._start_time is None:
return self.timeout
# Timer has started and hasn't been stopped
if self._end_time is None:
return self.timeout - (time.time() - self._start_time)
# Time has been start and been stopped
return self.timeout - (self._end_time - self._start_time)
def restart(self) -> None:
"""Restart the timer."""
self.start()
def start(self) -> None:
"""Resets and starts the timer running."""
self._start_time = time.time()
self._end_time = None
def stop(self) -> None:
"""Stops the timer and resets it."""
self._end_time = time.time()
@property
def timeout(self) -> Optional[float]:
"""Return the number of seconds set for :attr:`~Timer.timeout`."""
return self._timeout
@timeout.setter
def timeout(self, value: Optional[float]) -> None:
"""Set the number of seconds before the timer expires.
Parameters
----------
value : numeric or None
The number of seconds before the timer expires. A value of ``None``
means the timer never expires.
"""
self._timeout = value