Skip to main content

Python client for the Honeyframe data platform — a dataikuapi-style SDK

Project description

honeyframeapi

A dataikuapi-style Python client for the Honeyframe data platform (Honeyframe Platform / platform.hubstudio.id). Script the platform from a notebook: read data into pandas, build dashboards and cards, browse datasets and connectors.

If you've used dataikuapi, this will feel identical — construct one client, then navigate to project / dataset / dashboard handles.

import dataikuapi
client = dataikuapi.DSSClient(host, api_key)   # Dataiku
import honeyframeapi
client = honeyframeapi.HoneyframeClient(host, username=..., password=..., project_id=1)  # Honeyframe

Install

pip install -e sdk/python                # core (httpx only)
pip install -e "sdk/python[pandas]"      # + pandas for get_dataframe()/sql()

Authenticate

Three ways, in precedence order:

import honeyframeapi

# 1. email / password (works against any deployment today; auto-refreshes the 8h JWT)
client = honeyframeapi.HoneyframeClient(
    "https://platform.hubstudio.id",
    username="you@hubstudio.id", password="…",
    project_id=1,
)

# 2. a token you already hold — a JWT, or (preferred for automation) a
#    long-lived Personal Access Token minted from the UI
#    (avatar menu → "Personal access tokens") or via client.create_pat()
client = honeyframeapi.HoneyframeClient("https://platform.hubstudio.id", token="hf_…", project_id=1)

# 3. from environment variables
#    HONEYFRAME_URL (or HUB_API_BASE), HONEYFRAME_TOKEN,
#    HONEYFRAME_USERNAME/PASSWORD (or HUB_USERNAME/PASSWORD), HONEYFRAME_PROJECT_ID
client = honeyframeapi.HoneyframeClient.from_env()

Vibe-code the warehouse, end to end

One governed loop, and it adapts to the deployment — see examples/vibe_code_end_to_end.py:

proj = client.get_project(1)
proj.engine()                      # 'dbt' or 'native' — does this install have dbt?
proj.upload_dataframe("raw", df, materialize=True)   # push local data in
if proj.uses_dbt():
    proj.dbt.create_model("stg_x", sql="SELECT … FROM {{ ref('raw') }}")
    proj.dbt.run(select="stg_x")   # author + build a dbt model
df = proj.sql("SELECT * FROM stg_x")                 # read results back
proj.get_dataset("raw").upstream()                   # trace lineage

# …then share it: dashboard → webapp → token-gated public link
dash = proj.create_dashboard("Demo")
dash.add_card("By region", "bar", "SELECT region, total FROM stg_x")
app  = client.publish_webapp("demo", "Demo", config={"pages": [...]})
print(app.create_public_link(expires_days=7)["share_url"])

(On a native install the authoring lines change — see proj.engine() — but the upload → read → dashboard → webapp → share legs are identical.)

Read data into pandas

# ad-hoc SQL — the analogue of dwh-adira's run_sql()
df = client.sql("""
    SELECT booking_source, COUNT(*) AS n
    FROM marts.fact_appointment
    GROUP BY booking_source ORDER BY n DESC
""")

# or read a whole dataset
proj = client.get_project(1)
df = proj.get_dataset("fact_appointment").get_dataframe()
head = proj.get_dataset("fact_appointment").head(20)
stats = proj.get_dataset("fact_appointment").profile()

Build a dashboard from code

This replaces the hand-rolled requests script in dwh-adira (scripts/upload_dashboards.py) — same card dicts, ergonomic API:

proj = client.get_project(1)
dash = proj.create_dashboard("Appointments Overview",
                             description="Booking channels & volume")

dash.add_card("Total Appointments", "kpi",
              "SELECT COUNT(*) AS n FROM marts.fact_appointment",
              config={"color_theme": "ocean"}, size_x=6, size_y=2)

dash.add_card("By Booking Source", "donut",
              "SELECT booking_source AS name, COUNT(*) AS value "
              "FROM marts.fact_appointment GROUP BY booking_source",
              config={"nameField": "name", "valueField": "value"})

results = dash.execute_all()
print("Open:", dash.url)

Porting an existing upload_dashboards.py block? Pass the dicts straight through:

