Skip to content

Make uuid1() and uuid7() reproducible under a fixed seed#2427

Open
vidigoat wants to merge 1 commit into
joke2k:masterfrom
vidigoat:fix-uuid1-uuid7-seedability
Open

Make uuid1() and uuid7() reproducible under a fixed seed#2427
vidigoat wants to merge 1 commit into
joke2k:masterfrom
vidigoat:fix-uuid1-uuid7-seedability

Conversation

@vidigoat

Copy link
Copy Markdown

What does this change

uuid1() and uuid7() now derive their timestamp from the seeded Faker generator instead of time.time(), so they return the same value on every run under a fixed seed, matching uuid4(). Adds test_uuid1_seedability and test_uuid7_seedability.

What was wrong

Both methods built their timestamp bits from the wall clock:

  • uuid1: nanoseconds = int(time.time() * 1e9)
  • uuid7: unix_ts_ms = int(time.time() * 1000) + ...

The wall-clock value dominates the high bits, so the output changes between runs even with a fixed seed. This breaks the seeding guarantee documented in the README ("A Seed produces the same result when the same methods with the same version of faker are called") and contradicts these methods' own docstrings, which state the timestamp is chosen "to ensure seedability". uuid4() is reproducible; uuid1()/uuid7() are not:

import time
from faker import Faker

def draw(m):
    Faker.seed(0)
    return getattr(Faker(), m)()

a1, a7 = draw("uuid1"), draw("uuid7")
time.sleep(2)
b1, b7 = draw("uuid1"), draw("uuid7")
print(a1 == b1, a7 == b7)  # False False on master

How this fixes it

The timestamp is drawn from self.generator.random over a fixed range (up to 2035-01-01 UTC) instead of the wall clock. The RFC 4122 (v1) and RFC 9562 (v7) version/variant bit layout is unchanged, so the generated UUIDs are still structurally valid time-based UUIDs — they are now simply reproducible under a fixed seed. import time is no longer used and is removed.

Fixes #2426

AI Assistance Disclosure (REQUIRED)

  • If AI tools were used, I have disclosed which ones, and fully reviewed and verified their output.

I used an AI assistant to help draft this description and cross-check the RFC bit layouts. I reviewed and verified the change myself: reproduced the bug on master, confirmed the two new tests fail before the fix and pass after, and ran the full test suite (2393 passed) plus make lint (isort/black 24.4.0/flake8 clean on the changed files; the pre-existing mypy findings in json() are unrelated).

Checklist

  • I have read the documentation about CONTRIBUTING
  • I have read the documentation about Coding style
  • I have run make lint

uuid1() and uuid7() built their timestamp bits from time.time(), so their
output changed between runs even with a fixed seed, unlike uuid4(). This
contradicts Faker's documented seeding guarantee and the methods' own
docstrings, which state the timestamp is drawn to ensure seedability.

Draw the timestamp from the seeded generator instead of the wall clock,
keeping the RFC 4122 / RFC 9562 version and variant bit layout intact. Add
test_uuid1_seedability and test_uuid7_seedability mirroring
test_uuid4_seedability.

Closes joke2k#2426

@fcurella fcurella left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uuid1() and uuid7() are not reproducible under a fixed seed (timestamp taken from time.time())

2 participants