Skip to content

Parsing and Validation

This guide covers how to parse UUID strings and validate input.

Parsing Typed UUID Strings

Using from_string()

The from_string() class method parses a string into a TypedUUID:

from typed_uuid import create_typed_uuid_class

UserUUID = create_typed_uuid_class('User', 'user')

# Parse a typed UUID string
user_id = UserUUID.from_string('user-550e8400-e29b-41d4-a716-446655440000')
print(user_id.uuid)  # 550e8400-e29b-41d4-a716-446655440000

Accepted Formats

from_string() accepts multiple formats:

# Full typed format
user_id = UserUUID.from_string('user-550e8400-e29b-41d4-a716-446655440000')

# Plain UUID (type prefix added automatically)
user_id = UserUUID.from_string('550e8400-e29b-41d4-a716-446655440000')

# Case-insensitive UUID part
user_id = UserUUID.from_string('user-550E8400-E29B-41D4-A716-446655440000')

Type Validation

When parsing typed strings, the type must match:

UserUUID = create_typed_uuid_class('User', 'user')
OrderUUID = create_typed_uuid_class('Order', 'order')

# This works
user_id = UserUUID.from_string('user-550e8400-e29b-41d4-a716-446655440000')

# This raises InvalidTypeIDError - wrong type
user_id = UserUUID.from_string('order-550e8400-e29b-41d4-a716-446655440000')
# InvalidTypeIDError: Type mismatch: expected user, got order

Auto-Detection with parse()

When you don't know the type ahead of time:

from typed_uuid import TypedUUID, create_typed_uuid_class

# Register types first
UserUUID = create_typed_uuid_class('User', 'user')
OrderUUID = create_typed_uuid_class('Order', 'order')

# Auto-detect type from string
uuid1 = TypedUUID.parse('user-550e8400-e29b-41d4-a716-446655440000')
uuid2 = TypedUUID.parse('order-550e8400-e29b-41d4-a716-446655440000')

print(isinstance(uuid1, UserUUID))   # True
print(isinstance(uuid2, OrderUUID))  # True

parse() with Short Format

Auto-detection also works with short format:

# Standard format
uuid1 = TypedUUID.parse('user-550e8400-e29b-41d4-a716-446655440000')

# Short format
uuid2 = TypedUUID.parse('user_7n42DGM5Tflk9n8mt7Fhc7')

# Both return UserUUID instances

Validation Methods

Using validate()

The validate() method accepts multiple input types:

from uuid import UUID

UserUUID = create_typed_uuid_class('User', 'user')

# Validate string input
user_id = UserUUID.validate('user-550e8400-e29b-41d4-a716-446655440000')

# Validate UUID object
user_id = UserUUID.validate(UUID('550e8400-e29b-41d4-a716-446655440000'))

# Validate existing TypedUUID
existing = UserUUID()
user_id = UserUUID.validate(existing)

# Returns the same instance if already correct type
print(user_id is existing)  # True

Input Type Handling

Input Type Behavior
str Parsed as UUID string
UUID Wrapped in TypedUUID
Same TypedUUID type Returned as-is
Different TypedUUID type Raises ValueError if type_id differs
Other types Raises ValueError

Error Handling

InvalidUUIDError

Raised when the UUID format is invalid:

from typed_uuid import InvalidUUIDError

try:
    user_id = UserUUID.from_string('not-a-valid-uuid')
except InvalidUUIDError as e:
    print(f"Invalid UUID: {e}")

InvalidTypeIDError

Raised when the type_id is invalid or mismatched:

from typed_uuid import InvalidTypeIDError

try:
    # Wrong type prefix
    user_id = UserUUID.from_string('order-550e8400-e29b-41d4-a716-446655440000')
except InvalidTypeIDError as e:
    print(f"Type mismatch: {e}")

Catching All TypedUUID Errors

Both errors inherit from TypedUUIDError:

from typed_uuid import TypedUUIDError

try:
    user_id = UserUUID.from_string(some_input)
except TypedUUIDError as e:
    print(f"Error: {e}")

Validation Patterns

API Input Validation

from typed_uuid import InvalidUUIDError, InvalidTypeIDError

def get_user(user_id_str: str):
    """Get user by ID with validation."""
    try:
        user_id = UserUUID.from_string(user_id_str)
    except InvalidUUIDError:
        raise ValueError(f"Invalid user ID format: {user_id_str}")
    except InvalidTypeIDError:
        raise ValueError(f"Not a user ID: {user_id_str}")

    return fetch_user(user_id)

Safe Parsing with Default

def parse_user_id(value: str, default=None):
    """Parse user ID, returning default on failure."""
    try:
        return UserUUID.from_string(value)
    except (InvalidUUIDError, InvalidTypeIDError):
        return default

# Usage
user_id = parse_user_id(request.args.get('id'), default=None)
if user_id is None:
    return {"error": "Invalid user ID"}, 400

Batch Validation

def validate_user_ids(ids: list[str]) -> tuple[list[UserUUID], list[str]]:
    """Validate a list of user IDs, separating valid from invalid."""
    valid = []
    invalid = []

    for id_str in ids:
        try:
            valid.append(UserUUID.from_string(id_str))
        except (InvalidUUIDError, InvalidTypeIDError):
            invalid.append(id_str)

    return valid, invalid

# Usage
valid_ids, invalid_ids = validate_user_ids(request.json['user_ids'])
if invalid_ids:
    return {"error": "Invalid IDs", "invalid": invalid_ids}, 400

Format Pattern

Get a regex pattern for validation:

pattern = UserUUID.format_pattern()
print(pattern)  # ^[a-zA-Z0-9]+-[0-9a-f]{8}-[0-9a-f]{4}-...

import re
if re.match(pattern, some_string):
    print("Looks like a valid typed UUID")

This is useful for:

  • Pre-validation before parsing
  • Database constraints
  • API schema validation