From 44bc939fb04f946287b8ebdc19bf928fde4bab26 Mon Sep 17 00:00:00 2001 From: Stefaan Lippens Date: Fri, 16 Dec 2022 12:06:54 +0100 Subject: [PATCH 1/3] Add `shift()` method to pytest `time_machine` fixture (#247) --- CHANGELOG.rst | 4 ++++ README.rst | 2 +- src/time_machine/__init__.py | 8 ++++++++ tests/test_time_machine.py | 14 +++++++++++++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3178027..6c006af 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +* Add ``shift()`` method to the ``time_machine`` pytest fixture. + + Thanks to Stefaan Lippens in `PR 312 `__. + * Mock ``time.monotonic()`` and ``time.monotonic_ns()``. They return the values of ``time.time()`` and ``time.time_ns()`` respectively, rather than real monotonic clocks. diff --git a/README.rst b/README.rst index 020c930..265464c 100644 --- a/README.rst +++ b/README.rst @@ -297,7 +297,7 @@ pytest plugin ------------- time-machine also works as a pytest plugin. -It provides a function-scoped fixture called ``time_machine`` that has one method, ``move_to()``, which has the same signature as ``Coordinates.move_to()``. +It provides a function-scoped fixture called ``time_machine`` with methods ``move_to()`` and ``shift()``, which have the same signature as their equivalents in ``Coordinates``. This can be used to mock your test at different points in time and will automatically be un-mock when the test is torn down. For example: diff --git a/src/time_machine/__init__.py b/src/time_machine/__init__.py index e7ce191..81a0e0b 100644 --- a/src/time_machine/__init__.py +++ b/src/time_machine/__init__.py @@ -437,6 +437,14 @@ def move_to( assert self.coordinates is not None self.coordinates.move_to(destination, tick=tick) + def shift(self, delta: dt.timedelta | int | float) -> None: + if self.traveller is None: + raise RuntimeError( + "Initialize with `move_to()` first before using `shift()`" + ) + assert self.coordinates is not None + self.coordinates.shift(delta=delta) + def stop(self) -> None: if self.traveller is not None: self.traveller.stop() diff --git a/tests/test_time_machine.py b/tests/test_time_machine.py index 5528b41..3eafd32 100644 --- a/tests/test_time_machine.py +++ b/tests/test_time_machine.py @@ -717,7 +717,7 @@ def test_fixture_used_tick_true(time_machine): assert original < time.time() < EPOCH + 10.0 -def test_fixture_used_twice(time_machine): +def test_fixture_move_to_twice(time_machine): time_machine.move_to(EPOCH) assert time.time() == EPOCH @@ -725,6 +725,18 @@ def test_fixture_used_twice(time_machine): assert time.time() == EPOCH_PLUS_ONE_YEAR +def test_fixture_move_to_and_shift(time_machine): + time_machine.move_to(EPOCH, tick=False) + assert time.time() == EPOCH + time_machine.shift(100) + assert time.time() == EPOCH + 100 + + +def test_fixture_shift_without_move_to(time_machine): + with pytest.raises(RuntimeError): + time_machine.shift(100) + + # escape hatch tests From 6c5694a93efde80dca77506e1b6e965d46c8f0eb Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 19 Sep 2023 10:54:17 +0100 Subject: [PATCH 2/3] Improve error message and test --- src/time_machine/__init__.py | 2 +- tests/test_time_machine.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/time_machine/__init__.py b/src/time_machine/__init__.py index 81a0e0b..c0d6bda 100644 --- a/src/time_machine/__init__.py +++ b/src/time_machine/__init__.py @@ -440,7 +440,7 @@ def move_to( def shift(self, delta: dt.timedelta | int | float) -> None: if self.traveller is None: raise RuntimeError( - "Initialize with `move_to()` first before using `shift()`" + "Initialize time_machine with move_to() before using shift()." ) assert self.coordinates is not None self.coordinates.shift(delta=delta) diff --git a/tests/test_time_machine.py b/tests/test_time_machine.py index 3eafd32..9736be4 100644 --- a/tests/test_time_machine.py +++ b/tests/test_time_machine.py @@ -733,9 +733,13 @@ def test_fixture_move_to_and_shift(time_machine): def test_fixture_shift_without_move_to(time_machine): - with pytest.raises(RuntimeError): + with pytest.raises(RuntimeError) as excinfo: time_machine.shift(100) + assert excinfo.value.args == ( + "Initialize time_machine with move_to() before using shift().", + ) + # escape hatch tests From e43e499392c177b6d96c05f1789ffb78e6a4d4c8 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 19 Sep 2023 10:55:41 +0100 Subject: [PATCH 3/3] Show shift() in example --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 265464c..755325c 100644 --- a/README.rst +++ b/README.rst @@ -316,6 +316,10 @@ For example: assert dt.date.today().isoformat() == "2015-10-21" + time_machine.shift(dt.timedelta(days=1)) + + assert dt.date.today().isoformat() == "2015-10-22" + If you are using pytest test classes, you can apply the fixture to all test methods in a class by adding an autouse fixture: .. code-block:: python