Skip to content

Exceptions

This reference documents the custom exception classes provided by the pico_fastapi project. These exceptions are used to signal failures in application configuration and in controller discovery, and they allow you to handle these conditions explicitly in your code.

Overview

  • PicoFastAPIError is the common base class for all custom errors in pico_fastapi.
  • InvalidConfigurerError is raised when an object passed as a “configurer” is invalid (e.g., it does not implement the expected interface).
  • NoControllersFoundError is raised when the controller discovery process completes without finding any controllers.

Catching the base class lets you handle all pico_fastapi-specific errors in one place. Catching the specific subclasses lets you handle configuration vs. discovery failures differently.

Typical import:

from pico_fastapi.exceptions import (
    PicoFastAPIError,
    InvalidConfigurerError,
    NoControllersFoundError,
)

PicoFastAPIError

Base class for all pico_fastapi exceptions.

  • Use this to catch any pico_fastapi-specific error without matching a concrete subclass.
  • When writing library or application code on top of pico_fastapi, prefer catching PicoFastAPIError instead of broad exceptions like Exception, to avoid masking unrelated errors.

Example:

try:
    bootstrap_app()
except PicoFastAPIError as exc:
    # Handle configuration or discovery errors uniformly
    logger.error(f"pico_fastapi startup failed: {exc}")
    raise

InvalidConfigurerError

Raised when an object provided to configure the application is invalid.

Constructor signature: - InvalidConfigurerError(obj)

The obj argument is the offending object. The exception message typically includes information about the object to aid debugging.

When to raise: - If the configurer does not implement required methods or attributes. - If the configurer is of the wrong type.

Example usage in an application bootstrap:

from pico_fastapi.exceptions import InvalidConfigurerError

def bootstrap(configurer):
    # Validate expected interface
    if not hasattr(configurer, "configure"):
        raise InvalidConfigurerError(configurer)

    # Optionally more checks, e.g., callable or type
    if not callable(getattr(configurer, "configure", None)):
        raise InvalidConfigurerError(configurer)

    # Proceed with configuration
    configurer.configure()

Example handling:

try:
    bootstrap(my_configurer)
except InvalidConfigurerError as exc:
    # Provide a user-friendly message or remediation
    print(f"Invalid configurer: {exc}")
    # Decide whether to recover or exit

NoControllersFoundError

Raised when the system cannot find any controllers during discovery.

Constructor signature: - NoControllersFoundError()

When to raise: - After scanning designated modules or packages for controllers and no eligible controllers are found.

Example usage during discovery:

from pico_fastapi.exceptions import NoControllersFoundError

def discover_and_register_controllers(package: str):
    controllers = discover_controllers(package=package)  # project-specific function
    if not controllers:
        raise NoControllersFoundError()

    for controller in controllers:
        register_controller(controller)

Example handling:

try:
    discover_and_register_controllers("app.controllers")
except NoControllersFoundError:
    # Decide how to handle an empty application
    logger.warning("No controllers found; the API will expose no endpoints.")
    # You may halt startup or continue with limited functionality

Recommendations

  • Prefer raising InvalidConfigurerError and NoControllersFoundError for configuration and discovery issues instead of generic errors like ValueError or RuntimeError. This makes error handling clearer and more robust.
  • Catch PicoFastAPIError at application boundaries (e.g., startup) to handle all pico_fastapi-specific failures in a single place.
  • Do not rely on the exact exception message in code paths; match on the exception class to make your code resilient to message changes.