Minimal DSL for API data extraction
Project description
Siphon
A minimal DSL for extracting data from JSON APIs.
Like a siphon draws liquid from a container, Siphon draws the data you need from nested JSON structures—just define the paths, and let it flow.
Install
pip install siphon-dsl
Or with uv:
uv add siphon-dsl
Quick Start
from siphon import process
data = {
"data": {
"id": "prod_123",
"items": [
{"id": 1, "status": "active", "name": "Widget"},
{"id": 2, "status": "inactive", "name": "Gadget"},
{"id": 3, "status": "active", "name": "Thing"},
],
}
}
spec = {
"extract": {
"id": "$.data.id",
"all_active": {
"path": "$.data.items[*]",
"where": {"status": "active"},
"select": {"item_id": "id", "item_name": "name"},
"collect": True,
},
}
}
result = process(spec, data)
Output:
{
"id": "prod_123",
"all_active": [
{"item_id": 1, "item_name": "Widget"},
{"item_id": 3, "item_name": "Thing"}
]
}
Features
| Feature | Syntax | Description |
|---|---|---|
| Simple paths | $.data.id |
Extract nested values |
| Array iteration | $.items[*].name |
Traverse arrays |
| Filtering | where: {status: "active"} |
Filter by field values |
| Ancestor filtering | where: {parentId: 123} |
Filter by parent-level properties |
| Projection | select: {new: "old"} |
Rename and reshape fields |
| Collect | collect: true |
Return all matches (default: first only) |
| Reduce | reduce: "min_time" |
Aggregate array values to a single result |
Spec Format
Simple extraction
extract:
id: "$.data.id"
name: "$.data.name"
Extended extraction
extract:
active_items:
path: "$.data.items[*]"
where: {status: "active"}
select: {item_id: "id", item_name: "name"}
collect: true
Reduce (aggregation)
extract:
earliest_slot:
path: "$.items[*].from_datetime"
reduce: min_time # earliest time-of-day across all items
latest_slot:
path: "$.items[*].to_datetime"
reduce: max_time # latest time-of-day across all items
total_price:
path: "$.items[*].price"
reduce: sum
unique_categories:
path: "$.items[*].category"
reduce: distinct
Available operators:
| Operator | Description |
|---|---|
min_time / max_time |
Earliest/latest time-of-day (ignores date + timezone) |
min_date / max_date |
Earliest/latest calendar date (ignores time) |
min_datetime / max_datetime |
Earliest/latest full datetime (timezone-normalised) |
min_int / max_int |
Minimum/maximum numeric value |
sum |
Sum of numeric values |
count |
Count of non-null values (returns 0 for empty) |
first / last |
First or last value in traversal order |
concat |
Join values as a string (default separator ", ") |
distinct |
Deduplicated list, preserving first-seen order |
For concat with a custom separator use the dict form:
"reduce": {"op": "concat", "sep": " | "}
Fetch from API
from siphon import fetch_and_process
spec = {
"request": {"path": "/products"},
"extract": {
"id": "$.data.id",
"names": {"path": "$.data.items[*].name", "collect": True},
},
}
result = fetch_and_process(spec, "https://api.example.com")
Requires requests:
pip install siphon-dsl[http]
Typed Specs (Pydantic)
from siphon.typed import process_spec, ExtractSpec, FieldSpec
spec = ExtractSpec(
extract={
"id": "$.data.id",
"active_items": FieldSpec(
path="$.data.items[*]",
where={"status": "active"},
select={"item_id": "id", "name": "name"},
collect=True,
),
}
)
result = process_spec(spec, data)
Requires pydantic:
pip install siphon-dsl[typed]
Why Siphon?
- Minimal — ~100 lines of code, no dependencies
- Declarative — specs are data, not code
- Composable — combine paths, filters, and projections
Spec History
See specs/ for version history and full documentation. Latest: v0.8 — adds reduce aggregation operators.
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 siphon_dsl-0.8.0b1.tar.gz.
File metadata
- Download URL: siphon_dsl-0.8.0b1.tar.gz
- Upload date:
- Size: 9.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a6331c9bd4f3d0bce33c21e61e7c8ae7b33ff11cd9ad10d821a99270670c56d
|
|
| MD5 |
84f99eafcfdc633cbc30856468b02ad7
|
|
| BLAKE2b-256 |
6822dbcc2b5ffb184cf2be8875f49eb6273993b0ad45a693a00fb3d13199b4c4
|
Provenance
The following attestation bundles were made for siphon_dsl-0.8.0b1.tar.gz:
Publisher:
workflow.yml on alpeshvas/siphon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
siphon_dsl-0.8.0b1.tar.gz -
Subject digest:
4a6331c9bd4f3d0bce33c21e61e7c8ae7b33ff11cd9ad10d821a99270670c56d - Sigstore transparency entry: 1281999955
- Sigstore integration time:
-
Permalink:
alpeshvas/siphon@41fce1ba80bd718eb1866f0a0b9945a0b06f9106 -
Branch / Tag:
refs/tags/0.8.0b1 - Owner: https://github.com/alpeshvas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@41fce1ba80bd718eb1866f0a0b9945a0b06f9106 -
Trigger Event:
release
-
Statement type:
File details
Details for the file siphon_dsl-0.8.0b1-py3-none-any.whl.
File metadata
- Download URL: siphon_dsl-0.8.0b1-py3-none-any.whl
- Upload date:
- Size: 11.4 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 |
5aac1825ec490a9df871c528abb3479d1342d9dc5de828d03f704e72e0aea180
|
|
| MD5 |
ede66e6ad002da23655e04207f28a7e8
|
|
| BLAKE2b-256 |
57e794843d3fe8cc50d6b41a45125c4ee45610a6692e9ad91d909ab65d8db571
|
Provenance
The following attestation bundles were made for siphon_dsl-0.8.0b1-py3-none-any.whl:
Publisher:
workflow.yml on alpeshvas/siphon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
siphon_dsl-0.8.0b1-py3-none-any.whl -
Subject digest:
5aac1825ec490a9df871c528abb3479d1342d9dc5de828d03f704e72e0aea180 - Sigstore transparency entry: 1281999978
- Sigstore integration time:
-
Permalink:
alpeshvas/siphon@41fce1ba80bd718eb1866f0a0b9945a0b06f9106 -
Branch / Tag:
refs/tags/0.8.0b1 - Owner: https://github.com/alpeshvas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@41fce1ba80bd718eb1866f0a0b9945a0b06f9106 -
Trigger Event:
release
-
Statement type: