Skip to content

feat: Add logfire.db_api — PEP 249 DB API 2.0 interface#1692

Merged
dmontagu merged 14 commits intomainfrom
feat/db-api-2
Feb 10, 2026
Merged

feat: Add logfire.db_api — PEP 249 DB API 2.0 interface#1692
dmontagu merged 14 commits intomainfrom
feat/db-api-2

Conversation

@dmontagu
Copy link
Copy Markdown
Contributor

@dmontagu dmontagu commented Feb 8, 2026

Summary

  • Add logfire.db_api module implementing PEP 249 (DB API 2.0), wrapping the existing LogfireQueryClient
  • Enable Logfire query data to work out of the box with pandas read_sql(), marimo SQL cells, Jupyter %%sql magic, and any other DB API 2.0 compatible tool — notably, marimo has built-in support for DB API 2.0 connections in its SQL cells
  • Uses query_json_rows under the hood with client-side parameter interpolation (pyformat style). Plan is to move to server-side parameterization in a follow-up once the params field is plumbed through the backend query endpoint
  • Default limit of 10,000 rows per query (the server-side max) with a truncation warning when results may be incomplete. This mirrors how other thin DB API wrappers over REST APIs handle server-side row limits — auto-pagination would require SQL rewriting and has no snapshot isolation between pages, so we surface the limit transparently instead
  • Add type stubs in logfire-api. @alexmojaki — not sure this module really belongs in logfire-api since it's a tool for querying data rather than something libraries would use as a no-op shim. Happy to remove the stubs if you agree
  • Add documentation section to the existing query API guide

Adds a DB API 2.0 (PEP 249) compatible module that wraps LogfireQueryClient,
enabling Logfire query data to work with any tool that supports standard Python
database connections — pandas read_sql(), marimo SQL cells, Jupyter %%sql, etc.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Feb 8, 2026

Deploying logfire-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7f132c2
Status: ✅  Deploy successful!
Preview URL: https://96b654e2.logfire-docs.pages.dev
Branch Preview URL: https://feat-db-api-2.logfire-docs.pages.dev

View logs

base_url: str | None = None,
timeout: float = 30.0,
*,
min_timestamp: datetime | None = None,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a default, not having one in the query client is enough of a problem

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a default of timedelta(days=30) which gets resolved to datetime.now(utc) - timedelta at connection time. The min_timestamp parameter now accepts datetime | timedelta | None:

  • timedelta (default) — relative window computed at connect time
  • datetime — exact bound
  • None — no filter

Copy link
Copy Markdown
Collaborator

@alexmojaki alexmojaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new logfire.db_api module implementing a PEP 249 (DB API 2.0) interface on top of LogfireQueryClient, enabling interoperability with DB-API consumers (e.g., pandas read_sql, notebook SQL magics), plus accompanying tests and documentation.

Changes:

  • Introduce logfire.db_api with connect(), Connection, Cursor, parameter interpolation, and truncation warnings at the server row limit.
  • Add comprehensive pytest coverage for connection/cursor behavior, fetching methods, parameter substitution, timestamps, and warnings.
  • Document usage patterns (basic usage, pandas, parameters, row limits) in the query API guide.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
logfire/db_api.py New DB API 2.0 wrapper around LogfireQueryClient with client-side param interpolation and truncation warnings.
tests/test_db_api.py New tests validating PEP 249-style behaviors and the wrapper’s HTTP request construction via mock transport.
docs/how-to-guides/query-api.md New documentation section explaining how to use logfire.db_api with common tools.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add default min_timestamp of 30 days ago (accepts datetime, timedelta, or None)
- Reject str/bytes as parameters in _substitute_params
- Use pytest.warns for truncation warning test
- Fix skip directive in marimo docs example
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

- Use `if parameters is not None:` so empty dict/list still triggers
  `%%` → `%` conversion per pyformat paramstyle
- Remove unused `marimo` import from docs code block
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

…on-level filters

Previously, cursor-level min_timestamp/max_timestamp used `or` fallback
which made it impossible to explicitly disable a connection-level timestamp
filter from a cursor (None would always fall through to the connection value).
Now _UNSET means "inherit from connection" and None means "no filter".
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 8 additional findings in Devin Review.

Open in Devin Review

@dmontagu
Copy link
Copy Markdown
Contributor Author

Re: Devin's comment about truncation warning and limit=None:

Good catch. Disallowed limit=None on cursors — the type is now int (not int | None), so it always resolves to a concrete limit (either the cursor override or the connection's default of 10,000). This avoids the silent server-side 500-row cap.

When limit=None was passed through, the server would silently cap at 500
rows and our truncation warning wouldn't fire since effective_limit was
None. Now cursor.limit is typed as int, always resolving to a concrete
value.
@dmontagu dmontagu enabled auto-merge (squash) February 10, 2026 23:26
@dmontagu dmontagu merged commit 8eeaa47 into main Feb 10, 2026
14 checks passed
@dmontagu dmontagu deleted the feat/db-api-2 branch February 10, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants