Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ on:
branches: [main, master]

jobs:
base-install:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install base package without acceleration or development extras
run: python -m pip install .
- name: Verify installed extraction without pandas or SciPy
run: python -m benchmark.issue148_scipy_free --installed

test:
runs-on: ${{ matrix.os }}
env:
Expand All @@ -26,8 +41,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[yaml,mcp]
pip install pytest pytest-cov pytest-mock
pip install -e .[yaml,mcp,fast]
pip install pytest pytest-cov pytest-mock pandas
- name: Run tests (non-COM suite)
if: runner.os != 'Windows'
run: |
Expand Down
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,32 @@

All notable changes to this project are documented in this file. This changelog follows the [Keep a Changelog](https://keepachangelog.com/) format and covers changes from v0.2.70 onward.

## [Unreleased]
## [Unreleased]

### Changed

- Replaced production pandas cell extraction with direct openpyxl worksheet
iteration and lazy xlrd reading for legacy `.xls` files, preserving existing
cell normalization and serialized output.
- Shared extraction-scoped openpyxl workbooks across compatible stages and
per-sheet table detection, opening the formula variant only when requested.
- Isolated COM and rendering imports from light extraction while retaining
best-effort OOXML shapes/charts and legacy helper override behavior.
- Moved SciPy to the optional `fast` extra (also included in `all`), retaining
accelerated selection when installed and the existing Python fallback otherwise.

### Added

- Added regression coverage for previous-reader parity, workbook resource
lifetime and loader counts, subprocess import boundaries, and clustering
equivalence with SciPy-free execution.
- Added a reproducible comparison of SciPy, Python and sparse-set border
clustering, with exact output equivalence and recorded Windows timings.

### Fixed

- Preserved live pipeline backend overrides through lazy backend resolution.
- Avoided materializing blank cells when reading a shared sparse worksheet.

## [0.8.2] - 2026-09-26

Expand Down
3 changes: 2 additions & 1 deletion README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ pip install exstruct
オプション依存:

- YAML: `pip install pyyaml`
- 罫線クラスタリングの高速化: `pip install exstruct[fast]`(SciPy)。未導入時は既存の Python 実装へフォールバックします。NumPy は引き続き必須依存です。
- TOON: `pip install python-toon`
- レンダリング(PDF/PNG): Excel + `pip install pypdfium2 pillow`(`mode=libreoffice` では非対応)
- まとめて導入: `pip install exstruct[yaml,toon,render]`
- まとめて導入: `pip install exstruct[yaml,toon,render,fast]`

プラットフォーム注意:

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ LLM/RAG pipelines and local automation.
pip install exstruct
```

Optional extras:

Optional extras:

- Border-clustering acceleration: `pip install exstruct[fast]` (SciPy). Base extraction uses the existing Python fallback when SciPy is unavailable; NumPy remains a core dependency.
- YAML: `pip install pyyaml`
- TOON: `pip install python-toon`
- Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow` (`mode=libreoffice` is not supported)
- Install everything at once: `pip install exstruct[yaml,toon,render]`
- Install these extras at once: `pip install exstruct[yaml,toon,render,fast]`

Platform note:

Expand Down
124 changes: 124 additions & 0 deletions benchmark/baselines/issue148-2026-10-03-correctness.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"schema_version": 1,
"timestamp_utc": "2026-10-03T05:40:38.779016+00:00",
"source_revision": "5bcb0e47984104414956c9232bfca75b5076ddec",
"source_dirty": true,
"python": "3.11.13 (main, Jul 23 2025, 00:29:09) [MSC v.1944 64 bit (AMD64)]",
"platform": "Windows-10-10.0.22631-SP0",
"dependencies": {
"numpy": "2.4.6",
"scipy": "1.17.1",
"pandas": "3.0.6",
"openpyxl": "3.1.5"
},
"environment": {},
"mode": "light",
"warm_repeats": 0,
"check_only": true,
"cases": {
"sparse-small": {
"shape": [
40,
20
],
"occupied": 44,
"grid_bytes": 800,
"grid_sha256": "0cd619ad2bd7fdf774c43d425d46517f184fc920f564310d1bdbf54db4b72e19",
"fixture_sha256": "bd45bc2a80e9d05e01ce2d92b9ed4d0044334bbb43bc0d4908e16727044ee0c8",
"min_size": 4,
"cluster": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"light_extraction_serialization": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"components": 2,
"output_sha256": "445a94b9270a585d90837a5300c1b69b991dd2dfacc39c4372ca602b3c0dfc64",
"output_bytes": 949,
"bbox_order_equal": true,
"serialized_output_equal": true
},
"sparse-large": {
"shape": [
2000,
200
],
"occupied": 74,
"grid_bytes": 400000,
"grid_sha256": "89f650b3baefdf79bcd1f302e11b3c220e3bf418b721e25524e2abb2a4efb41f",
"fixture_sha256": "2a0c9f8b89ec25861017a8b6b81fb65f401972b9fa92a523b2b015325a02098e",
"min_size": 4,
"cluster": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"light_extraction_serialization": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"components": 2,
"output_sha256": "395c4470fa9b7fc1d1b718da9bed660289418ffbeafe03410cdf3424bb7b3957",
"output_bytes": 1649,
"bbox_order_equal": true,
"serialized_output_equal": true
},
"dense-style-heavy": {
"shape": [
300,
80
],
"occupied": 24000,
"grid_bytes": 24000,
"grid_sha256": "9bf7697f1260d5f1781eb4878282d81007950425b289f00ffbea23d2b83c0ee8",
"fixture_sha256": "c6980bfa1f606bc3caad0c8c0e1204f57382e903fcacf479595c747c29b25072",
"min_size": 4,
"cluster": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"light_extraction_serialization": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"components": 1,
"output_sha256": "4027f972fe8832c95d84355c866b8235401a4453286019fa04a7a4880fdac503",
"output_bytes": 398897,
"bbox_order_equal": true,
"serialized_output_equal": true
},
"many-disconnected": {
"shape": [
300,
100
],
"occupied": 4000,
"grid_bytes": 30000,
"grid_sha256": "4daa7f0eafcaa14efcdd9b8b9465d5011bbdc0925e5c6da6cf69d36087d5100f",
"fixture_sha256": "a73151afb9ae566ec8908d46473693a1edf6b0449a445072df21b2a021a6bac3",
"min_size": 4,
"cluster": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"light_extraction_serialization": {
"scipy": {},
"python": {},
"candidate_sparse": {}
},
"components": 1000,
"output_sha256": "ea1cff42a0a4b84b8166f36bd8e88c3db4fd0329431f56c5c32820da916e7a1a",
"output_bytes": 81361,
"bbox_order_equal": true,
"serialized_output_equal": true
}
}
}
Loading
Loading