Skip to content

v0.26.0 — config set-default-bucket + null rowsCount fix

Choose a tag to compare

@padak padak released this 01 May 11:11
· 748 commits to main since this release
dfd8ee1

What is new in v0.26.0

This release bundles a new feature from #234 and a bug-fix family from #235 (closing #233).

#234 — Discoverable storage.output.default_bucket wrapper

Thanks to @ottomansky (Maxmilián Ottomanský) for designing and implementing this -- a much friendlier surface than telling users to hand-craft a kbagent config update --set 'storage.output.default_bucket=...' invocation against an internal raw-mode workaround.

  • New: kbagent config set-default-bucket --bucket BUCKET_ID | --clear [--dry-run] [--branch ID] -- discoverable wrapper around the raw-mode storage.output.default_bucket workaround documented at https://keboola.atlassian.net/wiki/spaces/SUP/pages/3770155030/ (epic KBCP-108). Read-modify-write that preserves all sibling keys under storage.output and the rest of the configuration. Same-value writes short-circuit with {"changed": false} (no API call, no version bump). --clear removes only the default_bucket key, leaving an empty storage.output: {} if no other siblings live there (intentional -- mirrors set_nested_value's parent-creation semantics; Storage API treats output: {} and missing output identically as 'use the auto-derived bucket'). Live-validated end-to-end on three component types -- row-based GCS extractor, root-only keboola.ex-cnb-exchange-rates, and ex-generic-v2 with multiple jobs -- output tables routed to the configured bucket at job runtime in every case. The per-table destination override (the second method shown in the support article) keeps using the existing kbagent config update --set 'storage.output.tables=[...]' -- no new wrapper there because per-table mappings have many fields that don't fit a single-purpose flag.

#235 — sync pull --with-samples no longer crashes on rowsCount: null (closes #233)

Thanks to @jakubsebek-kosik for the detailed report with traceback, root-cause analysis, and a suggested fix. Reproduced live against kosik-sales to confirm 1:1 traceback before the fix and clean execution after.

  • Fix: kbagent sync pull --with-samples no longer crashes with TypeError: '>' not supported between instances of 'NoneType' and 'int' when one or more tables in the project return rowsCount: null from the Storage API (typical for newly-created or empty tables on some backends, reproduced live against kosik-sales). dict.get("rowsCount", 0) returns the default 0 only when the key is missing -- if the key is present with a null value, .get() returns None, and the > 0 comparison crashed Python 3 before any sample was fetched. The filter and sort key in SyncService._fetch_samples() now coerce None to 0 via a small _rows() helper used in both places (t.get("rowsCount") or 0), so empty/null-rowcount tables are gracefully skipped exactly like rowsCount: 0 ones.

  • Fix: same dict.get(k, 0) -> dict.get(k) or 0 defensive coercion applied to 5 sibling locations that did not crash but produced inconsistent JSON shapes (null instead of 0) when the Storage API returned rowsCount / dataSizeBytes / tablesCount as null: SyncService._write_storage_metadata() (both the buckets-index summary at storage/buckets.json and per-table JSON files at storage/tables/<bucket>/<table>.json), StorageService.list_buckets(), StorageService.list_tables(), StorageService.get_table_detail(), and SharingService.list_shared(). Without this, JSON consumers (LLM agents reading .keboola/ workspace files, downstream aggregation that does arithmetic) would see null for what is documented as an int field. Behavior is otherwise unchanged -- the fix only flips the Python serialization of API-returned-null from null to 0.

  • Tests: 7 new regression tests covering the full null-coercion surface: 2 in tests/test_sync_storage_jobs.py::TestFetchSamples (filter + sort paths -- both fail on 0.25.3 with the exact TypeError from the issue traceback), 1 in tests/test_sync_storage_jobs.py::TestWriteStorageMetadata (verifies storage/buckets.json and per-table JSON files surface 0 not null), 2 in tests/test_storage_tables.py::TestStorageNullNumericCoercion (list_buckets and list_tables service output), 1 in tests/test_storage_describe_service.py::TestGetTableDetailDescriptionExtraction (get_table_detail), and 1 in tests/test_sharing_service.py::TestListShared (list_shared).

Upgrade

uv tool upgrade keboola-agent-cli
# or
uv tool install --reinstall keboola-agent-cli

Plugin users: /plugin update kbagent from inside Claude Code.