Skip to content

python(feat): add client side detect config for parquet - #819

Merged
alden-sift merged 22 commits into
mainfrom
eng-12274-implement-parquet-config-detection-client-side-in
Oct 23, 2026
Merged

alden-sift merged 22 commits into
mainfrom
eng-12274-implement-parquet-config-detection-client-side-in

Conversation

@alden-sift

@alden-sift alden-sift commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Flat dataset Parquet config detection fails for wide files (many columns and/or long column names) because the client sends the Parquet footer to the server's DetectConfig endpoint, and footers over the server's 20 MiB gRPC receive limit are rejected with RESOURCE_EXHAUSTED.

This PR detects PARQUET_FLATDATASET configs on the client from the footer schema with pyarrow, the same way HDF5, TDMS, ULog, and MCAP configs are detected. Single channel per row Parquet still uses server detection.

detect_config and import_from_path now also accept relative_start_time so files with relative time can be detected and imported without editing the config.

Also refactored by moving helper functions either into _internal module or moved them into ImportConfig as methods.

Dependency change: flat dataset Parquet detection now requires pyarrow. Install it with pip install sift-stack-py[parquet].

Validation

Recreation

detect_config on a Parquet file with 20,000 columns and long column names:

import os

import dotenv
import dotenv
from sift_client import SiftClient
from sift_client._internal.util.file import extract_parquet_footer
from sift_client.sift_types.data_import import DataTypeKey

dotenv.load_dotenv()
pq_file = "data/super-wide-and-big-name.parquet"
client = SiftClient(
    api_key=os.getenv("SIFT_API_KEY"),
    grpc_url=os.getenv("SIFT_GRPC_URL"),
    rest_url=os.getenv("SIFT_REST_URL"),
)
footer_bytes, _ = extract_parquet_footer(pq_file)
print(f"footer size: {len(footer_bytes)} bytes")
client.data_import.import_from_path(
    pq_file, asset="test-long-parquet-1", data_type=DataTypeKey.PARQUET_FLATDATASET
)

Before this change:

grpc.aio._call.AioRpcError: <AioRpcError of RPC that terminated with:
        status = StatusCode.RESOURCE_EXHAUSTED
        details = "grpc: received message larger than max (29943806 vs. 20971520)"

After this change:

alden@MacBook-Pro eng-12274-test % /Users/alden/projects/eng-12274-test/.venv/bin/python /Users/alden/projects/eng-12274-test/main.py
size of footer bytes: 29943832
Upload [super-wide-and-big-name.parquet] |████████████████████████████████████████| 32.3MB/32.3MB [100%] in 0.7s (46.70MB/s) 

Behavior validation

  • Automated test: ran the old (server side) and the new (client side) config detection on Parquet files covering every time type, scalar and complex types, structs, durations, and embedded configs to ensure identical behavior.
  • Manual test: Parquet files imported through the client and through the webapp produced identical runs.
  • Unit tests: _tests/_internal/test_parquet.py.
  • Integration tests

@alden-sift
alden-sift requested a review from wei-sift October 7, 2026 21:52
@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Python docs preview: https://sift-stack.github.io/sift/python/pr-819/

Deployed from dfdc9fb. The link may take up to a minute to become live as GitHub Pages propagates.

alden-sift and others added 3 commits October 9, 2026 14:43
Detect PARQUET_FLATDATASET import configs locally from the Parquet footer
schema with pyarrow instead of calling the server DetectConfig endpoint.
Detection matches the server: struct fields are flattened, the first
top-level time typed column is the time column, and configs embedded by
Sift exports are used directly. The time column is excluded from the data
columns, and an INT64/UINT64 column named ts, timestamp, or time is used
when no time typed column exists.

Add relative_start_time to detect_config and import_from_path. It applies
to Parquet only and warns when ignored for other formats or absolute time
formats.

Add a parquet extra for pyarrow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python 3.8 resolves pyarrow 17, which cannot build float16 arrays from
Python floats or write view types to Parquet. Build the float16 column
from numpy values and move the view types into a test that is skipped
when the installed pyarrow cannot write them.
@alden-sift
alden-sift marked this pull request as ready for review October 9, 2026 22:39
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
Comment thread python/lib/sift_client/_internal/util/parquet.py Outdated
Comment thread python/lib/sift_client/sift_types/data_import.py Outdated
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
Comment thread python/pyproject.toml
Comment thread python/lib/sift_client/resources/sync_stubs/__init__.pyi Outdated
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
Comment thread python/lib/sift_client/resources/data_imports.py Outdated
@alden-sift alden-sift self-assigned this Oct 12, 2026
TimeFormat gains UNSPECIFIED, matching the proto's TIME_FORMAT_UNSPECIFIED.
A CSV DetectConfig response without a detected format no longer raises;
detect_config applies the caller's time_format or ABSOLUTE_UNIX_NANOSECONDS
instead. Importing with an unspecified format raises the existing "format
must be set" errors.
Drop UNSPECIFIED from the public TimeFormat enum. CsvImportConfig maps the
proto's TIME_FORMAT_UNSPECIFIED to None, matching Parquet, TDMS, and HDF5.
TimeColumnBase.format now defaults to None, so CSV and Parquet time columns
share the same rule: optional at construction, required at import.
@alden-sift
alden-sift merged commit 8e4f7b8 into main Oct 23, 2026
27 checks passed
@alden-sift
alden-sift deleted the eng-12274-implement-parquet-config-detection-client-side-in branch October 23, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants