All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
list_managed_tables,load_managed_table,add_managed_table,delete_managed_table,delete_managed_database, andexecute_sqlaccept an already-resolvedManagedDatabase(as returned bycreate_managed_database) in place of a name/id. When passed one, they skip theget_database/list_databasesread probe. This lets an API key scoped to create + load but not read/databasesbootstrap a managed database and load into it within a single run: the caller holds theManagedDatabasefromcreateand drives the load/add/query ops with zero reads. The name/id string path is unchanged.
load_managed_tableaccepts akeyargument — the merge key columns fordelete/update/upsertloads, matched per-load instead of requiring a key declared at table creation. Omit it to use the table's declared key; ignored forreplace/append. Requireshotdata>=0.8.0.
upload_parquet()now delegates to the SDK'shotdata.uploads.UploadsApi.upload_file()instead of hand-rolling the session → PUT → finalize flow. Uploads gain concurrent part PUTs under a peak-memory budget, per-part retries, and ETag/size validation, making large uploads substantially faster. Errors still surface asRuntimeErrorwith the underlyingApiExceptionas the direct cause.
classify_sdk_errornow classifies HTTP 501 (Not Implemented) as terminal instead of transient — a permanent capability gap must not burn retries.
- The
POST /v1/filesfallback inupload_parquet(). Presigned upload sessions (POST /v1/uploads) are now required; a server that responds 501 raises a clearRuntimeErrorinstead of silently falling back to the full-file-in-memory upload path.
upload_parquet()now uses the presigned upload session API (POST /v1/uploads) instead of reading the entire file into memory before uploading. For multipart mode the file is streamed onepart_sizechunk at a time, eliminating the memory spike that caused OOM on large Parquet files. Falls back toPOST /v1/fileswhen the server returns 501.
load_managed_table(..., mode=...)selects the load mode (replace(default),append,delete,update,upsert) instead of always replacing the table.replace/appendapply the upload directly;delete/update/upsertmatch rows by the table's declared key. Backward compatible — omittingmodestill replaces.create_managed_database(..., keys={table: [cols]})andadd_managed_table(..., key=[cols])declare a table's row-identity key, enabling the key-based load modes on it. Requires ahotdataclient whose managed-table decl models carrykey(see the dependency floor bump); tables declared without a key stayreplace/append-only.
load_managed_table(..., mode="append")is no longer retried on transient errors. Every other mode is idempotent, but retrying anappendwhose commit succeeded before the response was received would duplicate the uploaded rows;appendnow runs at most once.modeis also now typed as a literal of the accepted values.
HotdataClientandManagedDatabaseClientacceptrequest_timeout(seconds, or a(connect, read)pair). The generated SDK otherwise issues every HTTP request with urllib3's no-timeout default, so a stalled or unreachable server blocks the calling thread indefinitely; the new parameter applies a socket-level deadline to every call through the client while still honoring an explicit per-call_request_timeout. Also exported asapply_default_request_timeout(api_client, timeout)for callers holding a raw generated client. Default remains no timeout (behavior unchanged unless opted in).
- Repository text cleanup: the changelog and test docstrings no longer reference external issue trackers. No functional changes; 0.6.2 is byte-identical to 0.6.1 in package code.
ManagedDatabaseClient.fetch_tablenow carries theX-Database-Idscope header on the result poll, the query-run poll, and the Arrow fetch — not only on the query submit. Results of database-scoped queries are themselves database-scoped, so every read against an existing synced table (merge/append loads, dlt state restore) failed with400: Bad Requestonce the table had data.- API error messages now include the response body (flattened, truncated to 500 chars).
400: Bad Requestalone hid the server's actual explanation.
- The
hotdataSDK dependency is now>=0.6.0, and the scope above rides its nativex_database_idparameters (get_result,get_query_run,get_result_arrow). Note 0.6.0 madex_database_idrequired onget_result_arrow, so older framework releases cannot run on it.
HotdataClient.add_managed_table(database, table, *, schema)declares a new table on an existing managed database (wrapping the SDKadd_database_tableendpoint). This allows additive schema evolution without recreating the database.
- Adopt the
hotdata0.5.0 SDK surface (dependency bumped from>=0.4.1to>=0.5.0). The release is backward compatible for everything the framework uses; the only API changes are additive (a new optionalformatfield onLoadManagedTableRequestand an optionalformatparameter onResultsApi.get_result), so no framework code changes were required.
ManagedDatabaseClient.fetch_tablenow waits for the persisted result to reachreadybefore fetching it as Arrow on the synchronous query path (it previously only waited on the async path). This fixes failures on read-modify-write loads (merge/append) and state reads against the live backend, where the result is often stillprocessingwhen the inline preview returns.
- Renamed the distribution from
hotdata-runtimetohotdata-frameworkand the import package fromhotdata_runtimetohotdata_framework. Consumers should depend onhotdata-frameworkand useimport hotdata_framework. The GitHub repository is nowsdk-python-framework. - Added PyPI classifiers, keywords, and an updated description identifying the project as a Python framework.
- Adopt the
hotdata0.4.1 SDK surface. - New typed error-handling public API:
HotdataError,HotdataTerminalError,HotdataTransientError, andclassify_sdk_error(hotdata_framework/errors.py). ManagedDatabaseClientfor managed database operations (hotdata_framework/managed_client.py).py.typedmarker so downstream consumers pick up inline type information.
- Bump the
hotdatadependency pin to>=0.4.1. - Add ruff and mypy tooling configuration and dev dependencies (
ruff>=0.5,mypy>=1.5); apply ruff lint/format cleanup across the package.
- Release 0.2.4
- Release 0.2.3
- Release 0.2.2
execute_sqlaccepts an optionaldatabasekeyword argument. When provided, the database name is resolved to an ID and sent as theX-Database-Idheader so SQL can reference managed database tables as"default"."<schema>"."<table>". Behaviour is unchanged whendatabaseis omitted.
- Switch managed database operations from the connections API to the dedicated
/databasesAPI (hotdata>=0.2.3required). create_managed_databasefirst parameter renamed fromnametodescription(keyword-only).ManagedDatabasedataclass: replacename/source_typefields withdescription/default_connection_id.resolve_managed_databasetries direct ID lookup first, then falls back to a description scan.list_managed_databasesnow fetches all databases regardless of source type.list_managed_tables,load_managed_table, anddelete_managed_tableusedefault_connection_idinstead of databaseidfor connection-scoped operations.
create_managed_databaseaccepts an optionalexpires_atparameter.
MANAGED_SOURCE_TYPE,build_managed_config, andcreate_connection_requestremoved from the public API.
- Managed database helpers on
HotdataClient.
- Initial release.