Delete Set public Set private Add tags Delete tags
  Add tag   Cancel
  Delete tag   Cancel
  • • DevOps notes •
  •  
  • AI
  • Tags
  • Login

Custom Exceptions: Tailoring Error Signals/shaare/hTTdng

  • python
  • python

Custom Exceptions: Tailoring Error Signals

  • Built-in exceptions are great, but often too generic for application-specific failures.
  • A custom exception like ServiceConnectionError immediately conveys context compared to a plain Exception.
  • Defining a base exception class groups related errors; subclasses add specificity for targeted handling.
  • Catching except BaseError: handles all related issues, while except SpecificError: addresses one case precisely.

Simple Custom Exceptions (Inheritance)

  • Create a new exception by subclassing Exception or another exception class.
  • Using pass is enough when no extra logic or attributes are needed.
  • Catch the base class (AutomationError) to handle any related subclass errors in one block.
  • Use subclasses (FileProcessingError, APICallError) when context-specific handling is required.
class AutomationError(Exception):
    """Base for all automation script errors."""
    pass

class FileProcessingError(AutomationError):
    """Error during file processing stage."""
    pass

class APICallError(AutomationError):
    """Error during an external API call."""
    pass

def process_file(filepath):
    raise FileProcessingError(f"Failed to process file at path: {filepath}")

try:
    process_file("nonexistent.csv")
except FileProcessingError as e:
    print(f"File error: {e}")
except AutomationError:
    print("Other automation error occurred.")

Adding Context with __init__

  • Override __init__ in your exception class to capture context (e.g., filename, invalid value).
  • Store custom attributes on self and build a clear message passed to super().__init__().
  • Inherit from a built-in exception (ValueError) when semantics align, allowing broad catches.
  • Attribute access (e.key_name) provides extra debugging info in handlers.
class ConfigValueError(ValueError):
    """Raised when a config value is invalid."""
    def __init__(self, key_name, invalid_value, message="Invalid configuration value."):
        self.key_name = key_name
        self.invalid_value = invalid_value
        full_message = f"{message} for key '{key_name}': received '{invalid_value}'"
        super().__init__(full_message)

try:
    raise ConfigValueError("timeout", -5, message="Timeout cannot be negative")
except ConfigValueError as e:
    print(f"{e}")
    print(f"   -> key: {e.key_name}")
    print(f"   -> value: {e.invalid_value}")

Raising and Catching Enhanced Custom Exceptions

  • Raise custom exceptions by instantiating them with relevant arguments: raise MyError(arg1, arg2).
  • In except blocks, catch specific exceptions and access their attributes for tailored recovery or logging.
  • Fallback except BaseError: catches any related subclass if no more specific handler exists.
class DeploymentError(Exception):
    """Base class for deployment-related errors."""
    pass

class InvalidEnvironmentError(DeploymentError):
    """Raised when environment is invalid."""
    def __init__(self, env_name, allowed_envs):
        self.env_name = env_name
        self.allowed_envs = allowed_envs
        super().__init__(f"Invalid environment '{env_name}'. Allowed values: {allowed_envs}")

class PackageMissingError(DeploymentError):
    """Raised when required packages are missing."""
    def __init__(self, package_name, host):
        self.package_name = package_name
        self.host = host
        super().__init__(f"Package '{package_name}' is missing on host {host}.")

def deploy_app(environment, package):
    allowed_envs = ["staging", "production"]

    if environment not in allowed_envs:
        raise InvalidEnvironmentError(environment, allowed_envs)

    if environment == "production" and package == "critical-lib":
        raise PackageMissingError(package, f"server-{environment}")

    print(f"Deployment to {environment} with package {package} succeeded.")

for env, pkg in [("dev", "tool"), ("production", "critical-lib"), ("staging", "tool")]:
    try:
        deploy_app(env, pkg)
    except DeploymentError as e:
        print(e)
1 month ago Permalink
cluster icon
  • Lambda Functions : Lambda Functions Python functions defined with def allow multiple statements, clear naming, and support for docstrings, making them ideal for complex...
  • Mocking : Mocking Fundamentals Introduction When unit testing DevOps scripts that interact with external systems, tests can become slow, unreliable, difficult ...
  • Working with YAML files : Working with YAML files YAML (“YAML Ain’t Markup Language”) focuses on human readability. Indentation replaces braces and brackets, comments are allo...
  • Python Functions Are First‑Class Citizens : Python Functions Are First‑Class Citizens In Python, functions behave like any other object (strings, ints, lists). Because they are "first‑clas...
  • Fixtures in Pytest : Fixtures in Pytest As tests grow more complex, repeating setup and cleanup steps makes tests harder to read and maintain. Pytest fixtures allow centr...


(97)
Filter untagged links
Fold Fold all Expand Expand all Are you sure you want to delete this link? Are you sure you want to delete this tag? The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community