Lewati ke konten utama

SDK

Honeyframe ships a first-party Python client, honeyframeapi, modeled on the dataikuapi usage pattern. It wraps the REST API behind typed resource handles so you can script projects, datasets, recipes, dashboards, agents, and bundles from a notebook or a CI job instead of hand-rolling HTTP calls.

The current release is honeyframeapi 0.1.2. The public PyPI debut was 0.1.0; 0.1.1 adds webapp building (not just publishing) and ML model training (not just reading) — see Dashboards and webapps and Machine learning below; 0.1.2 adds the API Services wrapper — turn datasets, lookups, and ML models into key-gated REST endpoints from code — see API Services. (Internally the package iterated through a 0.4.x series during development; the version was reset to 0.1.0 for the public release, so 0.1.0 is the first version you'll see on PyPI — there is no public 0.4.x.)

The package ships a PEP 561 py.typed marker and is mypy-clean, so your editor and type-checker see the full type surface.

Installation

pip install honeyframeapi

Optional extras:

  • pandasDataFrame returns from get_dataframe(), sql(), to_parquet(). Install pip install honeyframeapi[pandas] (or just pip install pandas pyarrow). to_csv() works without pandas (stdlib csv).

Authentication

The recommended credential is a Personal Access Token (PAT) — a long-lived hf_… token you mint from the platform UI (or from the SDK itself). Unlike the short-lived JWT, a PAT doesn't expire on the hour, so it's the right fit for scripts and automation. See Authentication → Personal Access Tokens.

from honeyframeapi import HoneyframeClient

client = HoneyframeClient(
base_url="https://platform.your-domain.com",
token="hf_xxxxxxxxxxxxxxxxxxxx", # a Personal Access Token
)

Or read everything from the environment with from_env(), which picks up HONEYFRAME_* (and legacy HUB_*) variables:

import os
# HONEYFRAME_URL, HONEYFRAME_TOKEN (or HONEYFRAME_USER + HONEYFRAME_PASSWORD), HONEYFRAME_ORG_ID
client = HoneyframeClient.from_env()

Two auth modes are supported under the hood:

  • TokenAuth — carries a PAT (hf_…) verbatim. No refresh needed.
  • LoginAuth — username/password; the client logs in to mint a JWT and auto-re-logs-in on 401. Use a PAT in preference for unattended jobs.

The client injects Authorization, X-Org-Id, and X-Project-Id headers automatically, maps HTTP status codes to typed exceptions (HoneyframeAuthError, etc.), and retries idempotent requests (GET/HEAD/OPTIONS) on transient failures — httpx.TransportError or a 502/503/504 — with bounded exponential backoff. Writes are never auto-retried (a transport error may have already applied server-side). Tune with max_retries (default 2) and retry_backoff (default 0.5s); set max_retries=0 to disable.

Core handles

The client mirrors the dataikuapi object model. Top-level accessors:

AccessorWhat it covers
client.get_project(id)Project handle — the entry point for most work.
client.jobsJobsAPIlist_runs / get_run / wait / abort / trigger / logs.
client.sql(...)Run a governed SQL query, returns a DataFrame.
client.create_pat / list_pats / revoke_patManage Personal Access Tokens from code.
client.list_webapps / get_webapp / publish_webapp / create_webappWebapp publishing and building (see below).
client.create_api_service / get_api_serviceAPIService handle — multi-endpoint key-gated serving (see API Services). Also project.create_api_service for the project-scoped form.

From a Project handle:

  • Datasetscreate_dataset / import_dataset / get_dataset; upload_dataframe(name, df) and upload_file(name, path) create a managed dataset (stored as Parquet) from local data; dag() returns {nodes, edges} for the project lineage graph.
  • ConnectorsConnector handle: create / get / update / delete / test.
  • Scenarioslist_scenarios / get_scenario / create_scenario; Scenario.run / run_and_wait / get_last_runs.
  • Recipesget_recipe; Recipe.get_metadata / runs / build / save_prepare_steps, and Recipe.save(recipe_type=, steps=) for full-control authoring of any recipe type.
  • Bundlescreate_bundle / list_bundles / bundle(version); Bundle.activate(target_name, target_slug) clones into a new project, Bundle.download() streams the stored zip.
  • Managed folderslist_folders / get_folder / create_folder; Folder.list_files / upload / upload_bytes / download / read_bytes / mkdir / delete_file.
  • AgentsAgent.ask() runs a multi-turn chat session against a published agent.
  • Published assetsPublishedAsset.publish / unpublish / update, plus data-API key mint / list / revoke (the one-time dk_… secret).
  • Machine learningtrain_model / score_model / cluster_model / evaluate_model (and the lower-level create_ml_recipeMlRecipe handle) train and apply models; list_models / get_model return SavedModel handles. See Machine learning.
  • Engine introspectionProject.engine() returns 'dbt' or 'native'; Project.uses_dbt() is the boolean shorthand. A script can branch on whether this install has dbt before choosing how to author the warehouse.

Reading data

project = client.get_project("sales")
ds = project.get_dataset("orders")

df = ds.get_dataframe() # paginates /explore, returns a DataFrame
ds.head(20) # preview rows
ds.profile() # column statistics
answer = ds.ask("how many orders last week?") # natural-language query

Exports go to local files, reading through the same paginated /explore path so server-side data-policy / PII masking is applied — an export can never see more than the caller can browse:

ds.to_csv("orders.csv") # no pandas needed
ds.to_parquet("orders.parquet") # needs pandas + pyarrow
ds.to_csv("orders.csv", max_rows=10_000)

Lineage

ds.upstream() # recursive ancestors — what feeds this dataset
ds.downstream() # recursive dependents — what breaks if I change it
project.dag() # {nodes, edges} for the whole project

Lineage reads through the model catalog, so it works on dbt and native-engine tenants alike.

Authoring the warehouse from code

The SDK is a governed gateway for building the warehouse, not just reading it — no SSH or psql.

# Governed SQL — project-scoped, SELECT-guarded, statement-timeout enforced
df = project.sql("select region, sum(amount) from orders group by 1")

Warehouse DDL goes through dbt authoring (the dbt-native engine's contract), not raw DDL. On a dbt install:

dbt = project.dbt # DbtIDE handle over /api/dbt/*
dbt.write("models/marts/revenue.sql", "select ...")
dbt.create_model("revenue", "select ...")
dbt.run(select="revenue")
dbt.test()
dbt.build()
dbt.compile()
dbt.list_models()
dbt.git_status(); dbt.commit("add revenue mart"); dbt.push()

On a native-only install (no dbt), author target='sql' recipes via Recipe.save(...) / save_prepare_steps(...) instead. Project.engine() lets one script drive either path.

This closes the end-to-end loop: detect engine → upload → author → run → read → lineage → publish.

Dashboards and webapps

dash = project.create_dashboard("Sales overview")
dash.add_card({...})
dash.add_cards([...]) # accepts the bulk dict shape verbatim
dash.execute_all()

Publish a dashboard as a webapp and mint token-gated public share links — entirely from code:

webapp = client.publish_webapp(...)
link = webapp.create_public_link()
print(webapp.public_url(link.token)) # shareable URL
webapp.revoke_public_link(link.token)

Webapp exposes config, public_links, create_public_link, revoke_public_link, url, and public_url(token, host=).

Building a webapp from code (0.1.1). Beyond publishing an existing dashboard, you can assemble a multi-page webapp from page and block builders and create it in one call. The block builders cover page, card_ref, html_block, code_card (including the process_map card type), and nav_item:

from honeyframeapi import page, card_ref, html_block, code_card, nav_item

webapp = client.create_webapp(
name="Ops console",
pages=[
page("Overview", blocks=[
html_block("<h1>Operations</h1>"),
card_ref(dashboard_id="...", card_id="..."),
]),
],
nav=[nav_item("Overview", "/overview")],
publish=True, # opt-in; draft by default — omit to keep it unpublished
)

A Webapp handle also supports incremental editing: update, publish / unpublish, add_page, and set_nav.

Machine learning

honeyframeapi 0.1.1 can train models, not just read them. The high-level helpers build a typed run config (input table, target, features, algorithm) and create-then-run an ML recipe via /api/flow/ai-recipes:

model = project.train_model(
table="customers",
target="churned",
features=["tenure", "monthly_charges", "plan"],
algorithm="random_forest",
test_size=0.2,
)
project.score_model(model_id=model.id, table="new_customers", output_table="churn_scored")
project.cluster_model(table="customers", k=5, output_table="segments")
metrics = project.evaluate_model(model_id=model.id, table="holdout")

For full control, create_ml_recipe(...) returns an MlRecipe handle (create → run_config → run). Trained models are addressable as SavedModel handles:

for m in project.list_models():
print(m.name, m.info()["task"], m.metrics())

model = project.get_model("churn")
model.feature_importance() # ranked drivers
model.versions() # version history
model.activate() # promote a version
model.delete() # guarded delete

API Services

honeyframeapi 0.1.2 wraps API Services — group several key-gated REST endpoints under one published asset and call them with a minted dk_… key, entirely from Python. An API service is project-scoped, so the client (or the call) must carry a project_id. See the API Services product page for the serving model.

An APIService handle subclasses PublishedAsset, so it inherits publish / unpublish / update. Build the endpoint list with the endpoint builders — sql_endpoint, lookup_endpoint, model_endpoint, and function_endpoint (the function kind is deferred — the serving runtime returns 501 until the sandbox lands):

from honeyframeapi import lookup_endpoint, model_endpoint

svc = client.create_api_service( # or project.create_api_service(...)
"serving", "Serving",
endpoints=[
lookup_endpoint("patient", "marts.dim_patient", "patient_key"),
model_endpoint("noshow_risk", model_id=12),
],
publish=True, # draft by default — omit to keep unpublished
)

# Mint a key scoped to a subset of endpoints (None = all endpoints)
key = svc.create_key(name="app", allowed_endpoints=["noshow_risk"])

# Call an endpoint through the X-API-Key serving route
out = svc.call("noshow_risk", {"features": {"age": 34}}, api_key=key.key)
print(out["predictions"])

create_api_service returns a draft; pass publish=True (or call svc.publish()) to make the endpoints callable. Edit the config incrementally with add_endpoint(endpoint) / set_endpoints([...]) (read-modify-write — editing the draft doesn't republish on its own), then publish() / unpublish().

call(endpoint, payload, api_key=) hits the public serving route: sql/lookup endpoints read via GET + params (method='GET'), model endpoints score online via the default POST + payload ({'features': {...}} or {'rows': [...]}). test(endpoint, payload) is the builder dry-run — same dispatch the serving route uses, but JWT-authenticated (admin-unmasked, no key needed) for trying an endpoint before minting one.

Metrics and checks

ds.add_metric(...)
ds.compute_metrics() # computes active metrics only
ds.metric_history("row_count")
ds.add_metric_check(...)
ds.metrics_status()

Name-based lookups resolve name → id for you.

CLI

The package installs a honeyframe console script. Flags go after the subcommand (kubectl / gh style), and most commands take --format json|csv:

honeyframe whoami
honeyframe version
honeyframe projects
honeyframe datasets -p sales
honeyframe sql "select 1" -p sales

# Personal Access Tokens
honeyframe pat create --name ci-token
honeyframe pat list
honeyframe pat revoke <id>

# Scenarios
honeyframe scenario list -p sales
honeyframe scenario run <name> -p sales

# Warehouse loop
honeyframe engine -p sales # dbt vs native
honeyframe lineage orders [--down] -p sales
honeyframe upload orders data.csv [--replace] [--materialize] -p sales
honeyframe export orders out.csv [--max-rows N] -p sales

When to drop to the REST API

honeyframeapi covers the common authoring and analytics surface. For endpoints it doesn't wrap yet, fall back to the documented Core API and the OpenAPI spec, or generate a client with openapi-generator-cli:

openapi-generator-cli generate \
-i https://platform.your-domain.com/openapi.json \
-g python \
-o ./honeyframe-client-py

Regenerate after each release; the OpenAPI document is the source of truth and changes per version.