CodeSampleX

Пример

freezegun 1.5.5: Freeze the clock in a Python test with freezegun so datetime, time.time and time.monotonic agree, and know what freeze_time cannot reach

Проверенный пример — pypi freezegun 1.5.5: Freeze the clock in a Python test with freezegun so datetime, time.time and time.monotonic agree, and know what…

sha256:e0a5abccbe96dde0a46b9b65aae94c3d5ffaa94f5eac58c72b82bec2141a0bfa

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
3
Ключи подписи, собравшие его
3
Заявленная среда python 3.12 linux x64 python 3.12 python pip

Среды запусков проверки

Окружение Контракт Этапы Запуск
python 3.12 · linux alpine/x64 · docker ed25519:a2ec939a4c60e243 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-14
python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 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
Цель
Freeze the clock in a Python test with freezegun so datetime, time.time and time.monotonic agree, and know what freeze_time cannot reach
Пакеты
Символы
  • freezegun.freeze_time
  • FrozenDateTimeFactory.tick
  • FrozenDateTimeFactory.move_to
  • tz_offset
  • datetime.datetime.now
  • datetime.datetime.utcnow
  • datetime.date.today
  • time.time
  • time.monotonic
  • time.perf_counter
Окружение
python 3.12
Создан
2026-08-14T13:20:26Z

Контракт

  1. assert freeze_time as a context manager pins datetime.now(), datetime.utcnow(), time.time(), time.time_ns() and date.today() to one instant that does not tick between reads
  2. assert the frozen readings agree with each other, so datetime.now().timestamp() is exactly time.time()
  3. assert a module that did `from datetime import datetime` before the freeze is frozen too, because freeze_time rebinds the name that module already holds
  4. assert freeze_time rewrites the test file's own globals as well, so a bare handle kept for comparison becomes the fake class and compares equal to it
  5. assert a bound classmethod captured at import (now = datetime.now) escapes the sweep and keeps returning real time inside the freeze
  6. assert a module-level constant computed at import (DEFAULT_START = datetime.now()) keeps its real value and its real class, and still passes isinstance against the frozen datetime
  7. assert a duration measured against that stale constant comes out negative by more than twenty-five years with nothing raised
  8. assert a datetime subclass defined at import ignores the freeze in now() but follows it in today(), because CPython builds today() on time.time and now() on the C system clock
  9. assert tick() advances one second and returns the new time, and tick(timedelta) and tick(float) advance further, with time.time() moving alongside
  10. assert move_to() sets an absolute time, returns None, and carries the module's readings and the subclass's today() with it
  11. assert time.monotonic and time.perf_counter are frozen to the same wall clock as time.time, so a duration spanning the boundary of the freeze measures about thirty years
  12. assert moving the frozen clock backwards makes time.monotonic() go backwards
  13. assert a module first imported inside the freeze keeps the frozen constant, as a FakeDatetime instance, after the block ends
  14. assert leaving the block restores datetime, the rewritten module globals and the real monotonic clock
  15. assert tz_offset is added to now() but never to utcnow(), so those two are what differ by the offset
  16. assert an aware now(timezone.utc) carries the same reading as the naive now() rather than a UTC-correct one, so its timestamp() disagrees with time.time() by exactly tz_offset
  17. assert the naive now().timestamp() equals time.time(), and date.today() takes the offset so a large enough offset changes the date
  18. assert tz_offset accepts a timedelta, so an offset that is not a whole number of hours works
  19. assert datetime.utcnow() raises a DeprecationWarning on python 3.12 in real time and none at all under a freeze

Файлы

  • csx.json
  • requirements.txt
  • src/__init__.py
  • src/clock.py
  • src/late_import.py
  • test/contract.py

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

