-
Notifications
You must be signed in to change notification settings - Fork 814
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clock] Add a centralised Clock, responsible for anything related to …
…time This makes time quite easier to mock during integration tests :-)
- Loading branch information
Olivier Philippon
committed
May 17, 2022
1 parent
6669216
commit f5969fb
Showing
7 changed files
with
180 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import asyncio | ||
from time import monotonic | ||
|
||
|
||
""" | ||
A module that serves as the single source of truth for everything time-related in a Textual app. | ||
Having this logic centralised makes it easier to simulate time in integration tests, | ||
by mocking the few functions exposed by this module. | ||
""" | ||
|
||
|
||
# N.B. This class and its singleton instance have to be hidden APIs because we want to be able to mock time, | ||
# even for Python modules that imported functions such as `get_time` *before* we mocked this internal _Clock. | ||
# (so mocking public APIs such as `get_time` wouldn't affect direct references to then that were done during imports) | ||
class _Clock: | ||
def get_time(self) -> float: | ||
return monotonic() | ||
|
||
async def aget_time(self) -> float: | ||
return self.get_time() | ||
|
||
async def sleep(self, seconds: float) -> None: | ||
await asyncio.sleep(seconds) | ||
|
||
|
||
# That's our target for mocking time! :-) | ||
_clock = _Clock() | ||
|
||
|
||
def get_time() -> float: | ||
""" | ||
Get the current wall clock time. | ||
Returns: | ||
float: the value (in fractional seconds) of a monotonic clock, i.e. a clock that cannot go backwards. | ||
""" | ||
return _clock.get_time() | ||
|
||
|
||
async def aget_time() -> float: | ||
""" | ||
Asynchronous version of `get_time`. Useful in situations where we want asyncio to be | ||
able to "do things" elsewhere right before we fetch the time. | ||
Returns: | ||
float: the value (in fractional seconds) of a monotonic clock, i.e. a clock that cannot go backwards. | ||
""" | ||
return await _clock.aget_time() | ||
|
||
|
||
async def sleep(seconds: float) -> None: | ||
""" | ||
Coroutine that completes after a given time (in seconds). | ||
Args: | ||
seconds (float): the duration we should wait for before unblocking the awaiter | ||
""" | ||
return await _clock.sleep(seconds) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.