CodeSampleX

샘플

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

이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다. 통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다. 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

컨트랙트

  1. assert freeze_time with auto_tick_seconds steps the clock forward on every read of datetime.now() or time.time()
  2. assert reading time.time() under auto_tick_seconds steps the clock again, so datetime.now().timestamp() and time.time() disagree by the step width
  3. assert calling tick() on StepTickTimeFactory advances by auto_tick_seconds rather than one second, and returns the new datetime
  4. assert freeze_time(tick=True) streams real elapsed wall-clock time forward from the frozen starting point
  5. assert move_to on a ticking freeze resets the base instant and returns None without raising AttributeError
  6. assert tick() on FrozenDateTimeFactory and TickingDateTimeFactory returns the new datetime object rather than None
  7. assert queue is in DEFAULT_IGNORE_LIST in 1.5.0, so queue timeouts evaluate against real monotonic time
  8. assert freezegun.configure(default_ignore_list=[]) sets an empty ignore tuple rather than falling back to default ignore list
  9. 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

소스 아티팩트 내려받기 (tar.gz)

소스

NOTES.md
# 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.
csx.json
{"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"}
requirements.txt
freezegun==1.5.5
python-dateutil==2.9.0.post0
six==1.17.0
src/__init__.py
"""Package root for freezegun boundary tests."""
src/scheduler.py
"""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}
test/contract.py
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]))}"
    )

오리진 시더

csx-seed