Skip to main content

:::note Generated reference Generated from honeyframeapi 0.1.8 — do not edit by hand. :::

honeyframeapi.project

Project handle — datasets, SQL, dashboards, recipes, scenarios and more for one project.

Every project-scoped call carries this project's id as the X-Project-Id header, so a single client can drive many projects:

proj = client.get_project(1)
proj.list_datasets()
df = proj.get_dataset("fact_orders").get_dataframe()
dash = proj.create_dashboard("Ops Overview")

class Project​

Project.get_summary()​

get_summary() -> dict

Fetch (and cache) the project detail record.

Project.get_settings()​

get_settings() -> dict

Project.list_datasets()​

list_datasets(*, layer: Optional[str] = None, origin: Optional[str] = None, search: Optional[str] = None, tags: Optional[str] = None) -> list[dict]

List datasets in this project, with optional filters.

Project.get_dataset()​

get_dataset(name: str) -> Dataset

Return a Dataset handle (does not fetch until used).

ai_search(intent: str, *, tags: Optional[list] = None, limit: int = 10) -> dict

Rank this project's datasets against a natural-language intent.

Project-scoped HoneyframeClient.ai_search_datasets — returns {"results": [...], "intent": ..., "count": n}. For the org-wide (cross-project) search, call the client method with project_id=None.

Project.list_dataset_tags()​

list_dataset_tags() -> list

Every distinct dataset tag in this project (GET /api/datasets/tags).

Union of the dedicated tags[] column and the legacy settings.tags JSON path — both are live server-side.

Project.apply_dataset_tags()​

apply_dataset_tags(names: list, *, add: Optional[list] = None, remove: Optional[list] = None) -> dict

Bulk-tag datasets: per dataset tags = (existing ∪ add) − remove.

POST /api/datasets/tags/apply. Writes both the tags[] column and settings.tags so the list view and the settings modal agree. Returns {"updated": n, "missing": [names not in this project]} — a name the project doesn't have is reported, not an error. Needs org.admin.

Project.create_dataset()​

create_dataset(name: str, *, dataset_type: str = 'sql_table', layer: str = 'source', friendly_name: str = '', description: str = '', connector_id: Optional[int] = None, connection_config: Optional[dict] = None, schema_config: Optional[dict] = None, sync_mode: str = 'batch', sync_interval: Optional[int] = None) -> Dataset

Create a dataset in this project and return its handle.

For an external SQL table, point at a connector + connection_config={"schema_name": …, "table_name": …}. The returned handle uses the name the server stored (it lowercases and turns spaces/dashes into _).

Project.import_dataset()​

import_dataset(name: str, *, unique_id: str = '', schema_name: str = '', layer: str = '') -> dict

Import an existing physical table as a dataset.

Project.register_source_table()​

register_source_table(schema_name: str, table_name: str, *, connector_id: Optional[int] = None, friendly_name: str = '', name: Optional[str] = None) -> Dataset

Register an existing raw table as a discoverable source_table dataset.

Use this to surface a table that already lives in a connector's database (e.g. a staging schema in the warehouse) in the dataset picker, without copying any data. Unlike import_dataset (which only finds tables already known to the dbt/native catalog), this registers any physical schema.table directly.

The registered dataset is immediately queryable — the server records schema_name + connection_config so the resolver runs SELECT … FROM <schema_name>.<table_name> natively. To bulk-register every table in a schema, see register_schema.

Returns a Dataset handle for the registered table.

Project.register_schema()​

register_schema(schema_name: str, *, connector_id: int, search: str = '') -> list[Dataset]

Register every table in a connector schema as source_table datasets.

Lists the tables in schema_name via the connector, then registers each one (see register_source_table). search filters the table names server-side. Returns the list of registered Dataset handles. Idempotent — re-registering an existing table is a no-op.

Project.upload_dataframe()​

upload_dataframe(name: str, df, *, friendly_name: str = '', description: str = '', replace: bool = False, materialize: bool = False) -> Dataset

Upload a pandas DataFrame as a managed dataset and return its handle.

