uuid.SafeUUID

A "safe" UUID was generated with synchronization that guarantees no two processes get the same one. Only uuid1 can know, and only when the platform's uuid_generate_time_safe reports it; every other UUID, and most uuid1 values in practice, say unknown.

uuid classPython 3.7+Live demo
Common call
u.is_safe is uuid.SafeUUID.safe
Returns
True / False
Replaces
Guessing whether uuid1 is unique across processes
Watch out
unknown is the usual value; it does not mean unsafe
class uuid.SafeUUID(Enum)
→ SafeUUID

Demo

Live evaluation
SafeUUID(value) returns the member with that value.
Try:
Inputs
valueint0, -1 …
Code
import uuid
uuid.SafeUUID(0)
Result
<SafeUUID.safe: 0>

Lookup by value accepts only 0, -1 and None; anything else, including the string 'safe', raises ValueError. Use SafeUUID['safe'] or SafeUUID.safe for names. A UUID you construct yourself always reports SafeUUID.unknown unless you pass is_safe=.

Parameters

NameTypeRequiredDescription
valueint | NoneyesSafeUUID(value) looks a member up by value: 0, -1 or None. SafeUUID[name] looks it up by name.

Return value

SafeUUID — One of the three members.

Attributes

AttributeTypeMeaning
SafeUUID.safeSafeUUIDValue 0: the platform generated the UUID in a multiprocessing-safe way.
SafeUUID.unsafeSafeUUIDValue -1: it was not generated in a multiprocessing-safe way.
SafeUUID.unknownSafeUUIDValue None: the platform does not say.
UUID.is_safeSafeUUIDRead-only attribute of every UUID (a __slots__ entry); set by the is_safe= keyword of UUID(), default SafeUUID.unknown.
uuid.EnumtypeNot an API: enum.Enum, imported by uuid.py to define SafeUUID, so it shows up as a public module attribute. Import it from enum.

Common patterns

Insist on safe uuid1 values
Fall back to uuid4 when the platform cannot promise uniqueness across processes.
import uuid
u = uuid.uuid1()
if u.is_safe is not uuid.SafeUUID.safe:
    u = uuid.uuid4()
Carry the flag through storage
Pickling keeps is_safe; for your own formats store is_safe.value and restore with SafeUUID(value).
import uuid
row = {'id': u.hex, 'safe': u.is_safe.value}
back = uuid.UUID(row['id'], is_safe=uuid.SafeUUID(row['safe']))

Examples

1. The three members
import uuid list(uuid.SafeUUID)
Returns
[<SafeUUID.safe: 0>, <SafeUUID.unsafe: -1>, <SafeUUID.unknown: None>]
2. Default for any UUID
import uuid uuid.UUID(int=1).is_safe
Returns
<SafeUUID.unknown: None>
3. uuid4 does not say
import uuid uuid.uuid4().is_safe
Returns
<SafeUUID.unknown: None>
4. Set it when constructing
import uuid uuid.UUID(int=1, is_safe=uuid.SafeUUID.safe).is_safe
Returns
<SafeUUID.safe: 0>
5. unknown has the value None
import uuid uuid.SafeUUID['unknown'].value is None
Returns
True
6. A plain Enum, not an IntEnum
import uuid uuid.SafeUUID.safe == 0
Returns
False
7. uuid.Enum is enum.Enum
import uuid, enum uuid.Enum is enum.Enum
Returns
True

Pitfalls

1. Comparing is_safe with 0
SafeUUID is a plain Enum: members are never equal to their values. Compare with the member.
is_safe == 0
import uuid
uuid.UUID(int=1, is_safe=uuid.SafeUUID.safe).is_safe == 0
False
is SafeUUID.safe
import uuid
uuid.UUID(int=1, is_safe=uuid.SafeUUID.safe).is_safe is uuid.SafeUUID.safe
True
2. Reading unknown as unsafe
unknown means the platform gave no information, which is the normal case. The value None is also falsy, unlike unsafe (-1).
not value
import uuid
not uuid.uuid4().is_safe.value
True
compare members
import uuid
uuid.uuid4().is_safe is uuid.SafeUUID.unsafe
False
3. Changing is_safe later
UUIDs are immutable, is_safe included. Build a new UUID with is_safe=.
assign
import uuid
u = uuid.UUID(int=1)
u.is_safe = uuid.SafeUUID.safe
TypeError: UUID objects are immutable
new UUID
import uuid
u = uuid.UUID(int=1)
uuid.UUID(int=u.int, is_safe=uuid.SafeUUID.safe).is_safe
<SafeUUID.safe: 0>

When to use

Use it
  • Deciding whether uuid1 values from several processes on one machine can collide
Reach for something else
  • uuid4, uuid3, uuid5 → always unknown, and uniqueness does not depend on it
  • Using uuid.Enum in your code → import Enum from enum

Notes

CPython impl
Defined with @_simple_enum(Enum) in Lib/uuid.py. uuid1 sets it from the second result of _uuid.generate_time_safe() when the _uuid extension provides it and neither node nor clock_seq is given
In practice
On the two machines used to check this page (Windows CPython 3.13, Ubuntu WSL CPython 3.12) uuid._generate_time_safe was None, so uuid1().is_safe was SafeUUID.unknown
Pickling
UUID.__getstate__ stores is_safe.value only when it is not unknown, so pickles stay readable by Pythons older than 3.7
uuid.Enum
Shows up in dir(uuid) because uuid.py does from enum import Enum and the module has no __all__ (checked on 3.13)

FAQ

The platform did not report whether the UUID was generated in a multiprocessing-safe way. It is the default for every UUID and the usual result of uuid1.