Skip to main content

xldetect

CI

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 xlfilldown can 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.

Metadata

Release files for xldetect 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xldetect 1.0.1
File Size Uploaded Provenance
xldetect-1.0.1.tar.gz 37.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for xldetect 1.0.1
File Interpreter ABI Platform
xldetect-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 65.0 kB

Release files / xldetect-1.0.1.tar.gz

Download URL xldetect-1.0.1.tar.gz
Size 37.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c02065073e8c4f1f5343990dbcb1b3f35c7c7e4f17081c901b72cd198e8333f4
BLAKE2b-256 checksum
How to use checksums
b63f0db39635a79a5c3fa2b14aeb5f42741d4c1d374e98e040e59ca251a93b4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / xldetect-1.0.1-py3-none-any.whl

Download URL xldetect-1.0.1-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
223da69cfbece732a77936e25da525a53eb838ff6626091cda119c7b7ee96180
BLAKE2b-256 checksum
How to use checksums
d98c3dcab2d060da7a541f9cae6fafd9e4fed1cfe6c619f045d856a8e09d9d47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Security for xldetect 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page