Structural detection of table-like data regions, headers, and merged cells in Excel worksheets.
Project description
xldetect
Structural detection of table-like data regions, headers, and merged
cells in Excel worksheets. xldetect is the discovery step: it finds where
the tables are so a processing step (like
xlfilldown) can act on them.
Users say "grab the table", but a worksheet has no concept of one — just
scattered cells, merged banners, decorative titles, summary rows, and sometimes
several tables on one sheet. openpyxl tells you cell values; it does not tell
you where the data starts. xldetect answers that question from structure alone.
- Detect multiple rectangular data regions per sheet, across sheets
- Detect header row(s) from content cues (text-over-data) and formatting (bold/fill/border)
- Report and forward-fill merged cells
- Skip decorative title/banner rows
- Confidence score per region
- Emit regions in a shape
xlfilldowncan consume
Install
pip install xldetect
Requires Python 3.11+. Runtime dependency: openpyxl.
Quickstart (CLI)
xldetect inspect messy.xlsx
File: messy.xlsx
Sheets: 1 Regions: 2
Sheet 'Data': 2 region(s), used range 8 rows x 3 cols, 1 merged range(s)
Region 1: A2:C4 (confidence 0.933)
header row 2: Name, Region, Sales
data rows 3-4 (2 rows x 3 cols)
decorative rows skipped: 1
Region 2: A7:B8 (confidence 0.870)
header row 7: Product, Qty
data rows 8-8 (1 row x 2 cols)
Other output modes:
xldetect inspect messy.xlsx --json # full report as JSON
xldetect inspect messy.xlsx --xlfilldown # one xlfilldown plan per region
xldetect inspect messy.xlsx --sheet Data --min-blank-rows 2 --header-threshold 0.6
Quickstart (Python)
from xldetect import inspect_path
report = inspect_path("messy.xlsx")
for region in report.iter_regions():
print(region.range_a1, region.headers, region.confidence)
# A2:C4 ['Name', 'Region', 'Sales'] 0.933
Every result is a typed dataclass with a JSON-safe to_dict(). A Region
carries: sheet, min_row/max_row/min_col/max_col, range_a1, has_header,
header_rows/header_row, headers, data_start_row, n_data_rows,
n_cols, confidence, merged_ranges, decorative_rows, and notes.
Pairing with xlfilldown
xldetect finds the region; xlfilldown fills it down and ingests it.
from xldetect import inspect_path, to_xlfilldown_plan
import xlfilldown
report = inspect_path("messy.xlsx")
region = next(report.iter_regions())
plan = to_xlfilldown_plan(region, "messy.xlsx",
sheet_max_col=report.sheets[0].max_col)
if not plan["caveats"]:
xlfilldown.ingest_excel_to_sqlite(
file=plan["file"], sheet=plan["sheet"],
header_row=plan["header_row"], fill_cols=plan["fill_cols"],
db="out.db", table="data", if_exists="replace",
)
xlfilldown reads one header_row to the end of the sheet across all headered
columns. When a region does not span the full sheet (multiple regions, column
offsets), the plan's caveats list says so — read it before ingesting. See
LIMITATIONS.md.
Deliberate design tradeoffs
xldetect makes opinionated structural guesses. The behaviours most likely to
look like bugs (single-blank-row splitting, all-text header detection, summary
rows kept as data, formula caching) are documented with rationale and overrides
in LIMITATIONS.md.
Using with AI assistants
SKILL.md is an LLM-consumable guide (decision tree, worked
examples, anti-patterns) so coding agents call xldetect correctly instead of
hand-rolling region detection.
Development
pip install -e .[dev]
pytest # runs straight from a clean clone (pythonpath = src)
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xldetect-1.0.1.tar.gz.
File metadata
- Download URL: xldetect-1.0.1.tar.gz
- Upload date:
- Size: 37.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c02065073e8c4f1f5343990dbcb1b3f35c7c7e4f17081c901b72cd198e8333f4
|
|
| MD5 |
0b0396d3a12cabd7fe4fb65bf654edca
|
|
| BLAKE2b-256 |
b63f0db39635a79a5c3fa2b14aeb5f42741d4c1d374e98e040e59ca251a93b4d
|
File details
Details for the file xldetect-1.0.1-py3-none-any.whl.
File metadata
- Download URL: xldetect-1.0.1-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
223da69cfbece732a77936e25da525a53eb838ff6626091cda119c7b7ee96180
|
|
| MD5 |
559182c4f4f0beab60599f4535c49a2c
|
|
| BLAKE2b-256 |
d98c3dcab2d060da7a541f9cae6fafd9e4fed1cfe6c619f045d856a8e09d9d47
|