Skip to content

Decorator API

The @freeze_uuid decorator provides a clean way to configure UUID mocking at the function or class level.

Version-Specific Decorators

Use the version-specific decorators for clarity and to enable version-specific features:

Decorator UUID Version Extra Parameters
@freeze_uuid4(...) uuid4 (recommended) -
@freeze_uuid1(...) uuid1 node, clock_seq
@freeze_uuid6(...) uuid6 node, clock_seq
@freeze_uuid7(...) uuid7 -
@freeze_uuid8(...) uuid8 -
@freeze_uuid(...) uuid4 (backward compatibility) -
import uuid
from pytest_uuid import freeze_uuid4, freeze_uuid1, freeze_uuid7

@freeze_uuid4("12345678-1234-4678-8234-567812345678")
def test_uuid4():
    assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"

@freeze_uuid1(seed=42, node=0x123456789abc)
def test_uuid1_with_node():
    result = uuid.uuid1()
    assert result.node == 0x123456789abc

@freeze_uuid7(seed=42)
def test_uuid7():
    result = uuid.uuid7()
    assert result.version == 7

Stacking Multiple Versions

Mock multiple UUID versions in the same test:

@freeze_uuid4("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa")
@freeze_uuid1(seed=42)
def test_multiple_versions():
    assert str(uuid.uuid4()) == "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
    result1 = uuid.uuid1()
    assert result1.version == 1

Basic Usage

import uuid
from pytest_uuid import freeze_uuid

@freeze_uuid("12345678-1234-4678-8234-567812345678")
def test_with_decorator():
    assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"

Multiple UUIDs

Pass multiple UUIDs as a list:

@freeze_uuid([
    "11111111-1111-4111-8111-111111111111",
    "22222222-2222-4222-8222-222222222222",
])
def test_sequence():
    assert str(uuid.uuid4()) == "11111111-1111-4111-8111-111111111111"
    assert str(uuid.uuid4()) == "22222222-2222-4222-8222-222222222222"

Seeded UUIDs

Use a seed for reproducible UUIDs:

@freeze_uuid(seed=42)
def test_seeded():
    result = uuid.uuid4()
    assert result.version == 4

Custom Random Generator

Pass your own random.Random instance:

import random
from pytest_uuid import freeze_uuid

rng = random.Random(42)
rng.random()  # Advance the state

@freeze_uuid(seed=rng)
def test_custom_rng():
    # Gets UUIDs from the pre-advanced random state
    result = uuid.uuid4()

Exhaustion Behavior

Control what happens when UUIDs are exhausted:

import uuid
import pytest
from pytest_uuid import freeze_uuid, UUIDsExhaustedError

@freeze_uuid(
    ["11111111-1111-4111-8111-111111111111"],
    on_exhausted="raise",
)
def test_exhaustion():
    uuid.uuid4()  # OK
    with pytest.raises(UUIDsExhaustedError):
        uuid.uuid4()  # Raises

Options:

  • "cycle" (default): Loop back to the start
  • "random": Generate random UUIDs
  • "raise": Raise UUIDsExhaustedError

Ignoring Modules

Exclude modules from mocking:

@freeze_uuid("12345678-1234-4678-8234-567812345678", ignore=["sqlalchemy"])
def test_with_ignored():
    # Direct calls are mocked
    assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"
    # Calls from sqlalchemy get real UUIDs

Opting Out of Default Ignores

By default, certain packages (like botocore) are always ignored. Use ignore_defaults=False to mock all modules:

@freeze_uuid("12345678-1234-4678-8234-567812345678", ignore_defaults=False)
def test_mock_everything():
    # All uuid.uuid4() calls are mocked, including from botocore
    pass

Combine with ignore to replace the default list entirely:

@freeze_uuid(
    "12345678-1234-4678-8234-567812345678",
    ignore=["myapp.internal"],
    ignore_defaults=False,  # Don't include botocore
)
def test_custom_ignore():
    # Only myapp.internal is ignored (not botocore)
    pass

Class-Level Decorator

Apply to all methods in a test class:

@freeze_uuid("12345678-1234-4678-8234-567812345678")
class TestUserService:
    def test_create(self):
        assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"

    def test_update(self):
        assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"

Context Manager

Use freeze_uuid as a context manager for fine-grained control:

def test_context_manager():
    with freeze_uuid("12345678-1234-4678-8234-567812345678"):
        assert str(uuid.uuid4()) == "12345678-1234-4678-8234-567812345678"

    # Original uuid.uuid4 is restored
    assert uuid.uuid4() != uuid.UUID("12345678-1234-4678-8234-567812345678")

Access the freezer inside the context:

def test_with_freezer():
    with freeze_uuid("12345678-1234-4678-8234-567812345678") as freezer:
        uuid.uuid4()
        freezer.reset()  # Reset mid-test
        uuid.uuid4()

Inspecting the Seed Value

When using seeded generation, access the seed property to see the actual seed:

def test_inspect_seed():
    with freeze_uuid(seed=42) as freezer:
        assert freezer.seed == 42

    # With node-based seeding, see the computed seed
    with freeze_uuid(seed="node", node_id="test.py::test_foo") as freezer:
        print(f"Computed seed: {freezer.seed}")  # e.g., 8427193654

Note

The seed property returns None when using static UUIDs, sequences, or when a random.Random instance was passed directly.

Parameters

Parameter Type Description
uuids str, UUID, or sequence UUID(s) to return
seed int, Random, or "node" Seed for reproducible generation
on_exhausted str "cycle", "random", or "raise"
ignore list[str] Module prefixes to exclude from mocking
ignore_defaults bool Include default ignore list (default True)
node int Fixed MAC address for uuid1/uuid6
clock_seq int Fixed clock sequence for uuid1/uuid6