From 9c2ad50eb3ec00e0dc7b1e3eabb13cffafc1d0a8 Mon Sep 17 00:00:00 2001 From: Wei Qi Lu Date: Fri, 21 Aug 2026 16:25:18 -0700 Subject: [PATCH 1/5] python(feat): expose configurable gRPC decode limit --- python/CHANGELOG.md | 27 ++++ .../_internal/grpc_transport/transport.py | 13 +- .../_internal/low_level_wrappers/ingestion.py | 4 + .../_tests/_internal/test_transport.py | 51 ++++++++ python/lib/sift_client/resources/ingestion.py | 18 +++ .../sift_client/transport/base_connection.py | 5 + .../sift_client/transport/grpc_transport.py | 5 + python/pyproject.toml | 12 +- python/uv.lock | 115 +++++++++--------- 9 files changed, 182 insertions(+), 68 deletions(-) diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md index 16fab1cc90..f868596d51 100644 --- a/python/CHANGELOG.md +++ b/python/CHANGELOG.md @@ -5,6 +5,33 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### What's New + +#### Configurable gRPC decode limit + +Sets the largest gRPC response the client will decode. Defaults to 50 MB; raise it for large +payloads such as an ingestion config with many flows. + +```python +client = SiftClient( + connection_config=SiftConnectionConfig( + grpc_url="...", + rest_url="...", + api_key="...", + max_decoding_message_size=200 * 1024 * 1024, + ) +) +``` + +Streaming ingestion clients inherit the value and can override it per stream: + +```python +stream = await client.ingestion.create_ingestion_config_streaming_client( + ingestion_config, + max_decoding_message_size=200 * 1024 * 1024, +) +``` + ### Bugfixes - Fix `assets.archive` raising `AttributeError` by reading the correct response field, `archived_run_ids`. diff --git a/python/lib/sift_client/_internal/grpc_transport/transport.py b/python/lib/sift_client/_internal/grpc_transport/transport.py index 9df13825a4..63b41f2425 100644 --- a/python/lib/sift_client/_internal/grpc_transport/transport.py +++ b/python/lib/sift_client/_internal/grpc_transport/transport.py @@ -34,6 +34,9 @@ DEFAULT_REQUEST_TIMEOUT_SECONDS = 60.0 """Default per-call deadline applied to unary RPCs that don't set their own.""" +DEFAULT_MAX_DECODING_MESSAGE_SIZE = 50 * 1024 * 1024 +"""Largest response the client will decode, in bytes.""" + def get_ssl_credentials(cert_via_openssl: bool) -> grpc.ChannelCredentials: """ @@ -159,16 +162,16 @@ def _compute_channel_options(opts: SiftChannelConfig) -> list[tuple[str, Any]]: """ request_timeout = opts.get("request_timeout", DEFAULT_REQUEST_TIMEOUT_SECONDS) + max_decoding_message_size = ( + opts.get("max_decoding_message_size") or DEFAULT_MAX_DECODING_MESSAGE_SIZE + ) options = [ ("grpc.enable_retries", 1), ("grpc.service_config", RetryPolicy.default(timeout_seconds=request_timeout).as_json()), # Primary cannot be overriden: # https://github.com/grpc/grpc/blob/0498194240f55d7f4b12633ad01339fb690621bf/src/core/ext/filters/http/client/http_client_filter.cc#L97 ("grpc.secondary_user_agent", _compute_user_agent()), - ( - "grpc.max_receive_message_length", - 50 * 1024 * 1024, - ), # 50 MB — headroom for 1M-row GetData pages + ("grpc.max_receive_message_length", max_decoding_message_size), ] enable_keepalive = opts.get("enable_keepalive", True) @@ -243,6 +246,7 @@ class SiftChannelConfig(TypedDict): Default is False. - `request_timeout`: Default deadline in seconds applied to unary RPCs that don't set their own. Defaults to 60s. Set to `None` to disable the default deadline. + - `max_decoding_message_size`: Largest response to decode, in bytes. Defaults to 50 MB. """ uri: str @@ -251,3 +255,4 @@ class SiftChannelConfig(TypedDict): use_ssl: NotRequired[bool] cert_via_openssl: NotRequired[bool] request_timeout: NotRequired[float | None] + max_decoding_message_size: NotRequired[int | None] diff --git a/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py b/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py index f99b752603..e1d61fbb04 100644 --- a/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py +++ b/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py @@ -250,6 +250,7 @@ async def _build_sift_stream_instance( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, + max_decoding_message_size: int | None = None, ) -> SiftStreamPy: """Build a raw `SiftStreamPy` without wrapping it in a client. @@ -289,6 +290,7 @@ async def _build_sift_stream_instance( sift_builder = SiftStreamBuilderPy(uri=grpc_uri, apikey=api_key) sift_builder.enable_tls = enable_tls + sift_builder.max_decoding_message_size = max_decoding_message_size config_builder = sift_builder.ingestion_config(ingestion_config_form) config_builder.run = run_form @@ -341,6 +343,7 @@ async def create_sift_stream_instance( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, + max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingLowLevelClient: sift_stream_instance = await _build_sift_stream_instance( api_key=api_key, @@ -356,6 +359,7 @@ async def create_sift_stream_instance( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, + max_decoding_message_size=max_decoding_message_size, ) return cls(sift_stream_instance) diff --git a/python/lib/sift_client/_tests/_internal/test_transport.py b/python/lib/sift_client/_tests/_internal/test_transport.py index 2f0a1dbc33..8316461a2f 100644 --- a/python/lib/sift_client/_tests/_internal/test_transport.py +++ b/python/lib/sift_client/_tests/_internal/test_transport.py @@ -4,6 +4,11 @@ import pytest +from sift_client._internal.grpc_transport.transport import ( + DEFAULT_MAX_DECODING_MESSAGE_SIZE, + _compute_channel_options, +) +from sift_client.transport.base_connection import SiftConnectionConfig from sift_client.transport.grpc_transport import GrpcClient, GrpcConfig from sift_client.transport.rest_transport import DEFAULT_REST_TIMEOUT, RestClient, RestConfig @@ -150,3 +155,49 @@ def test_timeout_disabled_when_config_none(self): captured = self._capture_request_kwargs(client) client.get("/v1/ping") assert "timeout" not in captured + + +class TestMaxDecodingMessageSize: + @staticmethod + def _receive_limit(config: GrpcConfig) -> int: + options = dict(_compute_channel_options(config._to_sift_channel_config())) + return options["grpc.max_receive_message_length"] + + def test_defaults_to_50_mb(self): + config = GrpcConfig(url="https://grpc.sift.com", api_key="api") + assert self._receive_limit(config) == DEFAULT_MAX_DECODING_MESSAGE_SIZE + + def test_config_value_overrides_default(self): + config = GrpcConfig( + url="https://grpc.sift.com", api_key="api", max_decoding_message_size=100 * 1024 * 1024 + ) + assert self._receive_limit(config) == 100 * 1024 * 1024 + + def test_lowering_the_limit_is_honored(self): + config = GrpcConfig( + url="https://grpc.sift.com", api_key="api", max_decoding_message_size=1024 + ) + assert self._receive_limit(config) == 1024 + + def test_channel_config_carries_the_value(self): + config = GrpcConfig( + url="https://grpc.sift.com", api_key="api", max_decoding_message_size=17 + ) + assert config._to_sift_channel_config().get("max_decoding_message_size") == 17 + + def test_connection_config_forwards_to_grpc_config(self): + connection_config = SiftConnectionConfig( + grpc_url="https://grpc.sift.com", + rest_url="https://api.sift.com", + api_key="api", + max_decoding_message_size=64 * 1024 * 1024, + ) + assert connection_config.get_grpc_config().max_decoding_message_size == 64 * 1024 * 1024 + + def test_connection_config_default_leaves_it_unset(self): + connection_config = SiftConnectionConfig( + grpc_url="https://grpc.sift.com", rest_url="https://api.sift.com", api_key="api" + ) + grpc_config = connection_config.get_grpc_config() + assert grpc_config.max_decoding_message_size is None + assert self._receive_limit(grpc_config) == DEFAULT_MAX_DECODING_MESSAGE_SIZE diff --git a/python/lib/sift_client/resources/ingestion.py b/python/lib/sift_client/resources/ingestion.py index 10ad62da97..4b2ae5745d 100644 --- a/python/lib/sift_client/resources/ingestion.py +++ b/python/lib/sift_client/resources/ingestion.py @@ -162,6 +162,7 @@ async def create_ingestion_config_streaming_client( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, + max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingClient: """Create an IngestionConfigStreamingClient. @@ -179,6 +180,8 @@ async def create_ingestion_config_streaming_client( to enable tracing to stdout only, or TracingConfig.with_file() to enable tracing to both stdout and rolling log files. Defaults to None (tracing will be initialized with default settings if not already initialized). + max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the + client's configured value, or 50 MB. Returns: An initialized IngestionConfigStreamingClient. @@ -195,6 +198,7 @@ async def create_ingestion_config_streaming_client( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, + max_decoding_message_size=max_decoding_message_size, ) async def create_auto_register_streaming_client( @@ -211,6 +215,7 @@ async def create_auto_register_streaming_client( enable_tls: bool = True, tracing_config: TracingConfig | None = None, staged_configs: list[FlowConfig] | None = None, + max_decoding_message_size: int | None = None, ) -> AutoRegisterStreamingClient: """Create an `AutoRegisterStreamingClient`. @@ -246,6 +251,8 @@ async def create_auto_register_streaming_client( of a minimal derived config, preserving units, descriptions, and other metadata. The staged config is validated against the flow's channel names and types before use; a mismatch raises `RuntimeError`. + max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the + client's configured value, or 50 MB. Returns: An initialized `AutoRegisterStreamingClient`. @@ -263,6 +270,7 @@ async def create_auto_register_streaming_client( enable_tls=enable_tls, tracing_config=tracing_config, staged_configs=staged_configs, + max_decoding_message_size=max_decoding_message_size, ) @@ -298,6 +306,7 @@ async def _create( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, + max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingClient: """Create an IngestionConfigStreamingClient. @@ -316,6 +325,8 @@ async def _create( to enable tracing to stdout only, or TracingConfig.with_file() to enable tracing to both stdout and rolling log files. Defaults to None (tracing will be initialized with default settings for TracingConfig.with_file()). + max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the + client's configured value, or 50 MB. Returns: An initialized IngestionConfigStreamingClient. @@ -338,6 +349,8 @@ async def _create( grpc_config = sift_client.grpc_client._config api_key = grpc_config.api_key grpc_uri = grpc_config.uri + if max_decoding_message_size is None: + max_decoding_message_size = grpc_config.max_decoding_message_size # Convert the ingestion_config variants to a IngestionConfigFormPy if isinstance(ingestion_config, IngestionConfig): @@ -395,6 +408,7 @@ async def _create( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, + max_decoding_message_size=max_decoding_message_size, ) return cls(sift_client, low_level_client) @@ -637,6 +651,7 @@ async def _create( enable_tls: bool = True, tracing_config: TracingConfig | None = None, staged_configs: list[FlowConfig] | None = None, + max_decoding_message_size: int | None = None, ) -> AutoRegisterStreamingClient: try: from sift_stream_bindings import ( @@ -652,6 +667,8 @@ async def _create( grpc_config = sift_client.grpc_client._config api_key = grpc_config.api_key grpc_uri = grpc_config.uri + if max_decoding_message_size is None: + max_decoding_message_size = grpc_config.max_decoding_message_size if isinstance(ingestion_config, IngestionConfig): asset = sift_client.assets.get(asset_id=ingestion_config.asset_id) @@ -703,6 +720,7 @@ async def _create( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, + max_decoding_message_size=max_decoding_message_size, ) staged_configs_py = ( diff --git a/python/lib/sift_client/transport/base_connection.py b/python/lib/sift_client/transport/base_connection.py index 6586412fe7..4052f4769f 100644 --- a/python/lib/sift_client/transport/base_connection.py +++ b/python/lib/sift_client/transport/base_connection.py @@ -25,6 +25,7 @@ def __init__( use_ssl: bool = True, cert_via_openssl: bool = False, app_url: str | None = None, + max_decoding_message_size: int | None = None, ): """Initialize the connection configuration. @@ -38,6 +39,8 @@ def __init__( Set this for on-prem or custom deployments whose API host can't be mapped to a frontend automatically. When unset, the web-app URL is derived from ``rest_url`` for known hosts. + max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to + 50 MB. """ self.api_key = api_key self.grpc_url = grpc_url @@ -45,6 +48,7 @@ def __init__( self.use_ssl = use_ssl self.cert_via_openssl = cert_via_openssl self.app_url = app_url + self.max_decoding_message_size = max_decoding_message_size def get_grpc_config(self): """Create and return a GrpcConfig with the current settings. @@ -57,6 +61,7 @@ def get_grpc_config(self): api_key=self.api_key, use_ssl=self.use_ssl, cert_via_openssl=self.cert_via_openssl, + max_decoding_message_size=self.max_decoding_message_size, ) def get_rest_config(self): diff --git a/python/lib/sift_client/transport/grpc_transport.py b/python/lib/sift_client/transport/grpc_transport.py index 07a64b905e..e49f2988e0 100644 --- a/python/lib/sift_client/transport/grpc_transport.py +++ b/python/lib/sift_client/transport/grpc_transport.py @@ -48,6 +48,7 @@ def __init__( cert_via_openssl: bool = False, metadata: dict[str, str] | None = None, request_timeout: float | None = DEFAULT_REQUEST_TIMEOUT_SECONDS, + max_decoding_message_size: int | None = None, ): """Initialize the gRPC configuration. @@ -60,6 +61,8 @@ def __init__( metadata: Additional metadata to include in all requests. request_timeout: Default deadline in seconds applied to unary RPCs that don't set their own. Defaults to 60s. Set to None to disable the default deadline. + max_decoding_message_size: Largest response to decode, in bytes. Defaults to 50 MB. + Streaming ingestion clients inherit this value. """ parsed_url = urlparse(url) normalized_url = url @@ -77,6 +80,7 @@ def __init__( self.cert_via_openssl = cert_via_openssl self.metadata = metadata or {} self.request_timeout = request_timeout + self.max_decoding_message_size = max_decoding_message_size def _to_sift_channel_config(self) -> SiftChannelConfig: """Convert to a SiftChannelConfig. @@ -90,6 +94,7 @@ def _to_sift_channel_config(self) -> SiftChannelConfig: "use_ssl": self.use_ssl, "cert_via_openssl": self.cert_via_openssl, "request_timeout": self.request_timeout, + "max_decoding_message_size": self.max_decoding_message_size, } diff --git a/python/pyproject.toml b/python/pyproject.toml index 556a35f6cb..6c6fceea17 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -69,7 +69,7 @@ all = [ 'pyarrow>=17.0.0', 'pyulog~=1.2.2', "rosbags~=0.0 ; python_full_version >= '3.8.2'", - 'sift-stream-bindings==0.4.1', + 'sift-stream-bindings==0.5.0', 'types-pyOpenSSL<24.0.0', ] build = [ @@ -115,7 +115,7 @@ dev-all = [ 'pyulog~=1.2.2', "rosbags~=0.0 ; python_full_version >= '3.8.2'", 'ruff~=0.12.10', - 'sift-stream-bindings==0.4.1', + 'sift-stream-bindings==0.5.0', 'tomlkit~=0.13.3', 'types-pyOpenSSL<24.0.0', ] @@ -173,7 +173,7 @@ docs-build = [ 'pyulog~=1.2.2', "rosbags~=0.0 ; python_full_version >= '3.8.2'", 'ruff~=0.12.10', - 'sift-stream-bindings==0.4.1', + 'sift-stream-bindings==0.5.0', 'tomlkit~=0.13.3', 'types-pyOpenSSL<24.0.0', ] @@ -197,10 +197,10 @@ rosbags = [ "rosbags~=0.0 ; python_full_version >= '3.8.2'", ] sift-stream = [ - 'sift-stream-bindings==0.4.1', + 'sift-stream-bindings==0.5.0', ] sift-stream-bindings = [ - 'sift-stream-bindings==0.4.1', + 'sift-stream-bindings==0.5.0', ] tdms = [ 'npTDMS~=1.9', @@ -248,7 +248,7 @@ docs = [ openssl = ["pyOpenSSL<24.0.0", "types-pyOpenSSL<24.0.0", "cffi~=1.14"] tdms = ["npTDMS~=1.9"] rosbags = ["rosbags~=0.0 ; python_full_version >= '3.8.2'"] -sift-stream = ["sift-stream-bindings==0.4.1"] +sift-stream = ["sift-stream-bindings==0.5.0"] hdf5 = ["h5py~=3.11", "polars~=1.8"] # polars is only used by sift_py; remove once sift_py is fully deprecated ulog = ["pyulog~=1.2.2"] data-review = ["pyarrow>=17.0.0"] diff --git a/python/uv.lock b/python/uv.lock index 4834f607e9..0954ada5bc 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -4788,11 +4788,11 @@ requires-dist = [ { name = "ruff", marker = "extra == 'dev-all'", specifier = "~=0.12.10" }, { name = "ruff", marker = "extra == 'development'", specifier = "~=0.12.10" }, { name = "ruff", marker = "extra == 'docs-build'", specifier = "~=0.12.10" }, - { name = "sift-stream-bindings", marker = "extra == 'all'", specifier = "==0.4.1" }, - { name = "sift-stream-bindings", marker = "extra == 'dev-all'", specifier = "==0.4.1" }, - { name = "sift-stream-bindings", marker = "extra == 'docs-build'", specifier = "==0.4.1" }, - { name = "sift-stream-bindings", marker = "extra == 'sift-stream'", specifier = "==0.4.1" }, - { name = "sift-stream-bindings", marker = "extra == 'sift-stream-bindings'", specifier = "==0.4.1" }, + { name = "sift-stream-bindings", marker = "extra == 'all'", specifier = "==0.5.0" }, + { name = "sift-stream-bindings", marker = "extra == 'dev-all'", specifier = "==0.5.0" }, + { name = "sift-stream-bindings", marker = "extra == 'docs-build'", specifier = "==0.5.0" }, + { name = "sift-stream-bindings", marker = "extra == 'sift-stream'", specifier = "==0.5.0" }, + { name = "sift-stream-bindings", marker = "extra == 'sift-stream-bindings'", specifier = "==0.5.0" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = "~=2.0" }, { name = "tomlkit", marker = "extra == 'dev'", specifier = "~=0.13.3" }, { name = "tomlkit", marker = "extra == 'dev-all'", specifier = "~=0.13.3" }, @@ -4811,59 +4811,58 @@ provides-extras = ["all", "build", "data-review", "dev", "dev-all", "development [[package]] name = "sift-stream-bindings" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/02/32fc59d27b0e095c3b930411c0628dd485de98697d4fcadc6eb0f51c5476/sift_stream_bindings-0.4.1.tar.gz", hash = "sha256:bcbc06f5bcd7010f732866c171365023a746fd8f5ac323e81298646062d3fca4", size = 1332382, upload-time = "2026-06-10T21:52:53.506Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/27/f89ae81a33b258c91a7db46559532cf60379a0c5a6be77a45b4a78e21c65/sift_stream_bindings-0.4.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:414ca507825783edc298804e4f453378a411af6e503f417ad24ecbe16db8781f", size = 3884240, upload-time = "2026-06-10T21:51:19.311Z" }, - { url = "https://files.pythonhosted.org/packages/6e/50/5c5b8b0d728c6434dae328b716a46014d7cb2133e2e247e2ad1f52cf1aa8/sift_stream_bindings-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37388034b311b709e5fb6fdb5636651220ef25288676f91a8d66ca1af8daa507", size = 3824735, upload-time = "2026-06-10T21:51:21.427Z" }, - { url = "https://files.pythonhosted.org/packages/51/6f/5b17f8aecf38f9847dd189a4b22993ec8c084813ddeb475f489518bad95a/sift_stream_bindings-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1231efb8347638b7fe74f2d02cd9b66bd2ba30b3fbb59cc3616d8bac2295a10c", size = 4253788, upload-time = "2026-06-10T21:51:23.144Z" }, - { url = "https://files.pythonhosted.org/packages/6f/22/6b22c0baa4e443054bb966da2415af9b8a357facaf2f683ef5f09022d52a/sift_stream_bindings-0.4.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:318b3d6750e44747b933417d9250d62e8964b346dd9493f944eb0328e1f2291a", size = 3989000, upload-time = "2026-06-10T21:51:24.932Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a7/25d64598d277bf1ca834da9742e6fad53abf0195472cf7e8f6cf51a3aa4c/sift_stream_bindings-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cecaf224c52b002f136cd15cd89e4f37aa22cea25b469143eaa4dade51daea31", size = 4155448, upload-time = "2026-06-10T21:51:26.944Z" }, - { url = "https://files.pythonhosted.org/packages/02/40/6e0e858a09d595d92319fd0c8cb214563ea1434bf90947a66c35e33eb21e/sift_stream_bindings-0.4.1-cp310-cp310-win32.whl", hash = "sha256:33720642dc714ccaf47ff7ca4214a416e8bb4d112b45b96374108a8685816e3b", size = 2959856, upload-time = "2026-06-10T21:51:29.24Z" }, - { url = "https://files.pythonhosted.org/packages/64/e5/81603def8c64082e22c37332c4593ff63733e4c7123ad74303220bf9cff1/sift_stream_bindings-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2f1f4b0acb46a4343b006297e3d0a6f5f4268fa5d4961f885f2da5de554f96b", size = 3564806, upload-time = "2026-06-10T21:51:30.937Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ae/9cb41f5db6f3f624258bcc6a81feedcc912bb7fa6056a63c35ed3fad9102/sift_stream_bindings-0.4.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:98b33127355ff0da6002e18f3aa0b9a4a7c82c76de30e69e79e1f71f26e63092", size = 3884273, upload-time = "2026-06-10T21:51:32.94Z" }, - { url = "https://files.pythonhosted.org/packages/88/22/73d4bd1f09879fa0db61b37822ee7d347efd0854d22dda2ae3e98daf19ca/sift_stream_bindings-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46af2d575a9254c95a5a14e366f2db7c99db2c2e370a88188778d19c50dc91d8", size = 3824296, upload-time = "2026-06-10T21:51:35.147Z" }, - { url = "https://files.pythonhosted.org/packages/0c/60/06e31af253ad91ba282d5fef01bca6c30be931ce8579d21857ffb77903c9/sift_stream_bindings-0.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a17d09f806a05e5c75c264525cae9958e90ba74c10ffa1b36df6b90a4bb88c3", size = 4253630, upload-time = "2026-06-10T21:51:37.082Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ab/cbde1da0c04aa3ca03a42c2f04beb4e7121b6a2de96f5ce6523cf94e5c32/sift_stream_bindings-0.4.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d97fc10773ef3db1217e3cdc30aba444e19ff6b661306d14ee9b91c7b80064a7", size = 3988462, upload-time = "2026-06-10T21:51:38.691Z" }, - { url = "https://files.pythonhosted.org/packages/a8/5e/74035453894e8d1857f208468c006e089b1cfb5102008f66fe5d7f1db455/sift_stream_bindings-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d67da2b6d0730ae067242c5a7365f64c550d8a92da3841358781d6824b3fa2f", size = 4155012, upload-time = "2026-06-10T21:51:40.762Z" }, - { url = "https://files.pythonhosted.org/packages/7a/0c/ea36a80520d759649c40a934e17fc1f80dce7c14153c9b89024808fb9daf/sift_stream_bindings-0.4.1-cp311-cp311-win32.whl", hash = "sha256:9e135a88283db4e532134bc44ad6d5ce8dc152373ef79f895df0d597b01bbe27", size = 2956075, upload-time = "2026-06-10T21:51:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fa/875988632572b8c01045c9ff154b93770b338029d3baf9a2c38e6862275b/sift_stream_bindings-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:31d122364d73f5146758f49702a48cc709175f040d0645692c5864f1303e1941", size = 3541936, upload-time = "2026-06-10T21:51:44.692Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b7/232239fbbeef3cc7f3df2c232042ab52de466967f50c856a024be2ee8f48/sift_stream_bindings-0.4.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:149d99e1104bea3768eb2e08d52df952c606fb1794c9c1d2f0f810dc18ea1156", size = 3879865, upload-time = "2026-06-10T21:51:46.653Z" }, - { url = "https://files.pythonhosted.org/packages/f2/90/50e511164eabe000d4a4012e8c85004f30ede29ef53a65f3d89070f8fa22/sift_stream_bindings-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:540944329a9014817855d2fa1b85de25575a919dc9991776b4989e7e4c4315d3", size = 3820614, upload-time = "2026-06-10T21:51:48.436Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8e/391e838bb63368afabe82746614d870ceaf666e3c1d0259d5eb94b552153/sift_stream_bindings-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4373cf76911965fb6992b02b3d09c2e0664f76ce8294310b0808b02fbe6e2c79", size = 4248794, upload-time = "2026-06-10T21:51:50.216Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/fd5e7cfed78f26498b2c3b8e92bcfbbb92ff44a1e577fe001fb67ed8b22d/sift_stream_bindings-0.4.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:871525f01d0479e2f2a933bf6c1c681e88c1ee16332c656dd1e8b472747b5551", size = 3965073, upload-time = "2026-06-10T21:51:52.128Z" }, - { url = "https://files.pythonhosted.org/packages/d2/1c/a389979a20b0763569bb83963ff29f325d9617ed9c9ac80a71bcd01a24ea/sift_stream_bindings-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdc9e6665a8b0342ae9b0d5d9943edea2b5934412cb42118e1158374e5dd32ea", size = 4149380, upload-time = "2026-06-10T21:51:54.119Z" }, - { url = "https://files.pythonhosted.org/packages/fe/9c/22b5e7c7deb05a7cc0a0c3200225524a4708c170dd0066f5d84941c4b09e/sift_stream_bindings-0.4.1-cp312-cp312-win32.whl", hash = "sha256:ab758599ff4c399382cf23dafff82a06351d88b6d22b27604c02fad6517e30de", size = 2950936, upload-time = "2026-06-10T21:51:56.146Z" }, - { url = "https://files.pythonhosted.org/packages/0e/bc/caaa5ca2d46afdba79cff9eaaf278874abf31d93f25d01c188b8e085eb9c/sift_stream_bindings-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d9b44b8dcad6994340e0a3c15314b001505b2f6ef3ea3ba8de11dc8aede73e", size = 3565719, upload-time = "2026-06-10T21:51:58.314Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/f80ad9add605f204b97585bd0b3a902330f4d4139c2e7b88859b2aafde1c/sift_stream_bindings-0.4.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e2c356a582040202d7d536cd12ea79f11bd616f816153614331b9470423c94d5", size = 3879170, upload-time = "2026-06-10T21:52:00.276Z" }, - { url = "https://files.pythonhosted.org/packages/bc/15/ee8e0789e6a76a9aa82a2f1ed1f71b6780d29d7303d37313c08a9cfa01e1/sift_stream_bindings-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4856ee8229816164279cb1a67d91ed97a92a44b067b5440eb0f253c54cc118af", size = 3820639, upload-time = "2026-06-10T21:52:02.614Z" }, - { url = "https://files.pythonhosted.org/packages/70/fa/a0593a596ec6bd09520621bfd7c420f646959aad68123452b2c1cec77ff2/sift_stream_bindings-0.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef594e839715221dbe989d99ef68ea39220e360945e7e5d14ff730ad4c738ba5", size = 4248848, upload-time = "2026-06-10T21:52:04.33Z" }, - { url = "https://files.pythonhosted.org/packages/e9/1d/24c9a4697a8ac12afa07216988cdbd2ad1cc727d79ad629b347168f31104/sift_stream_bindings-0.4.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91fb6e4967fcdb3eae4d46ddbdd68ed09a3e31d74c5fd976f140848589fb4be1", size = 3964746, upload-time = "2026-06-10T21:52:06.042Z" }, - { url = "https://files.pythonhosted.org/packages/5f/f4/98083a70f243615185fd075816c0c2cc3ea686b93e1d549e659221521c29/sift_stream_bindings-0.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66aa56e05e7b3bdcbafdc7ed77837ccfc5bbf5d496f9986d339fdde8468b83a9", size = 4149008, upload-time = "2026-06-10T21:52:07.874Z" }, - { url = "https://files.pythonhosted.org/packages/0c/a1/0f6be4870531b8676249d6a6ac937db73a97d3f21ace326770d7b5f538c5/sift_stream_bindings-0.4.1-cp313-cp313-win32.whl", hash = "sha256:01bb90ce9f88a6285a71d9f69af3ca077feb7aeb2359caf12054be20f930632e", size = 2950417, upload-time = "2026-06-10T21:52:09.796Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a2/d7a60d6b9ba695a2a40ea022438808e92cb1d868852829758b5e3a1fed65/sift_stream_bindings-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:7f2ef2dd48ac5ae2d0ee4d328c61a55a6b386c27337f091c8e02388dfbb1b267", size = 3565436, upload-time = "2026-06-10T21:52:11.589Z" }, - { url = "https://files.pythonhosted.org/packages/2d/34/f24d6423704fca7a54fe8c31854c762151c39e487a0b182186f965becb02/sift_stream_bindings-0.4.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e8138aa74f1790dae77be269facc9c8075a13c457f850eab9244c18fb38df55e", size = 3901784, upload-time = "2026-06-10T21:52:14.028Z" }, - { url = "https://files.pythonhosted.org/packages/ed/96/3755c9d1f3a74ee62e7bef5c3241475e6f6a8c52186dff4a965d01502ca8/sift_stream_bindings-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4df255bc91e788e4ad90f0fa80304bcefa324364087210e12adebce8a4dbf988", size = 3840572, upload-time = "2026-06-10T21:52:15.839Z" }, - { url = "https://files.pythonhosted.org/packages/95/aa/3e8854da1f727bba680f1672730cf7d6e839240f454d3d50eaaf3b345388/sift_stream_bindings-0.4.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca5a04b7ffda2a4af2f56686d3a8f5e1f5e7fb79ea2b1f34f5b10d420e307b68", size = 4254159, upload-time = "2026-06-10T21:52:17.583Z" }, - { url = "https://files.pythonhosted.org/packages/55/5c/c3882742f3e562b2209a797954b86b0e2572422e1145b5e4107d6a07af07/sift_stream_bindings-0.4.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63308be820db09806ba94466cc4f06da7f5322ccde0fafea7dcd50245607661c", size = 3966376, upload-time = "2026-06-10T21:52:20.286Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e0/c9dc90e8e2f466547e631555d2f245e9ccde8bc657522b3d8e233cc69579/sift_stream_bindings-0.4.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6f04ad77ddcea0d65037dd13de3faec8c017d27ac2efb8a1098e1a4aeefab2", size = 4154576, upload-time = "2026-06-10T21:52:22.073Z" }, - { url = "https://files.pythonhosted.org/packages/46/fa/fb1885c117cd6022e6baef8220bc934541d4afe3897fd07ea1ad932fdefa/sift_stream_bindings-0.4.1-cp314-cp314-win32.whl", hash = "sha256:e308dedfbc591cddd1413dacb65df0149d03f60db5f66e87a5ae46e391d9f0c3", size = 2950792, upload-time = "2026-06-10T21:52:23.773Z" }, - { url = "https://files.pythonhosted.org/packages/8b/59/d901842f37740d5c307a35ee757b01a7c5202cac99299e4ab790f892a739/sift_stream_bindings-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:ff76e668beb46c1e2bfca5bc5ae9323c08ab258e79707a0efeb34d8c7f3d7998", size = 3565736, upload-time = "2026-06-10T21:52:25.434Z" }, - { url = "https://files.pythonhosted.org/packages/37/72/13d7e05f76df122276b42fec4ac22ce897f53fa27ab3778ffab06f09e5d7/sift_stream_bindings-0.4.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9e9e99d3bdeab43adf3d3899939824df102cac2d65305ff288b33ae48aa94e1f", size = 3885720, upload-time = "2026-06-10T21:52:27.586Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2a/b150c406c73c9fde69fe25d9e6665c133a66c5586cd899edb85bebfa5cf9/sift_stream_bindings-0.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f7e215f2d67fd3c4aeaeb7c2846da06967510f3791a6d6fe2407ac0d7c516a47", size = 3826193, upload-time = "2026-06-10T21:52:29.508Z" }, - { url = "https://files.pythonhosted.org/packages/a0/04/b17955b445a58c64a1f352d891c890a602ae54ca74c97d3175073c916833/sift_stream_bindings-0.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:041755e62c58aa3998100e8484836b9d563483272149caf91fff87bd9f449f63", size = 4258222, upload-time = "2026-06-10T21:52:31.539Z" }, - { url = "https://files.pythonhosted.org/packages/e6/cb/1268bc5c33520a743f8ce2a117e2a6358bdf2b14cddea6b2a0103efa992d/sift_stream_bindings-0.4.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1a9ec6da6127a7a0d929debc79fc25209a8b513a984f94de5dd2c05e836984a9", size = 3970637, upload-time = "2026-06-10T21:52:33.159Z" }, - { url = "https://files.pythonhosted.org/packages/31/76/9a6fbb1c06974472896e0bfa7a4f4333d43414ac97826e9842ee021660f0/sift_stream_bindings-0.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:376b73ac14a6d632541b72e43c65b40fa7cd33c8bf24711ad158e4e5afd4b2ce", size = 4158404, upload-time = "2026-06-10T21:52:35.172Z" }, - { url = "https://files.pythonhosted.org/packages/e2/31/91de8402b24fc6f8667a819ff4beaba7ea14c37c3ee5e81291164cc6b94e/sift_stream_bindings-0.4.1-cp38-cp38-win32.whl", hash = "sha256:98a6b8d9443494ea7eb04577ed0be6d897ba6f508bfa9f280c36c6f7c16db583", size = 2969215, upload-time = "2026-06-10T21:52:37.266Z" }, - { url = "https://files.pythonhosted.org/packages/f7/c5/7b0894b36214d20a524e6796afd74e9e73f27507cfb249108d07f2fa1da7/sift_stream_bindings-0.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:814d5be98dac339cf0d3fdfae1a548108f746799ec45b09bf7201e97a0065694", size = 3546322, upload-time = "2026-06-10T21:52:39.33Z" }, - { url = "https://files.pythonhosted.org/packages/4f/99/3b6221807d2d5e0f6a59a1ec6a9626d4465a9cdf017f20307c32c2a8284f/sift_stream_bindings-0.4.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:01fac583bff1369d88d01aeb75f84606f66222b944f4ba90f178bb2388085573", size = 3887560, upload-time = "2026-06-10T21:52:41.08Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ed/580842c5d5980decf0851d92edc9a65bd7d1d0f7081eb98cb9adb58e6b56/sift_stream_bindings-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:963ab300ce61d8bd473d7175870b6682f11104796b165cce82e2b2f4d93d2bb5", size = 3827976, upload-time = "2026-06-10T21:52:42.796Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f1/2cf5cb456bd1bdceb3dd068d732d7b6ccdf6f6314c88fe3e8a52b1c0363d/sift_stream_bindings-0.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db7175f31795e69ae8d72b84f313907e93809f89b203b6a5d80953705f248aca", size = 4257595, upload-time = "2026-06-10T21:52:44.629Z" }, - { url = "https://files.pythonhosted.org/packages/46/3f/2c3fa9d3a3feaaa475d26912f485cf4d922c9a95285e723549f9c41c0f49/sift_stream_bindings-0.4.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae9ce1facc71015afef22c9928de2e6a2fc03da6cf555d46c9aef46a9e25942", size = 3991235, upload-time = "2026-06-10T21:52:46.515Z" }, - { url = "https://files.pythonhosted.org/packages/05/b0/668425aafd97786e6ce93b639707d980263490705b3659e24a2a7820b710/sift_stream_bindings-0.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2a08c4bf0bc800e7c886f69ccdb6dc2a0f1cbc7f62a02baee4095a715676408", size = 4158934, upload-time = "2026-06-10T21:52:48.209Z" }, - { url = "https://files.pythonhosted.org/packages/27/7c/70f3216eda5b38bea0a3b29db3f1ad50f24edb794aef287cea5c3d41c187/sift_stream_bindings-0.4.1-cp39-cp39-win32.whl", hash = "sha256:d605b72c54c4ea364c7ae0c9130be6f9ad02ed22dc9748eb39663d33da47dec7", size = 2958142, upload-time = "2026-06-10T21:52:49.894Z" }, - { url = "https://files.pythonhosted.org/packages/b2/45/3fa380bcdf6fa4e34db72f76e93831686c2370bf20786452f43ff4298897/sift_stream_bindings-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:7a0616c1441ade6e0fe483d186cdc48f4451fc39095bdf872927ff477f97bcd0", size = 3566929, upload-time = "2026-06-10T21:52:51.813Z" }, +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/c4/326f7a02ad00fdc542c22085f00e312d8133b59d2e61850096d6c4e9929c/sift_stream_bindings-0.5.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:46de88c9ff5420ed26e8f0606ac53e629304913eaf2955a5d3750603df88d182", size = 3891241, upload-time = "2026-08-21T01:07:32.234Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ad/c46e4118c4329bd19468d33681444e3766dcab686184dafff3cf6661d064/sift_stream_bindings-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4167fc2e1ba84d163c04bab92090760a729a48647bdf3145a1abff02b5334306", size = 3837693, upload-time = "2026-08-21T01:07:33.923Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/2678e3ab4b6ddf1ad436b9bbcadbe651dd2544d46e739dc894785de921d2/sift_stream_bindings-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b2100bfd01635b65b9cd57d4a4e7e57c30ec3b8faa404948bcca78c8e10380f", size = 4296821, upload-time = "2026-08-21T01:07:36.082Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ae/373ae20219e19e74e653d610f3a375db017a53a4368425ab3bd03685c1bb/sift_stream_bindings-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef01d6425a5fd1fe4d8097187b3ae95aca8ea780fd343412b57513e4bc69c512", size = 4043621, upload-time = "2026-08-21T01:07:38.03Z" }, + { url = "https://files.pythonhosted.org/packages/ee/cd/42ee41f02a15ece72c8ab63d0399ad1b6f385b254cc51e8f4fe28a9feb8c/sift_stream_bindings-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4a7ca957d4eabbc8348c2c34a4fb25e84135a7984f7f598279986488d2d4aa9", size = 4071709, upload-time = "2026-08-21T01:07:39.52Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/8b6f5d9f03ce7e0e984b3baea7421de5d70eb8cd03deac398ec6b975a13e/sift_stream_bindings-0.5.0-cp310-cp310-win32.whl", hash = "sha256:68d8b251d5aba591a84ca049c50e4a800d5fbbb75b06f26a3f7903f69e44a9df", size = 2968879, upload-time = "2026-08-21T01:07:40.993Z" }, + { url = "https://files.pythonhosted.org/packages/12/89/7e0dfc1547d18509de8fc96db79b6c99d0d292e4d5dd5d04ca013d4448f7/sift_stream_bindings-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d0ac9bdb446c393695ba40d770ae7da46b84227af16c1fd83c10ca3cfe201496", size = 3583340, upload-time = "2026-08-21T01:07:42.485Z" }, + { url = "https://files.pythonhosted.org/packages/dd/bc/e96645feb415cd73202e666f012bdb5b7f20315fba16acecff96ada9be43/sift_stream_bindings-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e11f847c307f644eb79550c69770821c6777d52ef71847808fda2d031ff1fe93", size = 3891174, upload-time = "2026-08-21T01:07:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/a2/00/04c9855989b6a84592593ffc413b1d81077f513e9f43278a7ced3c776ec8/sift_stream_bindings-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301f11f4751f8299a14295aa1a386b15c698123cc0c6fdd82bc38ffab2b8886b", size = 3836012, upload-time = "2026-08-21T01:07:46.043Z" }, + { url = "https://files.pythonhosted.org/packages/c3/45/153a01383abcc222e672b9ba712ec02db55736074a6d6b1285a0ada22c3d/sift_stream_bindings-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00b6ed15b032dc6b766083e9b14094e02154c1d3e84dad63a681518f5fbcbf6", size = 4296493, upload-time = "2026-08-21T01:07:47.397Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a5/05ea3ca8b96aa72355875d7afa09429b064a55f2de6b527b9b05959909a9/sift_stream_bindings-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97e61a9d01769f51f39415758bc4e122e7d846415bce9a7aa976501520d6c860", size = 4043723, upload-time = "2026-08-21T01:07:48.996Z" }, + { url = "https://files.pythonhosted.org/packages/2e/56/0763ff5774d705d6568cf4639236e8179787acd37ee43e5548523d266b06/sift_stream_bindings-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7b5a7e25f41c7733c3c0d03b83535c4fe32b149739224212ccea69b2ea5757", size = 4071813, upload-time = "2026-08-21T01:07:50.549Z" }, + { url = "https://files.pythonhosted.org/packages/cb/88/17d9b34e6bd00da38bb472b822e2ed327d33b7795d3f6ecade2397c9cb5d/sift_stream_bindings-0.5.0-cp311-cp311-win32.whl", hash = "sha256:45ee0a6e76bc3c627c44720ba11b8dff3de4046956e48717fb212f5c0f8addd5", size = 2969009, upload-time = "2026-08-21T01:07:52.292Z" }, + { url = "https://files.pythonhosted.org/packages/ed/3f/1df4c177905fb60c19bec59e922385a26a6acaf82c2cec2a0081aca9f780/sift_stream_bindings-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:f6576ae3af67618be995bbad052e8f3852e932ac6122d2963bae4ba6e19136a3", size = 3583433, upload-time = "2026-08-21T01:07:54.396Z" }, + { url = "https://files.pythonhosted.org/packages/e3/80/b252d2bb5397d29fe841e0a5f52b55efbf360e0dae10a36add855c6c4988/sift_stream_bindings-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a4948971c4830bb9045d2cefb1af0c805b8d5bebc55ca9811163135886146833", size = 3888362, upload-time = "2026-08-21T01:07:55.916Z" }, + { url = "https://files.pythonhosted.org/packages/29/d1/58be73c8fc7f3813469dfd554eaea82f3e3b57fd89ed6e1435295d41ddcc/sift_stream_bindings-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32e53d8c20da4e67a1c8f927d5c858dfc7df0dfcf2179997d6f3c7bdb348820a", size = 3829886, upload-time = "2026-08-21T01:07:57.402Z" }, + { url = "https://files.pythonhosted.org/packages/55/c7/01de4dc3409fa4bd2e927ad7e276655e6d8c9fc42df5a0781f9efa43ed65/sift_stream_bindings-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9c0a0d7096cd768719d597b0cbfa501fb5ff5c9c265c9575f6b8003ee2387ce", size = 4293258, upload-time = "2026-08-21T01:07:59.305Z" }, + { url = "https://files.pythonhosted.org/packages/52/7b/238168ab32dbdef9471162b1510f822bee94e072c0e7cc14936b30532e28/sift_stream_bindings-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26ae7d212e00297aff39c193f523f7ca48409e6d00e55345dd94b04462b79e68", size = 4034648, upload-time = "2026-08-21T01:08:01.069Z" }, + { url = "https://files.pythonhosted.org/packages/19/5d/33ba1b7a84715e0c845cf9e016e41eb408d5c2d5a6baa98f0c577053b686/sift_stream_bindings-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deef0181f6f290da19fc0e60310ca100d53397f29da5637bb4c4b7485e69b62d", size = 4069883, upload-time = "2026-08-21T01:08:02.954Z" }, + { url = "https://files.pythonhosted.org/packages/c3/8f/3710f28b25a05d4256434a0f0990fd1248c9b4869c6d2736eb7cf9ab4e63/sift_stream_bindings-0.5.0-cp312-cp312-win32.whl", hash = "sha256:519d8dc1c9c34a14946e212201c1d8e46c2612aecb5967d10f2b577184ae5fb9", size = 2973067, upload-time = "2026-08-21T01:08:04.49Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3c/143b12daf55a15c0393e6b60f95a206cdb9a8f14fe253c990e21eee26a0d/sift_stream_bindings-0.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:6c6d22ae57249536ca517bdbe59ef7a3a78c72294facea37bea863b9c6454a20", size = 3580028, upload-time = "2026-08-21T01:08:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f6/92173904f4c7159cf442aa0b1085af79b34e24e33cbb61dcd82abf84673b/sift_stream_bindings-0.5.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e6049286b59ce1af52ac544d96d5d803d456406ae03cdb96a8bb82241ea2261b", size = 3887685, upload-time = "2026-08-21T01:08:07.484Z" }, + { url = "https://files.pythonhosted.org/packages/3f/98/8886abc6561fcc4274a44373b3f06747dc0c7331b3e74456fc777b88bf3e/sift_stream_bindings-0.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1d6939f4aca801c0e1b62b8604d2ee6750bee42953b00fd85342a9e36a20feaf", size = 3828388, upload-time = "2026-08-21T01:08:09.126Z" }, + { url = "https://files.pythonhosted.org/packages/45/0e/e61fefb70bdef6c02b441a868e9262ea2fd99bb45faba84408b1797b271f/sift_stream_bindings-0.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:074064022a20f5fa076af8b7c9befb0339135ac51b7325272ce3373ce5dbda88", size = 4293005, upload-time = "2026-08-21T01:08:10.606Z" }, + { url = "https://files.pythonhosted.org/packages/91/3f/72c0f18ce04e90bc9cccc3c36f5f1ac264e9ca69a3f9914f31272d03dd37/sift_stream_bindings-0.5.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a3997be6d32b85177b06c48e7ac4ff70730343ba63496183488e8cf9efea475c", size = 4032997, upload-time = "2026-08-21T01:08:12.204Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/3ee1b8d62d06cb886e47960e2bbd6ac91780c1001f98d159e6df1feba45e/sift_stream_bindings-0.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74790ee487f2bbedd9c469804059e270180897eff7b0792c5b66f905dff408f", size = 4068600, upload-time = "2026-08-21T01:08:13.654Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/c0470e9c99a021c247732045d6b012a7e3227ab63d76566e0d7d7ca7dbc6/sift_stream_bindings-0.5.0-cp313-cp313-win32.whl", hash = "sha256:4fdeeb72ceaf19ddb89ead096f6335a0c4de6ef0b9afc7988e48299dbdbc1e57", size = 2972887, upload-time = "2026-08-21T01:08:15.159Z" }, + { url = "https://files.pythonhosted.org/packages/95/71/f42f79053ae4bcc8dc85957201f013ae54fdf0e650f342406a37da098d6e/sift_stream_bindings-0.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:714f10bf45263ed910f97910069f57e9fb1425a1c66af78890b7200594af7781", size = 3579557, upload-time = "2026-08-21T01:08:16.827Z" }, + { url = "https://files.pythonhosted.org/packages/04/91/de14a6d06c9e949bd5e52d4650feca0b392ad921ad78f8570a908821735e/sift_stream_bindings-0.5.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:910d773ad86404d5d918b97000586103b9c46966b2d0f4979a23c79cfe107852", size = 3891609, upload-time = "2026-08-21T01:08:18.976Z" }, + { url = "https://files.pythonhosted.org/packages/7d/95/3a6d7905f1c3f77aab7e3ef539cc47d5886c423fde609916563742161258/sift_stream_bindings-0.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d58e14fb3070ef5ac1fb7dc8ca9f489a15d42f39753d207b7621dbeb8b073fc7", size = 3831695, upload-time = "2026-08-21T01:08:20.783Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/9feb6a50c95093b39058985335f256aff5f44b23444e241620a6255ff276/sift_stream_bindings-0.5.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85aa1fb8e19f2afd6b5c14a567ca14f17f82a791d0ed6c14ea8dda9db5cd026", size = 4294105, upload-time = "2026-08-21T01:08:22.674Z" }, + { url = "https://files.pythonhosted.org/packages/89/d9/cd94e818625c7c51d88990533113dcaad7cde79601647d0fe0eb6c91ee59/sift_stream_bindings-0.5.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:41b7b1a7a78c2bbb722a408cf07ced48aeea6b55c65091e063ac78eda80bcb04", size = 4029538, upload-time = "2026-08-21T01:08:24.211Z" }, + { url = "https://files.pythonhosted.org/packages/58/8d/4d3848e3e81a0bb568445d875e5adb12a0297eabfaaca1a722543f11a3a0/sift_stream_bindings-0.5.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:449776a0ba0fa40db45d70f969b1141a1494e04558a1f3d58321b24f8d88e529", size = 4065969, upload-time = "2026-08-21T01:08:25.734Z" }, + { url = "https://files.pythonhosted.org/packages/86/dc/6afcdd4b8312fee8ee60cc9a5f41ff9f76d601281eceb76837c809323908/sift_stream_bindings-0.5.0-cp314-cp314-win32.whl", hash = "sha256:56482095d3eafddfefceaef0981c429d955a1a09f957f01b1de4b113498a3055", size = 2973547, upload-time = "2026-08-21T01:08:27.326Z" }, + { url = "https://files.pythonhosted.org/packages/d0/de/ea53e52bbcd4685332af925937e645c1cf94c2f9e5f8c6e3143181dcee06/sift_stream_bindings-0.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:0458ed9efe0d6aaa6b79823eea1c69d2e9c6f6bf9aae10bb558b95a1d271bec9", size = 3582106, upload-time = "2026-08-21T01:08:28.926Z" }, + { url = "https://files.pythonhosted.org/packages/f9/76/90cb83f22f3b7309608c4d26a157a2371055d6f6d16b26c2e9044192b75c/sift_stream_bindings-0.5.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:a694f4577e3e56d8bc6c9a20d9f0958b77aeb912ead9193a4d382f67b3465b97", size = 3897833, upload-time = "2026-08-21T01:08:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/7cb11723f71ee6f1bf30bdf081b9ce9e4bdcf1718a36a013188c9f6bba9e/sift_stream_bindings-0.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:768809cbc3849679c580d5fbc81b06e24a8b0cf6bb134418bd7388dbbea4ad38", size = 3834978, upload-time = "2026-08-21T01:08:32.259Z" }, + { url = "https://files.pythonhosted.org/packages/8f/90/14185a35034faa6e6ae7ccc8c956353d7aa55a4fe9e509b5515fc9205b1d/sift_stream_bindings-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ac6a10e82d432af743e43a03e18a7d1ae576e458cfeb944b87874e1e0bd82dc", size = 4298876, upload-time = "2026-08-21T01:08:33.678Z" }, + { url = "https://files.pythonhosted.org/packages/5a/34/bc7b56c8c9b83517518430578b771a88a0a64e8a2340537698ef491b8a0d/sift_stream_bindings-0.5.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f15a94833fc6ab8fd126c364f902a513ad32a86ed845993a3e4076eb2092109", size = 4049318, upload-time = "2026-08-21T01:08:35.546Z" }, + { url = "https://files.pythonhosted.org/packages/c2/2c/f31da8cc8c01557744b3ac984cd31f8e746115bec9b8620995d304bb5821/sift_stream_bindings-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21670556d39e58a63ed4da4ed7ac44962b3cc6d498cb0b1ab586ff8729feb553", size = 4074753, upload-time = "2026-08-21T01:08:37.197Z" }, + { url = "https://files.pythonhosted.org/packages/d2/eb/a40f101b2cc837b68ad4c50512a3b51411d686729b878f463e6a8ba736ae/sift_stream_bindings-0.5.0-cp38-cp38-win32.whl", hash = "sha256:c80f3f128a32ddb7b888901fcc3a9cfb1927352fc58bca27f8cadbf541c5f84c", size = 2975419, upload-time = "2026-08-21T01:08:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0e/f005cbe1f25df4a2e2698b2affbd1e6b616241134a58d5c8df8935ae19a2/sift_stream_bindings-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:a606cd51db7841ca57e4073b2082f791f9a5486f693030d7cc859fbe71fd97ec", size = 3584761, upload-time = "2026-08-21T01:08:40.89Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a5/d386c6fb3ae1cb4f3574be893368e2822192ab3984b5cfaadc405093d8c6/sift_stream_bindings-0.5.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:35355e553d93040b3ab122ee8830c75089a18ac1efe394ea6901485c7c25093c", size = 3894556, upload-time = "2026-08-21T01:08:42.844Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6e/ee8182b860644b86ad0de09eb280d058bf97af85781c948ba66da0d179d0/sift_stream_bindings-0.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e00f0ac967ad665203b5147e4133fac8ee513e647bb323d752292aac949c121b", size = 3841965, upload-time = "2026-08-21T01:08:44.447Z" }, + { url = "https://files.pythonhosted.org/packages/4f/91/4591a0547c0c12f1eaa1eed78ffb976bf919fac089fcf5a53d7aab56d15e/sift_stream_bindings-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9c5d9d645358ab473d660c2c5c2a4c18bfebffbff8b5f63ba5c97e7a9500a61", size = 4299067, upload-time = "2026-08-21T01:08:46.227Z" }, + { url = "https://files.pythonhosted.org/packages/a0/31/00d9f0be43f18fa010ac38febc4d51a0859e3ab9e90b9c1791735b68837a/sift_stream_bindings-0.5.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ca9641d5dacad0e8bcf1e4032e08ab0b1f1bab93a691965aae9715c41ce7ba3", size = 4046896, upload-time = "2026-08-21T01:08:47.683Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3b/a7124d436bce8b635154fe6ef76a974c121ef9264cc78d7b44b7f99fdb80/sift_stream_bindings-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c4151526d3c858bfc10053bddaee554ace77103cdae5ab7e7d5be68d7316eff", size = 4074753, upload-time = "2026-08-21T01:08:49.329Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6a/351569f0af2b203982476b57d1dca06dd01037814b6cbc16cd94b3a4f82b/sift_stream_bindings-0.5.0-cp39-cp39-win32.whl", hash = "sha256:41f1d9056c90576644d8f13a8adb8f975ed9c5766a8870a5fb0c300511748c0c", size = 2970343, upload-time = "2026-08-21T01:08:50.956Z" }, + { url = "https://files.pythonhosted.org/packages/1c/79/841d2fe0072e71a0151e8d857b46541cf1e31db036ec6aafdc5bc7107ba2/sift_stream_bindings-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:1ac7619fc9b4d7656ae1a119cc88a641afff94f617e8e913b73cd7771879abf8", size = 3585698, upload-time = "2026-08-21T01:08:52.413Z" }, ] [[package]] From 0793a2865391af14c5a737b292ccd8a652c06aee Mon Sep 17 00:00:00 2001 From: Wei Qi Lu Date: Sat, 22 Aug 2026 13:21:15 -0700 Subject: [PATCH 2/5] update changelog example --- python/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md index f868596d51..93892c7d7a 100644 --- a/python/CHANGELOG.md +++ b/python/CHANGELOG.md @@ -26,7 +26,7 @@ client = SiftClient( Streaming ingestion clients inherit the value and can override it per stream: ```python -stream = await client.ingestion.create_ingestion_config_streaming_client( +stream = await client.async_.ingestion.create_ingestion_config_streaming_client( ingestion_config, max_decoding_message_size=200 * 1024 * 1024, ) From f8741d83f35ae2e2e48f2c2e669d7308044ef6d5 Mon Sep 17 00:00:00 2001 From: Wei Qi Lu Date: Sat, 22 Aug 2026 13:42:34 -0700 Subject: [PATCH 3/5] update changelog --- python/CHANGELOG.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md index 93892c7d7a..bea2591e4b 100644 --- a/python/CHANGELOG.md +++ b/python/CHANGELOG.md @@ -7,10 +7,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### What's New -#### Configurable gRPC decode limit +#### `max_decoding_message_size` -Sets the largest gRPC response the client will decode. Defaults to 50 MB; raise it for large -payloads such as an ingestion config with many flows. +The largest gRPC response the client will decode, in bytes. Defaults to 50 MB. Raise it for +responses that exceed the limit, such as an ingestion config with a very large flow schema. ```python client = SiftClient( @@ -23,14 +23,8 @@ client = SiftClient( ) ``` -Streaming ingestion clients inherit the value and can override it per stream: - -```python -stream = await client.async_.ingestion.create_ingestion_config_streaming_client( - ingestion_config, - max_decoding_message_size=200 * 1024 * 1024, -) -``` +Streaming ingestion clients inherit the value, and take `max_decoding_message_size` themselves +to override it for one stream. ### Bugfixes - Fix `assets.archive` raising `AttributeError` by reading the correct response field, `archived_run_ids`. From dbeee49e4e929fb261c875095da8b4d50f6c585d Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Tue, 25 Aug 2026 12:25:52 -0700 Subject: [PATCH 4/5] remove user-facing field --- python/CHANGELOG.md | 22 +-------- .../_internal/grpc_transport/transport.py | 16 +++---- .../_internal/low_level_wrappers/ingestion.py | 4 -- .../sift_client/_internal/pyproject_config.py | 2 +- .../_tests/_internal/test_transport.py | 48 ++----------------- python/lib/sift_client/resources/ingestion.py | 18 ------- .../sift_client/transport/base_connection.py | 5 -- .../sift_client/transport/grpc_transport.py | 5 -- 8 files changed, 14 insertions(+), 106 deletions(-) diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md index bea2591e4b..f44348c042 100644 --- a/python/CHANGELOG.md +++ b/python/CHANGELOG.md @@ -5,29 +5,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -### What's New - -#### `max_decoding_message_size` - -The largest gRPC response the client will decode, in bytes. Defaults to 50 MB. Raise it for -responses that exceed the limit, such as an ingestion config with a very large flow schema. - -```python -client = SiftClient( - connection_config=SiftConnectionConfig( - grpc_url="...", - rest_url="...", - api_key="...", - max_decoding_message_size=200 * 1024 * 1024, - ) -) -``` - -Streaming ingestion clients inherit the value, and take `max_decoding_message_size` themselves -to override it for one stream. - ### Bugfixes - Fix `assets.archive` raising `AttributeError` by reading the correct response field, `archived_run_ids`. +- Fix streaming ingestion failing to start when an ingestion config's flow schema exceeded the streaming client's 4 MiB decode limit. `sift-stream-bindings` 0.5.0 decodes up to 50 MiB. ## [v0.19.1] - July 27, 2026 diff --git a/python/lib/sift_client/_internal/grpc_transport/transport.py b/python/lib/sift_client/_internal/grpc_transport/transport.py index 63b41f2425..ac1ece5c2d 100644 --- a/python/lib/sift_client/_internal/grpc_transport/transport.py +++ b/python/lib/sift_client/_internal/grpc_transport/transport.py @@ -34,8 +34,13 @@ DEFAULT_REQUEST_TIMEOUT_SECONDS = 60.0 """Default per-call deadline applied to unary RPCs that don't set their own.""" -DEFAULT_MAX_DECODING_MESSAGE_SIZE = 50 * 1024 * 1024 -"""Largest response the client will decode, in bytes.""" +MAX_DECODING_MESSAGE_SIZE = 50 * 1024 * 1024 +"""Largest gRPC response the client will decode, in bytes. + +50 MiB, matching the Rust clients' `sift_connect::MAX_DECODING_MESSAGE_SIZE`. Sized to cover the +largest responses Sift returns, such as 1M-row `GetData` pages and large flow schemas, so it is +fixed rather than configurable. +""" def get_ssl_credentials(cert_via_openssl: bool) -> grpc.ChannelCredentials: @@ -162,16 +167,13 @@ def _compute_channel_options(opts: SiftChannelConfig) -> list[tuple[str, Any]]: """ request_timeout = opts.get("request_timeout", DEFAULT_REQUEST_TIMEOUT_SECONDS) - max_decoding_message_size = ( - opts.get("max_decoding_message_size") or DEFAULT_MAX_DECODING_MESSAGE_SIZE - ) options = [ ("grpc.enable_retries", 1), ("grpc.service_config", RetryPolicy.default(timeout_seconds=request_timeout).as_json()), # Primary cannot be overriden: # https://github.com/grpc/grpc/blob/0498194240f55d7f4b12633ad01339fb690621bf/src/core/ext/filters/http/client/http_client_filter.cc#L97 ("grpc.secondary_user_agent", _compute_user_agent()), - ("grpc.max_receive_message_length", max_decoding_message_size), + ("grpc.max_receive_message_length", MAX_DECODING_MESSAGE_SIZE), ] enable_keepalive = opts.get("enable_keepalive", True) @@ -246,7 +248,6 @@ class SiftChannelConfig(TypedDict): Default is False. - `request_timeout`: Default deadline in seconds applied to unary RPCs that don't set their own. Defaults to 60s. Set to `None` to disable the default deadline. - - `max_decoding_message_size`: Largest response to decode, in bytes. Defaults to 50 MB. """ uri: str @@ -255,4 +256,3 @@ class SiftChannelConfig(TypedDict): use_ssl: NotRequired[bool] cert_via_openssl: NotRequired[bool] request_timeout: NotRequired[float | None] - max_decoding_message_size: NotRequired[int | None] diff --git a/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py b/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py index e1d61fbb04..f99b752603 100644 --- a/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py +++ b/python/lib/sift_client/_internal/low_level_wrappers/ingestion.py @@ -250,7 +250,6 @@ async def _build_sift_stream_instance( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, - max_decoding_message_size: int | None = None, ) -> SiftStreamPy: """Build a raw `SiftStreamPy` without wrapping it in a client. @@ -290,7 +289,6 @@ async def _build_sift_stream_instance( sift_builder = SiftStreamBuilderPy(uri=grpc_uri, apikey=api_key) sift_builder.enable_tls = enable_tls - sift_builder.max_decoding_message_size = max_decoding_message_size config_builder = sift_builder.ingestion_config(ingestion_config_form) config_builder.run = run_form @@ -343,7 +341,6 @@ async def create_sift_stream_instance( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, - max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingLowLevelClient: sift_stream_instance = await _build_sift_stream_instance( api_key=api_key, @@ -359,7 +356,6 @@ async def create_sift_stream_instance( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, - max_decoding_message_size=max_decoding_message_size, ) return cls(sift_stream_instance) diff --git a/python/lib/sift_client/_internal/pyproject_config.py b/python/lib/sift_client/_internal/pyproject_config.py index ad97bbfa6a..ba12d204f3 100644 --- a/python/lib/sift_client/_internal/pyproject_config.py +++ b/python/lib/sift_client/_internal/pyproject_config.py @@ -16,7 +16,7 @@ # ``tomllib`` landed in 3.11; ``tomli`` is the same parser packaged for older # interpreters and is declared as a conditional install dep on 3.8-3.10. try: - import tomllib # type: ignore[import-not-found,unused-ignore] + import tomllib # type: ignore[import-not-found,import-untyped,unused-ignore] except ImportError: # pragma: no cover - exercised on 3.8-3.10 only import tomli as tomllib # type: ignore[no-redef,import-not-found,unused-ignore] diff --git a/python/lib/sift_client/_tests/_internal/test_transport.py b/python/lib/sift_client/_tests/_internal/test_transport.py index 8316461a2f..9d05289c5b 100644 --- a/python/lib/sift_client/_tests/_internal/test_transport.py +++ b/python/lib/sift_client/_tests/_internal/test_transport.py @@ -5,10 +5,9 @@ import pytest from sift_client._internal.grpc_transport.transport import ( - DEFAULT_MAX_DECODING_MESSAGE_SIZE, + MAX_DECODING_MESSAGE_SIZE, _compute_channel_options, ) -from sift_client.transport.base_connection import SiftConnectionConfig from sift_client.transport.grpc_transport import GrpcClient, GrpcConfig from sift_client.transport.rest_transport import DEFAULT_REST_TIMEOUT, RestClient, RestConfig @@ -158,46 +157,7 @@ def test_timeout_disabled_when_config_none(self): class TestMaxDecodingMessageSize: - @staticmethod - def _receive_limit(config: GrpcConfig) -> int: - options = dict(_compute_channel_options(config._to_sift_channel_config())) - return options["grpc.max_receive_message_length"] - - def test_defaults_to_50_mb(self): + def test_channel_uses_the_fixed_limit(self): config = GrpcConfig(url="https://grpc.sift.com", api_key="api") - assert self._receive_limit(config) == DEFAULT_MAX_DECODING_MESSAGE_SIZE - - def test_config_value_overrides_default(self): - config = GrpcConfig( - url="https://grpc.sift.com", api_key="api", max_decoding_message_size=100 * 1024 * 1024 - ) - assert self._receive_limit(config) == 100 * 1024 * 1024 - - def test_lowering_the_limit_is_honored(self): - config = GrpcConfig( - url="https://grpc.sift.com", api_key="api", max_decoding_message_size=1024 - ) - assert self._receive_limit(config) == 1024 - - def test_channel_config_carries_the_value(self): - config = GrpcConfig( - url="https://grpc.sift.com", api_key="api", max_decoding_message_size=17 - ) - assert config._to_sift_channel_config().get("max_decoding_message_size") == 17 - - def test_connection_config_forwards_to_grpc_config(self): - connection_config = SiftConnectionConfig( - grpc_url="https://grpc.sift.com", - rest_url="https://api.sift.com", - api_key="api", - max_decoding_message_size=64 * 1024 * 1024, - ) - assert connection_config.get_grpc_config().max_decoding_message_size == 64 * 1024 * 1024 - - def test_connection_config_default_leaves_it_unset(self): - connection_config = SiftConnectionConfig( - grpc_url="https://grpc.sift.com", rest_url="https://api.sift.com", api_key="api" - ) - grpc_config = connection_config.get_grpc_config() - assert grpc_config.max_decoding_message_size is None - assert self._receive_limit(grpc_config) == DEFAULT_MAX_DECODING_MESSAGE_SIZE + options = dict(_compute_channel_options(config._to_sift_channel_config())) + assert options["grpc.max_receive_message_length"] == MAX_DECODING_MESSAGE_SIZE diff --git a/python/lib/sift_client/resources/ingestion.py b/python/lib/sift_client/resources/ingestion.py index 4b2ae5745d..10ad62da97 100644 --- a/python/lib/sift_client/resources/ingestion.py +++ b/python/lib/sift_client/resources/ingestion.py @@ -162,7 +162,6 @@ async def create_ingestion_config_streaming_client( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, - max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingClient: """Create an IngestionConfigStreamingClient. @@ -180,8 +179,6 @@ async def create_ingestion_config_streaming_client( to enable tracing to stdout only, or TracingConfig.with_file() to enable tracing to both stdout and rolling log files. Defaults to None (tracing will be initialized with default settings if not already initialized). - max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the - client's configured value, or 50 MB. Returns: An initialized IngestionConfigStreamingClient. @@ -198,7 +195,6 @@ async def create_ingestion_config_streaming_client( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, - max_decoding_message_size=max_decoding_message_size, ) async def create_auto_register_streaming_client( @@ -215,7 +211,6 @@ async def create_auto_register_streaming_client( enable_tls: bool = True, tracing_config: TracingConfig | None = None, staged_configs: list[FlowConfig] | None = None, - max_decoding_message_size: int | None = None, ) -> AutoRegisterStreamingClient: """Create an `AutoRegisterStreamingClient`. @@ -251,8 +246,6 @@ async def create_auto_register_streaming_client( of a minimal derived config, preserving units, descriptions, and other metadata. The staged config is validated against the flow's channel names and types before use; a mismatch raises `RuntimeError`. - max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the - client's configured value, or 50 MB. Returns: An initialized `AutoRegisterStreamingClient`. @@ -270,7 +263,6 @@ async def create_auto_register_streaming_client( enable_tls=enable_tls, tracing_config=tracing_config, staged_configs=staged_configs, - max_decoding_message_size=max_decoding_message_size, ) @@ -306,7 +298,6 @@ async def _create( checkpoint_interval_seconds: int | None = None, enable_tls: bool = True, tracing_config: TracingConfig | None = None, - max_decoding_message_size: int | None = None, ) -> IngestionConfigStreamingClient: """Create an IngestionConfigStreamingClient. @@ -325,8 +316,6 @@ async def _create( to enable tracing to stdout only, or TracingConfig.with_file() to enable tracing to both stdout and rolling log files. Defaults to None (tracing will be initialized with default settings for TracingConfig.with_file()). - max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to the - client's configured value, or 50 MB. Returns: An initialized IngestionConfigStreamingClient. @@ -349,8 +338,6 @@ async def _create( grpc_config = sift_client.grpc_client._config api_key = grpc_config.api_key grpc_uri = grpc_config.uri - if max_decoding_message_size is None: - max_decoding_message_size = grpc_config.max_decoding_message_size # Convert the ingestion_config variants to a IngestionConfigFormPy if isinstance(ingestion_config, IngestionConfig): @@ -408,7 +395,6 @@ async def _create( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, - max_decoding_message_size=max_decoding_message_size, ) return cls(sift_client, low_level_client) @@ -651,7 +637,6 @@ async def _create( enable_tls: bool = True, tracing_config: TracingConfig | None = None, staged_configs: list[FlowConfig] | None = None, - max_decoding_message_size: int | None = None, ) -> AutoRegisterStreamingClient: try: from sift_stream_bindings import ( @@ -667,8 +652,6 @@ async def _create( grpc_config = sift_client.grpc_client._config api_key = grpc_config.api_key grpc_uri = grpc_config.uri - if max_decoding_message_size is None: - max_decoding_message_size = grpc_config.max_decoding_message_size if isinstance(ingestion_config, IngestionConfig): asset = sift_client.assets.get(asset_id=ingestion_config.asset_id) @@ -720,7 +703,6 @@ async def _create( checkpoint_interval_seconds=checkpoint_interval_seconds, enable_tls=enable_tls, tracing_config=tracing_config, - max_decoding_message_size=max_decoding_message_size, ) staged_configs_py = ( diff --git a/python/lib/sift_client/transport/base_connection.py b/python/lib/sift_client/transport/base_connection.py index 4052f4769f..6586412fe7 100644 --- a/python/lib/sift_client/transport/base_connection.py +++ b/python/lib/sift_client/transport/base_connection.py @@ -25,7 +25,6 @@ def __init__( use_ssl: bool = True, cert_via_openssl: bool = False, app_url: str | None = None, - max_decoding_message_size: int | None = None, ): """Initialize the connection configuration. @@ -39,8 +38,6 @@ def __init__( Set this for on-prem or custom deployments whose API host can't be mapped to a frontend automatically. When unset, the web-app URL is derived from ``rest_url`` for known hosts. - max_decoding_message_size: Largest gRPC response to decode, in bytes. Defaults to - 50 MB. """ self.api_key = api_key self.grpc_url = grpc_url @@ -48,7 +45,6 @@ def __init__( self.use_ssl = use_ssl self.cert_via_openssl = cert_via_openssl self.app_url = app_url - self.max_decoding_message_size = max_decoding_message_size def get_grpc_config(self): """Create and return a GrpcConfig with the current settings. @@ -61,7 +57,6 @@ def get_grpc_config(self): api_key=self.api_key, use_ssl=self.use_ssl, cert_via_openssl=self.cert_via_openssl, - max_decoding_message_size=self.max_decoding_message_size, ) def get_rest_config(self): diff --git a/python/lib/sift_client/transport/grpc_transport.py b/python/lib/sift_client/transport/grpc_transport.py index e49f2988e0..07a64b905e 100644 --- a/python/lib/sift_client/transport/grpc_transport.py +++ b/python/lib/sift_client/transport/grpc_transport.py @@ -48,7 +48,6 @@ def __init__( cert_via_openssl: bool = False, metadata: dict[str, str] | None = None, request_timeout: float | None = DEFAULT_REQUEST_TIMEOUT_SECONDS, - max_decoding_message_size: int | None = None, ): """Initialize the gRPC configuration. @@ -61,8 +60,6 @@ def __init__( metadata: Additional metadata to include in all requests. request_timeout: Default deadline in seconds applied to unary RPCs that don't set their own. Defaults to 60s. Set to None to disable the default deadline. - max_decoding_message_size: Largest response to decode, in bytes. Defaults to 50 MB. - Streaming ingestion clients inherit this value. """ parsed_url = urlparse(url) normalized_url = url @@ -80,7 +77,6 @@ def __init__( self.cert_via_openssl = cert_via_openssl self.metadata = metadata or {} self.request_timeout = request_timeout - self.max_decoding_message_size = max_decoding_message_size def _to_sift_channel_config(self) -> SiftChannelConfig: """Convert to a SiftChannelConfig. @@ -94,7 +90,6 @@ def _to_sift_channel_config(self) -> SiftChannelConfig: "use_ssl": self.use_ssl, "cert_via_openssl": self.cert_via_openssl, "request_timeout": self.request_timeout, - "max_decoding_message_size": self.max_decoding_message_size, } From 6d454bf9860d3cb531fe5dbe64931ca1a2477669 Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Tue, 25 Aug 2026 12:41:41 -0700 Subject: [PATCH 5/5] update --- .../lib/sift_client/_internal/grpc_transport/transport.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/python/lib/sift_client/_internal/grpc_transport/transport.py b/python/lib/sift_client/_internal/grpc_transport/transport.py index ac1ece5c2d..f982be61c4 100644 --- a/python/lib/sift_client/_internal/grpc_transport/transport.py +++ b/python/lib/sift_client/_internal/grpc_transport/transport.py @@ -35,12 +35,7 @@ """Default per-call deadline applied to unary RPCs that don't set their own.""" MAX_DECODING_MESSAGE_SIZE = 50 * 1024 * 1024 -"""Largest gRPC response the client will decode, in bytes. - -50 MiB, matching the Rust clients' `sift_connect::MAX_DECODING_MESSAGE_SIZE`. Sized to cover the -largest responses Sift returns, such as 1M-row `GetData` pages and large flow schemas, so it is -fixed rather than configurable. -""" +"""Largest gRPC response the client will decode, in bytes (50 MiB).""" def get_ssl_credentials(cert_via_openssl: bool) -> grpc.ChannelCredentials: