Changelog¶
All notable changes to xlea are documented here.
1.0.2 — 2026-03-13
Bug fix: HeaderNotFound raised lazily instead of eagerly (#3)
When calling read() or autoread() with a schema, the
HeaderNotFound exception was not raised immediately — it
was deferred until the caller started iterating over the returned generator.
This made error detection unpredictable and violated the principle of least
surprise.
Schema resolution is now eager: HeaderNotFound (and its
subclass MissingRequiredColumns) are raised at the
read() / autoread() call site, before any iteration begins.
# Before 1.0.2 — error only surfaced during iteration:
rows = xlea.autoread("bad.xlsx", schema=MySchema) # no error yet
for row in rows: # HeaderNotFound raised here — surprising!
...
# After 1.0.2 — error raised immediately:
rows = xlea.autoread("bad.xlsx", schema=MySchema) # HeaderNotFound here ✓
Additional changes in this release:
Added
.xlsm,.xltx,.xltmextensions to the openpyxl provider registryProviders now import their dependencies lazily and raise
ProviderErrorwith a helpful install hint onImportErrorMissingRequiredColumnsadded as a subclass ofHeaderNotFound— includes the names of the missing columns in the error messageIncompatibleReturnValueTypeErrorraised when a validator returns a non-boolvalueBoundSchemaheader search is now streaming — no longer buffers all rows into a tuple upfront
1.0.1
Bug fix: IndexError: tuple index out of range on empty rows
(#1)
Some Excel providers (openpyxl, xlrd) emit an empty tuple () for blank
rows in a spreadsheet instead of skipping them. Before this fix, xlea
attempted to access an index on that empty tuple and raised an uncaught
IndexError.
Empty rows are now normalised automatically: they are padded with
None values to match the required column width and passed through the
normal validation pipeline — either skipped (if skip_invalid_row=True)
or handled as any other row with missing values.
# Before 1.0.1:
for row in xlea.autoread("file_with_blank_rows.xlsx", schema=MySchema):
print(row.id) # IndexError on blank row ✗
# After 1.0.1:
for row in xlea.autoread("file_with_blank_rows.xlsx", schema=MySchema):
print(row.id) # blank rows handled gracefully ✓
1.0.0
Initial public release.
Declarative schema definition via
Column()descriptorsAutomatic header detection (position-independent)
Type conversion driven by annotations
Multi-row header support via
@config(header_rows=N)Built-in providers:
OpenPyXlProvider,XLRDProvider,PyXLSBProviderregister_provider()for custom file extensionsPer-column validators with
skip_invalid_rowsupport