freezegun is a Python library (currently at version 1.5.5) that enables your tests to 'travel through time' by mocking the `datetime`, `date`, `time`, and `pendulum` modules. It simplifies testing time-sensitive code by allowing developers to freeze the current time or simulate its passage, ensuring deterministic and reliable test execution. The project maintains a regular release cadence, with frequent patch and minor updates.
pip install freezegunVerified import paths — ran on the pinned version, not inferred.
The most common way to use freezegun is via the `@freeze_time` decorator for test functions or the `with freeze_time(...)` context manager for specific blocks of code. You can pass a string representing the desired date and time. The `tick=True` parameter allows time to advance naturally (or manually with `frozen_datetime.tick()`) after the initial freeze, useful for testing time-sensitive sequences or durations. It effectively mocks `datetime.datetime.now()`, `datetime.date.today()`, `time.time()`, and related functions.
For smaller projects, this overhead is usually negligible. For large projects with slow time-mocking tests, consider profiling to confirm `freezegun` as the bottleneck and evaluate alternatives like `time-machine`. Ensure `freezegun` is only active for the specific tests requiring time manipulation.
Upgrade to freezegun 1.4.0 or newer. Use the `real_asyncio=True` parameter with `freeze_time` (e.g., `with freeze_time('2023-01-01', real_asyncio=True):`) to allow asyncio event loops to use real monotonic time while other time functions remain frozen.Be aware of how time-related functions are imported and used in the code under test. If you encounter unmocked time, inspect the import path and call stack. For C extensions or deeply embedded time calls, `freezegun` might not be sufficient, and you might need to use other mocking strategies or a library that intercepts at a lower level (like `time-machine`).
Always specify the desired timezone when freezing time if your application is timezone-aware (e.g., `freeze_time('2023-10-26 14:30:00', tz_offset=-5)` or ensuring `datetime.now()` is explicitly timezone-aware where needed). Test edge cases like DST transitions to ensure consistent behavior.When testing code that makes external HTTP requests with SSL, ensure the frozen time is within the validity period of common SSL certificates. Alternatively, if appropriate for your test, consider mocking the external HTTP calls entirely or disabling SSL verification for that specific test (with caution).
When asserting time advancement with `freezegun`, consider using a small tolerance for `timedelta` comparisons (e.g., `assert abs((after_tick - start_time) - datetime.timedelta(seconds=5)) < datetime.timedelta(microseconds=100)`) or truncate `datetime` objects to milliseconds/seconds before comparison to avoid microsecond-level precision issues.
Instead of asserting for exact equality with `datetime.timedelta`, consider comparing with a small tolerance for microsecond differences (e.g., `assert abs(actual_timedelta - expected_timedelta) < datetime.timedelta(microseconds=10)`). Alternatively, round `datetime` objects to a desired precision (e.g., seconds or milliseconds) before comparison if microsecond accuracy is not critical for the test.
Ensure that `datetime` imports in the code under test occur within the scope of the `freezegun.freeze_time` decorator or context manager, or that `freezegun` is initialized early enough to patch already loaded modules.
Change the import statement to `import datetime` and then call `datetime.datetime.now()`, or if you import `from datetime import datetime`, directly call `datetime.now()` without the module prefix.
Investigate if another mocking library or a complex test fixture is also manipulating the `datetime` module. Ensure `freezegun` is the last to apply its patches, or use `freezegun.configure(default_ignore_list=[...])` or the `ignore` parameter on `freeze_time` to exclude conflicting modules.
If you explicitly need to freeze time within threads, you can remove `threading` from the ignore list using `freeze_time(..., ignore=['list', 'of', 'modules'] - {'threading'})` or `freezegun.configure(default_ignore_list=list(set(freezegun.config.default_ignore_list) - {'threading'}))`. Exercise caution as this can lead to deadlocks if `threading` internals are also frozen.