CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cloudinary

Python and Django SDK for Cloudinary, a cloud-based image and video management service with comprehensive transformation, optimization, and delivery capabilities

Overall
score

94%

Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive exception hierarchy for handling API errors, authentication issues, and operational failures.

Capabilities

Base Exception Classes

Core exception classes that form the foundation of Cloudinary error handling.

class Error(Exception):
    """Base exception class for all Cloudinary errors.
    
    All Cloudinary-specific exceptions inherit from this base class, allowing
    for comprehensive error handling and logging.
    
    Attributes:
        message (str): Error message describing the issue
        http_code (int): HTTP status code associated with the error (if applicable)
    """
    
    def __init__(self, message=None, http_code=None):
        """Initialize base error.
        
        Args:
            message (str, optional): Error message
            http_code (int, optional): HTTP status code
        """
        super(Error, self).__init__(message)
        self.message = message
        self.http_code = http_code
    
    def __str__(self):
        """Return string representation of the error."""
        return self.message or super(Error, self).__str__()

HTTP and API Errors

Exceptions related to HTTP communication and API responses.

class NotFound(Error):
    """Exception raised when a requested resource is not found.
    
    Typically corresponds to HTTP 404 responses from the Cloudinary API.
    Common scenarios:
    - Requesting a non-existent public_id
    - Accessing a deleted resource
    - Referencing an invalid transformation
    """

class NotAllowed(Error):
    """Exception raised when an operation is not permitted.
    
    Typically corresponds to HTTP 403 responses indicating insufficient permissions
    or account limitations.
    Common scenarios:
    - Attempting operations without proper API credentials
    - Exceeding account quotas or limits
    - Accessing restricted functionality
    """

class AlreadyExists(Error):
    """Exception raised when attempting to create a resource that already exists.
    
    Common scenarios:
    - Creating a transformation with an existing name
    - Uploading with overwrite=False to an existing public_id
    - Creating upload presets with duplicate names
    """

class RateLimited(Error):
    """Exception raised when API rate limits are exceeded.
    
    Indicates that too many requests have been made within the allowed time window.
    The client should implement backoff and retry logic.
    
    Attributes:
        retry_after (int): Seconds to wait before retrying (if provided by API)
    """
    
    def __init__(self, message=None, http_code=None, retry_after=None):
        """Initialize rate limit error.
        
        Args:
            message (str, optional): Error message
            http_code (int, optional): HTTP status code (typically 429)
            retry_after (int, optional): Seconds to wait before retry
        """
        super(RateLimited, self).__init__(message, http_code)
        self.retry_after = retry_after

class BadRequest(Error):
    """Exception raised for malformed requests or invalid parameters.
    
    Typically corresponds to HTTP 400 responses indicating client-side errors.
    Common scenarios:
    - Invalid transformation parameters
    - Malformed public_ids or resource identifiers
    - Missing required parameters
    - Invalid file formats or types
    """

class GeneralError(Error):
    """Exception raised for general API errors that don't fit other categories.
    
    Used for unexpected server errors, temporary service issues, or other
    unspecified problems with API operations.
    """

class AuthorizationRequired(Error):
    """Exception raised when authentication is required but missing or invalid.
    
    Typically corresponds to HTTP 401 responses indicating authentication failures.
    Common scenarios:
    - Missing API credentials
    - Invalid API key or secret
    - Expired or malformed authentication tokens
    - Attempting authenticated operations without proper credentials
    """

Error Handling Patterns

Basic Exception Handling

from cloudinary import uploader, api
from cloudinary.exceptions import Error, NotFound, NotAllowed, BadRequest, AuthorizationRequired

try:
    # Upload operation
    result = uploader.upload("nonexistent_file.jpg")
except NotFound as e:
    print(f"File not found: {e}")
except BadRequest as e:
    print(f"Invalid request: {e}")
except AuthorizationRequired as e:
    print(f"Authentication failed: {e}")
except Error as e:
    print(f"Cloudinary error: {e}")
    if hasattr(e, 'http_code'):
        print(f"HTTP status: {e.http_code}")
except Exception as e:
    print(f"Unexpected error: {e}")

API Operation Error Handling

from cloudinary import api
from cloudinary.exceptions import NotFound, NotAllowed, RateLimited

def safe_get_resource(public_id):
    """Safely retrieve resource with comprehensive error handling."""
    try:
        return api.resource(public_id)
    except NotFound:
        print(f"Resource '{public_id}' not found")
        return None
    except NotAllowed as e:
        print(f"Access denied for '{public_id}': {e}")
        return None
    except RateLimited as e:
        print(f"Rate limited. Retry after: {getattr(e, 'retry_after', 60)} seconds")
        return None
    except Error as e:
        print(f"Cloudinary API error: {e}")
        return None

def safe_delete_resources(public_ids):
    """Safely delete multiple resources with error handling."""
    try:
        result = api.delete_resources(public_ids)
        
        # Check for partial failures
        if result.get('partial'):
            print("Some resources could not be deleted:")
            for public_id in result.get('deleted', {}):
                if result['deleted'][public_id] != 'deleted':
                    print(f"  {public_id}: {result['deleted'][public_id]}")
        
        return result
    except NotAllowed as e:
        print(f"Deletion not allowed: {e}")
        return None
    except Error as e:
        print(f"Error during deletion: {e}")
        return None

Upload Error Handling