csx.json
{"case":{"caseId":"case:sha256:2a0a909b822e1ab12853fdc95b19fa90347df78a892a71865b814b223b648f26","constraints":{"runtime":"python"},"contract":["assert freeze_time as a context manager pins datetime.now(), datetime.utcnow(), time.time(), time.time_ns() and date.today() to one instant that does not tick between reads","assert the frozen readings agree with each other, so datetime.now().timestamp() is exactly time.time()","assert a module that did `from datetime import datetime` before the freeze is frozen too, because freeze_time rebinds the name that module already holds","assert freeze_time rewrites the test file's own globals as well, so a bare handle kept for comparison becomes the fake class and compares equal to it","assert a bound classmethod captured at import (now = datetime.now) escapes the sweep and keeps returning real time inside the freeze","assert a module-level constant computed at import (DEFAULT_START = datetime.now()) keeps its real value and its real class, and still passes isinstance against the frozen datetime","assert a duration measured against that stale constant comes out negative by more than twenty-five years with nothing raised","assert a datetime subclass defined at import ignores the freeze in now() but follows it in today(), because CPython builds today() on time.time and now() on the C system clock","assert tick() advances one second and returns the new time, and tick(timedelta) and tick(float) advance further, with time.time() moving alongside","assert move_to() sets an absolute time, returns None, and carries the module's readings and the subclass's today() with it","assert time.monotonic and time.perf_counter are frozen to the same wall clock as time.time, so a duration spanning the boundary of the freeze measures about thirty years","assert moving the frozen clock backwards makes time.monotonic() go backwards","assert a module first imported inside the freeze keeps the frozen constant, as a FakeDatetime instance, after the block ends","assert leaving the block restores datetime, the rewritten module globals and the real monotonic clock","assert tz_offset is added to now() but never to utcnow(), so those two are what differ by the offset","assert an aware now(timezone.utc) carries the same reading as the naive now() rather than a UTC-correct one, so its timestamp() disagrees with time.time() by exactly tz_offset","assert the naive now().timestamp() equals time.time(), and date.today() takes the offset so a large enough offset changes the date","assert tz_offset accepts a timedelta, so an offset that is not a whole number of hours works","assert datetime.utcnow() raises a DeprecationWarning on python 3.12 in real time and none at all under a freeze"],"goal":"Freeze the clock in a Python test with freezegun so datetime, time.time and time.monotonic agree, and know what freeze_time cannot reach","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","FrozenDateTimeFactory.tick","FrozenDateTimeFactory.move_to","tz_offset","datetime.datetime.now","datetime.datetime.utcnow","datetime.date.today","time.time","time.monotonic","time.perf_counter"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","runtimeVersion":"3.12","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","FrozenDateTimeFactory.tick","FrozenDateTimeFactory.move_to","tz_offset","datetime.datetime.now","datetime.datetime.utcnow","datetime.date.today","time.time","time.monotonic","time.perf_counter"],"verifierAdapter":"python@1"}
requirements.txt
# The full closure, because the sandbox installs with --no-deps. freezegun
# declares only python-dateutil>=2.7, which in turn still needs six.
freezegun==1.5.5
python-dateutil==2.9.0.post0
six==1.17.0
src/__init__.py
src/clock.py
"""An ordinary module that reads the clock, imported long before any freeze.

Nothing here knows a test exists. The names are bound once, at import, the
way normal code binds them, and that is exactly what makes this the right
thing to freeze against: freeze_time has to reach back into modules that
were already loaded when the test started.

It does that by walking sys.modules and rebinding every module attribute
whose identity IS the real datetime class or one of the real time
functions. So ``datetime``, ``time`` and ``monotonic`` below are swapped for
the duration of the freeze, and every function that reads them through the
module global sees frozen time. That is the difference between freezegun
and a hand-rolled patch: monkeypatching ``datetime.datetime`` in the test
module does not touch this module's already-bound name.

Three shapes here are outside what that sweep can reach, and they are here
on purpose because they are what people actually write:

  DEFAULT_START   a value, not a reference. The sweep rebinds names that
                  are the class; it cannot recompute a datetime that was
                  already derived from it.
  _captured_now   a bound classmethod pulled off the real class at import.
                  Its identity is not the class's identity, so the sweep
                  walks past it and it keeps calling the real clock.
  AuditStamp      a subclass. Its MRO still names the real datetime, and
                  freeze_time does not rewrite MROs.

test/contract.py measures what each of them does under a freeze. One of
the three does not behave the way the shape suggests.
"""

from datetime import datetime, timezone
from time import monotonic, time

# Computed once, at import, from whatever the real clock said at the moment
# this module was first loaded. A test that freezes time later cannot change
# it, so every duration measured against it is wrong by the distance between
# the freeze and the real clock.
DEFAULT_START = datetime.now()

# The same mistake in a different shape, and a common one in code that wants
# a cheap alias or an injectable clock.
_captured_now = datetime.now


class AuditStamp(datetime):
    """A datetime subclass, defined at import time.

    Domain code subclasses datetime to attach a repr, a serialiser or a
    validator. The class inherits the real classmethods, and freeze_time
    leaves the MRO alone, so the inherited methods are the real ones. The
    contract shows that this does not produce one consistent answer.
    """


def stamp():
    """Naive local time, the call almost every codebase makes."""
    return datetime.now()


def utc_stamp():
    """The aware replacement people move to when utcnow is deprecated."""
    return datetime.now(timezone.utc)


def utc_stamp_legacy():
    """The deprecated call the move above is meant to replace."""
    return datetime.utcnow()


def wall_clock():
    """Seconds since the epoch, through a name imported at module level."""
    return time()


def monotonic_reading():
    """A reading from the clock that is documented never to go backwards."""
    return monotonic()


def cached_stamp():
    return _captured_now()


def elapsed_since_start():
    """Seconds this module has been loaded, as its author intended it."""
    return (datetime.now() - DEFAULT_START).total_seconds()
src/late_import.py
"""The same constant as clock.DEFAULT_START, evaluated at a different moment.

test/contract.py imports this module for the first time from inside a frozen
block. The code is unremarkable; the point is that the value it keeps for the
rest of the process is decided by whichever test happened to import it first.
In a real suite that is decided by collection order.
"""

from datetime import datetime

IMPORTED_AT = datetime.now()
test/contract.py
import sys
import time
import warnings
from datetime import date, datetime, timedelta, timezone
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

import freezegun
from freezegun import freeze_time

# Imported before anything is frozen. That ordering is the subject of this
# file: every question below is about code that was already loaded, with its
# names already bound, when the test started.
from src import clock

REAL_START = clock.DEFAULT_START

# The real classes have to be stashed somewhere freeze_time cannot reach,
# and a module global is not that place. The sweep rebinds every module
# attribute that IS the real datetime class -- including this file's, and
# including one literally named REAL_DATETIME -- so a comparison against a
# bare global would compare the fake class to itself and pass. Values inside
# a container are not module attributes, so this dict survives the freeze.
REAL = {"datetime": type(REAL_START), "date": type(REAL_START.date())}

# Left exposed on purpose, to measure the rewrite happening.
EXPOSED_DATETIME = type(REAL_START)

# The contract tells real time from frozen time by era, so it needs a
# machine clock on this side of 2020. If this fails, the host clock is wrong
# and nothing below means anything.
assert REAL_START > datetime(2020, 1, 1), REAL_START

FROZEN = datetime(1999, 12, 31, 23, 59, 58, 500000)
FROZEN_EPOCH = 946684798.5

# A real monotonic reading, taken outside the freeze, to measure against
# later. It is uptime, not epoch seconds, so the guard below only has to
# rule out a host that has been running for thirty years.
real_monotonic_before = time.monotonic()
assert real_monotonic_before < 946_000_000

with freeze_time("1999-12-31 23:59:58.5") as frozen:
    # --- one instant, read every way there is --------------------------
    assert datetime.now() == FROZEN
    assert datetime.utcnow() == FROZEN
    assert time.time() == FROZEN_EPOCH
    assert time.time_ns() == 946_684_798_500_000_000
    assert date.today() == date(1999, 12, 31)
    assert type(date.today()) is not REAL["date"]

    # The readings agree with each other, which is the part hand-rolled
    # patches get wrong: patching datetime.now alone leaves time.time()
    # running, and any code that mixes the two sees the clock jump.
    assert datetime.now().timestamp() == time.time()

    # And it does not tick. Two reads with work between them are the same
    # instant, so a test can assert an exact timestamp.
    first = datetime.now()
    sum(range(200_000))
    assert datetime.now() == first

    # --- code that imported datetime before the freeze -----------------
    # src.clock did `from datetime import datetime` at import. freeze_time
    # walked sys.modules and rebound that name, so the module is frozen
    # without being told, without an injected clock, without an argument
    # threaded through five call sites.
    assert clock.datetime is not REAL["datetime"]
    assert clock.datetime.__name__ == "FakeDatetime"
    assert clock.stamp() == FROZEN
    assert clock.wall_clock() == FROZEN_EPOCH
    assert clock.monotonic_reading() == FROZEN_EPOCH

    # This file is a module too, so the sweep rewrote its globals on the
    # way past. The handle stashed at the top for comparison is now the
    # fake class itself, which is how a test asserting `type(x) is not
    # REAL_DATETIME` ends up asserting nothing at all.
    assert EXPOSED_DATETIME is clock.datetime
    assert EXPOSED_DATETIME is not REAL["datetime"]

    # A bound classmethod captured at import is not a reference to the
    # class, so the sweep walks past it. `now = datetime.now` at module
    # level keeps calling the real clock from inside the freeze, and what
    # comes back is still a datetime, so nothing raises -- the freeze just
    # does not apply to that one call site.
    assert clock.cached_stamp() > datetime(2020, 1, 1)

    # --- the trap: a constant computed at import stays computed ---------
    # freeze_time rebinds names that ARE the real class. DEFAULT_START is
    # not a name for the class, it is a value already derived from it, so
    # it holds what the real clock said at import and keeps holding it.
    assert clock.DEFAULT_START == REAL_START
    assert clock.DEFAULT_START > datetime(2020, 1, 1)
    assert type(clock.DEFAULT_START) is REAL["datetime"]

    # The frozen reading really is a different class, and isinstance still
    # will not tell you which one you are holding: FakeDatetime's metaclass
    # answers instance checks against the real class, so both values are
    # datetimes and nothing anywhere looks wrong.
    assert type(datetime.now()) is not REAL["datetime"]
    assert isinstance(clock.DEFAULT_START, datetime)
    assert isinstance(datetime.now(), datetime)

    # The bug that produces: a duration measured against the stale constant
    # comes out negative by the whole distance between the freeze and the
    # real clock, more than twenty-five years here, silently and with no
    # exception raised.
    assert clock.elapsed_since_start() < -8e8

    # --- a datetime subclass defined at import --------------------------
    # AuditStamp inherits from the real class and freeze_time does not
    # rewrite MROs, so now() is the real implementation reading the real
    # system clock. The freeze does not apply to it at all.
    assert clock.AuditStamp.now() > datetime(2020, 1, 1)

    # Same class, same freeze, opposite answer. Measured, not assumed:
    # CPython builds today() out of cls.fromtimestamp(time.time()) while
    # now() reads the system clock in C, and freeze_time patches time.time.
    # So today() is frozen and now() is not, on one class, more than
    # twenty-five years apart, and the class that was added to make
    # timestamps consistent is the one that reports two different days.
    assert clock.AuditStamp.today() == FROZEN

    # --- tick() and move_to() move the frozen clock ---------------------
    assert type(frozen).__name__ == "FrozenDateTimeFactory"

    # A bare tick() is one second and returns the new time.
    assert frozen.tick() == FROZEN + timedelta(seconds=1)
    assert datetime.now() == FROZEN + timedelta(seconds=1)
    assert time.time() == FROZEN_EPOCH + 1

    # A timedelta or a plain number of seconds moves further, here across
    # the rollover the frozen instant was chosen to sit in front of.
    assert frozen.tick(timedelta(minutes=1, seconds=30)) == datetime(
        2000, 1, 1, 0, 1, 29, 500000)
    assert frozen.tick(2.5) == datetime(2000, 1, 1, 0, 1, 32)
    assert datetime.now() == datetime(2000, 1, 1, 0, 1, 32)

    # move_to takes an absolute time and returns None, so
    # `now = frozen.move_to(...)` binds None rather than the new time.
    assert frozen.move_to("2000-01-01 00:00:00") is None
    assert datetime.now() == datetime(2000, 1, 1)
    assert time.time() == 946684800.0
    assert clock.stamp() == datetime(2000, 1, 1)

    # And the proof of the mechanism above: today() followed move_to, since
    # patched time.time is the only clock it shares with the freeze, while
    # now() on the same class is still reading the real one.
    assert clock.AuditStamp.today() == datetime(2000, 1, 1)
    assert clock.AuditStamp.now() > datetime(2020, 1, 1)

    # --- monotonic is handled, and that is the second trap --------------
    # freeze_time patches time.monotonic and time.perf_counter to the same
    # frozen wall clock, so they equal time.time() exactly. Real monotonic
    # clocks share no origin with the epoch, so a duration measured across
    # the boundary of the freeze is about thirty years long.
    assert time.monotonic() == time.time()
    assert time.perf_counter() == time.time()
    assert time.monotonic() - real_monotonic_before > 946_000_000

    # Moving the clock back moves "monotonic" back with it. Code holding
    # `deadline = time.monotonic() + timeout` never reaches its deadline,
    # and a retry loop written that way hangs instead of failing.
    monotonic_before_move = time.monotonic()
    frozen.move_to("1999-01-01")
    assert time.monotonic() < monotonic_before_move

    # --- the mirror image of the DEFAULT_START trap ---------------------
    # A module imported for the first time from inside a frozen block
    # computes its constant from the frozen clock, and keeps it for the
    # rest of the process. Whichever test imports it first decides.
    from src import late_import

    assert late_import.IMPORTED_AT == datetime(1999, 1, 1)

# --- leaving the block puts everything back -----------------------------
assert datetime.now() > datetime(2020, 1, 1)
assert clock.datetime is REAL["datetime"]
assert clock.stamp() > datetime(2020, 1, 1)
assert time.monotonic() < 946_000_000
assert EXPOSED_DATETIME is REAL["datetime"]
assert late_import.datetime is REAL["datetime"]

# Except the value: it is still 1999, and it is still one of freezegun's
# datetimes, in a module that will be imported from other tests all suite.
assert late_import.IMPORTED_AT == datetime(1999, 1, 1)
assert type(late_import.IMPORTED_AT) is not REAL["datetime"]

# --- tz_offset, measured rather than assumed ----------------------------
# freezegun's own README example. The expectation to check at the door is
# that tz_offset makes the naive clock local and an aware clock UTC. It does
# not. tz_offset is added to now(); utcnow() never gets it. So the pair that
# differs by the offset is now() against utcnow(), and an aware
# now(timezone.utc) reads exactly like the naive one with a UTC label
# stapled on -- a label that is wrong by the offset.
with freeze_time("2012-01-14 03:21:34", tz_offset=-4):
    naive = clock.stamp()
    aware = clock.utc_stamp()
    legacy_utc = clock.utc_stamp_legacy()

    assert naive == datetime(2012, 1, 13, 23, 21, 34)
    assert legacy_utc == datetime(2012, 1, 14, 3, 21, 34)
    assert naive - legacy_utc == timedelta(hours=-4)

    # The aware value carries the same reading as the naive one; only the
    # tzinfo differs. Subtracting a naive from an aware datetime raises, so
    # the two are compared by reading.
    assert aware == datetime(2012, 1, 13, 23, 21, 34, tzinfo=timezone.utc)
    assert aware.replace(tzinfo=None) == naive
    assert aware.utcoffset() == timedelta(0)

    # Which leaves the epoch clocks disagreeing by exactly tz_offset.
    # time.time() and the naive timestamp() are the instant that was
    # frozen; the aware one is four hours away from it. A test that stores
    # now(timezone.utc) and compares it against a value the code under test
    # built from time.time() is off by the offset, and the freeze looks
    # innocent while it happens.
    assert time.time() == 1326511294.0
    assert naive.timestamp() == time.time()
    assert aware.timestamp() - time.time() == -4 * 3600

    # date.today() takes the offset too, so an offset large enough to cross
    # midnight changes the date a report is filed under.
    assert date.today() == date(2012, 1, 13)

# The offset does not have to be whole hours, and a timedelta says so more
# clearly than a float.
with freeze_time("2012-01-14 03:21:34", tz_offset=timedelta(hours=5, minutes=30)):
    assert datetime.now() == datetime(2012, 1, 14, 8, 51, 34)
    assert datetime.utcnow() == datetime(2012, 1, 14, 3, 21, 34)

# --- one signal the freeze swallows -------------------------------------
# datetime.utcnow() is deprecated on 3.12 and says so. Under a freeze the
# call lands on freezegun's own classmethod, which warns about nothing, so a
# suite that runs everything frozen and turns DeprecationWarning into an
# error still will not find its utcnow calls.
with warnings.catch_warnings(record=True) as real_warnings:
    warnings.simplefilter("always")
    datetime.utcnow()
assert [type(w.message) for w in real_warnings] == [DeprecationWarning]

with freeze_time("1999-12-31 23:59:58.5"):
    with warnings.catch_warnings(record=True) as frozen_warnings:
        warnings.simplefilter("always")
        assert clock.utc_stamp_legacy() == FROZEN
    assert frozen_warnings == []

print("CONTRACT PASS: freezegun", freezegun.__version__,
      "froze datetime, time.time and monotonic together on python",
      ".".join(str(part) for part in sys.version_info[:2]))

Исходный сидер

anonymous