The frame is serialised to CSV and sent to POST /api/datasets/file/upload, which stores it as Parquet on the server (a managed, file-backed dataset). Uploaded data is invisible to PG-backed consumers (dbt, dashboards, agents) until materialised — pass materialize=True to copy it into t<pid>_uploads.<name> right away, or call Dataset.materialize later.

Project.upload_file()​

upload_file(name: str, path, *, friendly_name: str = '', description: str = '', replace: bool = False, materialize: bool = False) -> Dataset

Upload a local .csv or .xlsx file as a managed dataset.

Project.sql()​

sql(query: str, *, connector_id: Optional[int] = None, row_limit: int = 10000, params: Optional[dict] = None) -> Any

Run ad-hoc SQL in this project and return a pandas DataFrame.

Runs through the platform's governed POST /api/sql endpoint (SELECT only, within the project's schemas, data policies applied). params are named binds: sql("... WHERE d >= :p_start", params={"p_start": "2026-01-01"}).

When the server cut the result at row_limit (it reports truncated), the SDK emits a UserWarning and sets df.attrs["truncated"] = True ("truncated": True on the dict returned without pandas). Raise row_limit (the server caps it at 50,000) or page the query yourself.

Only on an older platform where /api/sql does not exist does it fall back to a hidden per-project scratch dashboard card (params is not supported there).

Project.list_dashboards()​

list_dashboards(tab: str = 'all') -> list[dict]

Dashboards of this project, as the server scopes them.

Sends project_id so the server lists this project's dashboards (it 403s a project you cannot read). Org-level dashboards (project_id null) are included, the same list the UI shows.

Project.create_dashboard()​

create_dashboard(title: str, *, description: Optional[str] = None, is_public: bool = False, collection_id: Optional[int] = None) -> Dashboard

Create a dashboard owned by this project and return its handle.

Project.get_dashboard()​

get_dashboard(dashboard_id: int) -> Dashboard

Project.list_connectors()​

list_connectors() -> list[dict]

Project.dbt​

property

dbt: DbtIDE

