CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-swiftclient

OpenStack Object Storage API Client Library

Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive error handling with detailed HTTP context, transaction IDs, and Swift-specific error information.

Capabilities

ClientException Class

Main exception class for Swift client operations with comprehensive HTTP context and error details.

class ClientException(Exception):
    def __init__(
        self,
        msg,
        http_scheme='',
        http_host='',
        http_port='',
        http_path='',
        http_query='',
        http_status=None,
        http_reason='',
        http_device='',
        http_response_content='',
        http_response_headers=None
    ):
        """
        Swift client exception with HTTP context.

        Parameters:
        - msg: str, primary error message
        - http_scheme: str, HTTP scheme (http/https)
        - http_host: str, HTTP host
        - http_port: str, HTTP port
        - http_path: str, HTTP request path
        - http_query: str, HTTP query string
        - http_status: int, HTTP status code
        - http_reason: str, HTTP reason phrase
        - http_device: str, Swift device identifier
        - http_response_content: str, HTTP response body
        - http_response_headers: dict, HTTP response headers

        Attributes:
        - msg: Primary error message
        - http_*: HTTP request/response context
        - transaction_id: Swift transaction ID from response headers
        """

    @classmethod
    def from_response(cls, resp, msg=None, body=None):
        """
        Create ClientException from HTTP response.

        Parameters:
        - resp: HTTP response object
        - msg: str, optional custom message (defaults to status and reason)
        - body: bytes, optional response body (defaults to response content)

        Returns:
        ClientException: exception with response context
        """

Common Exception Scenarios

Authentication Errors

# HTTP 401 Unauthorized
try:
    conn = Connection(authurl='...', user='...', key='wrong_password')
    conn.get_account()
except ClientException as e:
    if e.http_status == 401:
        print(f"Authentication failed: {e.msg}")
        print(f"Check credentials and try again")
    # e.transaction_id contains Swift transaction ID for debugging

Permission Errors

# HTTP 403 Forbidden
try:
    conn.put_object('restricted_container', 'file.txt', 'content')
except ClientException as e:
    if e.http_status == 403:
        print(f"Access denied: {e.msg}")
        print(f"Check account permissions for container")

Not Found Errors

# HTTP 404 Not Found
try:
    headers, content = conn.get_object('nonexistent', 'file.txt')
except ClientException as e:
    if e.http_status == 404:
        print(f"Object not found: {e.msg}")
        print(f"Container: {e.http_path.split('/')[-2]}")
        print(f"Object: {e.http_path.split('/')[-1]}")

Conflict Errors

# HTTP 409 Conflict
try:
    conn.delete_container('container_with_objects')
except ClientException as e:
    if e.http_status == 409:
        print(f"Cannot delete non-empty container: {e.msg}")
        print("Delete all objects first, then retry container deletion")

Rate Limiting

# HTTP 498 Rate Limited or HTTP 429 Too Many Requests
try:
    # Rapid operations that might trigger rate limiting
    for i in range(1000):
        conn.put_object('container', f'object_{i}', f'content_{i}')
except ClientException as e:
    if e.http_status in (498, 429):
        print(f"Rate limited: {e.msg}")
        print("Reduce request rate or increase retry backoff")

Server Errors

# HTTP 5xx Server Errors
try:
    conn.get_object('container', 'object')
except ClientException as e:
    if 500 <= e.http_status < 600:
        print(f"Server error: {e.http_status} {e.http_reason}")
        print(f"Transaction ID: {e.transaction_id}")
        print("Retry the operation or contact Swift administrator")

Usage Examples

Comprehensive Error Handling

from swiftclient import Connection, ClientException
import time

