Dumpio

Dokumentace

The dumpio-client package (Python ≥ 3.8, no required dependencies) sends faithful, typed value dumps and structured messages to Dumpio over HTTP. The serializer understands dict/list/tuple/set, dataclasses, arbitrary objects via __dict__/repr, bytes, and special float values; ORM models (SQLAlchemy, Django) render as their loaded columns with the internal state dropped (already-loaded data only — no lazy query is triggered). It infers member visibility from the _/__ convention, breaks cycles with ref nodes, and captures the calling file:line automatically. Ready-made integrations for Django, Flask, and FastAPI/Starlette.

1pip install dumpio-client
2 
3# optional framework extras:
4pip install "dumpio-client[django]"
5pip install "dumpio-client[flask]"
6pip install "dumpio-client[fastapi]"

Every helper is fire-and-forget and never raises into your app — if the viewer isn't running, the dump is dropped silently. Sending is synchronous (an HTTP POST with a short timeout, 1.5 s by default), so no flush() is needed.

Why send dumps to Dumpio instead of print()

  • It doesn't flood stdout. The dump travels over the network to a separate window, so you don't have to print objects into a WSGI server's log or a test runner's output.
  • It preserves types and structure. Instead of <object at 0x…> you see a typed tree — dataclasses, set, bytes, cycles via ref, attribute visibility.
  • It sorts things for you. Color flags, labels, and channels separate output from different places.
  • It won't crash the request. Everything is wrapped so a send error (e.g. when the viewer isn't running) can never leak into your app.

For the full list of dump types and how Dumpio renders them, see Dump types; if nothing shows up, start with Troubleshooting.

Quick start

1from dumpio_client import dumpio, dd
2 
3dumpio(user) # dump a variable
4dumpio(user, label="user", flag="green") # with a label and flag
5dd(a, b) # dump every argument and stop the script — sys.exit(1)

dumpio() returns the value it was given, so you can drop it into an expression without breaking it:

1return dumpio(compute_total(cart), label="total") # dumps and carries on

Which entry point should you use?

I want to… Use
Quickly dump a value dumpio(x)
Dump mid-expression without breaking the code dumpio(x) (returns x unchanged)
Add a flag / label / channel dumpio(x, label=…, flag=…, channel=…)
Dump and stop the script dd(x)
Send something other than a variable (exception, query, HTTP…) typed helpers dumpio_exception(), dumpio_query(), …

Configuration

Defaults are read from the environment, or you can set them via configure(...):

Option Env var Default
host DUMPIO_HOST localhost
port DUMPIO_PORT 21234
path /dumps
token DUMPIO_TOKEN ""
timeout (s) 1.5
enabled DUMPIO_DISABLE (set it to turn off) true
max_depth 6
max_items 100
max_string 2000
1from dumpio_client import configure
2 
3configure(host="127.0.0.1", port=21234, token="Dio-…")

The token is sent as the X-Dumpio-Token header. configure() returns the resulting config (you can also reach the exported config dict). The SDK speaks HTTP only (no TCP).

Core functions

Function Purpose
dumpio(value, label=None, flag="blue", channel="default") -> Any Send a variable dump and return value
dd(*values) -> None Dump every argument and stop the script with sys.exit(1)
configure(**options) -> dict Override config and return the result
serialize(value, ...) -> dict Return the typed tree without sending

Fluent builder & flood control

dio(value) returns a chainable builder that mirrors the PHP/Node clients. It ships on .send(), when used as a with block, or automatically when the object is dropped (CPython sends it at the end of the statement, like the PHP destructor).

1from dumpio_client import dio, stopwatch
2 
3dio(user).red().label("user").channel("auth") # auto-sends
4dio(payload).green().send() # explicit
5 
6dio(state).when(debug) # send only if truthy (.unless() is the opposite)
7 
8# Keep loops from flooding the viewer (keyed by call site, or a shared name):
9for row in rows:
10 dio(row).once() # only the first iteration
11 dio(row).limit(5) # at most 5
12 dio(row).count("rows") # one live-updating "×N" entry

Colors: red() yellow() blue() gray() purple() pink() green() (or flag("…")), plus label(), channel(), when()/unless(), once()/limit(n)/count(name?), send().

On non-CPython runtimes (e.g. PyPy) object collection isn't immediate, so call .send() or use with dio(x) as d: when you need the dump sent at a precise point.

Timing — stopwatch

1sw = stopwatch("import")
2# … work …
3sw.lap("parsed") # split time, keeps running
4# … more work …
5sw.stop("done") # final time

Each lap()/stop() sends a measure dump with the elapsed milliseconds (and a memory delta when tracemalloc is running).

Typed helpers

Each renders a dedicated view in the viewer and picks a sensible default flag. All accept the keyword arguments flag=, channel=, timestamp= and any additional payload fields.

