Python SDK and CLI for the Querri data analysis platform
Project description
Querri — Python SDK and CLI
CLI: Interact with the Querri data analysis platform from the terminal or in scripts. Python SDK: Embed Querri analytics in your Python web application with one method call.
Install
pip install querri
CLI Quick Start
The querri CLI lets you upload data, create analysis projects, and ask questions — interactively or from scripts.
Auth
querri auth login # browser-based login
querri whoami # confirm who you're logged in as
For scripted/non-interactive use, set QUERRI_API_KEY instead of relying on stored tokens:
export QUERRI_API_KEY=qk_your_api_key
export QUERRI_ORG_ID=org_your_org_id
Example workflow: upload a file and analyze it
# Upload a file (CSV, Excel, JSON, etc.)
querri --json file upload path/to/data.csv
# Create a project
querri --json project new "My Analysis"
# Add the file to the project (triggers ingestion + agent summary)
querri --json project add-source <file_id>
# Ask a question
querri --json project chat -m "What are the top 5 products by revenue?"
For scripting, add --no-interactive to prevent prompts and --json for parseable output. Note that --json and other global flags must come before the subcommand:
querri --json --no-interactive project chat -m "Summarize the data" # correct
querri project chat -m "Summarize the data" --json # WRONG
Self-documenting
The CLI covers all Querri resources — projects, files, sources, views, dashboards, sharing, API keys, users, policies, embed sessions, and more.
querri --help
querri <command> --help
See skills/querri-cli/SKILL.md for the full command reference.
Python SDK
For embedding Querri analytics in a Python web application. Use alongside the @querri-inc/embed frontend component.
Quick Start
from querri import Querri
client = Querri(api_key="qk_your_api_key", org_id="org_...")
session = client.embed.get_session(
user="customer-42", # external ID from your system
ttl=3600,
)
print(session["session_token"]) # JWT to pass to the frontend
Wire a session endpoint
Flask:
from flask import Flask, jsonify, request
from querri import Querri
app = Flask(__name__)
client = Querri() # reads QUERRI_API_KEY and QUERRI_ORG_ID from env
@app.route("/api/querri-session", methods=["POST"])
def querri_session():
# Derive user identity from YOUR auth system — never from the request body.
auth_user = get_authenticated_user()
session = client.embed.get_session(
user={"external_id": auth_user.id, "email": auth_user.email},
access={
"sources": ["src_sales_data"],
"filters": {"tenant_id": auth_user.tenant_id},
},
origin=request.headers.get("Origin"),
ttl=3600,
)
return jsonify(session)
Django and FastAPI follow the identical pattern — see docs/server-sdk.md for those examples.
Add the embed (React)
import { QuerriEmbed } from '@querri-inc/embed/react';
<QuerriEmbed
style={{ width: '100%', height: '600px' }}
serverUrl="https://app.querri.com"
auth={{ sessionEndpoint: '/api/querri-session' }}
/>
Security: Always derive user identity and access from server-side auth. Never read
useroraccessfrom the request body — a malicious client can impersonate any user or escalate access.
Configuration
The SDK reads configuration from constructor arguments or environment variables:
| Parameter | Env Variable | Default | Description |
|---|---|---|---|
api_key |
QUERRI_API_KEY |
(required) | Your qk_ API key |
org_id |
QUERRI_ORG_ID |
(required) | Organization ID |
host |
QUERRI_HOST |
https://app.querri.com |
Server host |
timeout |
QUERRI_TIMEOUT |
30.0 |
Request timeout (seconds) |
max_retries |
QUERRI_MAX_RETRIES |
3 |
Retry attempts for transient errors |
Note: The parameter is
host, notbase_url. The SDK appends/api/v1automatically.
get_session() — Embed Sessions
The flagship convenience method: resolves or creates a user, applies access policies, and generates a session JWT in one call.
session = client.embed.get_session(
user={
"external_id": "customer-42",
"email": "alice@acme.com",
"first_name": "Alice",
},
access={
"sources": ["src_sales_data"],
"filters": {
"tenant_id": "acme",
"region": ["us-east", "us-west"], # list values are OR'd
},
},
origin="https://app.acme.com",
ttl=7200,
)
session["session_token"] # str — JWT for the embed
session["expires_in"] # int — seconds until expiry
session["user_id"] # str — Querri user ID
You can also pass pre-created policy IDs directly:
session = client.embed.get_session(
user={"external_id": "customer-42"},
access={"policy_ids": ["pol_abc123"]},
)
User-Scoped Client (as_user)
session = client.embed.get_session(user="customer-42", ttl=900)
with client.as_user(session) as user_client:
for project in user_client.projects.list():
print(project.name)
See docs/server-sdk.md for details on granting access and available resources.
All Resources
| Resource | Access | Key Methods |
|---|---|---|
client.dashboards |
Dashboard management | list, create, get, update, delete, refresh |
client.projects |
Analysis projects | list, create, get, run, run_status, list_steps |
client.projects.chats |
Chats within projects | create, list, stream, cancel, delete |
client.sources |
Sources, connectors & data | list, create, create_data_source, query, source_data, append_rows, replace_data, ask, sync, list_connectors |
client.views |
SQL-defined views | list, create, get, update, delete, run, preview, chat |
client.files |
File management | upload, list, get, delete |
client.users |
User management | list, create, get, update, delete |
client.keys |
API key management | create, list, get, delete |
client.audit |
Audit log | list |
client.usage |
Usage metrics | org_usage, user_usage |
client.sharing |
Sharing & permissions | share_project, share_dashboard, share_source |
Async Client
AsyncQuerri mirrors the sync API with async/await:
from querri import AsyncQuerri
async with AsyncQuerri() as client:
session = await client.embed.get_session(
user={"external_id": "cust-42", "email": "a@b.com"},
access={"sources": ["src_sales"]},
)
Error Handling
All errors extend QuerriError:
QuerriError
├── APIError — HTTP error responses
│ ├── ValidationError — 400
│ ├── AuthenticationError — 401
│ ├── PermissionError — 403
│ ├── NotFoundError — 404
│ ├── ConflictError — 409
│ ├── RateLimitError — 429 (auto-retried)
│ └── ServerError — 5xx (auto-retried)
├── StreamError — SSE stream issues
└── ConfigError — missing/invalid configuration
The SDK automatically retries 429 (always) and 5xx (idempotent methods only) with exponential backoff + jitter.
Full Reference
See docs/server-sdk.md for complete method signatures, all framework examples, and the get_session() deep dive.
Requirements
Development
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/test_integration.py -m integration -v # requires API credentials
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file querri-1.0.6.tar.gz.
File metadata
- Download URL: querri-1.0.6.tar.gz
- Upload date:
- Size: 172.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2d3051543ed3ee61ad4c44278eb7ac7eabff794b8feb51811183099fed402f5
|
|
| MD5 |
fdea6cbbc501acdd5c59797db77cc810
|
|
| BLAKE2b-256 |
1397859903b5a380e16354ee60573b3f41276d3e03041c73ea0afd6a4879fcf8
|
Provenance
The following attestation bundles were made for querri-1.0.6.tar.gz:
Publisher:
release.yml on Querri-inc/querri-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
querri-1.0.6.tar.gz -
Subject digest:
a2d3051543ed3ee61ad4c44278eb7ac7eabff794b8feb51811183099fed402f5 - Sigstore transparency entry: 1393458292
- Sigstore integration time:
-
Permalink:
Querri-inc/querri-python@cf85fa75dae770e04a6d93e58842056c2388a9b3 -
Branch / Tag:
refs/tags/v1.0.6 - Owner: https://github.com/Querri-inc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cf85fa75dae770e04a6d93e58842056c2388a9b3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file querri-1.0.6-py3-none-any.whl.
File metadata
- Download URL: querri-1.0.6-py3-none-any.whl
- Upload date:
- Size: 125.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de8c7787206c00e920a5cd3f420b022e40cebecd43292fc2738093b86629a200
|
|
| MD5 |
306f3a834ddfa4de3ee23b5f1422dde6
|
|
| BLAKE2b-256 |
0026ed2487d7ae5d342a40b3fe543fdd7844dbda6ed45991cbc42ffef1c92ba1
|
Provenance
The following attestation bundles were made for querri-1.0.6-py3-none-any.whl:
Publisher:
release.yml on Querri-inc/querri-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
querri-1.0.6-py3-none-any.whl -
Subject digest:
de8c7787206c00e920a5cd3f420b022e40cebecd43292fc2738093b86629a200 - Sigstore transparency entry: 1393458299
- Sigstore integration time:
-
Permalink:
Querri-inc/querri-python@cf85fa75dae770e04a6d93e58842056c2388a9b3 -
Branch / Tag:
refs/tags/v1.0.6 - Owner: https://github.com/Querri-inc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cf85fa75dae770e04a6d93e58842056c2388a9b3 -
Trigger Event:
push
-
Statement type: