Skip to content

Commit fd527c5

Browse files
authored
Bump time-machine from 2.19.0 to 3.1.0 (#230)
Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.19.0 to 3.1.0. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/adamchainz/time-machine/blob/main/docs/changelog.rst">time-machine's changelog</a>.</em></p> <blockquote> <h2>3.1.0 (2025-11-21)</h2> <ul> <li> <p>Optimize patching of <code>uuid</code> module. By avoiding using <code>unittest.mock</code>, this small overhead from starting <code>time_machine.travel()</code> has been reduced about 20x, from ~600ns to ~30ns by one benchmark.</p> <p><code>PR [#585](adamchainz/time-machine#585) &lt;https://github.com/adamchainz/time-machine/pull/585&gt;</code>__.</p> </li> </ul> <h2>3.0.0 (2025-11-18)</h2> <ul> <li> <p>Remove mocking of <code>time.monotonic()</code> and <code>time.monotonic_ns()</code>.</p> <p>This mocking caused too many issues, such as causing freezes in asyncio event loops (<code>Issue [#387](adamchainz/time-machine#387) &lt;https://github.com/adamchainz/time-machine/issues/387&gt;</code><strong>), preventing pytest-durations from timing tests correctly (<code>Issue [#505](adamchainz/time-machine#505) &lt;https://github.com/adamchainz/time-machine/issues/505&gt;</code></strong>), and triggering timeouts in psycopg (<code>Issue [#509](adamchainz/time-machine#509) &lt;https://github.com/adamchainz/time-machine/issues/509&gt;</code>__). The root cause here is that mocking the monotonic clock breaks its contract, allowing it to move backwards when it’s meant to only move forwards.</p> <p>As an alternative, use |unittest.mock|__ to mock the monotonic function for the specific tested modules that need it. That means that your code should import <code>monotonic()</code> or <code>monotonic_ns()</code> directly, so that your tests can mock it in those places only. For example, if your system under test looks like:</p> <p>.. |unittest.mock| replace:: <code>unittest.mock</code> __ <a href="https://docs.python.org/3/library/unittest.mock.html">https://docs.python.org/3/library/unittest.mock.html</a></p> <p>.. code-block:: python</p> <pre><code># example.py from time import monotonic <p>def measurement(): start = monotonic() ... end = monotonic() return end - start </code></pre></p> <p>…then your tests can mock <code>monotonic()</code> like this:</p> <p>.. code-block:: python</p> <pre><code>from unittest import TestCase, mock <p>import example</p> <p>class MeasurementTests(TestCase): def test_success(self): with mock.patch.object(example, &quot;monotonic&quot;, side_effect=[0.0, 1.23]): result = example.measurement() assert result == 1.23 </code></pre></p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/adamchainz/time-machine/commit/b9f7500d03de270766fcfaf694f4beccf57eae5e"><code>b9f7500</code></a> Version 3.1.0</li> <li><a href="https://github.com/adamchainz/time-machine/commit/965e906ec5b7acbeb348cf1dc85252918aa79f9e"><code>965e906</code></a> Optimize patching of uuid module (<a href="https://redirect.github.com/adamchainz/time-machine/issues/585">#585</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/5d2e8dd4a427988e53d8fcce74b717dd4d0f9538"><code>5d2e8dd</code></a> Version 3.0.0</li> <li><a href="https://github.com/adamchainz/time-machine/commit/39ba19f3409b6ab32e04fc5ed10016efa85b7675"><code>39ba19f</code></a> Upgrade cibuildwheel to 3.3.0 (<a href="https://redirect.github.com/adamchainz/time-machine/issues/581">#581</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/3a0d5dd43e440761bfff4696856db301cf189560"><code>3a0d5dd</code></a> Raise ValueError from escape_hatch functions when not travelling (<a href="https://redirect.github.com/adamchainz/time-machine/issues/580">#580</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/ac23916b4d37d838d04fbb0709d76ed50e7113e2"><code>ac23916</code></a> Improve usage documentation (<a href="https://redirect.github.com/adamchainz/time-machine/issues/579">#579</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/d10f0003cd619636de38373f774759e84e6ce3ac"><code>d10f000</code></a> Parse str destinations with datetime.fromisoformat() first (<a href="https://redirect.github.com/adamchainz/time-machine/issues/578">#578</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/b82045133a6414e84c4521c5d50322861026d62f"><code>b820451</code></a> Reorder changelog</li> <li><a href="https://github.com/adamchainz/time-machine/commit/48f1af50f646198196c6d7ed7a14f7f23ed88482"><code>48f1af5</code></a> Make dateutil an optional dependency (<a href="https://redirect.github.com/adamchainz/time-machine/issues/576">#576</a>)</li> <li><a href="https://github.com/adamchainz/time-machine/commit/5559f89b6d61cf4156f64eb87919a7fdd2477b4e"><code>5559f89</code></a> Remove Python 3.9 from cibuildwheel target list (<a href="https://redirect.github.com/adamchainz/time-machine/issues/575">#575</a>)</li> <li>Additional commits viewable in <a href="https://github.com/adamchainz/time-machine/compare/2.19.0...3.1.0">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=time-machine&package-manager=pip&previous-version=2.19.0&new-version=3.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details>
2 parents 1921e6d + 47a4b86 commit fd527c5

File tree

3 files changed

+22
-22
lines changed

3 files changed

+22
-22
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ dev-pytest = [
9494
"pytest-mock == 3.15.1",
9595
"pytest-asyncio == 1.3.0",
9696
"async-solipsism == 0.8",
97-
"time-machine == 2.19.0",
97+
"time-machine == 3.1.0",
9898
]
9999
dev = [
100100
"frequenz-dispatch[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",

tests/test_frequenz_dispatch.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def event_loop_policy() -> async_solipsism.EventLoopPolicy:
4343

4444

4545
@fixture
46-
def fake_time() -> Iterator[time_machine.Coordinates]:
46+
def fake_time() -> Iterator[time_machine.Traveller]:
4747
"""Replace real time with a time machine that doesn't automatically tick."""
4848
# destination can be a datetime or a timestamp (int), so are moving to the
4949
# epoch (in UTC!)
@@ -165,7 +165,7 @@ async def _test_new_dispatch_created(
165165
async def test_existing_dispatch_updated(
166166
test_env: _TestEnv,
167167
generator: DispatchGenerator,
168-
fake_time: time_machine.Coordinates,
168+
fake_time: time_machine.Traveller,
169169
) -> None:
170170
"""Test that an existing dispatch is updated."""
171171
sample = generator.generate_dispatch()
@@ -203,7 +203,7 @@ async def test_existing_dispatch_updated(
203203
async def test_existing_dispatch_deleted(
204204
test_env: _TestEnv,
205205
generator: DispatchGenerator,
206-
fake_time: time_machine.Coordinates,
206+
fake_time: time_machine.Traveller,
207207
) -> None:
208208
"""Test that an existing dispatch is deleted."""
209209
sample = await _test_new_dispatch_created(test_env, generator.generate_dispatch())
@@ -226,7 +226,7 @@ async def test_existing_dispatch_deleted(
226226
async def test_dispatch_inf_duration_deleted(
227227
test_env: _TestEnv,
228228
generator: DispatchGenerator,
229-
fake_time: time_machine.Coordinates,
229+
fake_time: time_machine.Traveller,
230230
) -> None:
231231
"""Test that a dispatch with infinite duration can be deleted while running."""
232232
# Generate a dispatch with infinite duration (duration=None)
@@ -261,7 +261,7 @@ async def test_dispatch_inf_duration_deleted(
261261
async def test_dispatch_inf_duration_updated_stopped_started(
262262
test_env: _TestEnv,
263263
generator: DispatchGenerator,
264-
fake_time: time_machine.Coordinates,
264+
fake_time: time_machine.Traveller,
265265
) -> None:
266266
"""Test that a dispatch with infinite duration can be stopped and started by updating it."""
267267
# Generate a dispatch with infinite duration (duration=None)
@@ -310,7 +310,7 @@ async def test_dispatch_inf_duration_updated_stopped_started(
310310
async def test_dispatch_inf_duration_updated_to_finite_and_stops(
311311
test_env: _TestEnv,
312312
generator: DispatchGenerator,
313-
fake_time: time_machine.Coordinates,
313+
fake_time: time_machine.Traveller,
314314
) -> None:
315315
"""Test updating an inf. duration changing to finite.
316316
@@ -353,7 +353,7 @@ async def test_dispatch_inf_duration_updated_to_finite_and_stops(
353353
async def test_dispatch_schedule(
354354
test_env: _TestEnv,
355355
generator: DispatchGenerator,
356-
fake_time: time_machine.Coordinates,
356+
fake_time: time_machine.Traveller,
357357
) -> None:
358358
"""Test that a random dispatch is scheduled correctly."""
359359
sample = replace(
@@ -400,7 +400,7 @@ async def test_dispatch_schedule(
400400
async def test_dispatch_inf_duration_updated_to_finite_and_continues(
401401
test_env: _TestEnv,
402402
generator: DispatchGenerator,
403-
fake_time: time_machine.Coordinates,
403+
fake_time: time_machine.Traveller,
404404
) -> None:
405405
"""Test that updating an infinite duration dispatch to a finite duration.
406406
@@ -447,7 +447,7 @@ async def test_dispatch_inf_duration_updated_to_finite_and_continues(
447447
async def test_dispatch_new_but_finished(
448448
test_env: _TestEnv,
449449
generator: DispatchGenerator,
450-
fake_time: time_machine.Coordinates,
450+
fake_time: time_machine.Traveller,
451451
) -> None:
452452
"""Test that a finished dispatch is not started at startup."""
453453
# Generate a dispatch that is already finished
@@ -503,7 +503,7 @@ async def test_dispatch_new_but_finished(
503503
async def test_notification_on_actor_start(
504504
test_env: _TestEnv,
505505
generator: DispatchGenerator,
506-
fake_time: time_machine.Coordinates,
506+
fake_time: time_machine.Traveller,
507507
) -> None:
508508
"""Test that the actor sends notifications for all running dispatches on start."""
509509
# Generate a dispatch that is already running
@@ -545,7 +545,7 @@ async def test_notification_on_actor_start(
545545
async def test_notification_on_actor_start_inf_duration(
546546
test_env: _TestEnv,
547547
generator: DispatchGenerator,
548-
fake_time: time_machine.Coordinates,
548+
fake_time: time_machine.Traveller,
549549
) -> None:
550550
"""Test that the actor sends notifications for indefinite dispatches on start."""
551551
# Generate a dispatch that is already running
@@ -586,7 +586,7 @@ async def test_notification_on_actor_start_inf_duration(
586586

587587
@pytest.mark.parametrize("merge_strategy", [MergeByType(), MergeByTypeTarget()])
588588
async def test_multiple_dispatches_merge_running_intervals(
589-
fake_time: time_machine.Coordinates,
589+
fake_time: time_machine.Traveller,
590590
generator: DispatchGenerator,
591591
merge_strategy: MergeStrategy,
592592
) -> None:
@@ -664,7 +664,7 @@ async def test_multiple_dispatches_merge_running_intervals(
664664

665665
@pytest.mark.parametrize("merge_strategy", [MergeByType(), MergeByTypeTarget()])
666666
async def test_multiple_dispatches_sequential_intervals_merge(
667-
fake_time: time_machine.Coordinates,
667+
fake_time: time_machine.Traveller,
668668
generator: DispatchGenerator,
669669
merge_strategy: MergeStrategy,
670670
) -> None:
@@ -734,7 +734,7 @@ async def test_multiple_dispatches_sequential_intervals_merge(
734734

735735
@pytest.mark.parametrize("merge_strategy", [MergeByType(), MergeByTypeTarget()])
736736
async def test_at_least_one_running_filter(
737-
fake_time: time_machine.Coordinates,
737+
fake_time: time_machine.Traveller,
738738
generator: DispatchGenerator,
739739
merge_strategy: MergeStrategy,
740740
) -> None:
@@ -831,7 +831,7 @@ async def test_at_least_one_running_filter(
831831
],
832832
)
833833
async def test_dry_run_dispatches_not_merged(
834-
fake_time: time_machine.Coordinates,
834+
fake_time: time_machine.Traveller,
835835
generator: DispatchGenerator,
836836
merge_strategy: MergeStrategy,
837837
) -> None:

tests/test_managing_actor.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def event_loop_policy() -> async_solipsism.EventLoopPolicy:
5252

5353

5454
@fixture
55-
def fake_time() -> Iterator[time_machine.Coordinates]:
55+
def fake_time() -> Iterator[time_machine.Traveller]:
5656
"""Replace real time with a time machine that doesn't automatically tick."""
5757
# destination can be a datetime or a timestamp (int), so are moving to the
5858
# epoch (in UTC!)
@@ -147,7 +147,7 @@ async def test_env() -> AsyncIterator[_TestEnv]:
147147

148148
async def test_simple_start_stop(
149149
test_env: _TestEnv,
150-
fake_time: time_machine.Coordinates,
150+
fake_time: time_machine.Traveller,
151151
) -> None:
152152
"""Test behavior when receiving start/stop messages."""
153153
now = _now()
@@ -194,7 +194,7 @@ async def test_simple_start_stop(
194194

195195

196196
async def test_start_failed(
197-
test_env: _TestEnv, fake_time: time_machine.Coordinates
197+
test_env: _TestEnv, fake_time: time_machine.Traveller
198198
) -> None:
199199
"""Test auto-retry after 60 seconds."""
200200
# pylint: disable=protected-access
@@ -283,7 +283,7 @@ def test_heapq_dispatch_start_stop_compare(test_env: _TestEnv) -> None:
283283
assert scheduled_events[1].dispatch_id == dispatch2.id
284284

285285

286-
async def test_dry_run(test_env: _TestEnv, fake_time: time_machine.Coordinates) -> None:
286+
async def test_dry_run(test_env: _TestEnv, fake_time: time_machine.Traveller) -> None:
287287
"""Test the dry run mode."""
288288
dispatch = test_env.generator.generate_dispatch()
289289
dispatch = replace(
@@ -321,7 +321,7 @@ async def test_dry_run(test_env: _TestEnv, fake_time: time_machine.Coordinates)
321321

322322
@pytest.mark.parametrize("strategy", [MergeByTypeTarget(), MergeByType(), None])
323323
async def test_manage_abstraction(
324-
fake_time: time_machine.Coordinates,
324+
fake_time: time_machine.Traveller,
325325
generator: DispatchGenerator,
326326
strategy: MergeStrategy | None,
327327
) -> None:
@@ -417,7 +417,7 @@ async def new_mock_receiver(
417417

418418
async def test_actor_dispatcher_update_isolation(
419419
test_env: _TestEnv,
420-
fake_time: time_machine.Coordinates,
420+
fake_time: time_machine.Traveller,
421421
) -> None:
422422
"""Test that updates for one dispatch don't affect other actors of the same type."""
423423
dispatch_type = "ISOLATION_TEST"

0 commit comments

Comments
 (0)