dash.add_cards(DASHBOARDS[0]["cards"])   # list of {"title","card_type","sql_query","card_config",…}

Publish a webapp + share it by link

The last mile: wrap dashboard cards in a webapp and hand a stakeholder a URL they can open without an account (token-gated, PII-masked).

app = client.publish_webapp(
    "ops-overview", "Ops Overview",
    config={"pages": [{"key": "home", "title": "Home", "blocks": [
        {"kind": "card_ref", "dashboard_id": dash.dashboard_id,
         "card_id": dash.cards[0].card_id},
    ]}]},
)

link = app.create_public_link(label="exec share", expires_days=30)
print(link["token"])                       # shown ONCE — store it
print(app.public_url(link["token"],        # anonymous URL on the SaaS host
                     host="https://hospital.hubstudio.id"))

# later: audit + revoke
for l in app.public_links():
    print(l["label"], l["status"], l["view_count"])
app.revoke_public_link(link["id"])

publish_webapp is project-scoped — set project_id on the client first.

Build a multi-page app from code (no hand-rolled config)

The builders compose pages, blocks and filters for you — including the two flexible block kinds: code_card (a governed read-only SELECT → chart, run server-side with an 8s timeout + 5k-row cap) and html_block (freeform HTML/CSS/JS; mode="sandboxed" runs arbitrary JS — even a canvas game — in an opaque-origin iframe with a CSP that blocks outbound network, so it can't read your JWT or phone home). Add data_sql= to a sandboxed block and the server runs that governed SELECT and postMessages the rows into the fenced iframe — the "data bridge", so your custom JS renders real DWH data without any API access of its own.

from honeyframeapi import (
    page, nav_item, code_card, html_block, card_ref,
    filters, date_range_filter, branch_filter,
)

app = client.create_webapp(
    "ops-overview", "Ops Overview",
    pages=[page(
        "home", "Home",
        blocks=[
            card_ref(dash.dashboard_id, dash.cards[0].card_id, w=12, h=4),
            code_card("SELECT branch_name, visits FROM marts.v_branch_visits "
                      "WHERE :period_start <= visit_date AND visit_date <= :period_end",
                      "bar", x=12, w=12, h=4, title="Visits by branch"),
            html_block("<canvas id=game></canvas><script>/* … */</script>",
                       mode="sandboxed", w=12, h=8, title="Mini-game"),
            # DATA BRIDGE: a fenced sandboxed block that renders REAL data —
            # the server runs data_sql and postMessages the rows into the iframe
            # (the JS listens for e.data.source === 'honeyframe').
            html_block("<div id=viz></div><script>addEventListener('message',e=>{"
                       "if(e.data?.source==='honeyframe')draw(e.data.rows)})</script>",
                       mode="sandboxed", w=12, h=8, title="Custom viz",
                       data_sql="SELECT branch_name, visits FROM marts.v_branch_visits"),
            html_block("<i>internal note</i>", public_hidden=True, w=12, h=2),
        ],
        # page-level filters bound into the SQL above by param name
        filters=filters(
            period=date_range_filter(),                       # :period_start/:period_end
            branch=branch_filter("branch_id_codes", mode="multi",
                                 options_sql="SELECT afya_code AS value, branch_name AS label "
                                             "FROM marts.v_hospital_360 WHERE total_appointments > 0"),
        ),
    )],
    nav=[nav_item("home", "Home", icon="gauge")],
    publish=True,
)

# incremental edits read-modify-write the stored config for you
app.add_page(page("detail", "Detail", [code_card("SELECT 1", "kpi")]),
             nav=nav_item("detail", "Detail"), publish=True)
app.set_theme({"primaryColor": "#0E7C66"})
app.remove_page("detail")

Scenarios, jobs & recipes (dataikuapi parity)

Closes the gap behind dwh-adira's run_instinct_daily_scenario.py and scaffold_* scripts:

proj = client.get_project(1)

# scenarios — trigger and poll like dataikuapi's scenario.run()
sc = proj.get_scenario("daily_pipeline")
final = sc.run_and_wait()                 # polls to terminal state
print(final["status"], final.get("steps_failed"))

# jobs / pipeline
runs = client.jobs.list_runs(status="failed")
run  = client.jobs.trigger("dbt_run", select="int_appointments_unioned+")
print(client.jobs.logs("dbt_run", lines=100))

# recipes (dbt-engine build)
proj.get_recipe("dim_patient").build(downstream=True, wait=True)

# datasets — create like create_sql_table_dataset()
proj.create_dataset("ekko", connector_id=5,
                    connection_config={"schema_name": "RAW_RSL", "table_name": "EKKO"})

# datasets — surface an existing raw table in the picker (no data copied)
proj.register_source_table("staging_inbd", "stgops_master_dokter", connector_id=5)
proj.register_schema("staging_inbd", connector_id=5)   # or the whole schema, idempotent

# connectors (org-level)
conn = client.create_connector("SAP Prod", "postgresql", config={"host": "…"})
print(conn.test())

# publish a data API + mint a key
asset = client.create_asset("data_api", "appointments", "Appointments API", config={...})
asset.publish()
print(asset.create_api_key(name="readonly").key)   # dk_… shown once

# chat with an agent
print(client.get_agent(42).ask("Cancellations last month?")["answer"])

CLI

Installing the package also installs a honeyframe command. Flags go after the subcommand (kubectl/gh style).

export HONEYFRAME_URL=https://platform.hubstudio.id
export HONEYFRAME_TOKEN=hf_…            # a PAT (preferred) or JWT

honeyframe whoami
honeyframe projects -f csv
honeyframe datasets -p 1
honeyframe sql "SELECT COUNT(*) FROM marts.fact_appointment" -p 1 -f csv
honeyframe engine -p 1                       # dbt or native install?
honeyframe upload sales sales.csv --materialize -p 1
honeyframe lineage fact_appointment --down -p 1
honeyframe export fact_appointment out.parquet --max-rows 100000 -p 1
honeyframe pat create --name laptop --expires-days 90
honeyframe scenario run daily_pipeline -p 1 --wait

Resource map

Handle Get it from Key methods
HoneyframeClient constructor sql, list_projects, get_project, get_dashboard, jobs, list_connectors, create_connector, get_connector, list_my_credentials, list_knowledge_bases, create_knowledge_base, get_knowledge_base, kb_connector_options, llm_mesh_overview, get_llm_policy, set_llm_policy, llm_mesh_usage, list_card_templates, create_card_template, list_collections, create_collection, update_collection, delete_collection, list_assets, create_asset, get_asset, list_webapps, get_webapp, publish_webapp, list_agents, get_agent, chat, get_auth_info
Project client.get_project(id_or_slug) list_datasets, get_dataset, create_dataset, import_dataset, register_source_table, register_schema, sql, create_dashboard, list_scenarios, get_scenario, create_scenario, get_recipe, run_dbt, change_recipe_engines, create_bundle, list_bundles, bundle, list_signoffs, list_bundle_activations, dbtDbtIDE, get_preferences, set_preferences, list_connectors
Dataset project.get_dataset(name) get_dataframe, head, profile, get_metadata, ask, materialize, versions, preview_version, rollback_version, update_version, delete
Dashboard project.create_dashboard(...) / client.get_dashboard(id) add_card, add_cards, execute_all (filters=[...]), cards, update, move_to_collection, public_links, create_public_link, revoke_public_link, export_pdf, shares, add_share, update_share, remove_share, revisions, create_revision, get_revision, diff_revisions, restore_revision, undo, undo_card, url
Card dashboard.cards / dashboard.add_card(...) execute, update, delete, unlink_template
CardTemplate client.create_card_template(...) / client.list_card_templates() update, delete, insert_into, link_into, preview, duplicate, versions, get_version, restore_version
Connector client.create_connector(...) / client.get_connector(id) test, update, delete, set_my_credentials, delete_my_credentials, rotate, secret_history, rollback_secret
Scenario project.get_scenario(id_or_name) run, run_and_wait, get_last_runs, update, delete, list_triggers, add_trigger, update_trigger, delete_trigger, list_reporters, add_reporter, update_reporter, delete_reporter, test_reporter
Recipe project.get_recipe(model_name) get_metadata, runs, build, engine_status, save_prepare_steps, save
Bundle project.create_bundle(...) / project.bundle(version) download, activate, deploy, push, governance_status, request_signoff, submit_feedback, submit_for_approval, approve, reject, abandon
KnowledgeBase client.create_knowledge_base(...) / client.get_knowledge_base(id) update, delete, docs, upload_doc, remove_doc, embed, sync, clear, search, check_vector_store, create_tool, link_agent, unlink_agent, usage
JobsAPI client.jobs list_runs, get_run, wait, abort_run, trigger, logs
PublishedAsset client.create_asset(...) / client.get_asset(id) publish, unpublish, update, create_api_key, list_api_keys, revoke_api_key, versions, rollback, diff_versions
APIService client.create_api_service(...) / client.get_api_service(id) add_endpoint, set_endpoints, publish, create_key, call, test, versions, rollback, diff_versions
Webapp client.publish_webapp(...) / client.get_webapp(key) config, public_links, create_public_link, revoke_public_link, versions, rollback, diff_versions, url, public_url
DbtIDE project.dbt() write_file, read_file, create_model, list_models, compile, run, test, build, git_commit
Agent client.get_agent(id) ask, ask_stream

Global-filter builders (from honeyframeapi import ...): dashboard_filter, filter_between, filter_compare, filter_in — build the filters=[...] list Dashboard.execute_all applies to every card whose SQL references the filter column.

Errors

Every failure raises a subclass of honeyframeapi.HoneyframeError: HoneyframeAuthError (401/403), HoneyframeNotFoundError (404), HoneyframeValidationError (400/409/422), HoneyframeAPIError (other non-2xx), each carrying .status_code and .detail.

Scope

Shipped: auth (login + token), projects, datasets→pandas + create/import/ materialize + snapshot versions & as-of time-travel reads, ad-hoc SQL, dashboards + cards, connectors (full CRUD + test), knowledge banks (RAG build loop) + LLM Mesh governance/spend, scenarios (run/wait/history + triggers + reporters), project bundles + Govern-style deployment sign-offs, jobs + pipeline triggers + logs, recipes (inspect + dbt build + author prepare steps + per-recipe engine selection), published assets + data-API-key minting, agent chat. This covers the dataikuapi surface used across the dwh-adira scripts.

Personal Access Tokens (hf_…) are first-class: mint from the settings UI or client.create_pat(name, expires_days=…), then authenticate with token="hf_…". They're independently revocable, scoped to the minting user, and don't carry the 8h JWT expiry — the right credential for cron/automation.

Still planned: richer recipe authoring (SQL/Python recipe payloads beyond prepare steps).

client.sql() note: there's no public raw-SQL endpoint yet, so sql() runs through a hidden per-project scratch dashboard card (zero backend change). It honors the platform's per-card row cap — for full-table extracts use Dataset.get_dataframe(). When a POST /api/sql endpoint lands, only the internals change; sql()'s signature is stable.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

honeyframeapi-0.1.7.tar.gz (126.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

honeyframeapi-0.1.7-py3-none-any.whl (95.6 kB view details)

Uploaded Python 3

File details

Details for the file honeyframeapi-0.1.7.tar.gz.

File metadata

  • Download URL: honeyframeapi-0.1.7.tar.gz
  • Upload date:
  • Size: 126.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.15

File hashes

Hashes for honeyframeapi-0.1.7.tar.gz
Algorithm Hash digest
SHA256 0717dac8359f8688b665e9d83aedee8c8adf6f95f3af2407269650b23504f69d
MD5 93b19d856fffe4436130447d74fe6cf1
BLAKE2b-256 4bfe78b83ada45bf9ca71eb645206c3fa0b0ecaf9b8f1641d971070a4f7f33f7

See more details on using hashes here.

File details

Details for the file honeyframeapi-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: honeyframeapi-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 95.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.15

File hashes

Hashes for honeyframeapi-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 2895f1cd00a8d3b96b855f98a6462dc59095fc8250e43ca00caea72583d5fcc8
MD5 9acf6e46215b8fefd78bae3aa624929d
BLAKE2b-256 ce140d18221df49a432dcae6e9bf79fa417f6af4fc02a0899a65b545f14adb8f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page