Helper Default flag Renders
message(text, **opts) blue generic titled data (extra keys as payload)
dumpio_exception(exc, context=None, **opts) red error + stack trace
dumpio_query(sql, bindings=None, time_ms=None, **opts) purple SQL query (connection=, message=)
dumpio_http(method, url, status=None, headers=None, body=None, response_time=None, **opts) by status HTTP request
dumpio_log(level, message, details=None, **opts) by level log
dumpio_model(cls_name, attributes, relations=None, exists=None, connection=None, **opts) one domain object
dumpio_collection(items, count=None, **opts) list
dumpio_table(columns, rows, **opts) explicit table
dumpio_measure(name, time_ms, memory=None, context=None, **opts) one timing
dumpio_performance(metrics, breakdown=None, context=None, **opts) a metric bundle
dumpio_event(event, entity=None, entity_id=None, actor=None, data=None, metadata=None, **opts) a domain event
dumpio_html(html, message=None, title=None, **opts) an HTML fragment/page in a sandboxed iframe
dumpio_mail(mail, **opts) a rendered email (envelope + body); mail = dict of html/text/subject/from/to/cc/bcc/attachments

Flag by HTTP status: None → blue, ≥ 500 → red, ≥ 400 → yellow, ≥ 300 → blue, else green. Flag by log level: emergency/alert/critical/error → red, warning/notice → yellow, info → blue, else gray.

Examples

1from dumpio_client import (
2 dumpio_exception, dumpio_query, dumpio_http,
3 dumpio_log, dumpio_table, dumpio_event,
4)
5 
6# An error with a structured stack trace and context
7try:
8 gateway.charge(order)
9except Exception as e:
10 dumpio_exception(e, context={"order_id": order.id, "user": user.email})
11 raise
12 
13# A database query with parameters and time
14dumpio_query("select * from orders where status = ?", ["paid"], 12.4)
15 
16# An outgoing HTTP call — the flag is derived from the status
17dumpio_http("POST", "https://api.stripe.com/v1/charges", 402, response_time=240)
18 
19# A log line with details (flag by level)
20dumpio_log("error", "Payment failed", {"gateway": "stripe", "code": "card_declined"})
21 
22# A table — columns + rows
23dumpio_table(["id", "status"], [[1, "paid"], [2, "pending"]], message="Orders")
24 
25# A business event with an actor and data
26dumpio_event("order.refunded", entity="Order", entity_id=42,
27 actor={"email": user.email}, data={"amount": 1990})

For a detailed look at how Dumpio renders each type (and how it parses exceptions), see Dump types and Exceptions.

Auto-capture outbound HTTP

capture_http() patches http.client — which urllib, requests and urllib3 all funnel through — so every outgoing request your app makes is forwarded to the viewer as an http dump. No per-call code needed.

1from dumpio_client import capture_http
2 
3stop = capture_http(channel="outbound")
4# ... your app makes HTTP calls ...
5stop() # restore the originals when you're done

It's idempotent, defensive (a capture failure never disturbs the request), and skips requests to the Dumpio viewer itself, so the SDK never dumps its own traffic. Pass ignore=lambda info: ... to skip noisy endpoints — info carries method / url / host / port.

httpx uses its own transport (httpcore), not http.client, so it isn't captured by this patch.

Auto-capture ORM queries (SQLAlchemy)

capture_sqlalchemy(engine) attaches to SQLAlchemy's public before_cursor_execute / after_cursor_execute events (no monkey-patching) and forwards every executed statement as a query dump with its bound parameters and timing. Works with a sync Engine or an AsyncEngine (its sync_engine is used).

1from dumpio_client import capture_sqlalchemy
2 
3stop = capture_sqlalchemy(engine, channel="db")
4# ... your app runs queries ...
5stop() # detach the listeners

The captured SQL and bindings are the driver-level ones (SQLAlchemy has already compiled named params to the DBAPI's paramstyle). Pass ignore=lambda info: ... to skip statements — info carries sql / bindings.

Framework integrations

Each integration imports its framework lazily and is defensive: importing the module without the framework, or the viewer being down, never breaks anything.

Django

1# settings.py
2MIDDLEWARE = [
3 # ...
4 "dumpio_client.django.DumpioMiddleware",
5]

Sends an http dump per request and an exception dump on view errors.

Flask

1from flask import Flask
2from dumpio_client.flask import DumpioFlask
3 
4app = Flask(__name__)
5DumpioFlask(app) # or: DumpioFlask().init_app(app)

Uses before_request / after_request / teardown_request to send http dumps and exceptions.

FastAPI / Starlette

1from fastapi import FastAPI
2from dumpio_client.fastapi import DumpioMiddleware
3 
4app = FastAPI()
5app.add_middleware(DumpioMiddleware)

An ASGI BaseHTTPMiddleware that sends one http dump per request. Degrades to a transparent no-op if Starlette isn't installed.

Standard logging (optional)

1import logging
2from dumpio_client.logging import DumpioHandler
3 
4logging.getLogger().addHandler(DumpioHandler())

Forwards log records as log dumps (and as exception dumps when a record carries exc_info).

What gets sent (the wire format)

Every dump carries a standard envelope (timestamp, flag, channel, type, language: "python", …) plus type-specific fields. The exact envelope, flags, and limits are described in Dump format; the value tree is the same as in the other SDKs.