CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-socketio

Socket.IO server and client for Python providing real-time bidirectional communication

Pending
Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive exception hierarchy for handling Socket.IO-specific errors including connection failures, timeouts, namespace issues, and disconnection scenarios. These exceptions provide detailed error information for robust error handling in Socket.IO applications.

Capabilities

SocketIOError

Base exception class for all Socket.IO-related errors. All other Socket.IO exceptions inherit from this class.

class SocketIOError(Exception):
    """
    Base exception class for all Socket.IO errors.
    
    Inherits from: Exception
    
    This is the base class for all Socket.IO-specific exceptions.
    Catch this exception to handle any Socket.IO-related error.
    """

Usage Example

import socketio

sio = socketio.Client()

try:
    sio.connect('http://localhost:5000')
    sio.emit('message', {'text': 'Hello'})
except socketio.SocketIOError as e:
    print(f'Socket.IO error occurred: {e}')
    # Handle any Socket.IO-related error

ConnectionError

Base class for connection-related errors. Raised when there are issues establishing or maintaining connections.

class ConnectionError(SocketIOError):
    """
    Base class for connection-related errors.
    
    Inherits from: SocketIOError
    
    This exception is raised when there are problems with Socket.IO connections,
    such as network issues, server unavailability, or connection failures.
    """

Usage Example

import socketio

sio = socketio.Client()

try:
    sio.connect('http://unreachable-server:5000')
except socketio.ConnectionError as e:
    print(f'Connection error: {e}')
    # Handle connection-related issues
    # Try alternative server, show offline mode, etc.

ConnectionRefusedError

Raised when a connection attempt is refused by the server, typically due to authentication failures or server policies.

class ConnectionRefusedError(ConnectionError):
    """
    Connection refused exception.
    
    Inherits from: ConnectionError
    
    Attributes:
        error_args (dict): Dictionary containing error details with 'message' key
                          and optional 'data' key for additional information
    """
    
    def __init__(self, *args):
        """
        Initialize the connection refused error.
        
        Args:
            *args: Error arguments, typically a message string or error dict
        """

Usage Example

import socketio

sio = socketio.Client()

@sio.event
def connect_error(data):
    print(f'Connection failed: {data}')

try:
    sio.connect('http://localhost:5000', auth={'token': 'invalid_token'})
except socketio.ConnectionRefusedError as e:
    print(f'Connection refused: {e}')
    if hasattr(e, 'error_args'):
        error_info = e.error_args
        print(f'Error message: {error_info.get("message")}')
        if 'data' in error_info:
            print(f'Additional data: {error_info["data"]}')
    
    # Handle authentication failure
    # Prompt for new credentials, redirect to login, etc.

# Server-side example that raises ConnectionRefusedError
sio_server = socketio.Server()

@sio_server.event
def connect(sid, environ, auth):
    if not auth or auth.get('token') != 'valid_token':
        raise socketio.ConnectionRefusedError('Authentication failed')
    print(f'Client {sid} authenticated successfully')

TimeoutError

Raised when a Socket.IO operation exceeds its specified timeout period.

class TimeoutError(SocketIOError):
    """
    Timeout-related exception.
    
    Inherits from: SocketIOError
    
    This exception is raised when Socket.IO operations take longer than
    the specified timeout period. Common scenarios include call() operations
    waiting for responses and connection attempts timing out.
    """

Usage Example

import socketio

sio = socketio.Client()
sio.connect('http://localhost:5000')

try:
    # This will raise TimeoutError if server doesn't respond within 5 seconds
    response = sio.call('slow_operation', {'data': 'test'}, timeout=5)
    print(f'Response: {response}')
except socketio.TimeoutError as e:
    print(f'Operation timed out: {e}')
    # Handle timeout scenario
    # Show loading indicator, retry, or provide fallback

# Async client example
async def async_example():
    sio = socketio.AsyncClient()
    await sio.connect('http://localhost:5000')
    
    try:
        response = await sio.call('async_operation', timeout=3)
        print(f'Async response: {response}')
    except socketio.TimeoutError as e:
        print(f'Async operation timed out: {e}')
    finally:
        await sio.disconnect()

# Server-side handler that might cause timeout
@sio_server.event
def slow_operation(sid, data):
    import time
    time.sleep(10)  # This will cause TimeoutError on client
    return {'result': 'completed'}

BadNamespaceError

Raised when attempting to use an invalid or unauthorized namespace.

class BadNamespaceError(SocketIOError):
    """
    Invalid namespace exception.
    
    Inherits from: SocketIOError
    
    This exception is raised when:
    - Attempting to connect to a namespace that doesn't exist
    - Using a namespace that the client is not authorized to access
    - Malformed namespace names
    """

Usage Example

import socketio

sio = socketio.Client()

try:
    sio.connect('http://localhost:5000', namespaces=['/chat', '/invalid-namespace'])
except socketio.BadNamespaceError as e:
    print(f'Invalid namespace: {e}')
    # Handle namespace error
    # Connect to default namespace or show error message

# Using specific namespace that might not exist
try:
    sio.emit('message', {'text': 'Hello'}, namespace='/nonexistent')
except socketio.BadNamespaceError as e:
    print(f'Namespace error: {e}')
    # Fall back to default namespace
    sio.emit('message', {'text': 'Hello'})

# Server-side namespace configuration
sio_server = socketio.Server()

# Only allow specific namespaces
@sio_server.event
def connect(sid, environ, auth):
    # Validate namespace access based on authentication
    namespace = environ.get('PATH_INFO', '/').split('/')[1]
    if namespace not in ['chat', 'game'] and auth.get('role') != 'admin':
        raise socketio.BadNamespaceError(f'Access denied to namespace: /{namespace}')

DisconnectedError

Raised when attempting to perform operations on a disconnected client or when unexpected disconnections occur.

class DisconnectedError(SocketIOError):
    """
    Client disconnection exception.
    
    Inherits from: SocketIOError
    
    This exception is raised when:
    - Attempting to emit events on a disconnected client
    - Trying to access session data for disconnected clients
    - Performing operations that require an active connection
    """

Usage Example

import socketio

sio = socketio.Client()

@sio.event
def disconnect():
    print('Disconnected from server')

try:
    sio.connect('http://localhost:5000')
    
    # Simulate network interruption or server shutdown
    # ... connection is lost ...
    
    # This will raise DisconnectedError
    sio.emit('message', {'text': 'Hello'})
    
except socketio.DisconnectedError as e:
    print(f'Client disconnected: {e}')
    # Handle disconnection
    # Attempt reconnection, switch to offline mode, etc.
    
    try:
        print('Attempting to reconnect...')
        sio.connect('http://localhost:5000')
        sio.emit('message', {'text': 'Reconnected'})
    except socketio.ConnectionError as reconnect_error:
        print(f'Reconnection failed: {reconnect_error}')

# Server-side example
sio_server = socketio.Server()

@sio_server.event
def handle_message(sid, data):
    try:
        # Try to access session data
        session = sio_server.get_session(sid)
        # Process message with session data
        sio_server.emit('response', {'processed': data}, room=sid)
    except socketio.DisconnectedError as e:
        print(f'Client {sid} disconnected during processing: {e}')
        # Clean up any resources associated with this client

# Async server example
@async_sio_server.event
async def async_handle_message(sid, data):
    try:
        async with async_sio_server.session(sid) as session:
            session['last_message'] = data
        await async_sio_server.emit('response', {'received': data}, room=sid)
    except socketio.DisconnectedError as e:
        print(f'Client {sid} disconnected: {e}')

Exception Handling Patterns

Comprehensive Error Handling

import socketio
import logging

logger = logging.getLogger(__name__)

sio = socketio.Client(logger=True)

def safe_emit(event, data, **kwargs):
    """Safely emit events with comprehensive error handling."""
    try:
        return sio.emit(event, data, **kwargs)
    except socketio.DisconnectedError:
        logger.error('Cannot emit: client disconnected')
        # Attempt reconnection
        try_reconnect()
    except socketio.BadNamespaceError as e:
        logger.error(f'Invalid namespace: {e}')
        # Fall back to default namespace
        return sio.emit(event, data)
    except socketio.SocketIOError as e:
        logger.error(f'Socket.IO error: {e}')
        # Handle generic Socket.IO errors
    except Exception as e:
        logger.error(f'Unexpected error: {e}')

def safe_call(event, data, timeout=30):
    """Safely call with response handling."""
    try:
        return sio.call(event, data, timeout=timeout)
    except socketio.TimeoutError:
        logger.warning(f'Call to {event} timed out after {timeout}s')
        return None
    except socketio.DisconnectedError:
        logger.error('Cannot call: client disconnected')
        if try_reconnect():
            # Retry after reconnection
            return sio.call(event, data, timeout=timeout)
        return None
    except socketio.SocketIOError as e:
        logger.error(f'Call failed: {e}')
        return None

def try_reconnect(max_attempts=3):
    """Attempt to reconnect with exponential backoff."""
    import time
    
    for attempt in range(max_attempts):
        try:
            delay = 2 ** attempt  # Exponential backoff
            logger.info(f'Reconnection attempt {attempt + 1} in {delay}s')
            time.sleep(delay)
            
            sio.connect('http://localhost:5000')
            logger.info('Reconnected successfully')
            return True
            
        except socketio.ConnectionRefusedError as e:
            logger.error(f'Connection refused: {e}')
            # Don't retry on authentication failures
            break
        except socketio.ConnectionError as e:
            logger.warning(f'Reconnection attempt {attempt + 1} failed: {e}')
            
    logger.error('All reconnection attempts failed')
    return False

Server-Side Error Handling

import socketio

sio = socketio.Server()

@sio.event
def connect(sid, environ, auth):
    try:
        # Validate authentication
        if not validate_auth(auth):
            raise socketio.ConnectionRefusedError('Invalid credentials')
        
        # Initialize client session
        sio.save_session(sid, {
            'user_id': auth['user_id'],
            'connected_at': time.time()
        })
        
        sio.enter_room(sid, 'authenticated_users')
        sio.emit('welcome', {'message': 'Connected successfully'}, room=sid)
        
    except socketio.ConnectionRefusedError:
        # Re-raise authentication errors
        raise
    except Exception as e:
        logger.error(f'Connection error for {sid}: {e}')
        raise socketio.ConnectionRefusedError('Internal server error')

@sio.event
def handle_message(sid, data):
    try:
        # Validate client connection
        session = sio.get_session(sid)
        
        # Process message
        result = process_message(data, session)
        sio.emit('message_result', result, room=sid)
        
    except socketio.DisconnectedError:
        logger.warning(f'Client {sid} disconnected during message processing')
    except Exception as e:
        logger.error(f'Message processing error for {sid}: {e}')
        sio.emit('error', {'message': 'Message processing failed'}, room=sid)

def validate_auth(auth):
    """Validate authentication credentials."""
    if not auth or 'token' not in auth:
        return False
    # Implement your authentication logic
    return auth['token'] == 'valid_token'

def process_message(data, session):
    """Process incoming message with error handling."""
    if not data or 'content' not in data:
        raise ValueError('Invalid message format')
    
    # Process the message
    return {
        'status': 'processed',
        'user_id': session['user_id'],
        'processed_at': time.time()
    }

Context Manager for Connection Handling

import socketio
from contextlib import contextmanager

@contextmanager
def socket_connection(url, **kwargs):
    """Context manager for safe Socket.IO connections."""
    sio = socketio.Client()
    try:
        sio.connect(url, **kwargs)
        yield sio
    except socketio.ConnectionError as e:
        print(f'Failed to connect: {e}')
        raise
    finally:
        if sio.connected:
            sio.disconnect()

# Usage
try:
    with socket_connection('http://localhost:5000') as sio:
        sio.emit('message', {'text': 'Hello'})
        response = sio.call('get_data', timeout=5)
        print(f'Response: {response}')
except socketio.TimeoutError:
    print('Operation timed out')
except socketio.SocketIOError as e:
    print(f'Socket.IO error: {e}')

Install with Tessl CLI

npx tessl i tessl/pypi-python-socketio

docs

clients.md

exceptions.md

index.md

integration.md

managers.md

namespaces.md

servers.md

tile.json