def robust_swift_operation(conn, container, obj, content, max_retries=3):
    """Perform Swift operation with comprehensive error handling."""

    for attempt in range(max_retries + 1):
        try:
            etag = conn.put_object(container, obj, content)
            print(f"Successfully uploaded {obj} with ETag {etag}")
            return etag

        except ClientException as e:
            print(f"Attempt {attempt + 1} failed: {e}")

            if e.http_status == 401:
                # Authentication error - don't retry
                print("Authentication failed - check credentials")
                raise

            elif e.http_status == 403:
                # Permission error - don't retry
                print("Access denied - check permissions")
                raise

            elif e.http_status == 404:
                # Container doesn't exist - create it and retry
                print(f"Container '{container}' not found, creating...")
                try:
                    conn.put_container(container)
                    print(f"Created container '{container}'")
                    continue  # Retry the upload
                except ClientException as create_error:
                    print(f"Failed to create container: {create_error}")
                    raise

            elif e.http_status == 409:
                # Conflict - might be temporary, retry
                if attempt < max_retries:
                    wait_time = 2 ** attempt  # Exponential backoff
                    print(f"Conflict error, retrying in {wait_time}s...")
                    time.sleep(wait_time)
                    continue
                else:
                    raise

            elif e.http_status in (498, 429):
                # Rate limiting - back off and retry
                if attempt < max_retries:
                    wait_time = 10 * (2 ** attempt)  # Longer backoff for rate limits
                    print(f"Rate limited, retrying in {wait_time}s...")
                    time.sleep(wait_time)
                    continue
                else:
                    raise

            elif e.http_status is None:
                # Network error
                if attempt < max_retries:
                    wait_time = 5 * (2 ** attempt)
                    print(f"Network error, retrying in {wait_time}s...")
                    time.sleep(wait_time)
                    continue
                else:
                    print("Max retries exceeded for network errors")
                    raise

            elif 500 <= e.http_status < 600:
                # Server error - retry with backoff
                if attempt < max_retries:
                    wait_time = 3 * (2 ** attempt)
                    print(f"Server error {e.http_status}, retrying in {wait_time}s...")
                    print(f"Transaction ID: {e.transaction_id}")
                    time.sleep(wait_time)
                    continue
                else:
                    print(f"Max retries exceeded for server error {e.http_status}")
                    print(f"Transaction ID: {e.transaction_id}")
                    raise

            else:
                # Other HTTP error - don't retry
                print(f"HTTP {e.http_status} {e.http_reason} - not retrying")
                raise

        except Exception as e:
            # Non-HTTP error (programming error, etc.)
            print(f"Unexpected error: {type(e).__name__}: {e}")
            raise

    # Should never reach here
    raise RuntimeError("Maximum retries exceeded")

# Usage
conn = Connection(...)
try:
    robust_swift_operation(conn, 'documents', 'important.txt', 'Important content')
except ClientException as e:
    print(f"Final error: {e}")

Error Context Analysis

def analyze_swift_error(e):
    """Analyze ClientException and provide detailed context."""

    print(f"Error: {e.msg}")
    print(f"HTTP Status: {e.http_status} {e.http_reason}")

    if e.transaction_id:
        print(f"Transaction ID: {e.transaction_id}")

    # Reconstruct URL
    if e.http_scheme and e.http_host:
        url = f"{e.http_scheme}://{e.http_host}"
        if e.http_port:
            url += f":{e.http_port}"
        if e.http_path:
            url += e.http_path
        if e.http_query:
            url += f"?{e.http_query}"
        print(f"Request URL: {url}")

    # Parse path for Swift components
    if e.http_path:
        path_parts = e.http_path.strip('/').split('/')
        if len(path_parts) >= 2:
            print(f"Swift Account: {path_parts[1]}")
        if len(path_parts) >= 3:
            print(f"Container: {path_parts[2]}")
        if len(path_parts) >= 4:
            print(f"Object: {'/'.join(path_parts[3:])}")

    # Response content analysis
    if e.http_response_content:
        content = e.http_response_content
        if len(content) > 200:
            content = content[:200] + "... (truncated)"
        print(f"Response content: {content}")

    # Common error patterns
    if e.http_status == 422:
        print("Unprocessable Entity - check request format and parameters")
    elif e.http_status == 413:
        print("Request Entity Too Large - object exceeds size limits")
    elif e.http_status == 412:
        print("Precondition Failed - check If-Match, If-None-Match headers")
    elif e.http_status == 416:
        print("Range Not Satisfiable - check Range header format")

