- Built on Rust SDK 2.0.1: The Python wrapper now depends on
databricks-zerobus-ingest-sdk = "2.0.1"from crates.io (was 1.2.0). Internal PyO3 binding was rewritten to use the newStreamBuildertypestate API exclusively. The Python-facing API surface (TableProperties,create_stream(client_id, client_secret, table_properties, options, headers_provider),ingest_record,RecordAcknowledgment, etc.) is unchanged. - Arrow Flight promoted to Beta:
ZerobusArrowStream/ArrowStreamConfigurationOptionsand the surrounding documentation are no longer labelled experimental/unsupported. The API is stabilising but may still change before reaching GA. (Mirrors the Rust SDK 2.0.1 promotion.) - Arrow Flight — graceful stream close: On server signaled close, the client pauses sending, drains in-flight acks within a bounded wait, then recovers.
stream_paused_max_wait_time_msonArrowStreamConfigurationOptions: Optional milliseconds cap for the paused wait (None= full server duration,0= immediate recovery).- Python SDK identifier on the wire: The SDK now reports itself as
zerobus-sdk-py/<version>on the HTTPuser-agentheader (previously it inherited the Rust SDK identifierzerobus-sdk-rs/<rust-version>). Server-side telemetry can now tell Python clients apart from Rust clients. AckCallback.on_erroris now delivered to Python: The PyO3 binding previously only logged ack errors viaeprintln!; subclasses overridingon_errorwould never see the call. They will now.
-
StreamConfigurationOptions.record_typeis no longer applied: Format is now set on the stream builder fromTableProperties(proto descriptor present → Proto, absent → JSON). The field is kept for API compatibility. -
StreamConfigurationOptions.max_inflight_recordsdefault raised from50_000to1_000_000to match the Rust SDK 2.0.1 default. Previously the Python wrapper hard-coded 50k while the Rust SDK quietly raised its default to 1M, so Python clients ran with a 20× lower in-flight ceiling than Rust clients for no good reason. Callers who relied on the old cap can pin it back explicitly:StreamConfigurationOptions(max_inflight_records=50_000)
TableProperties(name, MyMessage.DESCRIPTOR)proto-descriptor selection now picks the message by name when agoogle.protobuf.descriptor.Descriptorobject is passed. Previously the first message in theFileDescriptorProtowas always chosen, which silently mis-routed schemas for.protofiles containing multiple messages. Raw-bytes input still falls back to the first message (no name hint is available).
- Updated docstrings, the Arrow example files, and
zerobus.sdk.shared.arrowto reflect the Beta promotion.
- Bumped Rust dependencies to match the Rust SDK 2.0.1 workspace:
prost/prost-types0.13 → 0.14,tonic0.13 → 0.14,arrow-ipc/arrow-schema/arrow-array56.2 → 58.2. - Removed the in-tree
[patch.crates-io]redirect fordatabricks-zerobus-ingest-sdk— the 2.0.1 release is now resolved from crates.io. StreamConfigurationOptionsandArrowStreamConfigurationOptionsfields are now applied viaStreamBuildersetters because the underlying Rust structs are#[non_exhaustive]in 2.0.1.- Bounded the
HeadersProviderWrapperstatic-key leak: header names are now interned in a process-wide table so each distinct name is leaked at most once, instead of once perget_headers()call. - Shared payload-extraction, options-application, and the
AckCallbackbridge moved intopython/rust/src/common.rs, removing duplicated code betweensync_wrapper.rsandasync_wrapper.rs. ZerobusSdk.set_use_tls(...)is retained as a no-op for backwards compatibility. Rust SDK 2.0.1 removed the underlying TLS toggle; TLS is always controlled via the SDK builder.
- License: Migrated from the Databricks License to the Apache License 2.0
- Arrow Flight Support (Experimental): Added support for ingesting
pyarrow.RecordBatchandpyarrow.Tableobjects via Arrow Flight protocol- Note: Arrow Flight is not yet supported by default from the Zerobus server side.
- New
ZerobusArrowStreamclass (sync inzerobus.sdk.sync, async inzerobus.sdk.aio) withingest_batch(),wait_for_offset(),flush(),close(),get_unacked_batches()methods - New
ArrowStreamConfigurationOptionsfor configuring Arrow streams (max inflight batches, recovery, timeouts) - New
create_arrow_stream()andrecreate_arrow_stream()methods on both sync and asyncZerobusSdk - Accepts both
pyarrow.RecordBatchandpyarrow.Table(Tables are combined to a single batch internally) - Arrow is opt-in: install via
pip install databricks-zerobus-ingest-sdk[arrow](requirespyarrow>=14.0.0) - Arrow types gated behind
_core.arrowsubmodule — not loaded unless pyarrow is installed - Available from both
zerobus.sdk.syncandzerobus.sdk.aio, and re-exported from top-levelzerobuspackage
- Fixed proto generation tool to skip reserved field numbers 19000-19999 for tables with more than 19000 columns
- Bumped Rust SDK dependency to v1.0.1 with
arrow-flightfeature - Added
arrow-ipc,arrow-schema,arrow-array(v56.2.0) Rust dependencies for IPC serialization - Added PyO3 arrow module (
arrow.rs) withArrowStreamConfigurationOptions,ZerobusArrowStream,AsyncZerobusArrowStreampyclasses - Added Python-side serialization helpers in
zerobus.sdk.shared.arrow(_serialize_schema,_serialize_batch,_deserialize_batch)
- Added
create_arrow_stream(table_name, schema, client_id, client_secret, options=None, headers_provider=None)to sync and asyncZerobusSdk - Added
recreate_arrow_stream(old_stream)to sync and asyncZerobusSdk - Added
ZerobusArrowStreamclass (sync and async variants) with methods:ingest_batch(),wait_for_offset(),flush(),close(),get_unacked_batches(), properties:is_closed,table_name - Added
ArrowStreamConfigurationOptionsclass with fields:max_inflight_batches,recovery,recovery_timeout_ms,recovery_backoff_ms,recovery_retries,server_lack_of_ack_timeout_ms,flush_timeout_ms,connection_timeout_ms - Added optional dependency:
pyarrow>=14.0.0viapip install databricks-zerobus-ingest-sdk[arrow]
- Added HTTP proxy support via standard environment variables (
grpc_proxy,https_proxy,http_proxy), following gRPC core conventions. Proxied connections use HTTP CONNECT tunneling with end-to-end TLS. Supportsno_grpc_proxy/no_proxyfor bypass rules.
GA release of the Databricks Zerobus Ingest SDK for Python.
- v0.3.0 was yanked due to a breaking change introduced in that release: the
server_endpointparameter was changed to require thehttps://prefix, whereas v0.2.0 accepted URLs without it. v1.0.0 resolves this by acceptingserver_endpointboth with and without thehttps://prefix.
- Rust-Backed Implementation: Complete rewrite of the Python SDK as a thin wrapper around the Databricks Zerobus Rust SDK
- All core logic (gRPC, authentication, recovery, stream management) now handled by native Rust code
- Python bindings built using PyO3 and maturin
- Significant performance improvements: 2-5x throughput, lower latency, reduced memory footprint
- Single source of truth: Python SDK automatically inherits all Rust SDK improvements
- Architecture: Native Rust core with PyO3 bindings and full type stubs (
_zerobus_core.pyi) - Build System: Migrated from setuptools to maturin for Rust/Python integration
- Benefits: Native performance, Rust's memory safety guarantees, easier maintenance, consistent behavior across all SDK languages
- Configurable Logging: Added support for
RUST_LOGenvironment variable to control log levels- Users can now set
RUST_LOG=debugorRUST_LOG=tracefor detailed diagnostics - Default level is
infowhen not specified - Supports granular control:
RUST_LOG=zerobus_sdk=trace,tokio=info
- Users can now set
- Flexible Record Serialization:
ingest_record()now accepts multiple input types, giving clients control over serialization:- JSON mode: Accepts both
dict(SDK serializes) andstr(pre-serialized JSON string) - Protobuf mode: Accepts both
Messageobjects (SDK serializes) andbytes(pre-serialized) - This allows clients to optimize serialization separately or use custom serialization logic while maintaining backward compatibility
- JSON mode: Accepts both
- Updated README with new Delta type mappings (TIMESTAMP_NTZ, VARIANT)
- Updated
ingest_record()API documentation to show all accepted record types - Added inline examples demonstrating both serialization approaches (SDK-controlled vs. client-controlled)
- Updated examples README with clear explanations of serialization options
-
Implemented
get_unacked_records()andget_unacked_batches(): Return actual unacknowledged records/batches (as bytes) for recovery and monitoringget_unacked_records()returnsList[bytes]of unacknowledged record payloadsget_unacked_batches()returnsList[List[bytes]]where each batch contains record payloads- Available in both sync and async APIs
- Useful for implementing custom retry logic or monitoring stream health
-
Added
env-filterfeature totracing-subscriberdependency forRUST_LOGsupport -
generate_proto tool: Added support for TIMESTAMP_NTZ and VARIANT data types
- TIMESTAMP_NTZ maps to int64 (timestamp without timezone, microseconds since epoch)
- VARIANT maps to string (unshredded, JSON string format)
-
generate_proto tool: Added comprehensive unit tests for all pure functions (84 tests covering type parsing, type mapping, field validation, and proto file generation)
-
Enhanced
ingest_record()type validation to accept wider range of input types -
Added test coverage for both high-level objects (dict/Message) and pre-serialized data (str/bytes)
-
BREAKING: Host endpoints now require
https://scheme- Impact:
SERVER_ENDPOINTandUNITY_CATALOG_ENDPOINTmust includehttps://prefix - Migration: Update endpoint URLs to include
https:// - Old:
SERVER_ENDPOINT = "your-shard-id.zerobus.region.cloud.databricks.com" - New:
SERVER_ENDPOINT = "https://your-shard-id.zerobus.region.cloud.databricks.com"
- Impact:
-
BREAKING: Removed
create_stream_with_headers_provider()method- Migration: Use
create_stream()with theheaders_providerparameter instead - Old:
sdk.create_stream_with_headers_provider(custom_provider, table_properties, options) - New:
sdk.create_stream(client_id, client_secret, table_properties, options, headers_provider=custom_provider)
- Migration: Use
-
BREAKING: Removed
StreamStateenum- Reason: Internal state management now handled by Rust SDK
- Impact:
get_state()method no longer returns a meaningful state enum - Migration: Not typically used in primary workflows; remove any code that depends on
StreamState
-
Changed:
get_unacked_records()implementation (backward compatible)- Old: Returned
Iteratorthat yielded record payloads from the Python wrapper's internal queue - New: Returns
Iterator[bytes]that yields unacknowledged record payloads directly from the Rust SDK - Migration: No migration needed - iteration pattern remains the same:
for record in stream.get_unacked_records(): - Benefit: Direct access to Rust SDK's unacked records; more accurate representation of what hasn't been acknowledged by the server
- Note: Still returns an iterator for backward compatibility and memory efficiency
- Old: Returned
-
BREAKING: Changed
ack_callbacksignature inStreamConfigurationOptions- Old: Callback received detailed acknowledgment response object
- New: Callback receives single
offset: intparameter - Migration: Update callback signature from
def on_ack(self, response)todef on_ack(self, offset: int) - Impact: Simplified API; offset is the primary acknowledgment information needed
- DEPRECATED:
ingest_record()method (both sync and async)- Reason: Offers significantly lower throughput compared to
ingest_record_offset()andingest_record_nowait() - Migration:
- For sync API: Use
ingest_record_offset()for offset tracking oringest_record_nowait()for maximum throughput - For async API: Use
ingest_record_offset()with batchedasyncio.gather()pattern oringest_record_nowait()for maximum throughput
- For sync API: Use
- Performance Impact: New methods are 2-40x faster depending on record size
- Note: Method remains available for backward compatibility but will be removed in a future major version
- Reason: Offers significantly lower throughput compared to
- Added optional
headers_providerparameter tocreate_stream()methods- Defaults to internal OAuth 2.0 Client Credentials authentication when not provided
- Widened
ingest_record()type signature to accept:- JSON mode:
Union[dict, str](previouslystronly) - Protobuf mode:
Union[Message, bytes](previouslyMessageonly)
- JSON mode:
- All changes except removal of
create_stream_with_headers_provider()are backward compatible
- Loosened protobuf dependency constraint to support versions >= 4.25.0 and < 7.0
- JSON Serialization Support: Added support for JSON record serialization alongside Protocol Buffers (default)
- New
RecordType.JSONmode for ingesting JSON-encoded strings - No protobuf schema compilation required
- New
- Added
HeadersProviderabstraction for flexible authentication strategies - Implemented
OAuthHeadersProviderfor OAuth 2.0 Client Credentials flow (default authentication method used bycreate_stream())
- generate_proto tool: Fixed uppercase field names bug for nested fields
- generate_proto tool: Added validation for unsupported nested type combinations
- Now properly rejects:
array<array<...>>,array<map<...>>,map<map<...>, ...>,map<array<...>, ...>,map<..., map<...>>,map<..., array<...>>
- Now properly rejects:
- Logging: Fixed false alarm "Retriable gRPC error" logs when calling
stream.close()- CANCELLED errors during intentional stream closure are no longer logged as errors
- Logging: Unified log messages between sync and async SDK implementations
- Both SDKs now produce consistent logging output with same verbosity and format
- Error handling: Improved error messages to distinguish between recoverable and non-recoverable errors
- "Stream closed due to a non-recoverable error" vs "Stream failed permanently after failed recovery attempt"
- Added JSON and protobuf serialization examples for both sync and async APIs
- Restructured Quick Start guide to present JSON first as the simpler option
- Enhanced API Reference with JSON mode documentation
- Added Azure workspace and endpoint URL examples
- Build system: Loosened setuptools requirement from
>=77to>=61xw - License format: Changed license specification to PEP 621 table format for setuptools <77 compatibility
- Changed from
license = "LicenseRef-Proprietary"tolicense = {text = "LicenseRef-Proprietary"}
- Changed from
- generate_proto tool: Added support for TINYINT and BYTE data types (both map to int32)
- Logging: Added detailed initialization logging to async SDK to match sync SDK
- "Starting initializing stream", "Attempting retry X out of Y", "Sending CreateIngestStreamRequest", etc.
- StreamConfigurationOptions: Added
record_typeparameter to specify serialization formatRecordType.PROTO(default): For protobuf serializationRecordType.JSON: For JSON serialization- Example:
StreamConfigurationOptions(record_type=RecordType.JSON)
- ZerobusStream.ingest_record: Now accepts JSON strings (when using
RecordType.JSON) in addition to protobuf messages and bytes - Added
RecordTypeenum withPROTOandJSONvalues - Added
HeadersProviderabstract base class for custom header strategies - Added
OAuthHeadersProviderclass for OAuth 2.0 authentication with Databricks OIDC endpoint - Added
create_stream_with_headers_providermethod toZerobusSdkandaio.ZerobusSdkfor custom authentication header providers- Note: Custom headers providers must include both
authorizationandx-databricks-zerobus-table-nameheaders
- Note: Custom headers providers must include both
Initial release of the Databricks Zerobus Ingest SDK for Python.
- Added
ZerobusSdkclass for creating ingestion streams - Added
ZerobusStreamclass for managing stateful gRPC streams - Added
RecordAcknowledgmentfor blocking until record acknowledgment - Added asynchronous versions:
zerobus.sdk.aio.ZerobusSdkandzerobus.sdk.aio.ZerobusStream - Added
TablePropertiesfor configuring table schema and name - Added
StreamConfigurationOptionsfor stream behavior configuration - Added
ZerobusExceptionandNonRetriableExceptionfor error handling - Added
StreamStateenum for tracking stream lifecycle - Support for Python 3.9, 3.10, 3.11, 3.12, and 3.13