Metadata-Version: 2.4
Name: messy-xlsx
Version: 0.8.0
Summary: A Python library for parsing messy Excel files with intelligent structure detection and formula evaluation
Project-URL: Homepage, https://github.com/ivan-loh/messy-xlsx
Project-URL: Repository, https://github.com/ivan-loh/messy-xlsx
Project-URL: Issues, https://github.com/ivan-loh/messy-xlsx/issues
Author: Ivan
License-Expression: MIT
License-File: LICENSE
Keywords: data-extraction,excel,pandas,parser,spreadsheet,xlsx
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: fastexcel>=0.11.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: openpyxl>=3.1.0
Requires-Dist: pandas>=2.0.0
Provides-Extra: all
Requires-Dist: formulas>=1.2.0; extra == 'all'
Requires-Dist: xlcalculator>=0.4.0; extra == 'all'
Requires-Dist: xlrd>=2.0.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: hypothesis>=6.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0; extra == 'dev'
Requires-Dist: pyarrow>=14.0; extra == 'dev'
Requires-Dist: pytest-benchmark>=4.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
Requires-Dist: mkdocs>=1.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
Provides-Extra: formulas
Requires-Dist: formulas>=1.2.0; extra == 'formulas'
Requires-Dist: xlcalculator>=0.4.0; extra == 'formulas'
Provides-Extra: xls
Requires-Dist: xlrd>=2.0.0; extra == 'xls'
Description-Content-Type: text/markdown

# messy-xlsx

[![Tests](https://github.com/ivan-loh/messy-xlsx/actions/workflows/test.yml/badge.svg)](https://github.com/ivan-loh/messy-xlsx/actions/workflows/test.yml)
[![PyPI version](https://badge.fury.io/py/messy-xlsx.svg)](https://badge.fury.io/py/messy-xlsx)

Parse messy Excel files (XLSX, XLS, CSV) to clean pandas DataFrames with
intelligent structure detection, merged cell handling, and type normalization.

## Install

```bash
pip install messy-xlsx

# Optional: formula evaluation
pip install messy-xlsx[formulas]

# Optional: legacy .xls support
pip install messy-xlsx[xls]

# Everything
pip install messy-xlsx[all]
```

## Quick Start

```python
from messy_xlsx import MessyWorkbook, SheetConfig, read_excel

# Quick read
df = read_excel("data.xlsx")

# With options
df = read_excel("data.xlsx", sheet="Sheet1", skip_rows=2, normalize=False)

# Workbook API
with MessyWorkbook("data.xlsx") as wb:
    df = wb.to_dataframe(sheet="Sheet1")
    all_dfs = wb.to_dataframes()  # All sheets
    structure = wb.get_structure()

# From bytes (S3, cloud storage)
import io
wb = MessyWorkbook(io.BytesIO(content), filename="data.xlsx")
```

## Configuration

```python
from messy_xlsx import SheetConfig, MergeStrategy, HeaderDetectionMode

config = SheetConfig(
    # Row handling
    skip_rows=0,
    header_rows=1,
    skip_footer=0,
    cell_range=None,                       # "A1:F100"

    # Detection
    auto_detect=True,
    header_detection_mode="smart",         # or HeaderDetectionMode.SMART
    header_confidence_threshold=0.7,

    # Parsing
    merge_strategy="fill",                 # or MergeStrategy.FILL
    include_hidden=False,

    # Normalization
    normalize=True,
    normalize_dates=True,
    normalize_numbers=True,
    normalize_whitespace=True,
    sanitize_column_names=True,            # BigQuery-compatible names

    # Formulas
    evaluate_formulas=True,
)

wb = MessyWorkbook("data.xlsx", sheet_config=config)
```

All string-based config values accept both raw strings and enum types:

```python
from messy_xlsx import MergeStrategy

# These are equivalent:
SheetConfig(merge_strategy="fill")
SheetConfig(merge_strategy=MergeStrategy.FILL)

# Enums compare equal to strings:
assert MergeStrategy.FILL == "fill"  # True
```

Invalid values raise `ValueError` at construction time:

```python
SheetConfig(skip_rows=-1)              # ValueError
SheetConfig(merge_strategy="banana")   # ValueError
```

## Multi-Sheet

```python
from messy_xlsx import read_all_sheets, analyze_excel

# Read all sheets
results = read_all_sheets("data.xlsx")
for name, df in results.items():
    print(f"{name}: {len(df)} rows")

# Analyze without loading
info = analyze_excel("data.xlsx")
for sheet in info:
    print(f"{sheet.name}: {sheet.row_count} rows, {sheet.column_count} cols")
```

## Output

Output is compatible with BigQuery/Arrow. Column names are sanitized by default
and mixed-type columns are coerced to strings.

## Dependencies

- Python >= 3.10
- fastexcel >= 0.11
- openpyxl >= 3.1
- pandas >= 2.0
- numpy >= 1.24

Optional:
- formulas, xlcalculator (formula evaluation)
- xlrd (XLS support)

## Development

```bash
# Install with dev dependencies
make install

# Run tests, lint, type check
make ci

# Run benchmarks
make benchmark

# Serve documentation locally
make docs
```

## License

MIT