# Usage
try:
    conn.get_object('container', 'object')
except ClientException as e:
    analyze_swift_error(e)

Bulk Operation Error Handling

from swiftclient.service import SwiftService, SwiftError

def handle_bulk_errors(results_generator, operation_name):
    """Handle errors from SwiftService bulk operations."""

    success_count = 0
    error_count = 0

    for result in results_generator:
        if result['success']:
            success_count += 1
            print(f"✓ {result.get('object', result.get('container', 'item'))}")
        else:
            error_count += 1
            error = result['error']
            item = result.get('object', result.get('container', 'unknown'))

            print(f"✗ {item}: {error}")

            # Handle specific SwiftError types
            if isinstance(error, SwiftError):
                if error.exception:
                    underlying = error.exception
                    if isinstance(underlying, ClientException):
                        if underlying.http_status == 404:
                            print(f"   → Item not found, skipping")
                        elif underlying.http_status in (401, 403):
                            print(f"   → Access denied, check permissions")
                        elif underlying.http_status >= 500:
                            print(f"   → Server error, transaction: {underlying.transaction_id}")

            # Container context
            if error.container:
                print(f"   → Container: {error.container}")

            # Object context
            if error.obj:
                print(f"   → Object: {error.obj}")

            # Segment context (for large objects)
            if error.segment:
                print(f"   → Segment: {error.segment}")

    print(f"\n{operation_name} Summary:")
    print(f"  Success: {success_count}")
    print(f"  Errors:  {error_count}")

    return success_count, error_count

# Usage
with SwiftService(options=auth_options) as swift:
    # Handle upload errors
    upload_objects = ['file1.txt', 'file2.txt', 'missing_file.txt']
    results = swift.upload('container', upload_objects)
    handle_bulk_errors(results, "Upload")

    # Handle download errors
    download_objects = ['existing.txt', 'missing.txt']
    results = swift.download('container', download_objects)
    handle_bulk_errors(results, "Download")

Connection Error Recovery

def create_resilient_connection(options, max_connection_attempts=3):
    """Create Swift connection with automatic retry on connection errors."""

    for attempt in range(max_connection_attempts):
        try:
            conn = Connection(**options)
            # Test connection
            conn.head_account()
            print("Connection established successfully")
            return conn

        except ClientException as e:
            if e.http_status == 401:
                print(f"Authentication failed: {e.msg}")
                if 'token' in options:
                    print("Token may be expired, removing from options")
                    options = options.copy()
                    del options['token']
                    continue
                else:
                    raise  # Credential error, don't retry

            elif e.http_status is None:
                # Network error
                if attempt < max_connection_attempts - 1:
                    wait_time = 5 * (2 ** attempt)
                    print(f"Connection failed, retrying in {wait_time}s...")
                    time.sleep(wait_time)
                    continue
                else:
                    raise

            else:
                # Other HTTP error
                raise

        except Exception as e:
            print(f"Unexpected connection error: {e}")
            if attempt < max_connection_attempts - 1:
                time.sleep(2)
                continue
            else:
                raise

    raise RuntimeError("Failed to establish connection after all attempts")

# Usage
options = {
    'authurl': 'https://identity.example.com:5000/v3',
    'user': 'myuser',
    'key': 'mypassword',
    'auth_version': '3',
    'os_options': {'project_name': 'myproject'}
}

conn = create_resilient_connection(options)

Install with Tessl CLI

npx tessl i tessl/pypi-python-swiftclient

docs

authentication.md

bulk-operations.md

client-connection.md

command-line-interface.md

exceptions.md

index.md

low-level-operations.md

utilities.md

tile.json