Feedple Python SDK
The official Python SDK for the Feedple AI platform. Connect your database to Feedple with a single class — the SDK handles authentication, schema sync, and query execution automatically.
Table of Contents
- How It Works
- Requirements
- Installation
- Quick Start
- Configuration
- Identity & Access Control
- Schema Sync
- IR Query Execution
- Connection Management
- Utilities
- API Reference
- License
How It Works
Your App Feedple SDK Feedple API
│ │ │
│ FeedpleSDK(api_key, db, …) │ │
│─────────────────────────────>│ │
│ │── connect() ─────────────────>│
│ │<─ auth.ack (session_id) ──────│
│ │ │
│ │── schema.started ────────────>│
│ │── schema.data (chunks) ──────>│
│ │── schema.completed ──────────>│
│ │ │
│ │<─ ir.request (IR payload) ────│
│ │── ir.ack ────────────────────>│
│ │ [executes SQL against DB] │
│ │── ir.result ─────────────────>│
│ │ │
- Connect & Authenticate — Opens a persistent WebSocket connection and sends your API key. The server responds with a
session_idused to resume after disconnects. - Sync Schema — Inspects your database (tables, columns, PKs, FKs, indexes) and sends the schema to Feedple in chunks. Re-syncs on a configurable interval; skips if nothing changed.
- Execute Queries — Receives incoming IR query requests from Feedple, enforces RBAC, executes them safely against your database, and returns the results.
Requirements
- Python ≥ 3.8
- A database supported by SQLAlchemy (PostgreSQL, MySQL, SQLite, and others)
Installation
pip install feedple-sdk
Install with a specific database driver:
# PostgreSQL
pip install feedple-sdk psycopg2-binary
# MySQL
pip install feedple-sdk pymysql
# SQLite (built into Python — no extra driver needed)
pip install feedple-sdk
Quick Start
from sqlalchemy import create_engine
from feedple_sdk import FeedpleSDK, Identity
# 1. Create your database engine (SQLAlchemy)
db = create_engine("postgresql+psycopg2://user:pass@localhost/mydb")
# 2. Define which tables Feedple can access
identity = Identity(
name="production",
all_tables=True, # expose every table, or…
# allowed_tables=["users", "orders", "products"], # …restrict to specific tables
)
# 3. Initialise the SDK — it starts immediately in the background
sdk = FeedpleSDK(
api_key="sk_live_...",
db=db,
identity=identity,
)
# Your application keeps running normally.
# The SDK manages the WebSocket connection on a background thread.
Note:
FeedpleSDK.__init__starts a background daemon thread and returns immediately. Your application does not block.
Configuration
All parameters are keyword-only.
sdk = FeedpleSDK(
# Required
api_key="sk_live_...", # Your Feedple API key
db=engine, # SQLAlchemy Engine
identity=identity, # Identity (see below)
# Schema sync
auto_sync=True, # Sync schema on startup and periodically (default: True)
sync_interval=60, # Seconds between sync cycles (default: 60)
# Connection
reconnect_enabled=True, # Reconnect on disconnect (default: True)
max_retries=None, # Max reconnect attempts; None = unlimited (default: None)
probe_before_connect=False, # HTTP probe before WS handshake for clearer errors (default: False)
)
Parameter Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
required | Your Feedple API key. Raises ValueError if empty. |
db |
Engine |
required | SQLAlchemy database engine. |
identity |
Identity |
required | Controls which tables are accessible. |
auto_sync |
bool |
True |
Periodically re-inspect and send the schema. |
sync_interval |
int |
60 |
Seconds between schema re-sync cycles. |
reconnect_enabled |
bool |
True |
Automatically reconnect on connection loss. |
max_retries |
int | None |
None |
Cap on reconnect attempts. None means unlimited. |
probe_before_connect |
bool |
False |
Perform an HTTP GET before the WS handshake to surface clearer server error messages (e.g. 403 bodies). |
Identity & Access Control
Identity controls which database tables Feedple can see and query.
from feedple_sdk import Identity
# Grant access to all tables
admin_identity = Identity(
name="admin",
all_tables=True,
)
# Restrict to specific tables only
restricted_identity = Identity(
name="analytics-service",
allowed_tables=["users", "orders", "products", "events"],
all_tables=False, # default
)
Identity Fields
| Field | Type | Default | Description |
|---|---|---|---|
name |
str | None |
— | Human-readable label for this identity. |
allowed_tables |
list[str] |
[] |
Tables this identity may access. Ignored when all_tables=True. |
all_tables |
bool |
False |
When True, all current and future tables are accessible. |
Security: The SDK enforces RBAC on every IR query request. If the IR references a table not in
allowed_tables, aPermissionErroris raised and anir.erroris returned to the server — the query never reaches the database.
Schema Sync
The SDK automatically syncs your schema on startup and then every sync_interval seconds. You can also trigger a sync manually:
import asyncio
# Manually trigger a schema sync (async — must be called from an async context)
asyncio.run(sdk.sync_schema())
What gets synced
For each table the identity can access, the SDK sends:
- Columns — name, type string, nullable flag, default value
- Primary key — constrained column names
- Foreign keys — local columns, referenced table, referenced columns
- Indexes — name, column names, unique flag
- Unique constraints — name, column names
Sensitive column filtering
The following column names are never sent to Feedple, regardless of the identity setting:
password, token, secret, hash, salt, ssn, credit_card
You can call filter_sensitive_columns manually:
from feedple_sdk.core.schema_services import filter_sensitive_columns
safe_schema = filter_sensitive_columns(raw_schema)
IR Query Execution
The SDK receives IR (Intermediate Representation) query objects from the Feedple server and executes them against your database. You do not call this yourself — it is invoked automatically via the WebSocket.
IR Schema
ir = {
"operation": "query", # always "query"
"table": "orders", # primary FROM table
"fields": [ # columns to SELECT
{"column": "orders.id", "expression": None, "alias": None},
{"column": "orders.amount", "expression": "sum", "alias": "total"},
{"column": "orders.user_id","expression": "count(distinct)", "alias": "unique_users"},
],
"joins": [ # JOIN clauses
{
"table": "users",
"on_left": "orders.user_id",
"on_right": "users.id",
"join_type": "INNER", # "INNER" or "LEFT"
}
],
"filters": [ # WHERE conditions (ANDed together)
{"column": "orders.status", "operator": "eq", "value": "active"},
{"column": "orders.amount", "operator": "gte", "value": 100},
],
"group_by": ["orders.status"],
"having": [{"column": "orders.id", "operator": "gt", "value": 5}],
"order_by": ["orders.created_at DESC"],
"limit": 100,
"offset": 0,
}
Supported filter operators
| Operator | Aliases | SQL |
|---|---|---|
eq |
= |
col = ? |
neq |
!= |
col != ? |
gt |
> |
col > ? |
gte |
>= |
col >= ? |
lt |
< |
col < ? |
lte |
<= |
col <= ? |
in |
in_ |
col IN (?, ?, …) |
not_in |
not in |
col NOT IN (?, ?, …) |
is_null |
— | col IS NULL |
is_not_null |
— | col IS NOT NULL |
like |
— | col LIKE ? |
ilike |
— | col ILIKE ? |
Supported aggregate expressions
count, count(distinct), sum, avg, min, max
Connection Management
Reconnect behaviour
The SDK reconnects automatically with exponential back-off:
| Attempt | Delay |
|---|---|
| 1 | 5 s |
| 2 | 10 s |
| 3 | 20 s |
| 4+ | 40 s → capped at 60 s |
Authentication failures (auth.error) are not retried — the SDK stops immediately and logs the error.
Session resume
The session_id received in auth.ack is stored and re-sent on every reconnect attempt. The server resumes the session if it is still within TTL, or issues a new session ID if it has expired.
Stopping the SDK
sdk.stop()
Signals the background thread to stop, closes the WebSocket, and halts the event loop. Idempotent — safe to call multiple times.
Utilities
SQLCompiler
Validate and RBAC-check raw SQL strings before executing them yourself:
compiler = sdk._build_compiler()
# Raises PermissionError if the SQL references a denied table
safe_sql = compiler.compile("SELECT id, name FROM users WHERE active = 1")
Schema utilities
from feedple_sdk.core.schema_services import (
get_schema,
generate_schema_hash,
should_sync_schema,
filter_sensitive_columns,
)
schema = get_schema(db=engine, identity=identity)
hash_ = generate_schema_hash(schema)
changed = should_sync_schema(old_schema, new_schema)
API Reference
FeedpleSDK
class FeedpleSDK:
def __init__(
self,
*,
api_key: str,
db: Engine,
identity: Identity,
auto_sync: bool = True,
sync_interval: int = 60,
reconnect_enabled: bool = True,
max_retries: Optional[int] = None,
probe_before_connect: bool = False,
) -> None: ...
async def sync_schema(self) -> None: ...
def stop(self) -> None: ...
Identity
@dataclass
class Identity:
name: Optional[str]
allowed_tables: List[str] = field(default_factory=list)
all_tables: bool = False
PolicyEngine
class PolicyEngine:
def __init__(self, identity: Identity): ...
def can_access_table(self, table: str) -> bool: ...
def validate_ir_access(self, ir: dict) -> None: ...
SQLCompiler
class SQLCompiler:
def __init__(self, policy: PolicyEngine, dialect: str = "postgres"): ...
def parse(self, sql: str) -> exp.Expression: ...
def extract_tables(self, ast: exp.Expression) -> List[str]: ...
def validate_access(self, tables: List[str]) -> None: ...
def compile(self, sql: str) -> str: ...
Environment URLs
By default the production release SDK targets the official Feedple AI production cluster (https://feedple-ai-614817435356.us-central1.run.app).
To switch to a local development environment during SDK development, set DEV_ENV = True in src/feedple_sdk/core/request.py:
DEV_ENV = True # uses http://localhost:8000/api/v1 and ws://localhost:8000/api/v1/tenants/ws
License
feedple-sdk is distributed under the terms of the MIT license.
Release files for feedple-sdk 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| feedple_sdk-1.0.3.tar.gz | 37.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| feedple_sdk-1.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.5 kB
Release files / feedple_sdk-1.0.3.tar.gz
| Download URL | feedple_sdk-1.0.3.tar.gz |
|---|---|
| Size | 37.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
22dbb8302eec27495fffdcd3de0e53c8bcb7513e937d80f0cf8341cac972149a
|
|
BLAKE2b-256 checksum How to use checksums |
5a4dec9c4037f98b4b43f61662c2aa4aaa8f15347dc66236fb8269554503f7d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Release files / feedple_sdk-1.0.3-py3-none-any.whl
| Download URL | feedple_sdk-1.0.3-py3-none-any.whl |
|---|---|
| Size | 34.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
533dd918277b24861112d06026eec4d9ac07d09e2ecc530d0438097e00b9cffb
|
|
BLAKE2b-256 checksum How to use checksums |
b193f446bd30c9b12991b6dc10112fbaef1ef9dde2ea4ee2725cda530efb24c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|