CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

89

Quality

89%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

Overview
Quality
Evals
Security
Files

error-handling.mdplugins/developer-kit-python/rules/

paths:
**/*.py

Rule: Python Error Handling

Context

Establish a consistent error handling strategy for Python applications, ensuring meaningful error reporting, proper exception hierarchies, and clean recovery patterns.

Guidelines

Exception Hierarchy

  • Create a base ApplicationError inheriting from Exception for all domain-specific errors
  • Create specific exception classes for each error domain (e.g., OrderNotFoundError, PaymentDeclinedError)
  • Name exceptions with Error suffix (PEP 8 convention)
  • Include meaningful error messages and relevant context attributes
  • Keep the hierarchy shallow (max 2-3 levels deep)
class ApplicationError(Exception):
    """Base exception for all application errors."""

class NotFoundError(ApplicationError):
    """Raised when a requested resource is not found."""
    def __init__(self, resource: str, identifier: str | int) -> None:
        self.resource = resource
        self.identifier = identifier
        super().__init__(f"{resource} with ID '{identifier}' was not found")

class OrderNotFoundError(NotFoundError):
    def __init__(self, order_id: int) -> None:
        super().__init__("Order", order_id)

Exception Handling Best Practices

  • Never use bare except: — always catch specific exception types
  • Never silently swallow exceptions (except: pass)
  • Use except Exception only at the top-level error boundary
  • Re-raise with context: raise NewError("message") from original_error
  • Log exceptions with logger.exception() to capture the traceback
  • Use else clause for code that should run only if no exception was raised
  • Use finally for cleanup code that must always execute

Logging Errors

  • Use the logging module, never print() for error reporting
  • Use logger.exception("message") inside except blocks to capture traceback
  • Use logger.warning() for business rule violations
  • Use logger.error() for unexpected failures
  • Include structured context in log messages (IDs, parameters)

API Error Responses

For web frameworks (FastAPI, Flask, Django), return standardized error responses:

# FastAPI example
from fastapi import HTTPException, status

@app.exception_handler(NotFoundError)
async def not_found_handler(request: Request, exc: NotFoundError) -> JSONResponse:
    return JSONResponse(
        status_code=status.HTTP_404_NOT_FOUND,
        content={
            "type": "not_found",
            "title": "Resource Not Found",
            "detail": str(exc),
        },
    )

Validation

  • Use Pydantic for input validation — it raises ValidationError automatically
  • Do not manually raise exceptions for data validation that Pydantic can handle
  • Validate at the boundary (API layer), not deep inside business logic

Examples

✅ Good

import logging

logger = logging.getLogger(__name__)

class OrderService:
    def find_by_id(self, order_id: int) -> Order:
        order = self._repository.get(order_id)
        if order is None:
            raise OrderNotFoundError(order_id)
        return order

    def process_order(self, order_id: int) -> OrderResult:
        try:
            order = self.find_by_id(order_id)
            result = self._payment_gateway.charge(order)
        except PaymentGatewayError as e:
            logger.exception("Payment failed for order %d", order_id)
            raise PaymentProcessingError(order_id) from e
        else:
            logger.info("Order %d processed successfully", order_id)
            return result

❌ Bad

def process_order(order_id):
    try:
        order = get_order(order_id)
        charge(order)
    except:              # Bare except
        pass             # Silent swallow

def find_order(order_id):
    order = db.get(order_id)
    if not order:
        return None      # Returning None instead of raising

plugins

CHANGELOG.md

context7.json

CONTRIBUTING.md

README_CN.md

README_ES.md

README_IT.md

README.md

tessl.json

tile.json