hotdata-framework 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. hotdata_framework-0.4.0/.github/dependabot.yml +8 -0
  2. hotdata_framework-0.4.0/.github/workflows/check-release.yml +26 -0
  3. hotdata_framework-0.4.0/.github/workflows/ci.yml +33 -0
  4. hotdata_framework-0.4.0/.github/workflows/dependabot-automerge.yml +17 -0
  5. hotdata_framework-0.4.0/.github/workflows/publish.yml +69 -0
  6. hotdata_framework-0.4.0/.github/workflows/release.yml +54 -0
  7. hotdata_framework-0.4.0/.gitignore +50 -0
  8. hotdata_framework-0.4.0/CHANGELOG.md +86 -0
  9. hotdata_framework-0.4.0/CONTRACT.md +106 -0
  10. hotdata_framework-0.4.0/PKG-INFO +69 -0
  11. hotdata_framework-0.4.0/README.md +41 -0
  12. hotdata_framework-0.4.0/RELEASING.md +43 -0
  13. hotdata_framework-0.4.0/examples/basic_usage.py +25 -0
  14. hotdata_framework-0.4.0/hotdata_framework/__init__.py +71 -0
  15. hotdata_framework-0.4.0/hotdata_framework/client.py +524 -0
  16. hotdata_framework-0.4.0/hotdata_framework/databases.py +61 -0
  17. hotdata_framework-0.4.0/hotdata_framework/env.py +81 -0
  18. hotdata_framework-0.4.0/hotdata_framework/errors.py +31 -0
  19. hotdata_framework-0.4.0/hotdata_framework/health.py +27 -0
  20. hotdata_framework-0.4.0/hotdata_framework/http.py +17 -0
  21. hotdata_framework-0.4.0/hotdata_framework/managed_client.py +184 -0
  22. hotdata_framework-0.4.0/hotdata_framework/py.typed +0 -0
  23. hotdata_framework-0.4.0/hotdata_framework/result.py +75 -0
  24. hotdata_framework-0.4.0/pyproject.toml +98 -0
  25. hotdata_framework-0.4.0/scripts/check-release.py +68 -0
  26. hotdata_framework-0.4.0/scripts/extract-changelog.py +36 -0
  27. hotdata_framework-0.4.0/scripts/publish-workflow.sh +75 -0
  28. hotdata_framework-0.4.0/scripts/release.sh +191 -0
  29. hotdata_framework-0.4.0/scripts/update_changelog.py +62 -0
  30. hotdata_framework-0.4.0/tests/test_client.py +297 -0
  31. hotdata_framework-0.4.0/tests/test_contract.py +60 -0
  32. hotdata_framework-0.4.0/tests/test_databases.py +252 -0
  33. hotdata_framework-0.4.0/tests/test_health.py +62 -0
  34. hotdata_framework-0.4.0/tests/test_result.py +37 -0
  35. hotdata_framework-0.4.0/tests/test_update_changelog.py +48 -0
  36. hotdata_framework-0.4.0/tests/test_version.py +13 -0
  37. hotdata_framework-0.4.0/uv.lock +976 -0
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: uv
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ allow:
8
+ - dependency-name: hotdata
@@ -0,0 +1,26 @@
1
+ name: Check release metadata
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - 'pyproject.toml'
7
+ - 'CHANGELOG.md'
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ check:
14
+ name: Verify changelog matches version bump
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
18
+ with:
19
+ fetch-depth: 0
20
+
21
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
22
+ with:
23
+ python-version: '3.12'
24
+
25
+ - name: Check release metadata
26
+ run: python scripts/check-release.py
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "master"]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ test:
17
+ name: Test (Python 3.12)
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
21
+
22
+ - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v6
23
+ with:
24
+ enable-cache: true
25
+
26
+ - name: Set up Python
27
+ run: uv python install 3.12
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --locked
31
+
32
+ - name: Test
33
+ run: uv run pytest -v
@@ -0,0 +1,17 @@
1
+ name: Dependabot auto-merge
2
+
3
+ on: pull_request
4
+
5
+ permissions:
6
+ contents: write
7
+ pull-requests: write
8
+
9
+ jobs:
10
+ auto-merge:
11
+ runs-on: ubuntu-latest
12
+ if: github.actor == 'dependabot[bot]'
13
+ steps:
14
+ - name: Enable auto-merge
15
+ run: gh pr merge --squash --auto "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}"
16
+ env:
17
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,69 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v[0-9]*'
7
+
8
+ concurrency:
9
+ group: pypi-publish-${{ github.ref_name }}
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ build:
17
+ name: Build distribution
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
21
+
22
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
23
+ with:
24
+ python-version: '3.12'
25
+
26
+ - name: Install build tooling
27
+ run: python -m pip install --upgrade build twine
28
+
29
+ - name: Verify tag matches pyproject version
30
+ run: |
31
+ if [[ ! "$GITHUB_REF_NAME" =~ ^v[0-9] ]]; then
32
+ echo "Release tag '$GITHUB_REF_NAME' must start with 'v' followed by a digit (e.g. v1.0.0)" >&2
33
+ exit 1
34
+ fi
35
+ tag="${GITHUB_REF_NAME#v}"
36
+ pkg_version=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
37
+ if [ "$tag" != "$pkg_version" ]; then
38
+ echo "Release tag ($tag) does not match pyproject.toml version ($pkg_version)" >&2
39
+ exit 1
40
+ fi
41
+
42
+ - name: Build sdist and wheel
43
+ run: python -m build
44
+
45
+ - name: Check distribution metadata
46
+ run: python -m twine check --strict dist/*
47
+
48
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
49
+ with:
50
+ name: dist
51
+ path: dist/
52
+
53
+ publish:
54
+ name: Publish to PyPI
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ environment:
58
+ name: pypi
59
+ url: https://pypi.org/p/hotdata-framework
60
+ permissions:
61
+ id-token: write
62
+ steps:
63
+ - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
64
+ with:
65
+ name: dist
66
+ path: dist/
67
+
68
+ - name: Publish via Trusted Publishing
69
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
@@ -0,0 +1,54 @@
1
+ name: GitHub Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v[0-9]*'
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ release:
13
+ name: Create GitHub Release
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
17
+
18
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
19
+ with:
20
+ python-version: '3.12'
21
+
22
+ - name: Read package metadata
23
+ id: meta
24
+ run: |
25
+ pkg_name=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['name'])")
26
+ pkg_version="${GITHUB_REF_NAME#v}"
27
+ echo "name=${pkg_name}" >> "$GITHUB_OUTPUT"
28
+ echo "version=${pkg_version}" >> "$GITHUB_OUTPUT"
29
+
30
+ - name: Extract changelog notes
31
+ id: notes
32
+ run: |
33
+ set -euo pipefail
34
+ version="${GITHUB_REF_NAME#v}"
35
+ if [[ -f CHANGELOG.md ]]; then
36
+ body="$(python scripts/extract-changelog.py "$version")"
37
+ else
38
+ body="Release ${version}."
39
+ fi
40
+ delimiter="EOF_${RANDOM}_${RANDOM}"
41
+ {
42
+ echo "body<<${delimiter}"
43
+ echo "$body"
44
+ echo "${delimiter}"
45
+ } >> "$GITHUB_OUTPUT"
46
+
47
+ - name: Create GitHub Release
48
+ uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
49
+ with:
50
+ tag_name: ${{ github.ref_name }}
51
+ name: ${{ steps.meta.outputs.name }} ${{ steps.meta.outputs.version }}
52
+ body: ${{ steps.notes.outputs.body }}
53
+ generate_release_notes: false
54
+ make_latest: true
@@ -0,0 +1,50 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Distribution / packaging
8
+ .Python
9
+ build/
10
+ develop-eggs/
11
+ dist/
12
+ downloads/
13
+ eggs/
14
+ .eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+
25
+ # Virtual environments
26
+ .env
27
+ .venv
28
+ env/
29
+ venv/
30
+ ENV/
31
+
32
+ # Testing / coverage
33
+ .tox/
34
+ .nox/
35
+ .coverage
36
+ .coverage.*
37
+ .cache
38
+ .pytest_cache/
39
+ htmlcov/
40
+
41
+ # Type checkers
42
+ .mypy_cache/
43
+ .pyright/
44
+ .ruff_cache/
45
+
46
+ # IDEs
47
+ .idea/
48
+ .vscode/
49
+ *.swp
50
+ .DS_Store
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+
11
+ ## [0.4.0] - 2026-06-26
12
+
13
+ ### Changed
14
+
15
+ - **Renamed the distribution from `hotdata-runtime` to `hotdata-framework`** and the import package from `hotdata_runtime` to `hotdata_framework`. Consumers should depend on `hotdata-framework` and use `import hotdata_framework`. The GitHub repository is now `sdk-python-framework`.
16
+ - Added PyPI classifiers, keywords, and an updated description identifying the project as a Python framework.
17
+
18
+ ## [0.3.0] - 2026-06-22
19
+
20
+ ### Added
21
+
22
+ - Adopt the `hotdata` 0.4.1 SDK surface.
23
+ - New typed error-handling public API: `HotdataError`, `HotdataTerminalError`, `HotdataTransientError`, and `classify_sdk_error` (`hotdata_framework/errors.py`).
24
+ - `ManagedDatabaseClient` for managed database operations (`hotdata_framework/managed_client.py`).
25
+ - `py.typed` marker so downstream consumers pick up inline type information.
26
+
27
+ ### Changed
28
+
29
+ - Bump the `hotdata` dependency pin to `>=0.4.1`.
30
+ - Add ruff and mypy tooling configuration and dev dependencies (`ruff>=0.5`, `mypy>=1.5`); apply ruff lint/format cleanup across the package.
31
+
32
+
33
+ ## [0.2.4] - 2026-06-01
34
+
35
+ ### Changed
36
+
37
+ - Release 0.2.4
38
+
39
+ ## [0.2.3] - 2026-05-27
40
+
41
+ ### Changed
42
+
43
+ - Release 0.2.3
44
+
45
+ ## [0.2.2] - 2026-05-27
46
+
47
+ ### Changed
48
+
49
+ - Release 0.2.2
50
+
51
+ ## [0.2.1] - 2026-05-24
52
+
53
+ ### Added
54
+
55
+ - `execute_sql` accepts an optional `database` keyword argument. When provided, the database name is resolved to an ID and sent as the `X-Database-Id` header so SQL can reference managed database tables as `"default"."<schema>"."<table>"`. Behaviour is unchanged when `database` is omitted.
56
+
57
+ ## [0.2.0] - 2026-05-24
58
+
59
+ ### Changed
60
+
61
+ - Switch managed database operations from the connections API to the dedicated `/databases` API (`hotdata>=0.2.3` required).
62
+ - `create_managed_database` first parameter renamed from `name` to `description` (keyword-only).
63
+ - `ManagedDatabase` dataclass: replace `name`/`source_type` fields with `description`/`default_connection_id`.
64
+ - `resolve_managed_database` tries direct ID lookup first, then falls back to a description scan.
65
+ - `list_managed_databases` now fetches all databases regardless of source type.
66
+ - `list_managed_tables`, `load_managed_table`, and `delete_managed_table` use `default_connection_id` instead of database `id` for connection-scoped operations.
67
+
68
+ ### Added
69
+
70
+ - `create_managed_database` accepts an optional `expires_at` parameter.
71
+
72
+ ### Removed
73
+
74
+ - `MANAGED_SOURCE_TYPE`, `build_managed_config`, and `create_connection_request` removed from the public API.
75
+
76
+ ## [0.1.1] - 2026-05-19
77
+
78
+ ### Added
79
+
80
+ - Managed database helpers on `HotdataClient`.
81
+
82
+ ## [0.1.0] - 2026-05-06
83
+
84
+ ### Added
85
+
86
+ - Initial release.
@@ -0,0 +1,106 @@
1
+ # hotdata-framework Contract
2
+
3
+ `hotdata-framework` is the framework-agnostic runtime contract for Hotdata integrations.
4
+
5
+ ## Scope
6
+
7
+ This package provides shared primitives for:
8
+
9
+ - Environment and workspace resolution
10
+ - Query execution and polling
11
+ - Normalized tabular result handling
12
+ - Basic workspace health checks
13
+
14
+ ## Public Runtime Contract
15
+
16
+ The supported import surface is:
17
+
18
+ - `HotdataClient`
19
+ - `QueryResult`
20
+ - `from_env`
21
+ - `workspace_health_lines`
22
+ - `default_api_key`
23
+ - `default_host`
24
+ - `default_session_id`
25
+ - `explicit_workspace_id`
26
+ - `list_workspaces`
27
+ - `normalize_host`
28
+ - `pick_workspace`
29
+ - `resolve_workspace_selection`
30
+ - `ResultSummary`
31
+ - `RunHistoryItem`
32
+ - `WorkspaceSelection`
33
+ - `ManagedDatabase`
34
+ - `ManagedTable`
35
+ - `LoadManagedTableResult`
36
+ - `DEFAULT_SCHEMA`
37
+ - `is_parquet_path`
38
+
39
+ Adapters should import from `hotdata_framework` and treat this surface as the stable API.
40
+
41
+ ## Semantic Guarantees
42
+
43
+ ### `HotdataClient`
44
+
45
+ - Represents runtime context: API key, host, workspace, optional session.
46
+ - `from_env()` resolves runtime context from env vars and selected workspace.
47
+ - `execute_sql(sql)` returns `QueryResult` or raises `RuntimeError`/`TimeoutError`.
48
+ - `get_result(result_id)` returns a ready `QueryResult` and waits for readiness when needed.
49
+ - `connections()` returns the connections API wrapper for adapter UI/status features.
50
+ - `query_runs()` returns the query-runs API wrapper for adapter history views.
51
+ - `results()` returns the results API wrapper for adapter result pickers.
52
+ - `list_recent_results(...)` returns normalized `ResultSummary` entries.
53
+ - `list_run_history(limit=...)` returns normalized `RunHistoryItem` entries.
54
+ - `list_qualified_table_names(...)` returns sorted fully qualified table names.
55
+ - `columns_for_qualified(qualified, connection_id=...)` resolves table columns, and
56
+ adapters should pass `connection_id` when known.
57
+ - `uploads()` returns the uploads API wrapper for parquet staging.
58
+ - `list_managed_databases()` returns all databases via the `/databases` API.
59
+ - `resolve_managed_database(name_or_id)` resolves a database by id (direct lookup) or description (list scan).
60
+ - `create_managed_database(description=..., schema=..., tables=..., expires_at=...)` creates a database via the `/databases` API and optionally declares tables up front.
61
+ - `delete_managed_database(name_or_id)` deletes a database via the `/databases` API.
62
+ - `list_managed_tables(database, schema=...)` lists tables in a managed database.
63
+ - `upload_parquet(path)` uploads a local parquet file and returns an upload id.
64
+ - `load_managed_table(database, table, schema=..., upload_id=..., file=...)` publishes parquet data into a declared managed table.
65
+ - `delete_managed_table(database, table, schema=...)` deletes a managed table.
66
+
67
+ ### `QueryResult`
68
+
69
+ - Canonical tabular result model with `columns`, `rows`, and `row_count`.
70
+ - Carries server identifiers and execution metadata when available.
71
+ - `to_pandas()` converts to a DataFrame with stable column ordering.
72
+ - `to_records(max_rows=...)` returns row dicts keyed by column names.
73
+ - `metadata_dict()` returns normalized result metadata for adapter rendering.
74
+
75
+ ### Env Resolution
76
+
77
+ - `default_api_key()` reads `HOTDATA_API_KEY`.
78
+ - `default_host()` reads `HOTDATA_API_URL` (default: `https://api.hotdata.dev`) and normalizes it.
79
+ - `default_session_id()` reads `HOTDATA_SANDBOX`.
80
+ - `explicit_workspace_id()` reads `HOTDATA_WORKSPACE` (workspace public id).
81
+ - `pick_workspace()` prefers explicit env workspace, then active workspace, then first workspace.
82
+ - `resolve_workspace_selection()` is the canonical workspace selection algorithm. It returns `WorkspaceSelection` with selected workspace id, selection source, and discovered workspaces when auto-selected.
83
+
84
+ ## Adapter Responsibilities
85
+
86
+ Framework packages (Jupyter, Marimo, LangChain, LangGraph, LlamaIndex, Streamlit) own:
87
+
88
+ - Framework-native lifecycle and state management
89
+ - Rendering/UI concerns
90
+ - Tool/agent wrappers and callback integration
91
+
92
+ They should not duplicate runtime env/workspace/query semantics.
93
+
94
+ ## Runtime Non-Goals
95
+
96
+ `hotdata-framework` does not define framework UI primitives and does not require framework dependencies.
97
+
98
+ ## Versioning Policy
99
+
100
+ - Backward-incompatible contract changes require a major version bump.
101
+ - Additive contract changes are minor versions.
102
+ - Bug fixes that preserve contract semantics are patch versions.
103
+
104
+ ## Enforcement
105
+
106
+ Contract stability is enforced by tests that verify the public export surface and key behavioral invariants.
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: hotdata-framework
3
+ Version: 0.4.0
4
+ Summary: Python framework for building Hotdata integrations: workspace/session runtime, query execution, and managed databases
5
+ Project-URL: Homepage, https://www.hotdata.dev
6
+ Project-URL: Documentation, https://www.hotdata.dev/docs
7
+ Project-URL: Repository, https://github.com/hotdata-dev/sdk-python-framework
8
+ License: MIT
9
+ Keywords: analytics,arrow,data,framework,hotdata,pandas,python,sql
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: hotdata>=0.4.1
25
+ Requires-Dist: pandas>=2.0
26
+ Requires-Dist: pyarrow>=14.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # hotdata-framework
30
+
31
+ **A Python framework for building Hotdata integrations.**
32
+
33
+ Shared runtime primitives for Hotdata integrations: workspace/session semantics, execution context, query state, run history, and replayable result handles. Framework packages (Marimo, Jupyter, Streamlit, LangGraph) depend on this package.
34
+
35
+ Runtime boundary and guarantees are defined in `CONTRACT.md`.
36
+
37
+ ## Features
38
+
39
+ - **Environment-driven client setup** — create clients from `HOTDATA_API_KEY`, optional `HOTDATA_API_URL`, `HOTDATA_WORKSPACE`, and `HOTDATA_SANDBOX`.
40
+ - **Workspace resolution** — choose an explicit workspace from env, otherwise discover workspaces and select the active workspace or first available workspace.
41
+ - **Sandbox/session propagation** — pass sandbox session context through the SDK via `X-Session-Id`.
42
+ - **HTTP resilience** — configure SDK retries for transient connection failures and retry SQL execution on stale pooled sockets.
43
+ - **SQL execution helper** — run SQL through `POST /v1/query`, poll async query runs when needed, and return a `QueryResult`.
44
+ - **Result utilities** — convert query results to records, pandas DataFrames, or metadata dictionaries for adapter display layers.
45
+ - **History helpers** — list recent results and query run history with normalized dataclasses.
46
+ - **Managed databases** — create Hotdata-owned catalogs, declare tables, upload parquet, and load managed tables (mirrors `hotdata databases` in the CLI).
47
+ - **Health helpers** — build compact API/workspace health summaries for UI integrations.
48
+
49
+ Install:
50
+
51
+ ```bash
52
+ uv pip install hotdata-framework
53
+ # or: pip install hotdata-framework
54
+ ```
55
+
56
+ Example:
57
+
58
+ ```bash
59
+ python examples/basic_usage.py
60
+ ```
61
+
62
+ Development (uses **uv**; creates `.venv/` in this repo):
63
+
64
+ ```bash
65
+ uv sync --locked
66
+ uv run pytest
67
+ ```
68
+
69
+ `uv.lock` is checked in so CI can run `uv sync --locked`. The default **dev** group (pytest) is enabled via `[tool.uv] default-groups`.
@@ -0,0 +1,41 @@
1
+ # hotdata-framework
2
+
3
+ **A Python framework for building Hotdata integrations.**
4
+
5
+ Shared runtime primitives for Hotdata integrations: workspace/session semantics, execution context, query state, run history, and replayable result handles. Framework packages (Marimo, Jupyter, Streamlit, LangGraph) depend on this package.
6
+
7
+ Runtime boundary and guarantees are defined in `CONTRACT.md`.
8
+
9
+ ## Features
10
+
11
+ - **Environment-driven client setup** — create clients from `HOTDATA_API_KEY`, optional `HOTDATA_API_URL`, `HOTDATA_WORKSPACE`, and `HOTDATA_SANDBOX`.
12
+ - **Workspace resolution** — choose an explicit workspace from env, otherwise discover workspaces and select the active workspace or first available workspace.
13
+ - **Sandbox/session propagation** — pass sandbox session context through the SDK via `X-Session-Id`.
14
+ - **HTTP resilience** — configure SDK retries for transient connection failures and retry SQL execution on stale pooled sockets.
15
+ - **SQL execution helper** — run SQL through `POST /v1/query`, poll async query runs when needed, and return a `QueryResult`.
16
+ - **Result utilities** — convert query results to records, pandas DataFrames, or metadata dictionaries for adapter display layers.
17
+ - **History helpers** — list recent results and query run history with normalized dataclasses.
18
+ - **Managed databases** — create Hotdata-owned catalogs, declare tables, upload parquet, and load managed tables (mirrors `hotdata databases` in the CLI).
19
+ - **Health helpers** — build compact API/workspace health summaries for UI integrations.
20
+
21
+ Install:
22
+
23
+ ```bash
24
+ uv pip install hotdata-framework
25
+ # or: pip install hotdata-framework
26
+ ```
27
+
28
+ Example:
29
+
30
+ ```bash
31
+ python examples/basic_usage.py
32
+ ```
33
+
34
+ Development (uses **uv**; creates `.venv/` in this repo):
35
+
36
+ ```bash
37
+ uv sync --locked
38
+ uv run pytest
39
+ ```
40
+
41
+ `uv.lock` is checked in so CI can run `uv sync --locked`. The default **dev** group (pytest) is enabled via `[tool.uv] default-groups`.
@@ -0,0 +1,43 @@
1
+ # Releasing
2
+
3
+ Every release uses `./scripts/release.sh`. Do not bump versions, tag, or create GitHub Releases manually.
4
+
5
+ ## One-time setup
6
+
7
+ - Install [GitHub CLI](https://cli.github.com/) (`gh`) and authenticate.
8
+ - Ensure PyPI [trusted publishing](https://docs.pypi.org/trusted-publishers/) is configured for this repo (`publish.yml` uses the `pypi` GitHub environment).
9
+
10
+ ## Release steps
11
+
12
+ 1. Add user-facing notes under `## [Unreleased]` in `CHANGELOG.md`.
13
+ 2. Prepare the release PR:
14
+
15
+ ```bash
16
+ ./scripts/release.sh prepare patch # or minor | major | 1.2.3
17
+ ```
18
+
19
+ 3. Merge the PR after CI passes (including the changelog check).
20
+ 4. Publish from a clean default branch checkout:
21
+
22
+ ```bash
23
+ git checkout main # or master for hotdata-marimo
24
+ git pull
25
+ ./scripts/release.sh publish
26
+ ```
27
+
28
+ ## What happens automatically
29
+
30
+ Pushing a `vX.Y.Z` tag triggers two workflows:
31
+
32
+ | Workflow | Purpose |
33
+ |----------|---------|
34
+ | `publish.yml` | Build wheel/sdist and publish to PyPI |
35
+ | `release.yml` | Create the GitHub Release with notes from `CHANGELOG.md` |
36
+
37
+ ## Enforcement
38
+
39
+ - **PR check** (`check-release.yml`): if `pyproject.toml` version changes, `CHANGELOG.md` must contain a matching `## [X.Y.Z]` section.
40
+ - **Tag check** (`publish.yml`): the tag (without `v`) must match `[project].version` in `pyproject.toml`.
41
+ - **Publish guard** (`release.sh publish`): refuses to tag if the changelog section is missing.
42
+
43
+ Together, these make it hard to ship a version without changelog notes or a GitHub Release.
@@ -0,0 +1,25 @@
1
+ """Basic hotdata-framework usage."""
2
+
3
+ from hotdata_framework import from_env
4
+
5
+
6
+ def main() -> None:
7
+ client = from_env()
8
+ result = client.execute_sql("SELECT 1 AS ok")
9
+
10
+ print("result metadata:", result.metadata_dict())
11
+ print("records:", result.to_records(max_rows=5))
12
+
13
+ print("recent results:")
14
+ for item in client.list_recent_results(limit=5, offset=0):
15
+ print(item.to_dict())
16
+
17
+ print("run history:")
18
+ for item in client.list_run_history(limit=5):
19
+ print(item.to_dict())
20
+
21
+ client.close()
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()