Authoring handle over /api/dbt/* — write/run/version dbt models.

Project.get_recipe()​

get_recipe(model_name: str) -> Recipe

Return a Recipe handle for a flow model.

Project.run_dbt()​

run_dbt(select: Optional[str] = None, *, wait: bool = False, timeout: float = 1800.0, poll_interval: float = 5.0) -> dict

Trigger a dbt build in this project (dbt run or --select).

Returns the trigger response ({"status": "triggered", …}) at once. With wait=True it blocks until the build's run finishes and returns that run (status success / failed), via JobsAPI.trigger_and_wait. Needs org admin.

Project.build_native()​

build_native(select: Optional[str] = None, *, dry_run: bool = False, background: bool = False, wait: bool = False) -> dict

Build this project's native-engine recipes in dependency order — the native dbt run (POST /api/flow/build-native).

Native-engine orgs only (a dbt org gets 409 and builds with run_dbt). The server topo-sorts every target='sql' recipe by its dataset I/O and runs them through the recipe runner, stopping at the first failure.

select narrows the build dbt-style: model, model+, +model, +model+, comma-separated. dry_run=True returns the resolved order without executing (the native dbt ls --select) and wins over background. background=True returns {run_id, status:"running", …} immediately; add wait=True to block on the run and return its detail instead.

Sync returns {ordered, results:[{model,status,error}], built, total, ok, selected}. A recipe saved with no SQL fails here with "has empty inline_code" — land it first with Recipe.set_sql.

Project.change_recipe_engines()​

change_recipe_engines(names: list, target: str, *, dry_run: bool = False) -> dict

Change the compute engine of one or more recipes at once (the UI's "change recipe engines" bulk action). target ∈ sql (pin each to the native in-database engine) | dbt (pin to dbt) | auto (clear pins and reset to the org's default engine). A recipe that can't compile to the requested engine is reported not-ok and left untouched. dry_run=True reports the per-recipe outcome without writing. Returns {results: [{name, ok, from, to, messages}], dry_run, target}. Needs org admin. Read a single recipe's status via Recipe.engine_status.

Project.engine()​

engine(*, refresh: bool = False) -> str

The catalog engine profile for this org: 'dbt' or 'native'.

  • 'dbt' — dbt is installed; author transforms as dbt models via dbt (project.dbt.create_model / write_file + run).
  • 'native' — a standalone Honeyframe install with no dbt. There is no dbt IDE; author SQL transforms with the recipe API instead (get_recipe(name).save_prepare_steps(...) or .save(recipe_type='sql_query', steps=[...])). The server materialises them through the native engine automatically — the org's engine profile decides, so there is no per-call target flag.

Cached after the first call; pass refresh=True to re-read. Defaults to 'dbt' on pre-migration servers that don't expose the field yet.

Project.uses_dbt()​

uses_dbt() -> bool

True when this org authors transforms as dbt models (engine == 'dbt').

Project.dag()​

dag() -> dict

The project's full lineage DAG as {nodes: [...], edges: [...]}.

Walks through the model catalog, so it works on both dbt and native-engine tenants. For a single dataset's ancestors/dependents use Dataset.upstream / Dataset.downstream.

Project.list_scenarios()​

list_scenarios() -> list[dict]

Project.get_scenario()​

get_scenario(scenario: int | str) -> Scenario

Return a Scenario handle by id or name.

Project.create_scenario()​

create_scenario(name: str, *, display_name: Optional[str] = None, description: str = '', trigger_type: str = 'manual', steps: Optional[list] = None, is_active: bool = False, **extra) -> Scenario

Project.create_bundle()​

create_bundle(*, label: str = '', **opts) -> Bundle

Snapshot this project as the next bundle version. opts are the export include-flags (include_versions, include_managed_folder_files, include_vector_stores, include_job_runs, include_form_submissions, include_dbt_target).

Project.list_bundles()​

list_bundles() -> list[dict]

Bundle versions for this project (newest first).

Project.bundle()​

bundle(version: int) -> Bundle

Return a Bundle handle for a version.

Project.list_signoffs()​

list_signoffs() -> dict

Deployment sign-off status + audit log for every bundle version of this project — {mode, signoffs: {version: {status, blocking, reviewers, approver_user_id, log}}}. mode is the org's sign-off policy (whether the gate blocks a deploy). Drive a version's gate from the Bundle handle (Bundle.request_signoff etc.).

Project.list_bundle_activations()​

list_bundle_activations() -> list[dict]

Activation history for this project's bundles ({activation_id, bundle_id, version, target_project_id, node_role, activated_by, activated_at, is_active}).

Project.list_models()​

list_models(*, name: str | None = None) -> list[SavedModel]

Saved models in this project (name= narrows to one model's version history). Created by train_model / cluster_model recipes.

Project.get_model()​

get_model(model_id: int) -> SavedModel

Return a SavedModel handle (fetches lazily).

Project.list_experiments()​

list_experiments() -> list[Experiment]

Experiments in this project. The Analysis Lab logs into these automatically; the SDK adds its own runs alongside.

Project.create_experiment()​

create_experiment(name: str, *, description: str = '') -> Experiment

Create an experiment → an Experiment handle. Names are unique per project (a duplicate raises).

Project.get_experiment()​

get_experiment(experiment_id: int) -> Experiment

Return an Experiment handle (fetches lazily).

Project.create_ml_recipe()​

create_ml_recipe(name: str, recipe_type: str, *, inputs: list, config: dict, output_datasets=None) -> MlRecipe

Create an ML recipe of any type (train_model / score_model / cluster_model / evaluate_model). Prefer the typed helpers below.

Project.train_model()​

train_model(name: str, *, input_table: str, target_column: str, task_type: str, algorithm: str, features=None, hyperparams=None, test_size=None, max_rows=None, model_name=None, run: bool = True, wait: bool = True) -> MlRecipe

Train a supervised model — see ml.train_model.

Project.score_model()​

score_model(name: str, *, input_table: str, model_id: int, output_table=None, output_schema=None, max_rows=None, run: bool = True, wait: bool = True) -> MlRecipe

Score rows with a trained model — see ml.score_model.

Project.cluster_model()​

cluster_model(name: str, *, input_table: str, algorithm: str, features=None, hyperparams=None, output_table=None, output_schema=None, max_rows=None, model_name=None, run: bool = True, wait: bool = True) -> MlRecipe

Fit a clustering model — see ml.cluster_model.

Project.evaluate_model()​

evaluate_model(name: str, *, input_table: str, target_column: str, model_id: int, max_rows=None, run: bool = True, wait: bool = True) -> MlRecipe

Evaluate a trained model — see ml.evaluate_model.

Project.create_plugin_recipe()​

create_plugin_recipe(recipe_type: str, name: str, *, config: Optional[dict] = None, inputs: Optional[list] = None, output_datasets: Optional[list] = None, run: bool = False, wait: bool = False) -> PluginRecipe

Create a flow recipe of a plugin-contributed custom recipe_type — see plugin_recipe.create_plugin_recipe. Discover creatable types via plugin_recipe_types.

Project.list_notebooks()​

list_notebooks() -> list[dict]

List this project's notebooks (metadata + cell counts).

Project.create_notebook()​

create_notebook(name: str, *, description: str = '', cells: Optional[list] = None, tags: Optional[list] = None) -> Notebook

Create a notebook → a Notebook handle. cells items may be source strings or full cell dicts.

Project.get_notebook()​

get_notebook(notebook_id: int) -> Notebook

Fetch a notebook by id → a populated Notebook.

Project.import_ipynb()​

import_ipynb(src, *, name: Optional[str] = None, description: str = '', tags: Optional[list] = None) -> Notebook

Import a Jupyter .ipynb (path or parsed dict) as a platform notebook. Round-trips with export_ipynb.

Project.list_wiki_pages()​

list_wiki_pages() -> list[dict]

List this project's wiki pages (metadata; the body is omitted).

Project.create_wiki_page()​

create_wiki_page(title: str, *, body: str = '') -> WikiPage

Create a wiki page → a WikiPage handle.

Project.get_wiki_page()​

get_wiki_page(slug: str) -> WikiPage

Fetch a wiki page by slug → a populated WikiPage.

Project.list_comments()​

list_comments(object_type: str, object_id: str) -> list[dict]

The threaded comments on an object (dataset / dashboard / recipe / …).

Project.comment_count()​

comment_count(object_type: str, object_id: str) -> int

Number of comments on an object.

Project.add_comment()​

add_comment(object_type: str, object_id: str, body: str, *, parent_id: Optional[int] = None) -> dict

Post a comment, or a reply when parent_id is set, on an object.

Project.edit_comment()​

edit_comment(comment_id: int, body: str) -> dict

Edit a comment you authored.

Project.delete_comment()​

delete_comment(comment_id: int) -> None

Delete a comment (author; an admin may delete any).

Project.list_folders()​

list_folders() -> list[dict]

Managed folders visible to this project (project-scoped + org-wide).

Project.get_folder()​

get_folder(folder_id: int) -> Folder

Return a Folder handle (does not fetch until used).

Project.create_folder()​

create_folder(name: str, *, description: str = '', org_wide: bool = False) -> Folder

Create a managed folder in this project and return its handle.

Project.create_api_service()​

create_api_service(asset_key: str, title: str, *, endpoints: Optional[list] = None, publish: bool = False, description: str = '', roles: Optional[list] = None, is_public: bool = False, icon: str = '') -> APIService

Create a project-scoped API service and return its handle.

Delegates to HoneyframeClient.create_api_service with this project's scope. endpoints is a list from the endpoint builders (sql_endpoint / lookup_endpoint / model_endpoint); publish=True makes the endpoints callable now.

Project.get_preferences()​

get_preferences() -> dict

Per-user project preferences blob (free-form JSON).

Distinct from project variables (see list_variables): preferences are per-user UI state; variables are shared, typed, and referenced in SQL as :name / ${name}.

Project.set_preferences()​

set_preferences(prefs: dict) -> dict

Project.list_variables()​

list_variables() -> dict

Resolved project variables as {name: value} (local overrides standard).

Project.set_variable()​

set_variable(name: str, value, *, var_type: str = 'string', scope: str = 'standard') -> dict

Create/update a project variable. Referenced in SQL as :name / ${name}.

Project.delete_variable()​

delete_variable(name: str, *, scope: str = 'standard') -> dict

Verified against honeyframeapi 0.1.8.