from cloudinary import uploader
from cloudinary.exceptions import BadRequest, NotAllowed, GeneralError
import time

def robust_upload(file_path, **options):
    """Upload with retry logic and comprehensive error handling."""
    max_retries = 3
    retry_delay = 1
    
    for attempt in range(max_retries):
        try:
            result = uploader.upload(file_path, **options)
            print(f"Upload successful: {result['public_id']}")
            return result
            
        except BadRequest as e:
            print(f"Invalid upload parameters: {e}")
            # Don't retry for bad requests
            return None
            
        except NotAllowed as e:
            print(f"Upload not allowed: {e}")
            return None
            
        except RateLimited as e:
            retry_after = getattr(e, 'retry_after', retry_delay * (2 ** attempt))
            print(f"Rate limited. Waiting {retry_after} seconds...")
            time.sleep(retry_after)
            continue
            
        except GeneralError as e:
            if attempt < max_retries - 1:
                print(f"Upload failed (attempt {attempt + 1}): {e}")
                print(f"Retrying in {retry_delay} seconds...")
                time.sleep(retry_delay)
                retry_delay *= 2
                continue
            else:
                print(f"Upload failed after {max_retries} attempts: {e}")
                return None
                
        except Error as e:
            print(f"Unexpected Cloudinary error: {e}")
            return None
            
        except Exception as e:
            print(f"System error during upload: {e}")
            return None
    
    return None

# Usage
result = robust_upload(
    "image.jpg",
    public_id="my_image",
    folder="uploads",
    overwrite=True
)

if result:
    print(f"Successfully uploaded: {result['secure_url']}")
else:
    print("Upload failed after all retry attempts")

Batch Operation Error Handling

from cloudinary import api
from cloudinary.exceptions import Error

def process_resources_safely(public_ids, operation_func, **kwargs):
    """Process multiple resources with individual error handling."""
    results = []
    errors = []
    
    for public_id in public_ids:
        try:
            result = operation_func(public_id, **kwargs)
            results.append({'public_id': public_id, 'success': True, 'result': result})
        except NotFound:
            error_msg = f"Resource '{public_id}' not found"
            errors.append({'public_id': public_id, 'error': error_msg})
            results.append({'public_id': public_id, 'success': False, 'error': error_msg})
        except NotAllowed as e:
            error_msg = f"Operation not allowed for '{public_id}': {e}"
            errors.append({'public_id': public_id, 'error': error_msg})
            results.append({'public_id': public_id, 'success': False, 'error': error_msg})
        except Error as e:
            error_msg = f"Error processing '{public_id}': {e}"
            errors.append({'public_id': public_id, 'error': error_msg})
            results.append({'public_id': public_id, 'success': False, 'error': error_msg})
    
    return {
        'results': results,
        'errors': errors,
        'success_count': len([r for r in results if r['success']]),
        'error_count': len(errors)
    }

# Usage examples
def get_resource_details(public_id):
    return api.resource(public_id)

def update_resource_tags(public_id, tags):
    return api.update(public_id, tags=tags)

# Process multiple resources
public_ids = ["image1", "image2", "nonexistent", "image3"]

# Get details for all resources
details_result = process_resources_safely(public_ids, get_resource_details)
print(f"Successfully retrieved {details_result['success_count']} resources")
print(f"Failed to retrieve {details_result['error_count']} resources")

# Update tags for all resources
tag_result = process_resources_safely(
    public_ids, 
    update_resource_tags, 
    tags=["batch_processed", "updated"]
)

Advanced Error Recovery

import logging
from cloudinary.exceptions import *

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class CloudinaryErrorHandler:
    """Advanced error handler with logging and recovery strategies."""
    
    def __init__(self):
        self.error_counts = {}
    
    def handle_error(self, operation, error, context=None):
        """Handle errors with logging and recovery suggestions."""
        error_type = type(error).__name__
        self.error_counts[error_type] = self.error_counts.get(error_type, 0) + 1
        
        logger.error(f"{operation} failed: {error_type} - {error}")
        
        if context:
            logger.error(f"Context: {context}")
        
        # Provide recovery suggestions
        if isinstance(error, NotFound):
            logger.info("Recovery: Check if the resource exists or verify the public_id")
        elif isinstance(error, AuthorizationRequired):
            logger.info("Recovery: Verify API credentials and permissions")
        elif isinstance(error, RateLimited):
            retry_after = getattr(error, 'retry_after', 60)
            logger.info(f"Recovery: Wait {retry_after} seconds before retrying")
        elif isinstance(error, BadRequest):
            logger.info("Recovery: Check request parameters and format")
        elif isinstance(error, NotAllowed):
            logger.info("Recovery: Check account limits and permissions")
    
    def get_error_summary(self):
        """Get summary of encountered errors."""
        return dict(self.error_counts)

# Usage
error_handler = CloudinaryErrorHandler()

try:
    result = api.resource("nonexistent_image")
except Error as e:
    error_handler.handle_error(
        "Get resource", 
        e, 
        context={"public_id": "nonexistent_image"}
    )

# Get error statistics
print("Error summary:", error_handler.get_error_summary())

Install with Tessl CLI

npx tessl i tessl/pypi-cloudinary

docs

admin-api.md

configuration.md

django-integration.md

exceptions.md

index.md

provisioning-api.md

search-api.md

transformations.md

upload-api.md

tile.json