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.
- hotdata_framework-0.4.0/.github/dependabot.yml +8 -0
- hotdata_framework-0.4.0/.github/workflows/check-release.yml +26 -0
- hotdata_framework-0.4.0/.github/workflows/ci.yml +33 -0
- hotdata_framework-0.4.0/.github/workflows/dependabot-automerge.yml +17 -0
- hotdata_framework-0.4.0/.github/workflows/publish.yml +69 -0
- hotdata_framework-0.4.0/.github/workflows/release.yml +54 -0
- hotdata_framework-0.4.0/.gitignore +50 -0
- hotdata_framework-0.4.0/CHANGELOG.md +86 -0
- hotdata_framework-0.4.0/CONTRACT.md +106 -0
- hotdata_framework-0.4.0/PKG-INFO +69 -0
- hotdata_framework-0.4.0/README.md +41 -0
- hotdata_framework-0.4.0/RELEASING.md +43 -0
- hotdata_framework-0.4.0/examples/basic_usage.py +25 -0
- hotdata_framework-0.4.0/hotdata_framework/__init__.py +71 -0
- hotdata_framework-0.4.0/hotdata_framework/client.py +524 -0
- hotdata_framework-0.4.0/hotdata_framework/databases.py +61 -0
- hotdata_framework-0.4.0/hotdata_framework/env.py +81 -0
- hotdata_framework-0.4.0/hotdata_framework/errors.py +31 -0
- hotdata_framework-0.4.0/hotdata_framework/health.py +27 -0
- hotdata_framework-0.4.0/hotdata_framework/http.py +17 -0
- hotdata_framework-0.4.0/hotdata_framework/managed_client.py +184 -0
- hotdata_framework-0.4.0/hotdata_framework/py.typed +0 -0
- hotdata_framework-0.4.0/hotdata_framework/result.py +75 -0
- hotdata_framework-0.4.0/pyproject.toml +98 -0
- hotdata_framework-0.4.0/scripts/check-release.py +68 -0
- hotdata_framework-0.4.0/scripts/extract-changelog.py +36 -0
- hotdata_framework-0.4.0/scripts/publish-workflow.sh +75 -0
- hotdata_framework-0.4.0/scripts/release.sh +191 -0
- hotdata_framework-0.4.0/scripts/update_changelog.py +62 -0
- hotdata_framework-0.4.0/tests/test_client.py +297 -0
- hotdata_framework-0.4.0/tests/test_contract.py +60 -0
- hotdata_framework-0.4.0/tests/test_databases.py +252 -0
- hotdata_framework-0.4.0/tests/test_health.py +62 -0
- hotdata_framework-0.4.0/tests/test_result.py +37 -0
- hotdata_framework-0.4.0/tests/test_update_changelog.py +48 -0
- hotdata_framework-0.4.0/tests/test_version.py +13 -0
- hotdata_framework-0.4.0/uv.lock +976 -0
|
@@ -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()
|