Tables and columns#
The three classes below are the reading-and-writing heart of the package.
Table wraps a table group; its
create() / open() classmethods are the
two entry points, and its mapping-style access (table["name"], in,
iteration) hands out the column wrappers.
- class h5col.Table(group: Any)[source]#
A H5Col column-oriented table backed by an HDF5 group.
- static is_table_group(group: Any) bool[source]#
True if group is a H5Col table group (lenient CLASS check).
- classmethod open(group: Any) Table[source]#
Open an existing table group, checking its CLASS and VERSION major.
- Raises:
ConformanceError – If group is not a H5Col table group, or its
VERSIONis missing or unparsable.VersionError – If the table’s
VERSIONmajor exceeds the supported major.
- classmethod create(group: Any, columns: TableSpec | Sequence[ColumnSpec | ListColumnSpec], *, title: str | None = None, description: str | None = None, index_columns: Sequence[str] | None = None, column_order: Sequence[str] | None = None, units_vocabulary: str | None = None, encoding_type: str | None = None, encoding_version: str | None = None, default_chunk_bytes: int | None = None) Table[source]#
Create a new, empty table (
NROWS = 0) with the given columns.default_chunk_bytesoverrides the automatic (chunk-cache-scaled) target for columns that do not set an explicitchunksshape.- Raises:
SchemaError – If group is already a H5Col table group, a column spec is invalid, or an
index_columnsname is not among the declared columns.ReservedNameError – If a column name is a H5Col reserved name.
FillValueError – If a column’s fill value lies inside its declared valid range.
- classmethod from_arrays(group: Any, arrays: Mapping[str, Any], *, specs: Sequence[ColumnSpec] | None = None, **table_kwargs: Any) Table[source]#
Create a table from column arrays and write them in one call.
When specs is omitted, a
ColumnSpecis inferred per array (boolean, fixed-string sized to the longest value, or the array dtype). The column order followsarrays.
- property nrows: int#
The table’s logical row count (its
NROWSattribute).- Raises:
ConformanceError – If the group carries no
NROWSattribute.
- property generation: int | None#
The table’s
GENERATIONvalidity token, or None when absent.A table acquires
GENERATIONwhen its first search index is built and increments it on every subsequent mutation of committed data.
- property columns: dict[str, Column | ListColumn]#
The table’s columns by name, in column order, as wrapper objects.
- append(data: Mapping[str, Any], *, maintain_indexes: bool = False) None[source]#
Append rows following the H5Col write protocol.
Every provided column must supply the same number of rows
K. A scalar column absent from data is extended and left as its fill value (missing); a boolean column (which has no fill) must always be provided. A list column absent from data must be nullable — its new rows become null lists; a non-nullable list column must always be provided.NROWSis committed last, then the file is flushed.Nonein a column’s values marks that row as missing and is stored as the column’s fill value (for a categorical column, its fill code). A column with no fill to store — a boolean, which H5Col forbids from declaring one — rejectsNoneinstead of coercing it.By default, search indexes are not maintained: the
GENERATIONincrement that publishes the append disables them, detectably, andrefresh_indexes()restores them later — this keeps the hot append path fast. Withmaintain_indexes=True, every supported index is rewritten inside the append protocol (future-valued tokens before content) and remains valid after the commit; indexes this implementation cannot rebuild — unsupported kinds, element dtypes the builder does not handle, non-growable index datasets — are left entirely untouched, tokens included.- Raises:
OversizedStringError – If a fixed-length string value’s encoding exceeds the column’s byte budget (H5Col never silently truncates).
SchemaError – For unknown columns, values that are not 1-D, unequal column lengths, an omitted fill-less/boolean column, an omitted non-nullable list column, an unknown category label, or a
Nonein a column that declares no fill value.
- truncate(nrows: int, *, maintain_indexes: bool = False) None[source]#
Shrink the logical table to nrows rows (H5Col logical truncation).
The truncation is logical: no column dataset changes extent, and the rows
[nrows, old_NROWS)become reserved storage that consumers ignore. List columns need no extra writes — the smallerNROWSbounds their offsets recursively. Reclaiming physical space would require rewriting each column to its new extent, which this implementation does not do.Index handling mirrors
append()(the spec applies the same steps 4-6 with the new row count): by default every search index is left detectably stale by theGENERATIONbump; withmaintain_indexes=Truethe supported indexes are rebuilt inside the protocol and remain valid after the commit.Truncating to the current row count is a no-op (nothing changes, so nothing is published); growing is an error — that is what
append()is for.- Raises:
SchemaError – If nrows is negative or greater than the current row count.
- read(columns: Sequence[str] | None = None, *, where: Any = None, explain: bool = False) Any[source]#
Read columns (default all) as
{name: array}over[0, NROWS).With
where=(a queryExpression, aList[Tuple]= AND, or aList[List[Tuple]]= OR-of-ANDs), only the matching rows are returned. Withexplain=Truethe return value is a(result, QueryPlan)pair.- Raises:
KeyError – If a requested column name is not a column of the table.
SchemaError – If
where=is malformed or references an unknown column.
- select(where: Any = None) Selection[source]#
Build a lazy
Selectionover the table.Accepts a query
Expression, aList[Tuple](AND), or aList[List[Tuple]](OR-of-ANDs, pyarrow DNF).Noneselects every row.
- build_index(column: str, kind: str | None = None, *, name: str | None = None, description: str | None = None) SearchIndex[source]#
Build a search index over column (alias of
add_search_index()).
- property search_indexes: dict[str, SearchIndex]#
Every search-index dataset under
SEARCH_INDEXES, wrapped by kind.
- add_search_index(column: str, kind: str | None = None, *, name: str | None = None, description: str | None = None) SearchIndex[source]#
Build a search index over column and link it to the column.
With
kind=Nonethe family is picked automatically:BITMAPfor boolean and categorical columns (low cardinality, exact equality answers),CHUNK_MINMAXfor any other orderable column. Building an index over an unchanged table is not a mutation:GENERATIONis created (0) if absent but never incremented. The default dataset name is<column>__<kind, lowercased>— a readable convention only; the linkage is the object reference in the column’sSEARCH_INDEX_LIST.- Raises:
KeyError – If column is not a column of the table.
SchemaError – If column is a list column, no index family applies to its dtype (
kind=None), kind is unimplemented, orSEARCH_INDEXESalready holds a dataset of the chosen name.ReservedNameError – If name is a H5Col reserved name.
ConformanceError – If the table carries no
NROWSattribute.
- refresh_indexes() int[source]#
Rebuild every supported search index against the current table state.
Restores indexes left stale by
append(maintain_indexes=False)or by any other mutation. Returns the number of indexes refreshed; indexes of unsupported kinds are left untouched (and stay detectably stale).
- index_is_valid(index: SearchIndex | Any) bool[source]#
The H5Col consumer validity check for index (wrapper or dataset).
- validate(*, deep: bool = False) None[source]#
Check the H5Col consistency requirements, raising on any violation.
deep=Trueadditionally re-derives every valid search index from its column and compares (consistency rule 9’s semantic half) — an O(index build) check; the default run is structural only. A stale index is never an error: the validity check disables it, as the spec intends.- Raises:
ConformanceError – On the first consistency violation found.
VersionError – If the table’s
VERSIONmajor exceeds the supported major.
- add_column(spec: ColumnSpec | ListColumnSpec, *, default_chunk_bytes: int | None = None) Column | ListColumn[source]#
Add a new column to an existing table (schema evolution).
A scalar column is created and grown to the table’s current extent; its existing rows read as its fill value (missing). A fill-less (boolean) column, or a list column (whose “missing” analogue is a null list that would need explicit backfilling), cannot represent pre-existing rows, so adding one to a table that already has rows is refused.
- Raises:
SchemaError – If a column of that name already exists, the spec is invalid, or the column cannot backfill pre-existing rows (a boolean or list column on a non-empty table).
- class h5col.Column(dataset: Any, table: Table)[source]#
One column of a H5Col table, wrapping its rank-1 HDF5 dataset.
Reads decode to friendly Python values: fixed-length strings become
str, boolean columns become NumPybool, and numeric columns pass through.- property dtype: dtype#
The column’s NumPy dtype (its stored HDF5 datatype).
For a categorical column this is the integer code dtype, not the category labels (see
categories).
- property is_categorical: bool#
True if this is a categorical column (its values are category codes).
- property categories: NDArray[object_] | None#
The category labels, or None for a non-categorical column.
- property fill_value: Any#
The column’s fill value, or None when it declares none.
None is returned for boolean columns and for any column not in the
H5D_FILL_VALUE_USER_DEFINEDstate (e.g. a full-domain column that declares no missing-row semantics). h5py’s library-default fill value is not a H5Col sentinel and must not be surfaced as one.
- read_rows(rows: Any) NDArray[Any][source]#
Read just rows, decoded, in the order given.
Values are fetched with coalesced, chunk-aligned block reads, so a selection confined to a few chunks costs a few chunks rather than the whole column — in both time and peak memory. Rows may be given in any order and may repeat.
- Raises:
IndexError – If a row position is negative or not below
NROWS.ValueError – If rows is not one-dimensional.
- property search_indexes: list[SearchIndex]#
Search indexes bound to this column, from
SEARCH_INDEX_LIST.The wrappers are bound to this column, so their queries always run against it — even on a non-conformant file where another column also claims the same index dataset.
- Raises:
ConformanceError – If the column’s
SEARCH_INDEX_LISTattribute is malformed (not a 1-D array of object references).
- add_search_index(kind: str | None = None, *, name: str | None = None, description: str | None = None) SearchIndex[source]#
Build a search index over this column (
Table.add_search_index()).- Raises:
SchemaError – If no index family applies to the column’s dtype (
kind=None), kind is unimplemented, orSEARCH_INDEXESalready holds a dataset of the chosen name.ReservedNameError – If name is a H5Col reserved name.
ConformanceError – If the table carries no
NROWSattribute.
- build_index(kind: str | None = None, *, name: str | None = None, description: str | None = None) SearchIndex[source]#
Build a search index over this column (alias of
add_search_index()).
- class h5col.ListColumn(group: Any, table: Table)[source]#
One list column of a H5Col table, wrapping its
CLASS=LIST_COLUMNgroup.Reading returns one Python
listper row (orNonefor a null list), with elements decoded to friendly values — nested lists become nested Python lists, string elements becomestr, and missing leaf elements becomeNone.