Type-safe UUID management with prefix identification for Python
Project description
TypedUUID
A robust Python library for type-safe UUID management with prefix identification. TypedUUID enhances standard UUIDs by adding a type prefix, making it easy to identify what kind of entity a UUID represents at a glance.
Features
- Type-safe UUIDs: Prefix UUIDs with a type identifier (e.g.,
user-550e8400-e29b-41d4-a716-446655440000) - Human-readable: Instantly identify what type of entity a UUID belongs to
- Thread-safe: Safe for use in multi-threaded applications
- Framework integrations: Built-in support for SQLAlchemy, Pydantic, and FastAPI
- Zero hard dependencies: Core library works standalone; adapters activate when frameworks are installed
- Full validation: Comprehensive validation of type IDs and UUID formats
- Comparison support: Full support for equality, ordering, and hashing
Installation
pip install typed-uuid
Optional dependencies
# For SQLAlchemy support
pip install typed-uuid[sqlalchemy]
# For Pydantic support
pip install typed-uuid[pydantic]
# For FastAPI support (includes Pydantic)
pip install typed-uuid[fastapi]
# For all integrations
pip install typed-uuid[all]
Quick Start
from typed_uuid import create_typed_uuid_class
# Create a typed UUID class for users
UserUUID = create_typed_uuid_class('User', 'user')
# Generate a new UUID
user_id = UserUUID()
print(user_id) # user-550e8400-e29b-41d4-a716-446655440000
# Parse from string
user_id = UserUUID.from_string('user-550e8400-e29b-41d4-a716-446655440000')
# Create from existing UUID
from uuid import UUID
user_id = UserUUID(uuid_value=UUID('550e8400-e29b-41d4-a716-446655440000'))
# Get the raw UUID without prefix
raw_uuid = user_id.get_uuid() # '550e8400-e29b-41d4-a716-446655440000'
Type ID Rules
- Must be alphanumeric only (a-z, A-Z, 0-9)
- Case-sensitive (
userandUserare different types) - Cannot be empty
# Valid type IDs
UserUUID = create_typed_uuid_class('User', 'user')
OrderUUID = create_typed_uuid_class('Order', 'order')
ProductUUID = create_typed_uuid_class('Product', 'prod')
OrgUUID = create_typed_uuid_class('Organization', 'organization') # Long type IDs are fine
# Invalid type IDs (will raise InvalidTypeIDError)
create_typed_uuid_class('Invalid', 'user-id') # Contains hyphen
create_typed_uuid_class('Invalid', 'user@id') # Contains special character
create_typed_uuid_class('Invalid', '') # Empty
API Reference
TypedUUID Class
Class Methods
| Method | Description |
|---|---|
from_string(value) |
Parse a TypedUUID from a string |
generate() |
Generate a new instance with a random UUID |
validate(value) |
Validate and convert a value to this TypedUUID type |
is_type_registered(type_id) |
Check if a type_id is registered |
list_registered_types() |
List all registered type IDs |
get_class_by_type_id(type_id) |
Get the class for a type_id |
format_pattern() |
Get the regex pattern for validation |
Instance Properties
| Property | Description |
|---|---|
type_id |
The type identifier prefix |
uuid |
The underlying UUID object |
Instance Methods
| Method | Description |
|---|---|
get_uuid() |
Get the UUID string without the type prefix |
__str__() |
Returns the full typed UUID string |
__hash__() |
Enables use in sets and dict keys |
Factory Functions
create_typed_uuid_class(class_name, type_id)
Creates a new TypedUUID subclass with the specified type identifier.
UserUUID = create_typed_uuid_class('User', 'user')
create_typed_uuid_classes(name, type_id)
Creates both a TypedUUID class and its corresponding SQLAlchemy type (if SQLAlchemy is available).
# With SQLAlchemy installed
UserUUID, UserUUIDType = create_typed_uuid_classes('User', 'user')
# Without SQLAlchemy
UserUUID = create_typed_uuid_classes('User', 'user')
Framework Integrations
SQLAlchemy
TypedUUID integrates seamlessly with SQLAlchemy for database storage.
from sqlalchemy import Column, String
from sqlalchemy.orm import declarative_base
from typed_uuid import create_typed_uuid_classes
Base = declarative_base()
# Create both UUID class and SQLAlchemy type
UserUUID, UserUUIDType = create_typed_uuid_classes('User', 'user')
class User(Base):
__tablename__ = 'users'
id = Column(UserUUIDType(), primary_key=True, default=UserUUID)
name = Column(String(100))
# Usage
user = User(id=UserUUID(), name="Alice")
session.add(user)
session.commit()
# The ID is stored as 'user-550e8400-e29b-41d4-a716-446655440000' in the database
Pydantic
TypedUUID works with Pydantic v2 for validation and serialization.
from pydantic import BaseModel
from typed_uuid import create_typed_uuid_class
UserUUID = create_typed_uuid_class('User', 'user')
class UserModel(BaseModel):
id: UserUUID
name: str
# Validation from string
user = UserModel(id='user-550e8400-e29b-41d4-a716-446655440000', name='Alice')
# Validation from UUID instance
user = UserModel(id=UserUUID(), name='Bob')
# Serialization
print(user.model_dump_json())
# {"id": "user-550e8400-e29b-41d4-a716-446655440000", "name": "Bob"}
FastAPI
TypedUUID provides FastAPI path parameter support with automatic OpenAPI documentation.
from fastapi import FastAPI
from typed_uuid import create_typed_uuid_class
app = FastAPI()
UserUUID = create_typed_uuid_class('User', 'user')
@app.get("/users/{user_id}")
async def get_user(user_id: UserUUID.path_param(description="The user's ID")):
return {"user_id": str(user_id)}
# OpenAPI docs will show the parameter with:
# - Example: user-550e8400-e29b-41d4-a716-446655440000
# - Pattern validation
# - Description
Comparison and Hashing
TypedUUID instances support full comparison operations:
from typed_uuid import create_typed_uuid_class
UserUUID = create_typed_uuid_class('User', 'user')
id1 = UserUUID()
id2 = UserUUID()
# Equality
id1 == id2 # False (different UUIDs)
id1 == id1 # True
# String comparison
id1 == 'user-550e8400-e29b-41d4-a716-446655440000' # True if UUIDs match
# Ordering (for sorting)
sorted([id2, id1]) # Sorts by (type_id, uuid)
# Hashing (for sets and dicts)
user_set = {id1, id2}
user_dict = {id1: "Alice", id2: "Bob"}
JSON Serialization
TypedUUID supports multiple JSON serialization methods:
import json
from typed_uuid import create_typed_uuid_class, TypedUUID
UserUUID = create_typed_uuid_class('User', 'user')
user_id = UserUUID()
# Using default encoder
json.dumps({'id': user_id}, default=TypedUUID.json_default)
# Using __json__ method (supported by simplejson, FastAPI)
user_id.__json__() # 'user-550e8400-e29b-41d4-a716-446655440000'
# Direct string conversion
str(user_id) # 'user-550e8400-e29b-41d4-a716-446655440000'
Short Encoding
TypedUUID supports compact base62 encoding for URL-friendly identifiers:
from typed_uuid import create_typed_uuid_class
UserUUID = create_typed_uuid_class('User', 'user')
user_id = UserUUID()
# Get short representation
print(user_id.short) # user_7n42DGM5Tflk9n8mt7Fhc7
# Decode from short format
decoded = UserUUID.from_short('user_7n42DGM5Tflk9n8mt7Fhc7')
assert decoded.uuid == user_id.uuid
The short format uses underscore (_) as separator to distinguish from the standard hyphen-separated format.
Auto-Parsing
Parse typed UUIDs without knowing the type in advance:
from typed_uuid import TypedUUID, create_typed_uuid_class
UserUUID = create_typed_uuid_class('User', 'user')
OrderUUID = create_typed_uuid_class('Order', 'order')
# Auto-detect type from string (standard format)
entity = TypedUUID.parse('user-550e8400-e29b-41d4-a716-446655440000')
assert isinstance(entity, UserUUID)
# Also works with short format
entity = TypedUUID.parse('order_7n42DGM5Tflk9n8mt7Fhc7')
assert isinstance(entity, OrderUUID)
Pickle Support
TypedUUID instances can be pickled and unpickled:
import pickle
from typed_uuid import create_typed_uuid_class
UserUUID = create_typed_uuid_class('User', 'user')
user_id = UserUUID()
# Pickle and restore
data = pickle.dumps(user_id)
restored = pickle.loads(data)
assert restored.uuid == user_id.uuid
assert isinstance(restored, UserUUID)
Exceptions
| Exception | Description |
|---|---|
TypedUUIDError |
Base exception for all TypedUUID errors |
InvalidTypeIDError |
Raised when a type_id is invalid |
InvalidUUIDError |
Raised when a UUID value is invalid |
from typed_uuid import create_typed_uuid_class, InvalidTypeIDError, InvalidUUIDError
try:
create_typed_uuid_class('Invalid', 'too-long-type-id')
except InvalidTypeIDError as e:
print(f"Invalid type ID: {e}")
UserUUID = create_typed_uuid_class('User', 'user')
try:
UserUUID.from_string('not-a-valid-uuid')
except InvalidUUIDError as e:
print(f"Invalid UUID: {e}")
Thread Safety
TypedUUID is thread-safe. The class registry uses a lock to prevent race conditions when creating new TypedUUID classes from multiple threads.
from concurrent.futures import ThreadPoolExecutor
from typed_uuid import create_typed_uuid_class
def create_user_uuid():
# Safe to call from multiple threads
UserUUID = create_typed_uuid_class('User', 'user')
return UserUUID()
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(create_user_uuid) for _ in range(100)]
results = [f.result() for f in futures]
Registry
TypedUUID maintains a registry of all created classes, preventing duplicate type IDs:
from typed_uuid import create_typed_uuid_class, TypedUUID
# Create a class
UserUUID = create_typed_uuid_class('User', 'user')
# Calling again with the same type_id returns the existing class
UserUUID2 = create_typed_uuid_class('User', 'user')
assert UserUUID is UserUUID2 # Same class
# Check registered types
TypedUUID.list_registered_types() # ['user']
TypedUUID.is_type_registered('user') # True
TypedUUID.get_class_by_type_id('user') # UserUUID class
License
MIT License
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file typed_uuid-1.1.0.tar.gz.
File metadata
- Download URL: typed_uuid-1.1.0.tar.gz
- Upload date:
- Size: 13.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62b7a7564a9f6784131de64c673a0de7cac25ea12ec951197960f0677ba5c4a5
|
|
| MD5 |
399e2c6f689302938ce36938ebe36b8f
|
|
| BLAKE2b-256 |
dd2ed12f2136169f2c57703e4ce746abb9798b8e7ef4016f3228a3cfa95f34ac
|
Provenance
The following attestation bundles were made for typed_uuid-1.1.0.tar.gz:
Publisher:
publish.yml on boxcake/TypedUUID
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
typed_uuid-1.1.0.tar.gz -
Subject digest:
62b7a7564a9f6784131de64c673a0de7cac25ea12ec951197960f0677ba5c4a5 - Sigstore transparency entry: 827031274
- Sigstore integration time:
-
Permalink:
boxcake/TypedUUID@af00c325b6c8a77bceb1b9c36537f73a20f915e0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/boxcake
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@af00c325b6c8a77bceb1b9c36537f73a20f915e0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file typed_uuid-1.1.0-py3-none-any.whl.
File metadata
- Download URL: typed_uuid-1.1.0-py3-none-any.whl
- Upload date:
- Size: 16.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
777579cdf138261fed7fdb38e5c0121b22485873af88914740793429ac9f13cf
|
|
| MD5 |
b2f77bbb34dd0ca0f7d2de8b9d26e315
|
|
| BLAKE2b-256 |
7085cbcec2dec83d47288e1453e0a90f1e2e42cc42afd450e75c5ba15a7f6b04
|
Provenance
The following attestation bundles were made for typed_uuid-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on boxcake/TypedUUID
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
typed_uuid-1.1.0-py3-none-any.whl -
Subject digest:
777579cdf138261fed7fdb38e5c0121b22485873af88914740793429ac9f13cf - Sigstore transparency entry: 827031323
- Sigstore integration time:
-
Permalink:
boxcake/TypedUUID@af00c325b6c8a77bceb1b9c36537f73a20f915e0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/boxcake
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@af00c325b6c8a77bceb1b9c36537f73a20f915e0 -
Trigger Event:
release
-
Statement type: