Best Practices¶
Learn the optimal patterns and practices for using UUID-Forge effectively in production systems.
UUID Generation Fundamentals¶
Understanding Deterministic UUIDs¶
UUID-Forge generates UUIDv5 deterministic identifiers:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
# Configure generator with namespace and salt
config = IDConfig(
namespace=Namespace("myapp.com"),
salt="v1"
)
generator = UUIDGenerator(config)
# Same inputs always produce the same UUID
uuid1 = generator.generate("user", email="alice@example.com")
uuid2 = generator.generate("user", email="alice@example.com")
assert uuid1 == uuid2 # ✅ Always deterministic
Benefits:
- UUIDv5 uses strong SHA-1 hashing
- Excellent collision resistance
- Industry standard for deterministic UUIDs
- No database lookups needed to find existing IDs
When to Use Deterministic UUIDs¶
✅ Good Use Cases:
- Distributed systems needing consistent IDs
- Event deduplication in message queues
- Cache keys that need to be regenerated
- Cross-service entity identification
- Idempotent API operations
❌ Not Suitable For:
- Security tokens or session IDs (use random UUIDs)
- Cryptographic keys (use proper key generation)
- When inputs might contain PII that shouldn't be hashed
Namespace Design¶
Hierarchical Namespaces¶
Design namespaces hierarchically for better organization:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
# Root namespace for your organization
ROOT_DOMAIN = "mycompany.com"
# Service-specific namespaces with hierarchical structure
user_service_config = IDConfig(
namespace=Namespace(f"{ROOT_DOMAIN}/user-service"),
salt="user-service-v1"
)
order_service_config = IDConfig(
namespace=Namespace(f"{ROOT_DOMAIN}/order-service"),
salt="order-service-v1"
)
product_service_config = IDConfig(
namespace=Namespace(f"{ROOT_DOMAIN}/product-service"),
salt="product-service-v1"
)
# Environment-specific separation through salts
dev_user_config = IDConfig(
namespace=Namespace(f"{ROOT_DOMAIN}/user-service"),
salt="user-service-dev"
)
prod_user_config = IDConfig(
namespace=Namespace(f"{ROOT_DOMAIN}/user-service"),
salt="user-service-prod"
)
# Create generators
user_generator = UUIDGenerator(user_service_config)
order_generator = UUIDGenerator(order_service_config)
Namespace Naming Conventions¶
Follow consistent, URL-like naming patterns:
from uuid_forge import Namespace
# ✅ Good: Clear, hierarchical domain-style naming
good_namespaces = [
Namespace("mycompany.com/users/profiles"),
Namespace("mycompany.com/users/auth"),
Namespace("mycompany.com/orders/processing"),
Namespace("mycompany.com/orders/fulfillment"),
]
# ❌ Avoid: Ambiguous or flat naming
# "ns1", "namespace_a", "temp_ns", "users"
# ✅ Include version in the salt instead
config = IDConfig(
namespace=Namespace("mycompany.com/users"),
salt="v2" # Version here for easier migration
)
Namespace Strategy for Multi-Service Architectures¶
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from typing import Dict
class ServiceNamespaceManager:
"""Central manager for service namespaces"""
def __init__(self, organization: str, environment: str = "production"):
self.organization = organization
self.environment = environment
self.generators: Dict[str, UUIDGenerator] = {}
def get_generator(self, service: str, version: str = "v1") -> UUIDGenerator:
"""Get generator for a service"""
key = f"{service}-{version}"
if key not in self.generators:
config = IDConfig(
namespace=Namespace(f"{self.organization}/{service}"),
salt=f"{self.environment}-{version}"
)
self.generators[key] = UUIDGenerator(config)
return self.generators[key]
# Usage
manager = ServiceNamespaceManager("mycompany.com", "production")
user_gen = manager.get_generator("users", "v1")
order_gen = manager.get_generator("orders", "v1")
Input Data Preparation¶
Canonical Representation¶
Ensure consistent input representation for deterministic UUIDs:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config)
def prepare_user_attributes(user_data: dict) -> dict:
"""Prepare user data for consistent UUID generation"""
return {
"email": user_data["email"].lower().strip(),
"username": user_data["username"].lower().strip(),
"department": user_data.get("department", "").lower().strip()
}
# Use prepared attributes
raw_data = {"email": " Alice@Example.COM ", "username": "ALICE", "department": "Engineering"}
clean_attrs = prepare_user_attributes(raw_data)
user_uuid = generator.generate("user", **clean_attrs)
Handle Optional and Null Values¶
Be consistent with optional, null, and empty values:
def normalize_attributes(data: dict) -> dict:
"""Normalize attributes for UUID generation"""
normalized = {}
for key, value in data.items():
if value is None:
normalized[key] = "" # Consistent null representation
elif isinstance(value, str):
normalized[key] = value.strip().lower()
elif isinstance(value, (int, float, bool)):
normalized[key] = value
else:
# Convert other types to string
normalized[key] = str(value)
return normalized
# Usage
raw_attrs = {
"email": "user@example.com",
"age": 30,
"verified": True,
"middle_name": None, # Optional field
}
clean_attrs = normalize_attributes(raw_attrs)
user_uuid = generator.generate("user", **clean_attrs)
Attribute Ordering and Consistency¶
UUID-Forge handles attribute ordering automatically:
# These all produce the SAME UUID - order doesn't matter
uuid1 = generator.generate("user", email="a@example.com", id=123, region="us")
uuid2 = generator.generate("user", region="us", id=123, email="a@example.com")
uuid3 = generator.generate("user", id=123, email="a@example.com", region="us")
assert uuid1 == uuid2 == uuid3 # ✅ All identical
# But different attribute VALUES produce different UUIDs
uuid4 = generator.generate("user", email="a@example.com", id=123, region="eu")
assert uuid1 != uuid4 # ✅ Different region = different UUID
Performance Optimization¶
Reuse Generator Instances¶
Create UUIDGenerator instances once and reuse them:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
# ✅ Good: Create once, reuse many times
class UserService:
def __init__(self):
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
self.generator = UUIDGenerator(config)
def create_user_uuid(self, email: str, region: str):
return self.generator.generate("user", email=email, region=region)
# ❌ Avoid: Creating new instances repeatedly
def create_user_uuid_bad(email: str, region: str):
# Inefficient - creates new generator every call
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config)
return generator.generate("user", email=email, region=region)
Batch Processing¶
Process multiple items efficiently by reusing the generator:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from typing import List, Dict
from uuid import UUID
def process_users_batch(users: List[Dict[str, str]]) -> List[Dict]:
"""Process multiple users efficiently"""
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config)
return [
{
"uuid": generator.generate("user", **user),
"data": user
}
for user in users
]
# Process thousands of items efficiently
users = [
{"email": "user1@example.com", "region": "us"},
{"email": "user2@example.com", "region": "eu"},
# ... thousands more
]
results = process_users_batch(users)
Caching for Repeated Lookups¶
Cache UUIDs when the same inputs are queried frequently:
from functools import lru_cache
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
class CachedUUIDService:
def __init__(self, namespace: str, salt: str):
config = IDConfig(namespace=Namespace(namespace), salt=salt)
self.generator = UUIDGenerator(config)
@lru_cache(maxsize=10000)
def get_user_uuid(self, email: str) -> UUID:
"""Cache frequently accessed user UUIDs"""
return self.generator.generate("user", email=email)
@lru_cache(maxsize=10000)
def get_product_uuid(self, sku: str) -> UUID:
"""Cache frequently accessed product UUIDs"""
return self.generator.generate("product", sku=sku)
def clear_caches(self):
"""Clear all caches when needed"""
self.get_user_uuid.cache_clear()
self.get_product_uuid.cache_clear()
# Usage
service = CachedUUIDService("myapp.com", "v1")
# First call - generates UUID
uuid1 = service.get_user_uuid("alice@example.com")
# Second call - returned from cache (fast!)
uuid2 = service.get_user_uuid("alice@example.com")
assert uuid1 == uuid2
When NOT to Cache¶
Don't cache when:
- Inputs are highly varied (low cache hit rate)
- Memory is constrained
- UUID generation is already fast enough (it's very fast!)
Do cache when:
- Same inputs queried frequently
- Lookup patterns are predictable
- Cache hit rate will be high (>50%)
Error Handling¶
Robust Input Validation¶
Validate inputs before UUID generation:
import logging
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
from typing import Optional
logger = logging.getLogger(__name__)
def safe_generate_uuid(
generator: UUIDGenerator,
entity_type: str,
**attributes
) -> Optional[UUID]:
"""Safely generate UUID with proper error handling"""
try:
# Validate entity type
if not entity_type or not isinstance(entity_type, str):
raise ValueError("entity_type must be a non-empty string")
# Validate attributes
if not attributes:
raise ValueError("At least one attribute must be provided")
# Check for None or empty string values
for key, value in attributes.items():
if value is None or (isinstance(value, str) and not value.strip()):
raise ValueError(f"Attribute '{key}' cannot be None or empty")
return generator.generate(entity_type, **attributes)
except ValueError as e:
logger.error(f"Invalid input for UUID generation: {e}")
raise
except Exception as e:
logger.error(f"Unexpected error during UUID generation: {e}")
raise
# Usage
config = IDConfig(namespace=Namespace("myapp.com"), salt="v1")
generator = UUIDGenerator(config)
try:
user_uuid = safe_generate_uuid(
generator,
"user",
email="alice@example.com",
region="us"
)
except ValueError as e:
print(f"Validation error: {e}")
Environment-Based Fallback¶
Handle different environments with fallback configurations:
import os
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from typing import Optional
def create_generator_with_fallback(
service_name: str,
primary_namespace: Optional[str] = None,
fallback_namespace: str = "default.local"
) -> UUIDGenerator:
"""Create generator with environment-based fallback"""
try:
# Try to get namespace from environment
namespace_domain = (
primary_namespace
or os.environ.get("UUID_NAMESPACE_DOMAIN")
or fallback_namespace
)
config = IDConfig(
namespace=Namespace(f"{namespace_domain}/{service_name}"),
salt=os.environ.get("UUID_SALT_VERSION", "v1")
)
logger.info(f"Created UUID generator for {service_name} with namespace {namespace_domain}")
return UUIDGenerator(config)
except Exception as e:
logger.warning(f"Failed to create primary generator: {e}, using fallback")
# Use fallback configuration
config = IDConfig(
namespace=Namespace(f"{fallback_namespace}/{service_name}"),
salt="v1"
)
return UUIDGenerator(config)
# Usage
generator = create_generator_with_fallback("users", primary_namespace="mycompany.com")
Testing Strategies¶
Deterministic Testing¶
Leverage determinism for reliable, reproducible tests:
import pytest
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
def test_user_uuid_generation_is_deterministic():
"""Test that UUID generation is deterministic"""
config = IDConfig(namespace=Namespace("test.myapp.com"), salt="test-v1")
generator = UUIDGenerator(config)
# Generate UUID multiple times with same inputs
uuid1 = generator.generate("user", email="test@example.com", name="Test User")
uuid2 = generator.generate("user", email="test@example.com", name="Test User")
# Should be identical
assert uuid1 == uuid2
assert isinstance(uuid1, UUID)
def test_different_inputs_produce_different_uuids():
"""Test that different inputs produce different UUIDs"""
config = IDConfig(namespace=Namespace("test.myapp.com"), salt="test-v1")
generator = UUIDGenerator(config)
uuid1 = generator.generate("user", email="alice@example.com")
uuid2 = generator.generate("user", email="bob@example.com")
# Different inputs = different UUIDs
assert uuid1 != uuid2
def test_attribute_order_independence():
"""Test that attribute order doesn't matter"""
config = IDConfig(namespace=Namespace("test.myapp.com"), salt="test-v1")
generator = UUIDGenerator(config)
uuid1 = generator.generate("user", email="test@example.com", id=123, region="us")
uuid2 = generator.generate("user", region="us", id=123, email="test@example.com")
# Same attributes in different order = same UUID
assert uuid1 == uuid2
Test Data Management¶
Use consistent test fixtures:
import pytest
from uuid_forge import UUIDGenerator, IDConfig, Namespace
# Test fixtures
@pytest.fixture
def test_generator():
"""Create a generator for testing"""
config = IDConfig(namespace=Namespace("test.example.com"), salt="test-v1")
return UUIDGenerator(config)
@pytest.fixture
def test_users():
"""Sample test users"""
return [
{"email": "user1@test.com", "region": "us"},
{"email": "user2@test.com", "region": "eu"},
{"email": "user3@test.com", "region": "asia"},
]
def test_batch_uuid_generation(test_generator, test_users):
"""Test batch UUID generation"""
uuids = [
test_generator.generate("user", **user)
for user in test_users
]
# All UUIDs should be unique (different inputs)
assert len(set(uuids)) == len(uuids)
# All should be valid UUID objects
for uuid_obj in uuids:
assert isinstance(uuid_obj, UUID)
def test_uuid_regeneration(test_generator, test_users):
"""Test that UUIDs can be regenerated"""
# Generate UUIDs for all users
original_uuids = [
test_generator.generate("user", **user)
for user in test_users
]
# Regenerate UUIDs for same users
regenerated_uuids = [
test_generator.generate("user", **user)
for user in test_users
]
# Should be identical
assert original_uuids == regenerated_uuids
Production Deployment¶
Configuration Management¶
Use environment-specific configuration:
import os
from uuid_forge import UUIDGenerator, IDConfig, Namespace
import logging
logger = logging.getLogger(__name__)
def create_production_generator(service_name: str) -> UUIDGenerator:
"""Create generator with production configuration from environment"""
# Get configuration from environment variables
namespace_domain = os.environ.get(
"UUID_NAMESPACE_DOMAIN",
"myapp.com" # fallback
)
environment = os.environ.get("APP_ENVIRONMENT", "production")
version = os.environ.get("UUID_VERSION", "v1")
# Create configuration
config = IDConfig(
namespace=Namespace(f"{namespace_domain}/{service_name}"),
salt=f"{environment}-{version}"
)
logger.info(
f"Created UUID generator: service={service_name}, "
f"namespace={namespace_domain}, env={environment}, version={version}"
)
return UUIDGenerator(config)
# Usage
user_generator = create_production_generator("users")
order_generator = create_production_generator("orders")
Monitoring and Logging¶
Monitor UUID generation in production:
import logging
import time
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
from typing import Any
logger = logging.getLogger(__name__)
class MonitoredUUIDGenerator:
"""UUID generator with monitoring and metrics"""
def __init__(self, namespace: str, salt: str):
config = IDConfig(namespace=Namespace(namespace), salt=salt)
self.generator = UUIDGenerator(config)
self.generation_count = 0
self.total_time = 0.0
def generate(self, entity_type: str, **attributes) -> UUID:
"""Generate UUID with monitoring"""
start_time = time.time()
try:
result = self.generator.generate(entity_type, **attributes)
self.generation_count += 1
duration = time.time() - start_time
self.total_time += duration
# Log every 1000 generations
if self.generation_count % 1000 == 0:
avg_time = self.total_time / self.generation_count
logger.info(
f"UUID stats: count={self.generation_count}, "
f"avg_time={avg_time*1000:.2f}ms"
)
return result
except Exception as e:
logger.error(f"UUID generation failed: entity_type={entity_type}, error={e}")
raise
def get_stats(self) -> dict:
"""Get generation statistics"""
return {
"generation_count": self.generation_count,
"total_time_seconds": self.total_time,
"average_time_ms": (self.total_time / self.generation_count * 1000)
if self.generation_count > 0
else 0,
}
# Usage
generator = MonitoredUUIDGenerator("myapp.com/users", "prod-v1")
# Generate many UUIDs
for i in range(10000):
uuid = generator.generate("user", id=i, region="us")
# Check stats
stats = generator.get_stats()
print(f"Generated {stats['generation_count']} UUIDs")
print(f"Average time: {stats['average_time_ms']:.2f}ms")
Security Considerations¶
Sensitive Data Handling¶
⚠️ Important: UUID-Forge UUIDs are deterministic. Anyone with the same inputs can generate the same UUID.
Do NOT use for:
- Session tokens
- Authentication tokens
- Password reset tokens
- API keys
- Cryptographic keys
Best Practices:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from datetime import date
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config)
def generate_user_uuid_safe(user_data: dict):
"""Generate UUID using only non-sensitive identifiers"""
# ✅ Safe: Use non-sensitive business identifiers
safe_attributes = {
"user_id": user_data["id"], # Internal ID
"account_type": user_data["account_type"], # Public info
"created_date": user_data["created_at"].date().isoformat() # Public info
}
# ❌ NEVER include in UUIDs:
# - passwords (even hashed)
# - social security numbers
# - credit card numbers
# - health information
# - other PII that shouldn't be deterministically exposed
return generator.generate("user", **safe_attributes)
# Good: Email addresses CAN be used if acceptable in your use case
def generate_user_uuid_from_email(email: str):
"""Generate UUID from email (if appropriate for your security model)"""
# This is deterministic - same email always produces same UUID
# Only use if this behavior is acceptable in your system
return generator.generate("user", email=email.lower())
Namespace Isolation by Security Context¶
Isolate UUIDs by security level or access context:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from typing import Dict
from enum import Enum
class SecurityContext(Enum):
PUBLIC = "public"
INTERNAL = "internal"
ADMIN = "admin"
class ContextualUUIDGenerator:
"""Generate UUIDs with security context isolation"""
def __init__(self, base_namespace: str):
self.generators: Dict[SecurityContext, UUIDGenerator] = {}
# Create separate generators for each context
for context in SecurityContext:
config = IDConfig(
namespace=Namespace(f"{base_namespace}/{context.value}"),
salt=f"{context.value}-v1"
)
self.generators[context] = UUIDGenerator(config)
def generate(self, context: SecurityContext, entity_type: str, **attributes):
"""Generate UUID for a specific security context"""
return self.generators[context].generate(entity_type, **attributes)
# Usage
manager = ContextualUUIDGenerator("myapp.com")
# Public-facing resource UUIDs
public_uuid = manager.generate(
SecurityContext.PUBLIC,
"article",
slug="hello-world"
)
# Internal system UUIDs
internal_uuid = manager.generate(
SecurityContext.INTERNAL,
"audit_log",
user_id=123,
action="login"
)
# Admin-only resource UUIDs
admin_uuid = manager.generate(
SecurityContext.ADMIN,
"system_config",
key="database_connection"
)
# Same inputs, different contexts = different UUIDs
assert public_uuid != internal_uuid != admin_uuid
Migration and Versioning¶
Salt-Based Version Migration¶
Use salts to version your UUID generation scheme:
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from typing import Dict, Tuple
from uuid import UUID
class UUIDMigrationService:
"""Manage UUID schema migrations using salts"""
def __init__(self, namespace: str):
self.namespace = namespace
self.generators = {}
def get_generator(self, version: str) -> UUIDGenerator:
"""Get generator for a specific version"""
if version not in self.generators:
config = IDConfig(
namespace=Namespace(self.namespace),
salt=version
)
self.generators[version] = UUIDGenerator(config)
return self.generators[version]
def migrate_entity(
self,
entity_type: str,
old_version: str,
new_version: str,
**attributes
) -> Tuple[UUID, UUID]:
"""Generate both old and new UUIDs for migration"""
old_gen = self.get_generator(old_version)
new_gen = self.get_generator(new_version)
old_uuid = old_gen.generate(entity_type, **attributes)
new_uuid = new_gen.generate(entity_type, **attributes)
return old_uuid, new_uuid
# Usage: Migrating from v1 to v2 UUID scheme
migration = UUIDMigrationService("users.myapp.com")
# Generate migration mapping
users = [
{"email": "alice@example.com", "region": "us"},
{"email": "bob@example.com", "region": "eu"},
]
migration_map = {}
for user in users:
old_uuid, new_uuid = migration.migrate_entity(
"user",
old_version="v1",
new_version="v2",
**user
)
migration_map[old_uuid] = new_uuid
print(f"Migrate {old_uuid} -> {new_uuid}")
# Update database
# for old_uuid, new_uuid in migration_map.items():
# db.execute("UPDATE users SET id = %s WHERE id = %s", (new_uuid, old_uuid))
Zero-Downtime Migration Strategy¶
from uuid_forge import UUIDGenerator, IDConfig, Namespace
from uuid import UUID
from typing import Optional
class DualVersionUUIDGenerator:
"""Support both old and new UUID versions during migration"""
def __init__(self, namespace: str, old_salt: str, new_salt: str):
old_config = IDConfig(namespace=Namespace(namespace), salt=old_salt)
new_config = IDConfig(namespace=Namespace(namespace), salt=new_salt)
self.old_generator = UUIDGenerator(old_config)
self.new_generator = UUIDGenerator(new_config)
self.use_new_version = False # Feature flag
def generate(self, entity_type: str, **attributes) -> UUID:
"""Generate UUID using current version"""
if self.use_new_version:
return self.new_generator.generate(entity_type, **attributes)
return self.old_generator.generate(entity_type, **attributes)
def lookup_uuid(self, entity_type: str, **attributes) -> UUID:
"""Try new version first, fallback to old for lookups"""
if self.use_new_version:
return self.new_generator.generate(entity_type, **attributes)
# During migration, might need to check both versions
return self.old_generator.generate(entity_type, **attributes)
# Migration phases:
# Phase 1: Deploy code with both generators, use_new_version=False
dual = DualVersionUUIDGenerator("users.myapp.com", "v1", "v2")
# Phase 2: Run migration script to update all UUIDs in database
# Phase 3: Enable new version via feature flag
dual.use_new_version = True
# Phase 4: After verification, remove old generator code
Common Pitfalls to Avoid¶
❌ Inconsistent Input Normalization¶
from uuid_forge import UUIDGenerator, IDConfig, Namespace
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config)
# ❌ DON'T: Inconsistent casing and whitespace
uuid1 = generator.generate("user", email="User@Example.Com ")
uuid2 = generator.generate("user", email="user@example.com")
# These will be DIFFERENT because inputs differ!
# ✅ DO: Always normalize inputs
def normalize_email(email: str) -> str:
return email.lower().strip()
uuid1 = generator.generate("user", email=normalize_email("User@Example.Com "))
uuid2 = generator.generate("user", email=normalize_email("user@example.com"))
# Now these are the SAME ✓
❌ Creating New Generator Instances Repeatedly¶
# ❌ DON'T: Create new generator every call (inefficient)
def get_user_uuid_bad(user_email: str):
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
generator = UUIDGenerator(config) # New instance every time!
return generator.generate("user", email=user_email)
# ✅ DO: Create once, reuse many times
class UserService:
def __init__(self):
config = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
self.generator = UUIDGenerator(config) # Created once
def get_user_uuid(self, user_email: str):
return self.generator.generate("user", email=user_email)
❌ Mixing Salts/Namespaces for Same Entity¶
# ❌ DON'T: Use different configurations for the same entity type
config_a = IDConfig(namespace=Namespace("users.myapp.com"), salt="v1")
config_b = IDConfig(namespace=Namespace("users.myapp.com"), salt="v2")
gen_a = UUIDGenerator(config_a)
gen_b = UUIDGenerator(config_b)
# These will be DIFFERENT UUIDs for the same user!
uuid_a = gen_a.generate("user", email="alice@example.com")
uuid_b = gen_b.generate("user", email="alice@example.com")
assert uuid_a != uuid_b # Different salts = different UUIDs
# ✅ DO: Use consistent configuration throughout your application
❌ Including Timestamps in Deterministic UUIDs¶
from datetime import datetime
# ❌ DON'T: Include current timestamp (non-deterministic!)
def create_event_uuid_bad(event_type: str, user_id: int):
return generator.generate(
"event",
event_type=event_type,
user_id=user_id,
timestamp=datetime.utcnow().isoformat() # Changes every call!
)
# This defeats the purpose - UUIDs will be different every time!
# ✅ DO: Only include deterministic attributes
def create_event_uuid_good(event_type: str, user_id: int, event_date: str):
return generator.generate(
"event",
event_type=event_type,
user_id=user_id,
event_date=event_date # Use date, not timestamp
)
❌ Forgetting Entity Type Parameter¶
# ❌ DON'T: Forget the entity_type parameter
# uuid = generator.generate(email="alice@example.com") # TypeError!
# ✅ DO: Always include entity_type as first argument
uuid = generator.generate("user", email="alice@example.com")
Next Steps¶
- Use Cases - See real-world implementation examples
- API Reference - Detailed API documentation
- Development - Contributing to UUID-Forge