Skip to content

Commit 8a47491

Browse files
committed
Getting ready for release 4.9.1
1 parent d6016ae commit 8a47491

5 files changed

Lines changed: 60 additions & 58 deletions

File tree

ANNOUNCE.rst

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,35 @@
1-
Announcing Python-Blosc2 4.9.0
1+
Announcing Python-Blosc2 4.9.1
22
==============================
33

4-
Last year's big push was making ``NDArray`` a good ecosystem citizen — array
5-
API compliance, protocols, interop. This release does the same for
6-
``CTable``: instead of asking the tabular ecosystem to learn Blosc2's ways,
7-
``CTable`` now speaks its protocols directly. Arrow tools can read and write
8-
a ``CTable`` with zero glue code, a new string column type stores text in
9-
Arrow's own layout, and ``engine=blosc2.jit`` runs correctly *inside*
10-
pandas 3 itself. Compression doesn't have to mean an island — it can just be
11-
a fast, compact layer underneath the tools you already use.
12-
13-
The main highlights are:
14-
15-
- **Arrow PyCapsule interchange**: ``CTable.__arrow_c_stream__`` lets
16-
pyarrow, DuckDB, and Polars consume a ``CTable`` directly as a stream of
17-
record batches, with bounded memory — no ``to_arrow()`` copy step
18-
needed::
19-
20-
import duckdb, blosc2
21-
t = blosc2.CTable.open("trips.b2z")
22-
duckdb.sql("SELECT company, avg(fare) FROM t GROUP BY company").show()
23-
24-
pandas >= 3.0 gets the same treatment via the new
25-
``pandas.DataFrame.from_arrow(t)`` classmethod (the plain ``pd.DataFrame(t)``
26-
constructor doesn't use this protocol). ``CTable.from_arrow()`` now
27-
accepts any object implementing the same protocol on ingest too — a
28-
pyarrow Table, a Polars DataFrame, a Parquet reader — in addition to the
29-
existing ``(schema, batches)`` form, including Arrow's ``string_view``
30-
layout (Polars' default string export type).
31-
32-
- **``blosc2.utf8()``: string columns that speak Arrow's layout**. Instead of
33-
a blosc2-specific encoding, ``utf8()`` stores text exactly as Arrow does —
34-
int64 row offsets plus a UTF-8 byte blob — and reads back as NumPy
35-
``StringDType``. It's the new recommended default for free text: 7-13x
36-
smaller uncompressed than fixed-width ``string()`` on high-cardinality
37-
text, with a full query surface (comparisons, ``where()``, ``sort_by``,
38-
``group_by`` keys, ``fillna``, Arrow round-trip).
39-
40-
- **pandas engine, pandas 3 ready**: ``engine=blosc2.jit`` for
41-
``DataFrame.apply`` now returns a properly indexed ``DataFrame``/``Series``
42-
under pandas 3's default ``raw=False``, and ``Series.map(func,
43-
engine=blosc2.jit)`` is implemented for the first time.
44-
45-
- **``CTable`` grows a pandas-style API**: ``CTable.assign()`` plus an
46-
unbound ``blosc2.col()`` for chaining —
47-
``t.assign(profit=col("revenue") - col("cost"))[col("profit") > 0].sort_by("profit", ascending=False).head(10)``
48-
— and a real missing-data story: ``Column.fillna()``, ``CTable.dropna()``,
49-
and null-propagating arithmetic/comparisons on nullable columns (no more
50-
``t[t.x < 0]`` silently matching null rows). ``group_by().agg()`` accepts
51-
UDF aggregations, and ``CTable.apply()`` runs a UDF across live rows.
52-
53-
- **Faster indexed reads**: ``NDArray.iter_sorted()``/``argsort()`` on a
54-
``FULL``-indexed array reads the sidecar range directly instead of
55-
building the full permutation — ~52x faster and ~193x less memory for
56-
tail-style queries on a 20M-element array.
4+
This is a hot-fix release for the Arrow interop work introduced in 4.9.0 —
5+
one real performance regression and one clearer error message, both in
6+
``CTable``.
7+
8+
- **Faster dictionary-column Arrow export**: ``CTable.iter_arrow_batches()``
9+
(and therefore ``to_arrow()`` and the Arrow PyCapsule interchange,
10+
``__arrow_c_stream__``) was recomputing the full live-row-position array
11+
from scratch on every batch, for every dictionary-encoded string column —
12+
an ``O(n_rows)`` scan repeated ``O(n_rows / batch_size)`` times. It's now
13+
computed once per export call instead. 6-14x faster export for
14+
dictionary columns on a 1M-row benchmark.
15+
16+
- **Worth knowing regardless of this fix**: the Arrow PyCapsule protocol
17+
(``__arrow_c_stream__``) has no column-projection pushdown — a consumer
18+
that only needs two columns (DuckDB, pyarrow, Polars, pandas) still
19+
triggers export of *every* column in the table, since the raw Arrow C
20+
Stream interface has no way to say "I only need these." Use
21+
``CTable.select([...])`` to project down to the columns you actually
22+
need before handing the table off, especially if any column holds an
23+
expensive nested/list type::
24+
25+
sub = t.select(["company", "fare"])
26+
duckdb.sql("SELECT company, avg(sub.fare) FROM sub GROUP BY company").show()
27+
28+
- **Clearer error on ``mode="a"``**: opening a ``CTable`` with
29+
``mode="a"`` at a path that doesn't exist yet now raises a
30+
``FileNotFoundError`` explaining that ``mode="a"`` opens an existing
31+
table (use ``mode="w"`` to create one), instead of silently creating a
32+
new, empty table.
5733

5834
Install it with::
5935

RELEASE_NOTES.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,33 @@
22

33
## Changes from 4.9.0 to 4.9.1
44

5-
XXX version-specific blurb XXX
5+
A small hot-fix release for the Arrow interop work in 4.9.0: a real
6+
performance regression in dictionary-column export, and a clearer error
7+
message when opening a nonexistent `CTable` in append mode.
8+
9+
### Improvements
10+
11+
- `CTable.iter_arrow_batches()` (and therefore `to_arrow()` and the Arrow
12+
PyCapsule interchange, `__arrow_c_stream__`) no longer recomputes the
13+
full live-row-position array from scratch on every batch, for every
14+
dictionary column — an `O(n_rows)` scan that was repeated
15+
`O(n_rows / batch_size)` times. The position array is now computed once
16+
per export call instead. Measured 6-14x faster export for
17+
dictionary-encoded string columns (e.g. `company`) on a 1M-row table.
18+
- Reminder for anyone consuming a `CTable` through the Arrow PyCapsule
19+
protocol (DuckDB, pyarrow, Polars, pandas): the raw Arrow C Stream
20+
interface has no column-projection pushdown, so a consumer that only
21+
needs a few columns still triggers export of every column in the table.
22+
Use `CTable.select([...])` to project down to the columns you actually
23+
need before handing the table to the consumer, particularly if any
24+
column is an expensive nested/list type.
25+
26+
### Bug fixes
27+
28+
- Opening a `CTable` with `mode="a"` at a path that doesn't exist yet now
29+
raises a clear `FileNotFoundError` ("mode='a' opens an existing table;
30+
use mode='w' to create a new one") instead of silently falling through
31+
and creating a new, empty table.
632

733
## Changes from 4.8.1 to 4.9.0
834

doc/python-blosc2.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<p style="text-align: center; color: black; background-color: rgba(230, 169, 9, 0.65);">
88
<a href="https://github.com/Blosc/python-blosc2/blob/main/RELEASE_NOTES.md"
9-
style="font-size: 1.5em;">Version 4.9.0 released on 2026-07-17!</a>
9+
style="font-size: 1.5em;">Version 4.9.1 released on 2026-07-17!</a>
1010
<span style="display: inline-block; width: 20px;"></span>
1111
<span style="font-family: monospace;">pip install blosc2 -U</span>
1212
</p>

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ dependencies = [
4141
"rich",
4242
"threadpoolctl; platform_machine != 'wasm32'",
4343
]
44-
version = "4.9.1.dev0"
44+
version = "4.9.1"
4545
[project.entry-points."array_api"]
4646
blosc2 = "blosc2"
4747

src/blosc2/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = "4.9.1.dev0"
1+
__version__ = "4.9.1"
22
__array_api_version__ = "2024.12"

0 commit comments

Comments
 (0)