示例
freezegun 1.5.5: Handle freezegun 1.4 to 1.5 boundary where auto_tick_seconds steps on every single read, tick returns the updated datetime instead of None, move_to resets ticking clocks, and configure supports empty ignore lists
已验证示例 — pypi freezegun 1.5.5: Handle freezegun 1.4 to 1.5 boundary where auto_tick_seconds steps on every single read, tick returns the updated datetime…
sha256:ffee8ecfc1d9db446399a6256645a99ba9dbb9b5678b0f71103d093e585a9bd7
本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。
提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。
MIT-0
执行证据
声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。
- 证据依据
- 签名契约通过
- 验证回执
- 3
- 构建过它的签名密钥
- 3
声明的环境
python linux x64 python python pip
验证运行环境
| 环境 | 契约 | 阶段 | 运行日期 |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-16 |
| python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-18 |
| python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104… |
2026-09-08 |
案例
HOW- 目标
- Handle freezegun 1.4 to 1.5 boundary where auto_tick_seconds steps on every single read, tick returns the updated datetime instead of None, move_to resets ticking clocks, and configure supports empty ignore lists
- 符号
-
- freezegun.freeze_time
- StepTickTimeFactory.tick
- TickingDateTimeFactory.move_to
- FrozenDateTimeFactory.tick
- freezegun.configure
- DEFAULT_IGNORE_LIST
- 环境
- python
- 创建时间
- 2026-08-16T07:26:21Z
契约
- assert freeze_time with auto_tick_seconds steps the clock forward on every read of datetime.now() or time.time()
- assert reading time.time() under auto_tick_seconds steps the clock again, so datetime.now().timestamp() and time.time() disagree by the step width
- assert calling tick() on StepTickTimeFactory advances by auto_tick_seconds rather than one second, and returns the new datetime
- assert freeze_time(tick=True) streams real elapsed wall-clock time forward from the frozen starting point
- assert move_to on a ticking freeze resets the base instant and returns None without raising AttributeError
- assert tick() on FrozenDateTimeFactory and TickingDateTimeFactory returns the new datetime object rather than None
- assert queue is in DEFAULT_IGNORE_LIST in 1.5.0, so queue timeouts evaluate against real monotonic time
- assert freezegun.configure(default_ignore_list=[]) sets an empty ignore tuple rather than falling back to default ignore list
- assert decorator as_kwarg passes the factory and executes the function once, unlike as_arg which invokes the target function twice
文件
- NOTES.md
- csx.json
- requirements.txt
- src/__init__.py
- src/scheduler.py
- test/contract.py
源代码
# Notes
## Search Known Solution Result
`search_known_solution` returned existing published sample `sha256:e0a5abccbe96dde0a46b9b65aae94c3d5ffaa94f5eac58c72b82bec2141a0bfa` ("Freeze the clock in a Python test with freezegun so datetime, time.time and time.monotonic agree, and know what freeze_time cannot reach"), which proves standard `freeze_time` mechanics (sys.modules rebinding, stale constants at import, datetime subclasses, and tz_offset behavior).
## What a Model Would Have Written Instead
A model would assume `auto_tick_seconds` advances time only between operations and that `datetime.now().timestamp() == time.time()` remains synchronized, that `tick()` returns `None` or always advances by 1 second on step factories, that `move_to` cannot be called on ticking clocks (`tick=True`), that `queue.Queue` requires custom timeouts, and that `@freeze_time(..., as_arg=True)` invokes the target test function only once.
## How the Wrong Version Fails
On freezegun versions prior to 1.5.0, calling `move_to` on `freeze_time(tick=True)` fails loudly with `AttributeError: 'TickingDateTimeFactory' object has no attribute 'move_to'`, `tick()` silently returns `None` rather than the updated datetime instance, `queue.Queue.get(timeout=...)` hangs or deadlocks because `queue` was omitted from `DEFAULT_IGNORE_LIST`, and `configure(default_ignore_list=[])` silently falls back to default ignore patterns instead of honoring an empty list.
{"case":{"caseId":"case:sha256:1755ce3ed4e827a782d8aba2342891dc93dae5a332bf70277577f5bf48a46083","contract":["assert freeze_time with auto_tick_seconds steps the clock forward on every read of datetime.now() or time.time()","assert reading time.time() under auto_tick_seconds steps the clock again, so datetime.now().timestamp() and time.time() disagree by the step width","assert calling tick() on StepTickTimeFactory advances by auto_tick_seconds rather than one second, and returns the new datetime","assert freeze_time(tick=True) streams real elapsed wall-clock time forward from the frozen starting point","assert move_to on a ticking freeze resets the base instant and returns None without raising AttributeError","assert tick() on FrozenDateTimeFactory and TickingDateTimeFactory returns the new datetime object rather than None","assert queue is in DEFAULT_IGNORE_LIST in 1.5.0, so queue timeouts evaluate against real monotonic time","assert freezegun.configure(default_ignore_list=[]) sets an empty ignore tuple rather than falling back to default ignore list","assert decorator as_kwarg passes the factory and executes the function once, unlike as_arg which invokes the target function twice"],"goal":"Handle freezegun 1.4 to 1.5 boundary where auto_tick_seconds steps on every single read, tick returns the updated datetime instead of None, move_to resets ticking clocks, and configure supports empty ignore lists","kind":"HOW","packages":["pkg:pypi/freezegun@1.5.5","pkg:pypi/python-dateutil@2.9.0.post0","pkg:pypi/six@1.17.0"],"schemaVersion":1,"symbols":["freezegun.freeze_time","StepTickTimeFactory.tick","TickingDateTimeFactory.move_to","FrozenDateTimeFactory.tick","freezegun.configure","DEFAULT_IGNORE_LIST"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/freezegun@1.5.5","pkg:pypi/python-dateutil@2.9.0.post0","pkg:pypi/six@1.17.0"],"schemaVersion":1,"symbols":["freezegun.freeze_time","StepTickTimeFactory.tick","TickingDateTimeFactory.move_to","FrozenDateTimeFactory.tick","freezegun.configure","DEFAULT_IGNORE_LIST"],"verifierAdapter":"python@1"}
freezegun==1.5.5
python-dateutil==2.9.0.post0
six==1.17.0
"""Package root for freezegun boundary tests."""
"""Scheduler and sampling module demonstrating clock interactions under freezegun."""
import queue
import time
from datetime import datetime, timedelta
from freezegun import freeze_time
def sample_window():
"""Takes two consecutive readings to measure an instant.
Under a static freeze_time(), start == end.
Under auto_tick_seconds=N, start and end differ by N seconds on consecutive lines.
"""
start = datetime.now()
end = datetime.now()
return start, end
def epoch_pair():
"""Reads datetime.now() and time.time().
Under standard freeze_time(), naive datetime.now().timestamp() == time.time().
Under auto_tick_seconds=N, time.time() consumes a second tick, desyncing the two.
"""
dt = datetime.now()
ts = time.time()
return dt, ts
def wait_for_event(q, timeout_sec=0.01):
"""Waits for an item on a queue with a timeout.
In freezegun 1.5.0+, 'queue' is in DEFAULT_IGNORE_LIST, so timeouts evaluate against
the real monotonic clock and return promptly without hanging.
"""
try:
return q.get(timeout=timeout_sec)
except queue.Empty:
return None
@freeze_time("2025-01-01 09:00:00", as_kwarg="clock_handle")
def run_job(label, clock_handle=None):
"""Demonstrates single invocation with injected factory via as_kwarg."""
t0 = datetime.now()
clock_handle.tick(timedelta(minutes=30))
t1 = datetime.now()
return {"label": label, "t0": t0, "t1": t1}
import queue
import sys
import time
from datetime import datetime, timedelta
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import freezegun
import freezegun.config
from freezegun import freeze_time
from freezegun.api import (
FrozenDateTimeFactory,
StepTickTimeFactory,
TickingDateTimeFactory,
)
from src import scheduler
def test_auto_tick_seconds():
# --- 1. auto_tick_seconds advances on EVERY single clock access ---
# Naive expectation: time stays constant during a frozen block unless manually ticked.
# Reality: Every read of datetime.now() or time.time() consumes auto_tick_seconds.
with freeze_time("2024-01-01 12:00:00", auto_tick_seconds=5) as step_factory:
assert isinstance(step_factory, StepTickTimeFactory)
# scheduler.sample_window() calls datetime.now() twice on consecutive lines
t_start, t_end = scheduler.sample_window()
assert t_start == datetime(2024, 1, 1, 12, 0, 0)
assert t_end == datetime(2024, 1, 1, 12, 0, 5)
assert (t_end - t_start).total_seconds() == 5.0
# epoch_pair() calls datetime.now() then time.time()
# time.time() also consumes a tick, causing timestamp() and time.time() to diverge!
dt_val, ts_val = scheduler.epoch_pair()
assert dt_val == datetime(2024, 1, 1, 12, 0, 10)
assert ts_val == 1704110415.0 # corresponds to 12:00:15
assert ts_val - dt_val.timestamp() == 5.0
# Calling tick() on StepTickTimeFactory advances by step_width (5s), not 1s default!
# Internal state is at 12:00:20 before tick; tick moves it to 12:00:25 and returns it.
tick_result = step_factory.tick()
assert tick_result == datetime(2024, 1, 1, 12, 0, 25)
assert isinstance(tick_result, datetime)
def test_ticking_clock_and_move_to():
# --- 2. tick=True streams real elapsed wall time & 1.5.0 move_to ---
# Naive expectation: freeze_time always pins time to a static instant.
# Reality: tick=True allows time to flow forward at 1x speed from the freeze origin.
with freeze_time("2024-01-01 00:00:00", tick=True) as ticking_factory:
assert isinstance(ticking_factory, TickingDateTimeFactory)
t0 = datetime.now()
time.sleep(0.03)
t1 = datetime.now()
assert t1 > t0
# In freezegun 1.5.0, move_to was added to TickingDateTimeFactory.
# Prior to 1.5.0, calling move_to on a ticking freeze raised AttributeError.
move_result = ticking_factory.move_to("2025-06-01 00:00:00")
assert move_result is None
assert datetime.now().year == 2025
# tick() returns the updated datetime object
tick_result = ticking_factory.tick(timedelta(hours=2))
assert tick_result.year == 2025 and tick_result.hour == 2
assert isinstance(tick_result, datetime)
def test_tick_return_values():
# --- 3. tick() returns updated datetime in 1.5.0+ rather than None ---
# Naive expectation: tick() returns None like move_to() (as in freezegun <1.5.0).
# Reality: In 1.5.0+, all tick() methods return the updated datetime.
with freeze_time("2024-01-01 00:00:00") as static_factory:
assert isinstance(static_factory, FrozenDateTimeFactory)
res_tick = static_factory.tick(timedelta(seconds=45))
assert res_tick == datetime(2024, 1, 1, 0, 0, 45)
assert isinstance(res_tick, datetime)
# move_to continues to return None
res_move = static_factory.move_to("2024-01-02 00:00:00")
assert res_move is None
assert datetime.now() == datetime(2024, 1, 2, 0, 0, 0)
def test_queue_ignore_and_configure():
# --- 4. queue in DEFAULT_IGNORE_LIST & configure(default_ignore_list=[]) ---
# In 1.5.0, 'queue' was added to DEFAULT_IGNORE_LIST to prevent Queue.get(timeout)
# from blocking or failing on frozen monotonic time.
assert "queue" in freezegun.config.DEFAULT_IGNORE_LIST
q = queue.Queue()
with freeze_time("2024-01-01 00:00:00"):
# Queue get uses real monotonic time via call-stack inspection and returns promptly
item = scheduler.wait_for_event(q, timeout_sec=0.01)
assert item is None
# In 1.5.0, configure(default_ignore_list=[]) allows passing an empty list.
# In <1.5.0, passing [] evaluated as falsy and fell back to DEFAULT_IGNORE_LIST.
freezegun.configure(default_ignore_list=[])
with freeze_time("2024-01-01 00:00:00"):
assert freezegun.api.ignore_lists[-1] == ()
freezegun.configure(default_ignore_list=None)
def test_decorator_kwarg_vs_arg():
# --- 5. Decorator as_kwarg passes factory once; as_arg has double-invocation bug ---
res = scheduler.run_job("backup")
assert res["label"] == "backup"
assert res["t0"] == datetime(2025, 1, 1, 9, 0, 0)
assert res["t1"] == datetime(2025, 1, 1, 9, 30, 0)
# Prove as_arg double execution: _call_with_time_factory invokes func twice
call_records = []
@freeze_time("2024-01-01 00:00:00", as_arg=True)
def arg_target(*args):
call_records.append(args)
arg_target()
assert len(call_records) == 2
assert isinstance(call_records[0][0], FrozenDateTimeFactory)
assert call_records[1] == ()
if __name__ == "__main__":
test_auto_tick_seconds()
test_ticking_clock_and_move_to()
test_tick_return_values()
test_queue_ignore_and_configure()
test_decorator_kwarg_vs_arg()
print(
f"CONTRACT PASS: freezegun {freezegun.__version__} boundary behaviors verified on Python {'.'.join(map(str, sys.version_info[:2]))}"
)