Skip to main content

Static analysis tool for tracing exception flow through Python codebases

Project description

Bubble

Static analysis tool for tracing exception flow through Python codebases.

What can escape from my API endpoints? Bubble answers this by parsing your code, building a call graph, and computing which exceptions propagate to each entrypoint.

Quick Start

pip install bubble-analysis
# Check Flask routes for uncaught exceptions
bubble flask audit -d /path/to/project

# Check FastAPI routes
bubble fastapi audit -d /path/to/project

# Deep dive into one function
bubble escapes create_user -d /path/to/project

# Visualize the call tree
bubble trace create_user -d /path/to/project

What It Does

Bubble finds your HTTP routes and CLI scripts, traces the call graph, and reports which exceptions can escape:

$ bubble flask audit

Scanning 23 flask entrypoints...

3 entrypoints have uncaught exceptions:

  POST /users/import
    └─ FileNotFoundError (importers.py:45)
    └─ ValidationError (validators.py:12)

  GET /reports/{id}
    └─ PermissionError (auth.py:89)

20 entrypoints fully covered by exception handlers

For a specific endpoint, see the full picture:

$ bubble escapes create_user

Exceptions that can escape from POST /users:

  FRAMEWORK-HANDLED (converted to HTTP response):
    HTTPException
      └─ becomes: HTTP 404
      └─ raised in: routes/users.py:45 (get_user) [high confidence]

  CAUGHT BY GLOBAL HANDLER:
    ValidationError (@errorhandler(AppError))
      └─ raised in: validators.py:27 (validate_input) [high confidence]

  UNCAUGHT (will propagate to caller):
    ConnectionError
      └─ raised in: db/client.py:45 (execute) [medium confidence]
      └─ call path: create_user → save_user → db.execute

Visualize as a tree:

$ bubble trace create_user

POST /users  → escapes: ValidationError, ConnectionError
├── validate_input()  → ValidationError
│   └── raises ValidationError (validators.py:27)
└── save_user()  → ConnectionError
    └── db.execute()  → ConnectionError
        └── raises ConnectionError (db/client.py:45)

Features

  • Extensible: Adapt to any framework or custom pattern (see extending guide)
  • Entrypoint detection: Flask routes, FastAPI routes, CLI scripts (if __name__ == "__main__")
  • Global handler awareness: Understands @errorhandler, add_exception_handler
  • Exception hierarchy: Knows that catching AppError also catches ValidationError if it's a subclass
  • Polymorphism: Expands abstract method calls to all concrete implementations
  • Framework-handled exceptions: Detects HTTPException, ValidationError → HTTP responses
  • Confidence levels: Shows high/medium/low confidence based on resolution quality
  • Resolution modes: --strict for precision, --aggressive for recall
  • Exception stubs: Built-in stubs for requests, sqlalchemy, httpx, redis, boto3
  • JSON output: All commands support -f json for CI/automation
  • Caching: SQLite-based caching for fast repeated analysis
  • Python 3.10+: Supports Python 3.10, 3.11, 3.12, and 3.13

Commands

Core Commands (framework-agnostic)

Command Description
bubble raises <exception> Find all places an exception is raised
bubble escapes <function> Show what can escape from a specific function
bubble callers <function> Find all callers of a function
bubble catches <exception> Find all places an exception is caught
bubble trace <function> Visualize exception flow as a call tree
bubble exceptions Show the exception class hierarchy
bubble subclasses <class> Show class inheritance tree
bubble stubs <action> Manage exception stubs (list, init, validate)
bubble stats Show codebase statistics

Framework-Specific Commands

Command Description
bubble flask audit Check Flask routes for escaping exceptions
bubble flask entrypoints List Flask HTTP routes
bubble flask routes-to <exc> Which Flask routes can trigger this exception?
bubble fastapi audit Check FastAPI routes for escaping exceptions
bubble fastapi entrypoints List FastAPI HTTP routes
bubble fastapi routes-to <exc> Which FastAPI routes can trigger this exception?
bubble cli audit Check CLI scripts for escaping exceptions
bubble cli entrypoints List CLI scripts
bubble cli scripts-to <exc> Which CLI scripts can trigger this exception?

All commands accept:

  • -d, --directory: Directory to analyze (default: current)
  • -f, --format: Output format (text or json)
  • --no-cache: Disable caching

The escapes command accepts additional flags:

  • --strict: High precision mode - only includes precisely resolved calls
  • --aggressive: High recall mode - includes fuzzy matches

