timing.py
Overview
The `timing.py` module provides an abstraction layer for time-related functions used within the pytest testing framework. Its primary purpose is to isolate and control time-related operations such as retrieving the current time, measuring elapsed time intervals, and sleeping, ensuring that pytest's internal timing is not affected by external test mocks of the standard library `time` module. This is essential for reliable, deterministic test execution and accurate runtime measurement within pytest itself.
The module defines three core components:
Instant: Represents a precise point in time, capturing both a wall-clock timestamp and a high-resolution performance counter.Duration: Represents the elapsed time between twoInstantobjects.MockTiming: Provides a controllable, mockable timing implementation for use in pytest's own tests, enabling deterministic and fast control over time progression.
By using this module, pytest and tests that depend on pytest's timing infrastructure can avoid unintended side effects of monkeypatching or mocking standard time functions.
Classes and Functions
Instant
@dataclasses.dataclass(frozen=True)
class Instant:
time: float = dataclasses.field(default_factory=lambda: time(), init=False)
perf_count: float = dataclasses.field(default_factory=lambda: perf_counter(), init=False)
def elapsed(self) -> Duration:
...
def as_utc(self) -> datetime:
...
Description
`Instant` encapsulates a single point in time, capturing two complementary measures:
time: The wall-clock time as returned bytime.time(), representing the system’s current timestamp.perf_count: A high-resolution performance counter for measuring elapsed time accurately, based ontime.perf_counter().
This design is inspired by Rust’s `std::time::Instant`, which similarly distinguishes between real-world timestamps and monotonic timers for precise duration measurement.
Attributes
time: float
The Unix timestamp at the moment of creation, in seconds since the epoch (UTC).perf_count: float
The value of a high-resolution performance counter at creation, used to compute elapsed time without clock adjustments.
Methods
elapsed() -> Duration
Creates aDurationobject representing the time elapsed since thisInstantwas created. Internally, it compares the currentInstantwith the original one.as_utc() -> datetime
Converts the stored Unix timestamp (time) to adatetime.datetimeobject in UTC.
Usage Example
start = Instant()
# ... some operations ...
duration = start.elapsed()
print(f"Elapsed time: {duration.seconds} seconds")
print(f"Start time (UTC): {start.as_utc()}")
Duration
@dataclasses.dataclass(frozen=True)
class Duration:
start: Instant
stop: Instant
@property
def seconds(self) -> float:
...
Description
`Duration` represents the time span between two `Instant` objects, typically used to measure elapsed time intervals.
Attributes
start: Instant
The starting point of the duration.stop: Instant
The ending point of the duration.
Properties
seconds: float
Returns the elapsed time betweenstartandstopin seconds, calculated using the performance counter values for accuracy.
Usage Example
start = Instant()
# ... some operations ...
stop = Instant()
duration = Duration(start=start, stop=stop)
print(f"Duration in seconds: {duration.seconds}")
MockTiming
@dataclasses.dataclass
class MockTiming:
_current_time: float = datetime(2020, 5, 22, 14, 20, 50).timestamp()
def sleep(self, seconds: float) -> None:
...
def time(self) -> float:
...
def patch(self, monkeypatch: MonkeyPatch) -> None:
...
Description
The `MockTiming` class provides a deterministic, controllable mock of timing functions. It is used in pytest's own tests to simulate the passage of time without relying on real system clocks or delays. This allows tests to run instantly and produce reproducible results regardless of system timing.
Time in `MockTiming` is static and only advances when explicitly told to via the `sleep()` method.
Attributes
_current_time: float
Internal representation of the current time, initialized to a fixed timestamp (2020-05-22 14:20:50 UTC).
Methods
sleep(seconds: float) -> None
Advances the internal clock by the specified number of seconds. Does not actually pause execution.time() -> float
Returns the current mocked time as a float timestamp.patch(monkeypatch: MonkeyPatch) -> None
Uses pytest'smonkeypatchfixture to replace thesleep,time, andperf_counterfunctions in the_pytest.timingmodule with the mocked implementations provided by this instance. This enables deterministic control over timing during test execution.
Usage Example
def test_timing(monkeypatch):
mock = MockTiming()
mock.patch(monkeypatch)
start = Instant()
mock.sleep(5) # Advance mocked time by 5 seconds
stop = Instant()
duration = Duration(start, stop)
assert duration.seconds == 5
Implementation Details and Algorithms
Dual Time Measurement in
Instant:
The class captures both the system time (time.time()) and a monotonic performance counter (perf_counter()) at creation. This separation allows measuring elapsed durations accurately without being affected by system clock changes or adjustments.Immutable Data Structures:
BothInstantandDurationare dataclasses marked asfrozen=True, making them immutable. This ensures that once created, their values cannot be modified, supporting safe and predictable usage in timing calculations.Mocking with
MockTiming:
Instead of relying on system time,MockTiminguses a fixed start time and manually advances time through thesleep()method. Thepatch()method leverages pytest's monkeypatching to override timing functions in_pytest.timing, isolating test time control from the real system clock and avoiding interference with other tests or runtime measurements.Avoiding Test Interference:
The module explicitly imports standard time functions internally to avoid issues where external tests mock the globaltimemodule, which could inadvertently affect pytest's own timing measurements (referenced in the header comment as issue #185).
Interaction with Other System Components
Pytest Internal Timing:
This module is a foundational utility within pytest, providing consistent timing primitives used throughout pytest's runtime for measuring test durations, timeouts, and performance metrics.Test Fixtures:
TheMockTimingclass is used by pytest's internal tests and fixtures (e.g., themock_timingfixture) to simulate and control time progression deterministically during testing of timing-dependent features.Isolation from Standard Library Mocking:
By isolating time-related function calls,timing.pyensures that pytest's timing remains stable and unaffected by user tests that might monkeypatch or mock the standardtimemodule.
Public API
__all__ = ["perf_counter", "sleep", "time"]
The module exports the standard `perf_counter`, `sleep`, and `time` functions imported from the standard library, allowing other pytest components and plugins to use these safely.
Diagram: Class Structure of timing.py
classDiagram
class Instant {
+time: float
+perf_count: float
+elapsed() Duration
+as_utc() datetime
}
class Duration {
+start: Instant
+stop: Instant
+seconds : float
}
class MockTiming {
-_current_time: float
+sleep(seconds: float) void
+time() float
+patch(monkeypatch: MonkeyPatch) void
}
Duration --> Instant : start
Duration --> Instant : stop
Summary
The `timing.py` module is a critical utility for pytest's internal timing and test time control, providing:
Precise time instants (
Instant) with both wall-clock and performance counter values.Duration measurement (
Duration) between instants.A controllable mock timing system (
MockTiming) for deterministic pytest tests.
By encapsulating and isolating time functions, it ensures accurate, stable, and reliable timing operations across pytest's runtime and testing environment.