How to generate a random UUID which is reproducible (with a seed) in Python

PythonRandomUuid

Python Problem Overview


The uuid4() function of Python's module uuid generates a random UUID, and seems to generate a different one every time:

In [1]: import uuid

In [2]: uuid.uuid4()
Out[2]: UUID('f6c9ad6c-eea0-4049-a7c5-56253bc3e9c0')

In [3]: uuid.uuid4()
Out[3]: UUID('2fc1b6f9-9052-4564-9be0-777e790af58f')

I would like to be able to generate the same random UUID every time I run a script - that is, I'd like to seed the random generator in uuid4(). Is there a way to do this? (Or achieve this by some other means)?

What I've tried so far

I've to generate a UUID using the uuid.UUID() method with a random 128-bit integer (from a seeded instance of random.Random()) as input:

import uuid
import random

rd = random.Random()
rd.seed(0)
uuid.UUID(rd.getrandbits(128))

However, UUID() seems not to accept this as input:

Traceback (most recent call last):
  File "uuid_gen_seed.py", line 6, in <module>
    uuid.UUID(rd.getrandbits(128))
  File "/usr/lib/python2.7/uuid.py", line 133, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'long' object has no attribute 'replace'

Any other suggestions?

Python Solutions


Solution 1 - Python

Almost there:

uuid.UUID(int=rd.getrandbits(128))

This was determined with the help of help:

>>> help(uuid.UUID.__init__)
Help on method __init__ in module uuid:

__init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None) unbound uuid.UUID method
    Create a UUID from either a string of 32 hexadecimal digits,
    a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
    in little-endian order as the 'bytes_le' argument, a tuple of six
    integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
    8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
    the 'fields' argument, or a single 128-bit integer as the 'int'
    argument.  When a string of hex digits is given, curly braces,
    hyphens, and a URN prefix are all optional.  For example, these
    expressions all yield the same UUID:
    
    UUID('{12345678-1234-5678-1234-567812345678}')
    UUID('12345678123456781234567812345678')
    UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
    UUID(bytes='\x12\x34\x56\x78'*4)
    UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
                  '\x12\x34\x56\x78\x12\x34\x56\x78')
    UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
    UUID(int=0x12345678123456781234567812345678)
    
    Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
    be given.  The 'version' argument is optional; if given, the resulting
    UUID will have its variant and version set according to RFC 4122,
    overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.

Solution 2 - Python

[Faker][1] makes this easy

>>> from faker import Faker
>>> f1 = Faker()
>>> f1.seed(4321)
>>> print(f1.uuid4())
cc733c92-6853-15f6-0e49-bec741188ebb
>>> print(f1.uuid4())
a41f020c-2d4d-333f-f1d3-979f1043fae0
>>> f1.seed(4321)
>>> print(f1.uuid4())
cc733c92-6853-15f6-0e49-bec741188ebb

[1]: https://github.com/joke2k/faker "Faker"

Solution 3 - Python

This is based on a solution used here:

import hashlib
import uuid

m = hashlib.md5()
m.update(seed.encode('utf-8'))
new_uuid = uuid.UUID(m.hexdigest())

Solution 4 - Python

Since the straight-forward solution hasn't been posted yet to generate consistent version 4 UUIDs:

import random
import uuid

rnd = random.Random()
rnd.seed(123) # NOTE: Of course don't use a static seed in production

random_uuid = uuid.UUID(int=rnd.getrandbits(128), version=4)

where you can see then:

>>> random_uuid.version
4

This doesn't just "mock" the version information. It creates a proper UUIDv4: > The version argument is optional; if given, the resulting UUID will have its variant and version number set according to RFC 4122, overriding bits in the given hex, bytes, bytes_le, fields, or int.

Python 3.8 docs

Solution 5 - Python

Gonna add this here if anyone needs to monkey patch in a seeded UUID. My code uses uuid.uuid4() but for testing I wanted consistent UUIDs. The following code is how I did that:

import uuid
import random

# -------------------------------------------
# Remove this block to generate different
# UUIDs everytime you run this code.
# This block should be right below the uuid
# import.
rd = random.Random()
rd.seed(0)
uuid.uuid4 = lambda: uuid.UUID(int=rd.getrandbits(128))
# -------------------------------------------

# Then normal code:

print(uuid.uuid4().hex)
print(uuid.uuid4().hex)
print(uuid.uuid4().hex)
print(uuid.uuid4().hex)

Solution 6 - Python

Based on alex's solution, the following would provide a proper UUID4:

random.seed(123210912)
a = "%32x" % random.getrandbits(128)
rd = a[:12] + '4' + a[13:16] + 'a' + a[17:]
uuid4 = uuid.UUID(rd)

Solution 7 - Python

Simple solution based on the answer of @user10229295, with a comment about the seed. The Edit queue was full, so I opened a new answer:

import hashlib
import uuid

seed = 'Type your seed_string here' #Read comment below

m = hashlib.md5()
m.update(seed.encode('utf-8'))
new_uuid = uuid.UUID(m.hexdigest())

Comment about the string 'seed': It will be the seed from which the UUID will be generated: from the same seed string will be always generated the same UUID. You can convert integer with some significance as string, concatenate different strings and use the result as your seed. With this you will have control on the UUID generated, which means you will be able to reproduce your UUID knowing the seed you used: with the same seed, the UUID generated from it will be the same.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKurt PeekView Question on Stackoverflow
Solution 1 - PythonAlex HallView Answer on Stackoverflow
Solution 2 - PythoncitynormanView Answer on Stackoverflow
Solution 3 - Pythonuser10229295View Answer on Stackoverflow
Solution 4 - Pythonh345k34crView Answer on Stackoverflow
Solution 5 - PythonError - Syntactical RemorseView Answer on Stackoverflow
Solution 6 - PythonPerennialView Answer on Stackoverflow
Solution 7 - PythonAndrea BaldinoView Answer on Stackoverflow