Supported Frameworks

Detected automatically:

  • Flask (@app.route, @blueprint.route, @app.errorhandler)
  • FastAPI (@router.get/post/put/delete, add_exception_handler)
  • CLI scripts (if __name__ == "__main__")

Not yet supported:

  • Django
  • Celery tasks
  • Scheduled jobs (APScheduler, etc.)

Custom patterns can be added via .flow/detectors/.

Extending Bubble

Bubble is designed to be adapted to your codebase. The core engine handles exception propagation—you just tell it where your entrypoints are.

Every codebase has its own patterns: internal RPC frameworks, custom decorators, queue handlers, scheduled jobs. Bubble's extension system lets you teach it your patterns without modifying the core.

Full guide: docs/EXTENDING.md

What You Can Extend

Pattern Example How to add
Custom entrypoints Celery tasks, Django views, gRPC handlers EntrypointDetector
Custom error handlers Middleware, decorators GlobalHandlerDetector
Full framework Django REST Framework, Airflow Integration protocol

Quick Example

Drop a detector in .flow/detectors/ and bubble auto-loads it:

# .flow/detectors/celery.py
from bubble.protocols import EntrypointDetector
from bubble.integrations.base import Entrypoint
from bubble.enums import EntrypointKind

class CeleryTaskDetector(EntrypointDetector):
    def detect(self, source: str, file_path: str) -> list[Entrypoint]:
        # Find @app.task decorators, return Entrypoint objects
        ...

AI-Friendly Design

The protocol is intentionally simple for LLMs. Give your agent:

Read bubble/protocols.py and bubble/integrations/flask/detector.py.
Implement a detector for [YOUR FRAMEWORK] that finds [PATTERNS].
Put it in .flow/detectors/[framework].py

See docs/EXTENDING.md for complete examples including Celery, Django REST Framework, and custom decorator patterns.

Configuration

Bubble can be configured via .flow/config.yaml:

resolution_mode: default  # "strict", "default", or "aggressive"
exclude:
  - vendor
  - migrations

Exception Stubs

Bubble includes built-in stubs for common libraries (requests, sqlalchemy, httpx, redis, boto3). These declare what exceptions external library functions can raise.

Add custom stubs in .flow/stubs/:

# .flow/stubs/mylib.yaml
module: mylib

functions:
  do_thing:
    - MyLibError
    - TimeoutError

Manage stubs with bubble stubs list and bubble stubs validate.

How It Works

  1. Parse: LibCST parses all Python files
  2. Extract: Find functions, classes, raise/catch sites, calls, entrypoints
  3. Build call graph: Track who calls whom, resolve method calls
  4. Propagate: Fixed-point iteration computes which exceptions escape each function
  5. Report: For each entrypoint, show caught vs uncaught exceptions

Limitations

  • Over-approximation: May report more exceptions than actually possible (e.g., all implementations of an abstract method)
  • Under-approximation: Dynamic dispatch, eval(), and external libraries can't be fully traced
  • No runtime info: Analysis is purely static

Development

git clone https://github.com/ianm199/bubble-analysis
cd bubble-analysis
uv pip install -e ".[dev]"
uv run pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bubble_analysis-0.3.5.tar.gz (84.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bubble_analysis-0.3.5-py3-none-any.whl (85.2 kB view details)

Uploaded Python 3

File details

Details for the file bubble_analysis-0.3.5.tar.gz.

File metadata

  • Download URL: bubble_analysis-0.3.5.tar.gz
  • Upload date:
  • Size: 84.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for bubble_analysis-0.3.5.tar.gz
Algorithm Hash digest
SHA256 065715c995153c0838e3269da378099dd88bcf0448f7673e9d4e30ac39b7b4b9
MD5 8f26379584fdaf8c851567a40e2f60dd
BLAKE2b-256 07465f292c6876cf171127d2ea5df61b8bfe6613a6dec3755ecf62cf270d1877

See more details on using hashes here.

File details

Details for the file bubble_analysis-0.3.5-py3-none-any.whl.

File metadata

File hashes

Hashes for bubble_analysis-0.3.5-py3-none-any.whl
Algorithm Hash digest
SHA256 d5b59e74de3a1be149ac2481259b5ea41c737a312c3b4429bc891a585f088294
MD5 540b70e43d52087c8a8350fbc079eead
BLAKE2b-256 efd877dcff6e981b6d95ccf6e797efd0e2cc13efeffdc44d72e756b487e4b90c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page