fpstreams 2.2.0__tar.gz → 2.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fpstreams-2.2.0 → fpstreams-2.2.1}/CHANGELOG.md +16 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/PKG-INFO +11 -1
- {fpstreams-2.2.0 → fpstreams-2.2.1}/README.md +10 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/pyproject.toml +1 -1
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/Cargo.lock +1 -1
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/Cargo.toml +1 -1
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/__init__.py +3 -2
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/native.py +75 -35
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/flow.py +14 -12
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/__init__.py +3 -1
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/factory.py +5 -13
- {fpstreams-2.2.0 → fpstreams-2.2.1}/LICENSE +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/build.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/common.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/float/affine_pair.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/float/endpoints.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/float.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/integer/endpoints.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/integer.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/lib.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/numeric_mean.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/numpy_export.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/numpy_group/buffer.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/numpy_group.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/expr.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/prefix.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/row_filter.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/unique.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/value_filter.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair/value_map.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pair.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/pivot.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/records.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/adapters/namedtuple.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/adapters.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/global_numeric.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/group_numeric.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/group_pair_expr.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/join_callable/many.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/join_callable/unique.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/join_callable.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/join_exact.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational/join_i64.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed/composite.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed/global_multi/same_field.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed/global_multi.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed/group_multi.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed/single.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/relational_fixed.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/scalar_sort.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/scalar_unique.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/select.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/adapters.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/group_exact/pairs.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/group_exact/rows.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/group_exact.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/group_fixed.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/join_callable/behavior.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/join_callable/direct.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/join_callable.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/join_exact.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/numeric/buffers.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/numeric/kernels.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/numeric/reductions.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/numeric.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests/numpy_group.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/tests.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/unnest.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/rust/src/unpivot.rs +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/_native.pyi +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/_provenance.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/aggregate.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/async_flow.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/_collector_base.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/aggregate_program.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/aggregation.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/collector.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/program.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/reducer.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collecting/statistics.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/collectors.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/column.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/errors.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/exceptions.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/_pair_aggregate.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/_pair_dict.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/_pair_row_filter.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/_rows_fusion.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/_scalar_fusion.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/arrow.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_iterators.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_map.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_merge.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_ops.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_prefetch.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_queue.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_scheduler.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/async_timers.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/native.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/numpy_group.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/numpy_prefix.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/physical.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/relational/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/relational/arrow_global.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/relational/arrow_group.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/relational/arrow_group_rows.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/relational/join.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/sorted_streams.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/sorting.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/sync.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/execution/sync_ops.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expr.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/_codegen.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/_row_codegen.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/program.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/row.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/row_eval.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/row_ir.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/scalar.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/selectors.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/expressions/typed_ir.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/functional.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/gather.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/io_safety.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/option.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/async_plan.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/compiled.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/kernel_cache.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/plan.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/physical/relational.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/_pair_stages.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/arrow.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/arrow_source.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/async_.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/async_utils.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/compiler.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/explain.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/gather.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/logical.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/numpy.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/pair_i64_expression.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/plan_cache.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/semantic_analyzer.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/semantic_rules.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/semantics.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/source.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/planning/sync.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/primitives/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/primitives/option.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/primitives/result.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/py.typed +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/result.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/_distinct.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/failpoints.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/files.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/iterators.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/limits.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/metrics.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/query.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/report.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/resources.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/spill.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/runtime/tasks.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/storage/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/storage/codec.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/storage/spill_store.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/__init__.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/_async_identity.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/_flow_structural_list.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/_flow_unique_list.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/async_flow.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/async_terminals.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/flow_terminals.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/streams/pairs.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/_text_sources.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/arrow.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/dataframe.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/grouped.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/io.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/join.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/numpy.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/polars.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/records.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/rows.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/spill.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/spill_io.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/spill_limits.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/sql.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/tabular/sqlite_sink.py +0 -0
- {fpstreams-2.2.0 → fpstreams-2.2.1}/src/fpstreams/testing.py +0 -0
|
@@ -5,6 +5,22 @@ including changed defaults.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 2.2.1 - 2026-10-07
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Editors resolve the public `rows` factory directly, preserving method completion,
|
|
13
|
+
parameter hints, and docstrings instead of treating it as the record module.
|
|
14
|
+
- Core `flow()` and `rows()` factories retain iterable element types without optional
|
|
15
|
+
data adapters installed. A shared series protocol preserves one-dimensional series
|
|
16
|
+
typing without importing Polars into the core type declarations.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Automatic planning skips NumPy buffer probes for exact list, tuple, and range
|
|
21
|
+
sources. Python identity terminal plans on exact containers also avoid a temporary
|
|
22
|
+
decision object, reducing the fixed cost of small workloads.
|
|
23
|
+
|
|
8
24
|
## 2.2.0 - 2026-10-06
|
|
9
25
|
|
|
10
26
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fpstreams
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -87,6 +87,16 @@ python -m pip install "fpstreams[data]" # NumPy, pandas, and PyArrow
|
|
|
87
87
|
python -m pip install "fpstreams[polars]" # Polars and PyArrow
|
|
88
88
|
~~~
|
|
89
89
|
|
|
90
|
+
## Editor support
|
|
91
|
+
|
|
92
|
+
fpstreams includes inline type annotations, docstrings, and the `py.typed` marker.
|
|
93
|
+
Select the Python interpreter where fpstreams is installed in your editor to get
|
|
94
|
+
method completions, parameter hints, and hover documentation.
|
|
95
|
+
|
|
96
|
+
Version 2.2.1 fixes `rows` factory completion and keeps core
|
|
97
|
+
iterable element types when optional data adapters are absent. For example,
|
|
98
|
+
`flow([1, 2, 3])` is inferred as `Flow[int]`.
|
|
99
|
+
|
|
90
100
|
## Quick start
|
|
91
101
|
|
|
92
102
|
This example filters paid orders, groups them by region, and reports both the
|
|
@@ -32,6 +32,16 @@ python -m pip install "fpstreams[data]" # NumPy, pandas, and PyArrow
|
|
|
32
32
|
python -m pip install "fpstreams[polars]" # Polars and PyArrow
|
|
33
33
|
~~~
|
|
34
34
|
|
|
35
|
+
## Editor support
|
|
36
|
+
|
|
37
|
+
fpstreams includes inline type annotations, docstrings, and the `py.typed` marker.
|
|
38
|
+
Select the Python interpreter where fpstreams is installed in your editor to get
|
|
39
|
+
method completions, parameter hints, and hover documentation.
|
|
40
|
+
|
|
41
|
+
Version 2.2.1 fixes `rows` factory completion and keeps core
|
|
42
|
+
iterable element types when optional data adapters are absent. For example,
|
|
43
|
+
`flow([1, 2, 3])` is inferred as `Flow[int]`.
|
|
44
|
+
|
|
35
45
|
## Quick start
|
|
36
46
|
|
|
37
47
|
This example filters paid orders, groups them by region, and reports both the
|
|
@@ -39,9 +39,10 @@ from .streams import (
|
|
|
39
39
|
flow,
|
|
40
40
|
pairs,
|
|
41
41
|
)
|
|
42
|
-
from .tabular import Rows, SpillLimits
|
|
42
|
+
from .tabular import Rows, SpillLimits
|
|
43
|
+
from .tabular.factory import rows as rows
|
|
43
44
|
|
|
44
|
-
__version__ = "2.2.
|
|
45
|
+
__version__ = "2.2.1"
|
|
45
46
|
Stream = Flow
|
|
46
47
|
ParallelStream = Flow
|
|
47
48
|
|
|
@@ -44,6 +44,9 @@ _I64_MIN = -(2**63)
|
|
|
44
44
|
_I64_MAX = 2**63 - 1
|
|
45
45
|
_AUTO_THRESHOLD = 8
|
|
46
46
|
_AUTO_IDENTITY_I64_SUM_THRESHOLD = 65_536
|
|
47
|
+
_AUTO_IDENTITY_CONTAINER_REASON = (
|
|
48
|
+
"identity list/tuple stays in Python below its direct native crossover"
|
|
49
|
+
)
|
|
47
50
|
_COPY_SHORT_CIRCUIT_LIMIT = 1_024
|
|
48
51
|
_COPY_SHORT_CIRCUIT_RATIO = 64
|
|
49
52
|
_ALLOCATING_I64_MAP_ROOTS = frozenset({"add", "sub", "mul", "floordiv", "neg"})
|
|
@@ -108,61 +111,65 @@ def validate_terminal(terminal: str) -> TerminalName:
|
|
|
108
111
|
|
|
109
112
|
|
|
110
113
|
def _terminal_metadata(
|
|
111
|
-
decision: EngineDecision,
|
|
114
|
+
decision: EngineDecision | None,
|
|
112
115
|
plan: Pipeline,
|
|
113
116
|
terminal: TerminalName,
|
|
114
117
|
*,
|
|
115
118
|
source_is_container: bool | None = None,
|
|
119
|
+
python_reason: str = "",
|
|
116
120
|
) -> EngineDecision:
|
|
117
|
-
"""Attach
|
|
121
|
+
"""Attach terminal metadata, constructing a Python-only decision in one allocation."""
|
|
118
122
|
source = plan.source.native_data
|
|
119
|
-
|
|
123
|
+
engine = "python" if decision is None else decision.engine
|
|
124
|
+
program = None if decision is None else decision.program
|
|
125
|
+
crosses_native_boundary = engine in {"native", "hybrid"}
|
|
120
126
|
if source_is_container is None:
|
|
121
127
|
source_is_container = (
|
|
122
128
|
isinstance(source, (list, tuple)) or _numpy_buffer_kind(source) is not None
|
|
123
129
|
)
|
|
124
130
|
metadata_count = terminal == "count" and exact_count(plan) is not None
|
|
125
131
|
direct_i64_container_sum = (
|
|
126
|
-
|
|
127
|
-
and
|
|
128
|
-
and
|
|
129
|
-
and not
|
|
132
|
+
engine == "native"
|
|
133
|
+
and program is not None
|
|
134
|
+
and program.kind == "i64"
|
|
135
|
+
and not program.stages
|
|
130
136
|
and type(source) in (list, tuple)
|
|
131
137
|
and terminal == "sum"
|
|
132
138
|
)
|
|
133
139
|
direct_exact_container_mean = (
|
|
134
|
-
|
|
135
|
-
and
|
|
136
|
-
and not
|
|
140
|
+
engine == "native"
|
|
141
|
+
and program is not None
|
|
142
|
+
and not program.stages
|
|
137
143
|
and type(source) in (list, tuple)
|
|
138
144
|
and terminal == "mean"
|
|
139
145
|
and _exact_number_mean_available()
|
|
140
146
|
)
|
|
141
147
|
range_metadata = (
|
|
142
|
-
|
|
148
|
+
engine == "native"
|
|
143
149
|
and type(source) is range
|
|
144
150
|
and not plan.operations
|
|
145
151
|
and terminal in {"sum", "min", "max", "last"}
|
|
146
152
|
)
|
|
147
153
|
probe_path = (
|
|
148
|
-
|
|
149
|
-
and
|
|
154
|
+
engine == "native"
|
|
155
|
+
and program is not None
|
|
150
156
|
and type(source) in (list, tuple)
|
|
151
157
|
and terminal in {"first", "any", "all"}
|
|
152
|
-
and _container_probe_available(
|
|
158
|
+
and _container_probe_available(program.kind)
|
|
153
159
|
)
|
|
160
|
+
decision_reason = python_reason if decision is None else decision.reason
|
|
154
161
|
reason = (
|
|
155
|
-
f"{
|
|
162
|
+
f"{decision_reason}; bounded probe; only undecided fallback bulk-copies"
|
|
156
163
|
if probe_path
|
|
157
|
-
else f"{
|
|
164
|
+
else f"{decision_reason}; retained range terminal uses constant-time metadata"
|
|
158
165
|
if range_metadata
|
|
159
|
-
else
|
|
166
|
+
else decision_reason
|
|
160
167
|
)
|
|
161
168
|
return EngineDecision(
|
|
162
|
-
|
|
169
|
+
engine,
|
|
163
170
|
reason,
|
|
164
|
-
|
|
165
|
-
decision.native_operation_count,
|
|
171
|
+
program,
|
|
172
|
+
0 if decision is None else decision.native_operation_count,
|
|
166
173
|
# An undecided bounded probe restarts the legacy bulk adapter, and numeric
|
|
167
174
|
# buffer kernels may snapshot exporters before detached computation.
|
|
168
175
|
scans_source=crosses_native_boundary and source_is_container and not metadata_count,
|
|
@@ -173,7 +180,7 @@ def _terminal_metadata(
|
|
|
173
180
|
and not direct_i64_container_sum
|
|
174
181
|
and not direct_exact_container_mean
|
|
175
182
|
),
|
|
176
|
-
materializes=terminal == "list" or
|
|
183
|
+
materializes=terminal == "list" or engine == "hybrid",
|
|
177
184
|
complexity=(
|
|
178
185
|
"O(1)"
|
|
179
186
|
if metadata_count or range_metadata
|
|
@@ -234,6 +241,9 @@ def _numpy_f64_buffer(source: object) -> Any | None:
|
|
|
234
241
|
|
|
235
242
|
def _numpy_buffer_kind(source: object) -> NativeKind | None:
|
|
236
243
|
"""Return the exact native representation exposed by an explicit NumPy column."""
|
|
244
|
+
source_type = type(source)
|
|
245
|
+
if source_type is list or source_type is tuple or source_type is range:
|
|
246
|
+
return None
|
|
237
247
|
if _numpy_i64_buffer(source) is not None:
|
|
238
248
|
return "i64"
|
|
239
249
|
if _numpy_f64_buffer(source) is not None:
|
|
@@ -783,6 +793,45 @@ def _buffer_short_circuit_decision(
|
|
|
783
793
|
return None
|
|
784
794
|
|
|
785
795
|
|
|
796
|
+
def _identity_source_terminal_context(
|
|
797
|
+
plan: Pipeline,
|
|
798
|
+
terminal: TerminalName,
|
|
799
|
+
source: object,
|
|
800
|
+
) -> tuple[EngineDecision | None, NativeKind | None, bool]:
|
|
801
|
+
"""Choose exact-container routes before considering numeric buffer metadata."""
|
|
802
|
+
source_type = type(source)
|
|
803
|
+
if (
|
|
804
|
+
plan.engine == "auto"
|
|
805
|
+
and (source_type is list or source_type is tuple)
|
|
806
|
+
and terminal not in {"mean", "statistics"}
|
|
807
|
+
and not _auto_direct_i64_sum_candidate(source, terminal)
|
|
808
|
+
):
|
|
809
|
+
return (
|
|
810
|
+
_terminal_metadata(
|
|
811
|
+
None,
|
|
812
|
+
plan,
|
|
813
|
+
terminal,
|
|
814
|
+
source_is_container=True,
|
|
815
|
+
python_reason=_AUTO_IDENTITY_CONTAINER_REASON,
|
|
816
|
+
),
|
|
817
|
+
None,
|
|
818
|
+
True,
|
|
819
|
+
)
|
|
820
|
+
buffer_kind = _numpy_buffer_kind(source)
|
|
821
|
+
source_is_container = isinstance(source, (list, tuple)) or buffer_kind is not None
|
|
822
|
+
return (
|
|
823
|
+
_forced_native_exact_count_decision(
|
|
824
|
+
plan,
|
|
825
|
+
terminal,
|
|
826
|
+
source,
|
|
827
|
+
buffer_kind,
|
|
828
|
+
source_is_container=source_is_container,
|
|
829
|
+
),
|
|
830
|
+
buffer_kind,
|
|
831
|
+
source_is_container,
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
|
|
786
835
|
def _select_operation_terminal_engine(
|
|
787
836
|
plan: Pipeline,
|
|
788
837
|
terminal: TerminalName,
|
|
@@ -850,17 +899,11 @@ def select_terminal_engine(plan: Pipeline, terminal: TerminalName) -> EngineDeci
|
|
|
850
899
|
source = plan.source.native_data
|
|
851
900
|
if retained_one_shot := _retained_one_shot_decision(plan):
|
|
852
901
|
return _terminal_metadata(retained_one_shot, plan, terminal)
|
|
853
|
-
buffer_kind =
|
|
854
|
-
|
|
855
|
-
metadata_count = _forced_native_exact_count_decision(
|
|
856
|
-
plan,
|
|
857
|
-
terminal,
|
|
858
|
-
source,
|
|
859
|
-
buffer_kind,
|
|
860
|
-
source_is_container=source_is_container,
|
|
902
|
+
source_decision, buffer_kind, source_is_container = _identity_source_terminal_context(
|
|
903
|
+
plan, terminal, source
|
|
861
904
|
)
|
|
862
|
-
if
|
|
863
|
-
return
|
|
905
|
+
if source_decision is not None:
|
|
906
|
+
return source_decision
|
|
864
907
|
if buffered := _buffer_short_circuit_decision(plan, terminal, buffer_kind):
|
|
865
908
|
return _terminal_metadata(
|
|
866
909
|
buffered,
|
|
@@ -875,10 +918,7 @@ def select_terminal_engine(plan: Pipeline, terminal: TerminalName) -> EngineDeci
|
|
|
875
918
|
and not _auto_direct_i64_sum_candidate(source, terminal)
|
|
876
919
|
):
|
|
877
920
|
return _terminal_metadata(
|
|
878
|
-
EngineDecision(
|
|
879
|
-
"python",
|
|
880
|
-
"identity list/tuple stays in Python below its direct native crossover",
|
|
881
|
-
),
|
|
921
|
+
EngineDecision("python", _AUTO_IDENTITY_CONTAINER_REASON),
|
|
882
922
|
plan,
|
|
883
923
|
terminal,
|
|
884
924
|
source_is_container=source_is_container,
|
|
@@ -10,7 +10,6 @@ from contextlib import contextmanager
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from importlib import import_module
|
|
12
12
|
from typing import (
|
|
13
|
-
TYPE_CHECKING,
|
|
14
13
|
Any,
|
|
15
14
|
Generic,
|
|
16
15
|
Literal,
|
|
@@ -22,9 +21,6 @@ from typing import (
|
|
|
22
21
|
|
|
23
22
|
import fpstreams
|
|
24
23
|
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
import polars as pl
|
|
27
|
-
|
|
28
24
|
from ..expressions.selectors import Selector, compile_selector
|
|
29
25
|
from ..planning.explain import PlanExplanation, explain_query
|
|
30
26
|
from ..planning.gather import Gatherer
|
|
@@ -95,6 +91,17 @@ _MISSING = object()
|
|
|
95
91
|
_TABULAR_MODULE_ROOTS = frozenset(("pandas", "polars", "pyarrow"))
|
|
96
92
|
|
|
97
93
|
|
|
94
|
+
class _SeriesSource(Protocol[T]):
|
|
95
|
+
"""Describe a one-dimensional series without importing an optional adapter."""
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def shape(self) -> tuple[int]: ...
|
|
99
|
+
|
|
100
|
+
def __iter__(self) -> Iterator[T]: ...
|
|
101
|
+
|
|
102
|
+
def to_list(self) -> list[T]: ...
|
|
103
|
+
|
|
104
|
+
|
|
98
105
|
class _ArrowCStreamProvider(Protocol):
|
|
99
106
|
"""Static shape of the Arrow PyCapsule stream protocol."""
|
|
100
107
|
|
|
@@ -1365,14 +1372,6 @@ class _FlowFactory:
|
|
|
1365
1372
|
return self.from_dataframe(source)
|
|
1366
1373
|
return None
|
|
1367
1374
|
|
|
1368
|
-
if TYPE_CHECKING:
|
|
1369
|
-
|
|
1370
|
-
@overload
|
|
1371
|
-
def __call__(
|
|
1372
|
-
self,
|
|
1373
|
-
source: pl.Series,
|
|
1374
|
-
) -> Flow[Any]: ...
|
|
1375
|
-
|
|
1376
1375
|
@overload
|
|
1377
1376
|
def __call__(self, source: Flow[T]) -> Flow[T]: ...
|
|
1378
1377
|
|
|
@@ -1381,6 +1380,9 @@ class _FlowFactory:
|
|
|
1381
1380
|
# before considering structural tabular protocols.
|
|
1382
1381
|
def __call__(self, source: fpstreams.Rows[T]) -> Flow[T]: ... # type: ignore[overload-overlap]
|
|
1383
1382
|
|
|
1383
|
+
@overload
|
|
1384
|
+
def __call__(self, source: _SeriesSource[T]) -> Flow[T]: ...
|
|
1385
|
+
|
|
1384
1386
|
@overload
|
|
1385
1387
|
def __call__(
|
|
1386
1388
|
self,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Record-oriented pipelines and tabular interoperability."""
|
|
2
2
|
|
|
3
|
-
from .factory import rows
|
|
3
|
+
from .factory import rows as _rows_factory
|
|
4
4
|
from .grouped import GroupedRows
|
|
5
5
|
from .rows import Rows
|
|
6
6
|
from .spill_limits import SpillLimits
|
|
7
7
|
|
|
8
|
+
rows = _rows_factory
|
|
9
|
+
|
|
8
10
|
__all__ = ["GroupedRows", "Rows", "SpillLimits", "rows"]
|
|
@@ -4,13 +4,10 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from collections.abc import Callable, Iterable, Mapping
|
|
7
|
-
from typing import
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
import polars as pl
|
|
7
|
+
from typing import Any, BinaryIO, TextIO, TypeAlias, TypeVar, overload
|
|
11
8
|
|
|
12
9
|
from ..expressions.selectors import Selector
|
|
13
|
-
from ..streams.flow import Flow, _ArrowCStreamProvider, _DataFrameProvider
|
|
10
|
+
from ..streams.flow import Flow, _ArrowCStreamProvider, _DataFrameProvider, _SeriesSource
|
|
14
11
|
from .rows import Rows
|
|
15
12
|
from .sql import (
|
|
16
13
|
ConnectionFactory,
|
|
@@ -26,14 +23,6 @@ class _RowsFactory:
|
|
|
26
23
|
|
|
27
24
|
__slots__ = ()
|
|
28
25
|
|
|
29
|
-
if TYPE_CHECKING:
|
|
30
|
-
|
|
31
|
-
@overload
|
|
32
|
-
def __call__(
|
|
33
|
-
self,
|
|
34
|
-
source: pl.Series,
|
|
35
|
-
) -> Rows[Any]: ...
|
|
36
|
-
|
|
37
26
|
@overload
|
|
38
27
|
def __call__(self, source: Flow[T]) -> Rows[T]: ...
|
|
39
28
|
|
|
@@ -41,6 +30,9 @@ class _RowsFactory:
|
|
|
41
30
|
# Rows also exports Arrow, but the compatibility factory must preserve its record type.
|
|
42
31
|
def __call__(self, source: Rows[T]) -> Rows[T]: ... # type: ignore[overload-overlap]
|
|
43
32
|
|
|
33
|
+
@overload
|
|
34
|
+
def __call__(self, source: _SeriesSource[T]) -> Rows[T]: ...
|
|
35
|
+
|
|
44
36
|
@overload
|
|
45
37
|
def __call__(
|
|
46
38
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|