exstruct 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {exstruct-0.6.0 → exstruct-0.7.0}/PKG-INFO +674 -620
  2. {exstruct-0.6.0 → exstruct-0.7.0}/README.md +673 -619
  3. {exstruct-0.6.0 → exstruct-0.7.0}/pyproject.toml +5 -5
  4. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/cli/availability.py +49 -49
  5. exstruct-0.7.0/src/exstruct/cli/edit.py +411 -0
  6. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/cli/main.py +17 -3
  7. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/backends/openpyxl_backend.py +217 -217
  8. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/libreoffice.py +79 -13
  9. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/logging_utils.py +16 -16
  10. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/modeling.py +108 -108
  11. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/ranges.py +48 -48
  12. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/workbook.py +117 -117
  13. exstruct-0.7.0/src/exstruct/edit/__init__.py +128 -0
  14. exstruct-0.7.0/src/exstruct/edit/a1.py +94 -0
  15. exstruct-0.7.0/src/exstruct/edit/api.py +27 -0
  16. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/chart_types.py +59 -63
  17. exstruct-0.7.0/src/exstruct/edit/engine/__init__.py +8 -0
  18. exstruct-0.7.0/src/exstruct/edit/engine/openpyxl_engine.py +63 -0
  19. exstruct-0.7.0/src/exstruct/edit/engine/xlwings_engine.py +28 -0
  20. exstruct-0.7.0/src/exstruct/edit/errors.py +7 -0
  21. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/internal.py +4936 -4915
  22. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/models.py +1618 -1616
  23. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/normalize.py +216 -181
  24. {exstruct-0.6.0/src/exstruct/mcp → exstruct-0.7.0/src/exstruct/edit}/op_schema.py +458 -444
  25. exstruct-0.7.0/src/exstruct/edit/output_path.py +167 -0
  26. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/runtime.py +158 -159
  27. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/service.py +46 -13
  28. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/specs.py +64 -58
  29. {exstruct-0.6.0/src/exstruct/mcp/patch → exstruct-0.7.0/src/exstruct/edit}/types.py +69 -53
  30. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/errors.py +48 -48
  31. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/io/__init__.py +680 -680
  32. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/io/serialize.py +112 -112
  33. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/__init__.py +159 -159
  34. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/chunk_reader.py +450 -450
  35. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/extract_runner.py +304 -304
  36. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/io.py +71 -71
  37. exstruct-0.7.0/src/exstruct/mcp/op_schema.py +17 -0
  38. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/__init__.py +13 -13
  39. exstruct-0.7.0/src/exstruct/mcp/patch/chart_types.py +21 -0
  40. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/engine/__init__.py +6 -6
  41. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/engine/base.py +34 -34
  42. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/engine/openpyxl_engine.py +20 -18
  43. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/engine/xlwings_engine.py +21 -19
  44. exstruct-0.7.0/src/exstruct/mcp/patch/internal.py +570 -0
  45. exstruct-0.7.0/src/exstruct/mcp/patch/models.py +49 -0
  46. exstruct-0.7.0/src/exstruct/mcp/patch/normalize.py +25 -0
  47. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/ops/__init__.py +6 -6
  48. exstruct-0.7.0/src/exstruct/mcp/patch/ops/common.py +5 -0
  49. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/ops/openpyxl_ops.py +69 -69
  50. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch/ops/xlwings_ops.py +26 -26
  51. exstruct-0.7.0/src/exstruct/mcp/patch/runtime.py +79 -0
  52. exstruct-0.7.0/src/exstruct/mcp/patch/service.py +115 -0
  53. exstruct-0.7.0/src/exstruct/mcp/patch/specs.py +5 -0
  54. exstruct-0.7.0/src/exstruct/mcp/patch/types.py +27 -0
  55. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/patch_runner.py +80 -74
  56. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/render_runner.py +124 -124
  57. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/shared/__init__.py +39 -39
  58. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/shared/output_path.py +139 -139
  59. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/sheet_reader.py +472 -472
  60. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/tools.py +870 -870
  61. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/validate_input.py +76 -76
  62. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/models/maps.py +335 -335
  63. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/render/subprocess_worker.py +180 -180
  64. exstruct-0.6.0/src/exstruct/mcp/patch/ops/common.py +0 -7
  65. {exstruct-0.6.0 → exstruct-0.7.0}/LICENSE +0 -0
  66. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/__init__.py +0 -0
  67. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/constraints.py +0 -0
  68. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/__init__.py +0 -0
  69. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/_libreoffice_bridge.py +0 -0
  70. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/backends/__init__.py +0 -0
  71. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/backends/base.py +0 -0
  72. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/backends/com_backend.py +0 -0
  73. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/backends/libreoffice_backend.py +0 -0
  74. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/cells.py +0 -0
  75. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/charts.py +0 -0
  76. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/integrate.py +0 -0
  77. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/ooxml_drawing.py +0 -0
  78. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/pipeline.py +0 -0
  79. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/core/shapes.py +0 -0
  80. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/engine.py +0 -0
  81. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/server.py +0 -0
  82. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/mcp/shared/a1.py +0 -0
  83. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/models/__init__.py +0 -0
  84. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/models/types.py +0 -0
  85. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/py.typed +0 -0
  86. {exstruct-0.6.0 → exstruct-0.7.0}/src/exstruct/render/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: exstruct
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Excel to structured JSON (tables, shapes, charts) for LLM/RAG pipelines
5
5
  Keywords: excel,structure,data,exstruct
6
6
  Author: harumiWeb
@@ -64,638 +64,692 @@ Provides-Extra: toon
64
64
  Provides-Extra: yaml
65
65
  Description-Content-Type: text/markdown
66
66
 
67
- <p align="center">
68
- <a href="https://harumiweb.github.io/exstruct/">
69
- <img src="docs/assets/logo.png" alt="ExStruct Logo" width="600">
70
- </a>
71
- </p>
72
-
73
- <p align="center">
74
- <em>Excel Structured Extraction Engine</em>
75
- </p>
76
-
77
- <div align="center" style="max-width: 600px; margin: auto;">
78
-
79
- [![PyPI version](https://badge.fury.io/py/exstruct.svg)](https://pypi.org/project/exstruct/) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/exstruct?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/exstruct) ![Licence: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue?style=flat-square) [![pytest](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml/badge.svg)](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e081cb4f634e4175b259eb7c34f54f60)](https://app.codacy.com/gh/harumiWeb/exstruct/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![codecov](https://codecov.io/gh/harumiWeb/exstruct/graph/badge.svg?token=2XI1O8TTA9)](https://codecov.io/gh/harumiWeb/exstruct) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/harumiWeb/exstruct) ![GitHub Repo stars](https://img.shields.io/github/stars/harumiWeb/exstruct)
80
-
81
- </div>
82
-
83
- <p align="center">
84
- <a href="https://harumiweb.github.io/exstruct/README.md">
85
- English
86
- </a>
87
- |
88
- <a href="https://harumiweb.github.io/exstruct/README.ja.md">
89
- 日本語
90
- </a>
91
- </p>
92
-
67
+ <p align="center">
68
+ <a href="https://harumiweb.github.io/exstruct/">
69
+ <img width="600" alt="ExStruct Logo" src="https://github.com/user-attachments/assets/c1d4e616-890f-435c-9d53-fba054f861a8" />
70
+ </a>
71
+ </p>
72
+
73
+ <p align="center">
74
+ <em>Excel Structured Extraction Engine</em>
75
+ </p>
76
+
77
+ <div align="center" style="max-width: 600px; margin: auto;">
78
+
79
+ [![PyPI version](https://badge.fury.io/py/exstruct.svg)](https://pypi.org/project/exstruct/) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/exstruct?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/exstruct) ![Licence: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue?style=flat-square) [![pytest](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml/badge.svg)](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e081cb4f634e4175b259eb7c34f54f60)](https://app.codacy.com/gh/harumiWeb/exstruct/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![codecov](https://codecov.io/gh/harumiWeb/exstruct/graph/badge.svg?token=2XI1O8TTA9)](https://codecov.io/gh/harumiWeb/exstruct) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/harumiWeb/exstruct) ![GitHub Repo stars](https://img.shields.io/github/stars/harumiWeb/exstruct)
80
+
81
+ </div>
82
+
83
+ <p align="center">
84
+ <a href="README.md">
85
+ English
86
+ </a>
87
+ |
88
+ <a href="README.ja.md">
89
+ 日本語
90
+ </a>
91
+ </p>
92
+
93
93
  # ExStruct — Excel Structured Extraction Engine
94
94
 
95
- ExStruct reads Excel workbooks and outputs structured data such as cells, table candidates, shapes, charts, SmartArt, and print-area views as JSON by default. It provides a CLI, a Python API, and an MCP server, with extraction options tuned for LLM/RAG preprocessing and document understanding.
96
-
97
- - In COM/Excel environments (Windows), it performs rich extraction.
98
- - In non-COM environments (Linux/macOS):
99
- - if the LibreOffice runtime is available, it performs best-effort extraction for cells, table candidates, shapes, connectors, and charts
100
- - otherwise, it safely falls back to cells + table candidates + print areas
101
-
102
- Detection heuristics and output modes are adjustable for LLM/RAG pipelines.
103
-
104
- ## Main Features
105
-
106
- - **Excel -> structured JSON**: outputs cells, shapes, charts, SmartArt, table candidates, merged-cell ranges, print areas, and auto page-break areas by sheet or by area.
107
- - **Output modes**: `light` (cells + table candidates + print areas only), `libreoffice` (best-effort non-COM mode for `.xlsx/.xlsm`; adds merged cells, shapes, connectors, and charts when the LibreOffice runtime is available), `standard` (Excel COM mode with texted shapes + arrows, charts, SmartArt, and merged-cell ranges), `verbose` (all shapes with width/height plus cell hyperlinks).
108
- - **Formula extraction**: emits `formulas_map` (formula string -> cell coordinates) via openpyxl/COM. It is enabled by default in `verbose` and can be controlled with `include_formulas_map`.
95
+ ExStruct reads Excel workbooks into structured data and applies patch-based
96
+ editing workflows through a shared core. It provides extraction APIs, a
97
+ JSON-first editing CLI, and an MCP server for host-managed integrations, with
98
+ options tuned for LLM/RAG preprocessing, reviewable edit flows, and local
99
+ automation.
100
+
101
+ - In COM/Excel environments (Windows), it performs rich extraction.
102
+ - In non-COM environments (Linux/macOS):
103
+ - if the LibreOffice runtime is available, it performs best-effort extraction for cells, table candidates, shapes, connectors, and charts
104
+ - otherwise, it safely falls back to cells + table candidates + print areas
105
+
106
+ Detection heuristics, editing workflows, and output modes are adjustable for
107
+ LLM/RAG pipelines and local automation.
108
+
109
+ ## Choose an Interface
110
+
111
+ | Use case | Recommended interface | Why |
112
+ | --- | --- | --- |
113
+ | Write direct Python Excel-editing code | `openpyxl` / `xlwings` | Usually the better fit for imperative Python editing. Reach for `exstruct.edit` only when you specifically want ExStruct's patch contract in Python. |
114
+ | Run local operator or AI-agent edit workflows | `exstruct patch`, `make`, `ops`, `validate` | Canonical operational interface; JSON-first and dry-run friendly. |
115
+ | Run sandboxed or host-managed integrations | `exstruct-mcp` / MCP tools | Integration / compatibility layer that owns `PathPolicy`, transport, and artifact behavior. |
116
+
117
+ Extraction keeps the existing top-level Python API (`extract`, `process_excel`,
118
+ `ExStructEngine`) and the legacy `exstruct INPUT.xlsx ...` CLI entrypoint.
119
+
120
+ ## Main Features
121
+
122
+ - **Excel -> structured JSON**: outputs cells, shapes, charts, SmartArt, table candidates, merged-cell ranges, print areas, and auto page-break areas by sheet or by area.
123
+ - **Output modes**: `light` (cells + table candidates + print areas only), `libreoffice` (best-effort non-COM mode for `.xlsx/.xlsm`; adds merged cells, shapes, connectors, and charts when the LibreOffice runtime is available), `standard` (Excel COM mode with texted shapes + arrows, charts, SmartArt, and merged-cell ranges), `verbose` (all shapes with width/height plus cell hyperlinks).
124
+ - **Formula extraction**: emits `formulas_map` (formula string -> cell coordinates) via openpyxl/COM. It is enabled by default in `verbose` and can be controlled with `include_formulas_map`.
109
125
  - **Formats**: JSON (compact by default, `--pretty` for formatting), YAML, and TOON (optional dependencies).
110
126
  - **Backend metadata is opt-in**: shape/chart `provenance`, `approximation_level`, and `confidence` are omitted from serialized output by default. Enable them with `--include-backend-metadata` or `include_backend_metadata=True`.
127
+ - **Workbook editing interfaces**: use the editing CLI for primary ExStruct edit flows, keep MCP for host-owned safety controls, and use `exstruct.edit` only when you need the same patch contract from Python.
111
128
  - **Table detection tuning**: heuristics can be adjusted dynamically through the API.
112
- - **Hyperlink extraction**: in `verbose` mode, or with `include_cell_links=True`, cell links are emitted in `links`.
113
- - **CLI rendering**: in `standard` / `verbose`, PDF and sheet images can be generated when Excel COM is available.
114
- - **Safe fallback**: if Excel COM or the LibreOffice runtime is unavailable, the process does not crash and falls back to cells + table candidates + print areas.
115
-
116
- ## Installation
117
-
118
- ```bash
119
- pip install exstruct
120
- ```
121
-
122
- Optional extras:
123
-
124
- - YAML: `pip install pyyaml`
125
- - TOON: `pip install python-toon`
126
- - Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow` (`mode=libreoffice` is not supported)
127
- - Install everything at once: `pip install exstruct[yaml,toon,render]`
128
-
129
- Platform note:
130
-
131
- - Full COM extraction for shapes/charts targets Windows + Excel (xlwings/COM). On Linux/macOS/server environments, use `mode=libreoffice` as the best-effort rich mode or `mode=light` for minimal extraction. `.xls` is not supported in `mode=libreoffice`.
132
- - On Debian/Ubuntu/WSL, install LibreOffice together with `python3-uno`. ExStruct probes a compatible system Python automatically for `mode=libreoffice`; if your environment needs an explicit interpreter, set `EXSTRUCT_LIBREOFFICE_PYTHON_PATH=/usr/bin/python3`.
133
- - LibreOffice Python detection now runs the bundled bridge in `--probe` mode before selection. An incompatible `EXSTRUCT_LIBREOFFICE_PYTHON_PATH` fails fast instead of surfacing a delayed bridge `SyntaxError` during extraction.
134
- - If the isolated temporary LibreOffice profile fails before the UNO socket becomes ready, ExStruct retries once with the shared/default LibreOffice profile as a compatibility fallback and reports per-attempt startup detail if both launches fail.
135
- - GitHub Actions includes a required Linux smoke job on `ubuntu-24.04` that installs `libreoffice` + `python3-uno` and runs `tests/core/test_libreoffice_smoke.py` with `RUN_LIBREOFFICE_SMOKE=1`.
136
-
129
+ - **Hyperlink extraction**: in `verbose` mode, or with `include_cell_links=True`, cell links are emitted in `links`.
130
+ - **CLI rendering**: in `standard` / `verbose`, PDF and sheet images can be generated when Excel COM is available.
131
+ - **Safe fallback**: if Excel COM or the LibreOffice runtime is unavailable, the process does not crash and falls back to cells + table candidates + print areas.
132
+
133
+ ## Installation
134
+
135
+ ```bash
136
+ pip install exstruct
137
+ ```
138
+
139
+ Optional extras:
140
+
141
+ - YAML: `pip install pyyaml`
142
+ - TOON: `pip install python-toon`
143
+ - Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow` (`mode=libreoffice` is not supported)
144
+ - Install everything at once: `pip install exstruct[yaml,toon,render]`
145
+
146
+ Platform note:
147
+
148
+ - Full COM extraction for shapes/charts targets Windows + Excel (xlwings/COM). On Linux/macOS/server environments, use `mode=libreoffice` as the best-effort rich mode or `mode=light` for minimal extraction. `.xls` is not supported in `mode=libreoffice`.
149
+ - On Debian/Ubuntu/WSL, install LibreOffice together with `python3-uno`. ExStruct probes a compatible system Python automatically for `mode=libreoffice`; if your environment needs an explicit interpreter, set `EXSTRUCT_LIBREOFFICE_PYTHON_PATH=/usr/bin/python3`.
150
+ - LibreOffice Python detection now runs the bundled bridge in `--probe` mode before selection. An incompatible `EXSTRUCT_LIBREOFFICE_PYTHON_PATH` fails fast instead of surfacing a delayed bridge `SyntaxError` during extraction.
151
+ - If the isolated temporary LibreOffice profile fails before the UNO socket becomes ready, ExStruct retries once with the shared/default LibreOffice profile as a compatibility fallback and reports per-attempt startup detail if both launches fail.
152
+ - GitHub Actions includes dedicated LibreOffice smoke jobs on `ubuntu-24.04` and `windows-2025`. Linux installs `libreoffice` + `python3-uno`; Windows installs `libreoffice-fresh`, sets `EXSTRUCT_LIBREOFFICE_PATH`, and both jobs run `tests/core/test_libreoffice_smoke.py` with `RUN_LIBREOFFICE_SMOKE=1`.
153
+
137
154
  ## Quick Start CLI
138
-
139
- ```bash
140
- exstruct input.xlsx > output.json # compact JSON to stdout by default
141
- exstruct input.xlsx -o out.json --pretty # write pretty JSON to a file
142
- exstruct input.xlsx --format yaml # YAML (requires pyyaml)
143
- exstruct input.xlsx --format toon # TOON (requires python-toon)
144
- exstruct input.xlsx --sheets-dir sheets/ # write one file per sheet
145
- exstruct input.xlsx --auto-page-breaks-dir auto_areas/ # COM only; shown only when available
146
- exstruct input.xlsx --alpha-col # output column keys as A, B, ..., AA
147
- exstruct input.xlsx --include-backend-metadata # include shape/chart backend metadata
148
- exstruct input.xlsx --mode light # cells + table candidates only
149
- exstruct input.xlsx --mode libreoffice # best-effort extraction of shapes/connectors/charts without COM
150
- exstruct input.xlsx --pdf --image # PDF and PNGs (Excel COM required)
151
- ```
152
-
153
- Auto page-break export is available from both the API and the CLI when Excel/COM is available. The CLI exposes `--auto-page-breaks-dir` only in COM-capable environments.
154
- `mode=libreoffice` rejects `--pdf`, `--image`, and `--auto-page-breaks-dir` early. Use `standard` or `verbose` with Excel COM for those features.
155
- By default, the CLI keeps legacy 0-based numeric string column keys (`"0"`, `"1"`, ...). Use `--alpha-col` when you need Excel-style keys (`"A"`, `"B"`, ...).
156
- By default, serialized shape/chart output omits backend metadata (`provenance`, `approximation_level`, `confidence`) to reduce token usage. Use `--include-backend-metadata` or the corresponding Python/MCP option when you need it.
155
+
156
+ ```bash
157
+ exstruct input.xlsx > output.json # compact JSON to stdout by default
158
+ exstruct input.xlsx -o out.json --pretty # write pretty JSON to a file
159
+ exstruct input.xlsx --format yaml # YAML (requires pyyaml)
160
+ exstruct input.xlsx --format toon # TOON (requires python-toon)
161
+ exstruct input.xlsx --sheets-dir sheets/ # write one file per sheet
162
+ exstruct input.xlsx --auto-page-breaks-dir auto_areas/ # COM only; shown only when available
163
+ exstruct input.xlsx --alpha-col # output column keys as A, B, ..., AA
164
+ exstruct input.xlsx --include-backend-metadata # include shape/chart backend metadata
165
+ exstruct input.xlsx --mode light # cells + table candidates only
166
+ exstruct input.xlsx --mode libreoffice # best-effort extraction of shapes/connectors/charts without COM
167
+ exstruct input.xlsx --pdf --image # PDF and PNGs (Excel COM required)
168
+ ```
169
+
170
+ Auto page-break export is available from both the API and the CLI when Excel/COM is available. The CLI exposes `--auto-page-breaks-dir` only in COM-capable environments.
171
+ `mode=libreoffice` rejects `--pdf`, `--image`, and `--auto-page-breaks-dir` early. Use `standard` or `verbose` with Excel COM for those features.
172
+ By default, the CLI keeps legacy 0-based numeric string column keys (`"0"`, `"1"`, ...). Use `--alpha-col` when you need Excel-style keys (`"A"`, `"B"`, ...).
173
+ By default, serialized shape/chart output omits backend metadata (`provenance`, `approximation_level`, `confidence`) to reduce token usage. Use `--include-backend-metadata` or the corresponding Python/MCP option when you need it.
157
174
  Note: MCP `exstruct_extract` defaults to `options.alpha_col=true`, which differs from the CLI default (`false`).
158
175
 
159
- ## MCP Server (stdio)
160
-
161
- ### Quick Start with `uvx` (recommended)
162
-
163
- You can run it directly without installation:
176
+ ## Quick Start Editing CLI
164
177
 
165
178
  ```bash
166
- uvx --from 'exstruct[mcp]' exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
179
+ exstruct patch --input book.xlsx --ops ops.json --backend openpyxl
180
+ exstruct patch --input book.xlsx --ops - --dry-run --pretty < ops.json
181
+ exstruct make --output new.xlsx --ops ops.json --backend openpyxl
182
+ exstruct ops list
183
+ exstruct ops describe create_chart --pretty
184
+ exstruct validate --input book.xlsx --pretty
167
185
  ```
168
186
 
169
- Benefits:
170
-
171
- - no `pip install` required
172
- - automatic dependency management
173
- - isolated environment
174
- - easy version pinning: `uvx --from 'exstruct[mcp]==0.4.4' exstruct-mcp`
175
-
176
- ### Traditional installation
177
-
178
- You can also install it with pip:
179
-
180
- ```bash
181
- pip install exstruct[mcp]
182
- exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
183
- ```
184
-
185
- Available tools:
186
-
187
- - `exstruct_extract`
188
- - `exstruct_capture_sheet_images`
189
- - `exstruct_make`
190
- - `exstruct_patch`
191
- - `exstruct_read_json_chunk`
192
- - `exstruct_read_range`
193
- - `exstruct_read_cells`
194
- - `exstruct_read_formulas`
195
- - `exstruct_validate_input`
196
-
197
- Notes:
198
-
199
- - `exstruct_capture_sheet_images` is COM-only (Experimental) and supports optional `sheet` / `range` targeting (`A1:B2`, `Sheet1!A1:B2`, `'Sheet 1'!A1:B2`). When `out_dir` is omitted, it creates a unique `<workbook_stem>_images` directory under MCP `--root`.
200
- - MCP server startup defaults `EXSTRUCT_RENDER_SUBPROCESS=1` via `setdefault`. If you want in-process execution instead, set `EXSTRUCT_RENDER_SUBPROCESS=0` before launching the server.
201
- - Timeout tuning for `exstruct_capture_sheet_images`: `EXSTRUCT_MCP_CAPTURE_SHEET_IMAGES_TIMEOUT_SEC` (overall tool timeout), `EXSTRUCT_RENDER_SUBPROCESS_STARTUP_TIMEOUT_SEC` (worker startup), `EXSTRUCT_RENDER_SUBPROCESS_JOIN_TIMEOUT_SEC` (primary wait budget), and `EXSTRUCT_RENDER_SUBPROCESS_RESULT_TIMEOUT_SEC` (post-exit grace).
202
- - Subprocess failures return `stage=startup|join|result|worker`, which lets MCP clients distinguish bootstrap failures, timeouts, and worker-side rendering failures.
203
- - Trade-off of `EXSTRUCT_RENDER_SUBPROCESS=1`: extra subprocess startup/coordination overhead and more dependency on worker-side module resolution.
204
- - Trade-off of `EXSTRUCT_RENDER_SUBPROCESS=0`: weaker crash isolation and higher memory pressure risk in long-running processes.
205
- - Logs are written to stderr, and optionally to `--log-file`, to keep stdio responses clean.
206
- - On Windows with Excel, `standard` / `verbose` use COM for the richest extraction.
207
- - On Linux/macOS/server environments, `libreoffice` is the best-effort rich mode. It is not a strict subset of COM output; shapes, connectors, and charts are reconstructed from LibreOffice + OOXML metadata and may differ in fidelity.
208
- - In v1, `libreoffice` does not render PDFs/PNGs and does not compute auto page-break areas.
209
- - `exstruct_patch` supports `backend` selection.
210
- - `auto` (default): prefer COM when available, otherwise openpyxl
211
- - `com`: force COM (`dry_run` / `return_inverse_ops` / `preflight_formula_check` are not allowed)
212
- - `openpyxl`: force openpyxl (`.xls` is not supported)
213
- - `create_chart` is COM-only. Requests that include `create_chart` cannot use `backend="openpyxl"`, and they also reject `dry_run`, `return_inverse_ops`, and `preflight_formula_check`.
214
- - `create_chart` supports `chart_type` values `line`, `column`, `bar`, `area`, `pie`, `doughnut`, `scatter`, and `radar` (aliases: `column_clustered`, `bar_clustered`, `xy_scatter`, `donut`).
215
- - `create_chart` accepts either a single range string or `list[str]` for `data_range`, and both `data_range` and `category_range` support sheet-qualified ranges such as `Sheet2!A1:B10` and `'Sales Data'!A1:B10`.
216
- - `create_chart` also supports explicit titles with `chart_title`, `x_axis_title`, and `y_axis_title`.
217
- - `create_chart` and `apply_table_style` can be combined in one request when the backend resolves to COM (`backend="com"` or COM-capable `backend="auto"`).
218
- - For stable COM execution of `apply_table_style` on Windows, make sure desktop Excel is installed and runnable, and that the target `range` is a contiguous A1 range including the header row.
219
- - `exstruct_patch` error details may include `error_code`, `failed_field`, and `raw_com_message`. Table-related codes include `table_style_invalid`, `list_object_add_failed`, and `com_api_missing`.
220
- - `exstruct_patch` responses include the actual backend in `engine` (`com` / `openpyxl`). `restore_design_snapshot` remains openpyxl-only.
221
- - Use `exstruct_make` for creating new workbooks and `exstruct_patch` for editing existing ones.
222
- - `exstruct_make` creates a new workbook and applies `ops` in one call (`out_path` required, `ops` optional).
223
- - supported extensions: `.xlsx` / `.xlsm` / `.xls`
224
- - the initial sheet name is normalized to `Sheet1`
225
- - `.xls` requires COM, so `backend=openpyxl` is not allowed
226
-
227
- MCP setup guide for each AI agent:
228
-
229
- [MCP Server](https://harumiweb.github.io/exstruct/mcp/)
230
-
231
- ## Quick Start Python
232
-
233
- ```python
234
- from pathlib import Path
235
- from exstruct import extract, export, set_table_detection_params
236
-
237
- # Tune table detection (optional)
238
- set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
239
-
240
- # Modes: "light" / "standard" / "verbose"
241
- wb = extract("input.xlsx", mode="standard") # standard does not emit links by default
242
- export(wb, Path("out.json"), pretty=False) # compact JSON
243
- export(wb, Path("out.json"), include_backend_metadata=True) # opt into backend metadata
244
-
245
- # Helpful model methods: iteration, indexing, and direct serialization
246
- first_sheet = wb["Sheet1"] # get a sheet with __getitem__
247
- for name, sheet in wb: # __iter__ yields (name, SheetData)
248
- print(name, len(sheet.rows))
249
- wb.save("out.json", pretty=True) # save WorkbookData based on extension
250
- first_sheet.save("sheet.json") # save SheetData the same way
251
- print(first_sheet.to_yaml()) # YAML string (requires pyyaml)
252
- print(first_sheet.to_json(include_backend_metadata=True)) # opt in when needed
253
-
254
- # ExStructEngine: per-instance configuration
255
- from exstruct import (
256
- DestinationOptions,
257
- ExStructEngine,
258
- FilterOptions,
259
- FormatOptions,
260
- OutputOptions,
261
- StructOptions,
262
- export_auto_page_breaks,
263
- )
264
-
265
- engine = ExStructEngine(
266
- options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
267
- output=OutputOptions(
268
- format=FormatOptions(pretty=True),
269
- filters=FilterOptions(
270
- include_shapes=False,
271
- include_backend_metadata=True,
272
- ), # opt into backend metadata when needed
273
- destinations=DestinationOptions(sheets_dir=Path("out_sheets")), # save per-sheet files
274
- ),
275
- )
276
- wb2 = engine.extract("input.xlsx")
277
- engine.export(wb2, Path("out_filtered.json"))
278
-
279
- # Enable hyperlinks in standard mode
280
- engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
281
- with_links = engine_links.extract("input.xlsx")
282
-
283
- # Export one file per print area
284
- from exstruct import export_print_areas_as
285
- export_print_areas_as(wb, "areas", fmt="json", pretty=True)
286
-
287
- # Extract / export auto page-break areas (COM only; raises if no auto breaks exist)
288
- engine_auto = ExStructEngine(
289
- output=OutputOptions(
290
- destinations=DestinationOptions(auto_page_breaks_dir=Path("auto_areas"))
291
- )
292
- )
293
- wb_auto = engine_auto.extract("input.xlsx") # includes SheetData.auto_print_areas
294
- engine_auto.export(wb_auto, Path("out_with_auto.json"))
295
- export_auto_page_breaks(wb_auto, "auto_areas", fmt="json", pretty=True)
296
- ```
297
-
298
- **Note (non-COM environments):** even when Excel COM is unavailable, cells + `table_candidates` are still returned, but `shapes` / `charts` will be empty.
299
-
300
- ## Table Detection Parameters
301
-
302
- ```python
303
- from exstruct import set_table_detection_params
304
-
305
- set_table_detection_params(
306
- table_score_threshold=0.35, # raise it to be stricter
307
- density_min=0.05,
308
- coverage_min=0.2,
309
- min_nonempty_cells=3,
310
- )
311
- ```
312
-
313
- Higher values reduce false positives. Lower values reduce missed detections.
314
-
315
- ## Output Modes
316
-
317
- - **light**: cells + table candidates only (no COM required).
318
- - **standard**: texted shapes + arrows, charts (when COM is available), table candidates, and merged-cell ranges. Cell hyperlinks are emitted only when `include_cell_links=True`.
319
- - **verbose**: all shapes (with width/height), charts, table candidates, merged-cell ranges, hyperlinks, `colors_map`, and `formulas_map`.
320
-
321
- ## Error Handling / Fallback
322
-
323
- - If Excel COM is unavailable, extraction falls back to cells + table candidates automatically, and shapes/charts remain empty.
324
- - If shape extraction fails, ExStruct still returns cells + table candidates and only emits a warning.
325
- - The CLI writes errors to stdout/stderr and exits with a non-zero status on failure.
326
-
327
- ## Optional Rendering
328
-
329
- Excel and `pypdfium2` are required:
330
-
331
- ```bash
332
- exstruct input.xlsx --pdf --image --dpi 144
333
- ```
334
-
335
- This writes `<output>.pdf` and PNG files under `<output>_images/`.
336
-
337
- ## Example 1: Excel Structuring Demo
338
-
339
- To show how far exstruct can structure Excel, we parse an Excel workbook that combines the following three elements on a single sheet and show an LLM reasoning example based on the JSON output.
340
-
341
- - a table (sales data)
342
- - a line chart
343
- - a flowchart built only with shapes
344
-
345
- (The image below is the actual sample Excel sheet.)
346
- ![Sample Excel](docs/assets/demo_sheet.png)
347
- Sample Excel: `sample/sample.xlsx`
348
-
349
- ### 1. Input: Excel Sheet Overview
350
-
351
- This sample Excel contains the following data:
352
-
353
- ### 1) Table (sales data)
354
-
355
- | Month | Product A | Product B | Product C |
356
- | ------ | --------- | --------- | --------- |
357
- | Jan-25 | 120 | 80 | 60 |
358
- | Feb-25 | 135 | 90 | 64 |
359
- | Mar-25 | 150 | 100 | 70 |
360
- | Apr-25 | 170 | 110 | 72 |
361
- | May-25 | 160 | 120 | 75 |
362
- | Jun-25 | 180 | 130 | 80 |
363
-
364
- ### 2) Chart (line chart)
365
-
366
- - Title: Sales Data
367
- - Series: Product A / Product B / Product C (six months)
368
- - Y-axis: 0-200
369
-
370
- ### 3) Flowchart made with shapes
371
-
372
- The sheet includes the following flow:
187
+ - `patch` and `make` print JSON `PatchResult` to stdout.
188
+ - This is the canonical operational / agent interface for workbook editing.
189
+ - `ops list` / `ops describe` expose the public patch-op schema.
190
+ - `validate` reports workbook readability (`is_readable`, `warnings`, `errors`).
191
+ - Phase 2 keeps the legacy extraction CLI unchanged; it does not add
192
+ `exstruct extract` or interactive safety flags yet.
373
193
 
374
- - Start / End
375
- - Format check
376
- - Loop (items remaining?)
377
- - Error handling
378
- - Yes/No decision for sending email
194
+ Recommended edit flow:
379
195
 
380
- ### 2. Output: structured JSON generated by exstruct (excerpt)
196
+ 1. Build patch ops.
197
+ 2. Run `exstruct patch --dry-run` and inspect `PatchResult`, warnings, and diff.
198
+ 3. Pin `--backend openpyxl` when you want the dry run and the real apply to use the same engine.
199
+ 4. If you keep `--backend auto`, inspect `PatchResult.engine`; on Windows/Excel hosts the real apply may switch to COM.
200
+ 5. Re-run without `--dry-run` only after the result is acceptable.
381
201
 
382
- Below is a shortened JSON output example from parsing the workbook above.
383
-
384
- ```json
385
- {
386
- "book_name": "sample.xlsx",
387
- "sheets": {
388
- "Sheet1": {
389
- "rows": [
390
- {
391
- "r": 3,
392
- "c": {
393
- "1": "月",
394
- "2": "製品A",
395
- "3": "製品B",
396
- "4": "製品C"
397
- }
398
- },
399
- ...
400
- ],
401
- "shapes": [
402
- {
403
- "id": 1,
404
- "text": "開始",
405
- "l": 148,
406
- "t": 220,
407
- "kind": "shape",
408
- "type": "AutoShape-FlowchartProcess"
409
- },
410
- {
411
- "id": 2,
412
- "text": "入力データ読み込み",
413
- "l": 132,
414
- "t": 282,
415
- "kind": "shape",
416
- "type": "AutoShape-FlowchartProcess"
417
- },
418
- {
419
- "l": 193,
420
- "t": 246,
421
- "kind": "arrow",
422
- "begin_arrow_style": 1,
423
- "end_arrow_style": 2,
424
- "begin_id": 1,
425
- "end_id": 2,
426
- "direction": "N"
427
- },
428
- ...
429
- ],
430
- "charts": [
431
- {
432
- "name": "Chart 1",
433
- "chart_type": "Line",
434
- "title": "売上データ",
435
- "y_axis_range": [
436
- 0.0,
437
- 200.0
438
- ],
439
- "series": [
440
- {
441
- "name": "製品A",
442
- "name_range": "Sheet1!$C$3",
443
- "x_range": "Sheet1!$B$4:$B$9",
444
- "y_range": "Sheet1!$C$4:$C$9"
445
- },
446
- ...
447
- ],
448
- "l": 377,
449
- "t": 25
450
- }
451
- ],
452
- "table_candidates": [
453
- "B3:E9"
454
- ]
455
- }
456
- }
457
- }
458
- ```
459
-
460
- ### 3. How AI (Copilot / LLM) interprets the JSON
461
-
462
- ````md
463
- Below is a Markdown reconstruction of the Excel workbook. It expresses the table, chart, and flowchart as separate structures.
464
-
465
- ---
466
-
467
- ## Sales Data Table
468
-
469
- | Month | Product A | Product B | Product C |
470
- | ---------- | --------- | --------- | --------- |
471
- | 2025-01-01 | 120 | 80 | 60 |
472
- | 2025-02-01 | 135 | 90 | 64 |
473
- | 2025-03-01 | 150 | 100 | 70 |
474
- | 2025-04-01 | 170 | 110 | 72 |
475
- | 2025-05-01 | 160 | 120 | 75 |
476
- | 2025-06-01 | 180 | 130 | 80 |
477
-
478
- ---
479
-
480
- ## Sales Data (Line Chart)
481
-
482
- - Chart title: **売上データ**
483
- - Chart type: line chart
484
- - Y-axis range: 0 to 200
485
- - Data series:
486
- - Product A: 120 -> 135 -> 150 -> 170 -> 160 -> 180
487
- - Product B: 80 -> 90 -> 100 -> 110 -> 120 -> 130
488
- - Product C: 60 -> 64 -> 70 -> 72 -> 75 -> 80
489
-
490
- ---
491
-
492
- ## Process Flow (Mermaid Flowchart)
493
-
494
- ```mermaid
495
- flowchart TD
496
- A[Start]
497
- B[Load input data]
498
- C{Is the format valid?}
499
- D[Process one item]
500
- E{Items remaining?}
501
- F[Generate output]
502
- G{Send email?}
503
- H[Show error]
504
- I[Send email]
505
- J[Finish]
506
-
507
- A --> B
508
- B --> C
509
- C -->|yes| D
510
- C --> H
511
- D --> E
512
- E --> F
513
- F --> G
514
- G -->|yes| I
515
- G -->|no| J
516
- H --> J
517
- I --> J
518
- ```
519
- ````
520
-
521
- ## Example 2: A General Application Form
522
-
523
- ### Excel data
524
-
525
- ![General application form](docs/assets/demo_form.ja.png)
526
-
527
- ### ExStruct JSON
528
-
529
- (Truncated for brevity)
530
-
531
- ```json
532
- {
533
- "book_name": "ja_form.xlsx",
534
- "sheets": {
535
- "Sheet1": {
536
- "rows": [
537
- { "r": 1, "c": { "0": "介護保険負担限度額認定申請書" } },
538
- {
539
- "r": 3,
540
- "c": { "0": "(申請先)", "7": "     年    月    日" }
541
- },
542
- { "r": 4, "c": { "1": "X市長 " } },
543
- ...
544
- ],
545
- "table_candidates": ["B25:C26", "C37:D50"],
546
- "merged_cells": {
547
- "schema": ["r1", "c1", "r2", "c2", "v"],
548
- "items": [
549
- [55, 5, 55, 10, "申請者が被保険者本人の場合には、下記について記載は不要です。"],
550
- [54, 8, 54, 10, " "],
551
- [51, 5, 52, 6, "有価証券"],
552
- ...
553
- ]
554
- }
555
- }
556
- }
557
- }
558
- ```
559
-
560
- ### ExStruct JSON -> Markdown via LLM reasoning
561
-
562
- ```md
563
- # Long-Term Care Insurance Burden Limit Certification Application
564
-
565
- (Submitted to) Year Month Day
566
- Mayor of City X
567
-
568
- Attach the related documents below and apply for certification of the burden limit for food and housing expenses.
569
-
570
- ---
571
-
572
- ## Insured Person Information
573
-
574
- | Item | Value |
575
- | ---- | ----- |
576
- | Furigana | |
577
- | Name | |
578
- | Insured Person Number | |
579
- | Personal Number | |
580
- | Date of Birth | Meiji / Taisho / Showa Year Month Day |
581
- | Address | |
582
- | Contact | |
583
-
584
- ---
585
-
586
- ## Long-Term Care Facility Entered / Hospitalized In
587
-
588
- | Item | Value |
589
- | ---- | ----- |
590
- | Facility name / location | |
591
- | Contact | |
592
- | Date of entry / admission | Year Month Day |
593
-
594
- If the applicant has not entered a care insurance facility, or uses short stay only, this section is not required.
595
-
596
- ---
597
-
598
- ## Presence of a Spouse
599
-
600
- | Item | Value |
601
- | ---- | ----- |
602
- | Spouse | Yes / No |
603
-
604
- If "No", the following spouse section is not required.
605
-
606
- ---
607
-
608
- ## Notes
609
-
610
- 1. In this application, "spouse" includes a spouse living separately and a common-law partner.
611
- 2. If you own multiple assets of the same kind, list all of them and attach copies of bankbooks or equivalent documents.
612
- 3. If there is not enough space, write on the margin or on a separate sheet and attach it.
613
- 4. If benefits are obtained through a false declaration, the paid amount and up to twice that amount as an additional charge may need to be repaid under Article 22, Paragraph 1 of the Long-Term Care Insurance Act.
614
- ```
615
-
616
- ## Discussion
617
-
618
- The result above shows the following clearly:
619
-
620
- **ExStruct JSON is already in a format that AI can understand semantically as-is.**
621
-
622
- Other LLM inference samples built with this library are available in the following directories:
623
-
624
- - [Basic Excel](sample/basic/)
625
- - [Flowchart](sample/flowchart/)
626
- - [Gantt Chart](sample/gantt_chart/)
627
- - [Application forms with many merged cells](sample/forms_with_many_merged_cells/)
628
-
629
- ### 4. Summary
630
-
631
- This benchmark demonstrates that the library can:
632
-
633
- - analyze tables, charts, and shapes (flowcharts) at the same time
634
- - convert Excel's semantic structure into JSON
635
- - let AI/LLMs read that JSON directly and reconstruct workbook content
636
-
637
- In short, **exstruct = "an engine that converts Excel into a format AI can understand."**
638
-
639
- ## Benchmark
640
-
641
- ![Benchmark Chart](benchmark/public/plots/markdown_quality.png)
642
-
643
- This repository includes benchmark reports focused on RAG/LLM preprocessing of Excel documents.
644
- We track two perspectives: (1) core extraction accuracy and (2) reconstruction utility for downstream structure queries (RUB).
645
- See `benchmark/REPORT.md` for the working summary and `benchmark/public/REPORT.md` for the public bundle.
646
- Current results are based on n=12 cases and will be expanded further.
647
-
648
- ## Notes
649
-
650
- - Default JSON is compact to reduce token usage. Use `--pretty` / `pretty=True` when readability matters.
651
- - The field name is `table_candidates` (replacing the old `tables`). Adjust downstream schemas accordingly.
652
-
653
- ## Enterprise Use
654
-
655
- ExStruct is intended primarily for **library** use, not as a service.
656
-
657
- - no official support or SLA is provided
658
- - long-term stability is prioritized over rapid feature growth
659
- - enterprise use is expected to involve forking or internal customization
660
-
661
- It is suitable for teams that:
662
-
663
- - need transparency instead of black-box tooling
664
- - are comfortable maintaining internal forks when needed
665
-
666
- ## Print Areas and Auto Page-Break Areas (PrintArea / PrintAreaView)
667
-
668
- - `SheetData.print_areas` contains print areas (cell coordinates) in `light` / `standard` / `verbose`.
669
- - `SheetData.auto_print_areas` contains Excel COM-computed auto page-break areas only when auto page-break extraction is enabled (COM only).
670
- - Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to export one file per print area. If no print areas exist, nothing is written.
671
- - Use CLI `--auto-page-breaks-dir` (COM only), `DestinationOptions.auto_page_breaks_dir` (recommended), or `export_auto_page_breaks(...)` to export one file per auto page-break area. `export_auto_page_breaks(...)` raises `ValueError` when no auto page breaks exist.
672
- - `PrintAreaView` includes rows and table candidates inside the area, plus shapes/charts that intersect the area. When shape size is unknown, point-based overlap is used. With `normalize=True`, row/column indices are rebased to the area origin.
673
-
674
- ## Architecture
675
-
676
- ExStruct adopts a pipeline-oriented architecture that separates extraction strategy (Backend), orchestration (Pipeline), and semantic modeling.
677
-
678
- See: [docs/architecture/pipeline.md](docs/architecture/pipeline.md)
679
-
680
- ## Contributing
681
-
682
- If you plan to extend ExStruct internals, read the contributor architecture guide first.
683
-
684
- See: [docs/contributors/architecture.md](docs/contributors/architecture.md)
685
-
686
- ## Coverage Note
687
-
688
- The cell-structure inference logic (`cells.py`) depends on heuristic rules and Excel-specific behavior. Full coverage is intentionally not pursued, because exhaustive tests would not reflect real-world reliability.
689
-
690
- ## License
691
-
692
- BSD-3-Clause. See `LICENSE` for details.
693
-
694
- ## Documentation
695
-
696
- - API reference (GitHub Pages): https://harumiweb.github.io/exstruct/
697
- - JSON schemas are stored in `schemas/`, one file per model. Regenerate them with `python scripts/gen_json_schema.py` after model changes.
698
-
699
- ## Star History
202
+ ## MCP Server (stdio)
700
203
 
701
- [![Star History Chart](https://api.star-history.com/image?repos=harumiWeb/exstruct&type=date&legend=top-left)](https://www.star-history.com/?repos=harumiWeb%2Fexstruct&type=date&legend=top-left)
204
+ MCP is the integration / compatibility layer around the same editing core. Use
205
+ it when you need host-managed path restrictions, transport mapping, artifact
206
+ mirroring, or approval-aware agent execution. For ordinary Python workbook
207
+ editing, `openpyxl` / `xlwings` are usually a better fit. For local shell or
208
+ agent workflows, prefer the editing CLI.
209
+
210
+ If you previously used `exstruct_patch` / `exstruct_make` only because editing
211
+ was MCP-first, migrate new local workflows to `exstruct patch` or
212
+ `exstruct make` unless you specifically need MCP host controls or the shared
213
+ patch contract inside Python.
214
+
215
+ ### Quick Start with `uvx` (recommended)
216
+
217
+ You can run it directly without installation:
218
+
219
+ ```bash
220
+ uvx --from 'exstruct[mcp]' exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
221
+ ```
222
+
223
+ Benefits:
224
+
225
+ - no `pip install` required
226
+ - automatic dependency management
227
+ - isolated environment
228
+ - easy version pinning: `uvx --from 'exstruct[mcp]==0.4.4' exstruct-mcp`
229
+
230
+ ### Traditional installation
231
+
232
+ You can also install it with pip:
233
+
234
+ ```bash
235
+ pip install exstruct[mcp]
236
+ exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
237
+ ```
238
+
239
+ Available tools:
240
+
241
+ - `exstruct_extract`
242
+ - `exstruct_capture_sheet_images`
243
+ - `exstruct_make`
244
+ - `exstruct_patch`
245
+ - `exstruct_read_json_chunk`
246
+ - `exstruct_read_range`
247
+ - `exstruct_read_cells`
248
+ - `exstruct_read_formulas`
249
+ - `exstruct_validate_input`
250
+
251
+ Notes:
252
+
253
+ - `exstruct_capture_sheet_images` is COM-only (Experimental) and supports optional `sheet` / `range` targeting (`A1:B2`, `Sheet1!A1:B2`, `'Sheet 1'!A1:B2`). When `out_dir` is omitted, it creates a unique `<workbook_stem>_images` directory under MCP `--root`.
254
+ - MCP server startup defaults `EXSTRUCT_RENDER_SUBPROCESS=1` via `setdefault`. If you want in-process execution instead, set `EXSTRUCT_RENDER_SUBPROCESS=0` before launching the server.
255
+ - Timeout tuning for `exstruct_capture_sheet_images`: `EXSTRUCT_MCP_CAPTURE_SHEET_IMAGES_TIMEOUT_SEC` (overall tool timeout), `EXSTRUCT_RENDER_SUBPROCESS_STARTUP_TIMEOUT_SEC` (worker startup), `EXSTRUCT_RENDER_SUBPROCESS_JOIN_TIMEOUT_SEC` (primary wait budget), and `EXSTRUCT_RENDER_SUBPROCESS_RESULT_TIMEOUT_SEC` (post-exit grace).
256
+ - Subprocess failures return `stage=startup|join|result|worker`, which lets MCP clients distinguish bootstrap failures, timeouts, and worker-side rendering failures.
257
+ - Trade-off of `EXSTRUCT_RENDER_SUBPROCESS=1`: extra subprocess startup/coordination overhead and more dependency on worker-side module resolution.
258
+ - Trade-off of `EXSTRUCT_RENDER_SUBPROCESS=0`: weaker crash isolation and higher memory pressure risk in long-running processes.
259
+ - Logs are written to stderr, and optionally to `--log-file`, to keep stdio responses clean.
260
+ - On Windows with Excel, `standard` / `verbose` use COM for the richest extraction.
261
+ - On Linux/macOS/server environments, `libreoffice` is the best-effort rich mode. It is not a strict subset of COM output; shapes, connectors, and charts are reconstructed from LibreOffice + OOXML metadata and may differ in fidelity.
262
+ - In v1, `libreoffice` does not render PDFs/PNGs and does not compute auto page-break areas.
263
+ - `exstruct_patch` supports `backend` selection.
264
+ - `auto` (default): prefer COM when available, otherwise openpyxl
265
+ - `com`: force COM (`dry_run` / `return_inverse_ops` / `preflight_formula_check` are not allowed)
266
+ - `openpyxl`: force openpyxl (`.xls` is not supported)
267
+ - `create_chart` is COM-only. Requests that include `create_chart` cannot use `backend="openpyxl"`, and they also reject `dry_run`, `return_inverse_ops`, and `preflight_formula_check`.
268
+ - `create_chart` supports `chart_type` values `line`, `column`, `bar`, `area`, `pie`, `doughnut`, `scatter`, and `radar` (aliases: `column_clustered`, `bar_clustered`, `xy_scatter`, `donut`).
269
+ - `create_chart` accepts either a single range string or `list[str]` for `data_range`, and both `data_range` and `category_range` support sheet-qualified ranges such as `Sheet2!A1:B10` and `'Sales Data'!A1:B10`.
270
+ - `create_chart` also supports explicit titles with `chart_title`, `x_axis_title`, and `y_axis_title`.
271
+ - `create_chart` and `apply_table_style` can be combined in one request when the backend resolves to COM (`backend="com"` or COM-capable `backend="auto"`).
272
+ - For stable COM execution of `apply_table_style` on Windows, make sure desktop Excel is installed and runnable, and that the target `range` is a contiguous A1 range including the header row.
273
+ - `exstruct_patch` error details may include `error_code`, `failed_field`, and `raw_com_message`. Table-related codes include `table_style_invalid`, `list_object_add_failed`, and `com_api_missing`.
274
+ - `exstruct_patch` responses include the actual backend in `engine` (`com` / `openpyxl`). `restore_design_snapshot` remains openpyxl-only.
275
+ - Use `exstruct_make` for creating new workbooks and `exstruct_patch` for editing existing ones.
276
+ - `exstruct_make` creates a new workbook and applies `ops` in one call (`out_path` required, `ops` optional).
277
+ - supported extensions: `.xlsx` / `.xlsm` / `.xls`
278
+ - the initial sheet name is normalized to `Sheet1`
279
+ - `.xls` requires COM, so `backend=openpyxl` is not allowed
280
+
281
+ MCP setup guide for each AI agent:
282
+
283
+ [MCP Server](https://harumiweb.github.io/exstruct/mcp/)
284
+
285
+ ## Quick Start Python Extraction
286
+
287
+ ```python
288
+ from pathlib import Path
289
+ from exstruct import extract, export, set_table_detection_params
290
+
291
+ # Tune table detection (optional)
292
+ set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
293
+
294
+ # Modes: "light" / "standard" / "verbose"
295
+ wb = extract("input.xlsx", mode="standard") # standard does not emit links by default
296
+ export(wb, Path("out.json"), pretty=False) # compact JSON
297
+ export(wb, Path("out.json"), include_backend_metadata=True) # opt into backend metadata
298
+
299
+ # Helpful model methods: iteration, indexing, and direct serialization
300
+ first_sheet = wb["Sheet1"] # get a sheet with __getitem__
301
+ for name, sheet in wb: # __iter__ yields (name, SheetData)
302
+ print(name, len(sheet.rows))
303
+ wb.save("out.json", pretty=True) # save WorkbookData based on extension
304
+ first_sheet.save("sheet.json") # save SheetData the same way
305
+ print(first_sheet.to_yaml()) # YAML string (requires pyyaml)
306
+ print(first_sheet.to_json(include_backend_metadata=True)) # opt in when needed
307
+
308
+ # ExStructEngine: per-instance configuration
309
+ from exstruct import (
310
+ DestinationOptions,
311
+ ExStructEngine,
312
+ FilterOptions,
313
+ FormatOptions,
314
+ OutputOptions,
315
+ StructOptions,
316
+ export_auto_page_breaks,
317
+ )
318
+
319
+ engine = ExStructEngine(
320
+ options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
321
+ output=OutputOptions(
322
+ format=FormatOptions(pretty=True),
323
+ filters=FilterOptions(
324
+ include_shapes=False,
325
+ include_backend_metadata=True,
326
+ ), # opt into backend metadata when needed
327
+ destinations=DestinationOptions(sheets_dir=Path("out_sheets")), # save per-sheet files
328
+ ),
329
+ )
330
+ wb2 = engine.extract("input.xlsx")
331
+ engine.export(wb2, Path("out_filtered.json"))
332
+
333
+ # Enable hyperlinks in standard mode
334
+ engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
335
+ with_links = engine_links.extract("input.xlsx")
336
+
337
+ # Export one file per print area
338
+ from exstruct import export_print_areas_as
339
+ export_print_areas_as(wb, "areas", fmt="json", pretty=True)
340
+
341
+ # Extract / export auto page-break areas (COM only; raises if no auto breaks exist)
342
+ engine_auto = ExStructEngine(
343
+ output=OutputOptions(
344
+ destinations=DestinationOptions(auto_page_breaks_dir=Path("auto_areas"))
345
+ )
346
+ )
347
+ wb_auto = engine_auto.extract("input.xlsx") # includes SheetData.auto_print_areas
348
+ engine_auto.export(wb_auto, Path("out_with_auto.json"))
349
+ export_auto_page_breaks(wb_auto, "auto_areas", fmt="json", pretty=True)
350
+ ```
351
+
352
+ **Note (non-COM environments):** even when Excel COM is unavailable, cells + `table_candidates` are still returned, but `shapes` / `charts` will be empty.
353
+
354
+ ## Table Detection Parameters
355
+
356
+ ```python
357
+ from exstruct import set_table_detection_params
358
+
359
+ set_table_detection_params(
360
+ table_score_threshold=0.35, # raise it to be stricter
361
+ density_min=0.05,
362
+ coverage_min=0.2,
363
+ min_nonempty_cells=3,
364
+ )
365
+ ```
366
+
367
+ Higher values reduce false positives. Lower values reduce missed detections.
368
+
369
+ ## Output Modes
370
+
371
+ - **light**: cells + table candidates only (no COM required).
372
+ - **standard**: texted shapes + arrows, charts (when COM is available), table candidates, and merged-cell ranges. Cell hyperlinks are emitted only when `include_cell_links=True`.
373
+ - **verbose**: all shapes (with width/height), charts, table candidates, merged-cell ranges, hyperlinks, `colors_map`, and `formulas_map`.
374
+
375
+ ## Error Handling / Fallback
376
+
377
+ - If Excel COM is unavailable, extraction falls back to cells + table candidates automatically, and shapes/charts remain empty.
378
+ - If shape extraction fails, ExStruct still returns cells + table candidates and only emits a warning.
379
+ - The CLI writes errors to stdout/stderr and exits with a non-zero status on failure.
380
+
381
+ ## Optional Rendering
382
+
383
+ Excel and `pypdfium2` are required:
384
+
385
+ ```bash
386
+ exstruct input.xlsx --pdf --image --dpi 144
387
+ ```
388
+
389
+ This writes `<output>.pdf` and PNG files under `<output>_images/`.
390
+
391
+ ## Example 1: Excel Structuring Demo
392
+
393
+ To show how far exstruct can structure Excel, we parse an Excel workbook that combines the following three elements on a single sheet and show an LLM reasoning example based on the JSON output.
394
+
395
+ - a table (sales data)
396
+ - a line chart
397
+ - a flowchart built only with shapes
398
+
399
+ (The image below is the actual sample Excel sheet.)
400
+ <img width="1842" height="1242" alt="demo_sheet" src="https://github.com/user-attachments/assets/91f32b64-02a9-4269-a13f-9909e6e5b06f" />
401
+ Sample Excel: `sample/sample.xlsx`
402
+
403
+ ### 1. Input: Excel Sheet Overview
404
+
405
+ This sample Excel contains the following data:
406
+
407
+ ### 1) Table (sales data)
408
+
409
+ | Month | Product A | Product B | Product C |
410
+ | ------ | --------- | --------- | --------- |
411
+ | Jan-25 | 120 | 80 | 60 |
412
+ | Feb-25 | 135 | 90 | 64 |
413
+ | Mar-25 | 150 | 100 | 70 |
414
+ | Apr-25 | 170 | 110 | 72 |
415
+ | May-25 | 160 | 120 | 75 |
416
+ | Jun-25 | 180 | 130 | 80 |
417
+
418
+ ### 2) Chart (line chart)
419
+
420
+ - Title: Sales Data
421
+ - Series: Product A / Product B / Product C (six months)
422
+ - Y-axis: 0-200
423
+
424
+ ### 3) Flowchart made with shapes
425
+
426
+ The sheet includes the following flow:
427
+
428
+ - Start / End
429
+ - Format check
430
+ - Loop (items remaining?)
431
+ - Error handling
432
+ - Yes/No decision for sending email
433
+
434
+ ### 2. Output: structured JSON generated by exstruct (excerpt)
435
+
436
+ Below is a shortened JSON output example from parsing the workbook above.
437
+
438
+ ```json
439
+ {
440
+ "book_name": "sample.xlsx",
441
+ "sheets": {
442
+ "Sheet1": {
443
+ "rows": [
444
+ {
445
+ "r": 3,
446
+ "c": {
447
+ "1": "月",
448
+ "2": "製品A",
449
+ "3": "製品B",
450
+ "4": "製品C"
451
+ }
452
+ },
453
+ ...
454
+ ],
455
+ "shapes": [
456
+ {
457
+ "id": 1,
458
+ "text": "開始",
459
+ "l": 148,
460
+ "t": 220,
461
+ "kind": "shape",
462
+ "type": "AutoShape-FlowchartProcess"
463
+ },
464
+ {
465
+ "id": 2,
466
+ "text": "入力データ読み込み",
467
+ "l": 132,
468
+ "t": 282,
469
+ "kind": "shape",
470
+ "type": "AutoShape-FlowchartProcess"
471
+ },
472
+ {
473
+ "l": 193,
474
+ "t": 246,
475
+ "kind": "arrow",
476
+ "begin_arrow_style": 1,
477
+ "end_arrow_style": 2,
478
+ "begin_id": 1,
479
+ "end_id": 2,
480
+ "direction": "N"
481
+ },
482
+ ...
483
+ ],
484
+ "charts": [
485
+ {
486
+ "name": "Chart 1",
487
+ "chart_type": "Line",
488
+ "title": "売上データ",
489
+ "y_axis_range": [
490
+ 0.0,
491
+ 200.0
492
+ ],
493
+ "series": [
494
+ {
495
+ "name": "製品A",
496
+ "name_range": "Sheet1!$C$3",
497
+ "x_range": "Sheet1!$B$4:$B$9",
498
+ "y_range": "Sheet1!$C$4:$C$9"
499
+ },
500
+ ...
501
+ ],
502
+ "l": 377,
503
+ "t": 25
504
+ }
505
+ ],
506
+ "table_candidates": [
507
+ "B3:E9"
508
+ ]
509
+ }
510
+ }
511
+ }
512
+ ```
513
+
514
+ ### 3. How AI (Copilot / LLM) interprets the JSON
515
+
516
+ ````md
517
+ Below is a Markdown reconstruction of the Excel workbook. It expresses the table, chart, and flowchart as separate structures.
518
+
519
+ ---
520
+
521
+ ## Sales Data Table
522
+
523
+ | Month | Product A | Product B | Product C |
524
+ | ---------- | --------- | --------- | --------- |
525
+ | 2025-01-01 | 120 | 80 | 60 |
526
+ | 2025-02-01 | 135 | 90 | 64 |
527
+ | 2025-03-01 | 150 | 100 | 70 |
528
+ | 2025-04-01 | 170 | 110 | 72 |
529
+ | 2025-05-01 | 160 | 120 | 75 |
530
+ | 2025-06-01 | 180 | 130 | 80 |
531
+
532
+ ---
533
+
534
+ ## Sales Data (Line Chart)
535
+
536
+ - Chart title: **売上データ**
537
+ - Chart type: line chart
538
+ - Y-axis range: 0 to 200
539
+ - Data series:
540
+ - Product A: 120 -> 135 -> 150 -> 170 -> 160 -> 180
541
+ - Product B: 80 -> 90 -> 100 -> 110 -> 120 -> 130
542
+ - Product C: 60 -> 64 -> 70 -> 72 -> 75 -> 80
543
+
544
+ ---
545
+
546
+ ## Process Flow (Mermaid Flowchart)
547
+
548
+ ```mermaid
549
+ flowchart TD
550
+ A[Start]
551
+ B[Load input data]
552
+ C{Is the format valid?}
553
+ D[Process one item]
554
+ E{Items remaining?}
555
+ F[Generate output]
556
+ G{Send email?}
557
+ H[Show error]
558
+ I[Send email]
559
+ J[Finish]
560
+
561
+ A --> B
562
+ B --> C
563
+ C -->|yes| D
564
+ C --> H
565
+ D --> E
566
+ E --> F
567
+ F --> G
568
+ G -->|yes| I
569
+ G -->|no| J
570
+ H --> J
571
+ I --> J
572
+ ```
573
+ ````
574
+
575
+ ## Example 2: A General Application Form
576
+
577
+ ### Excel data
578
+
579
+ <img width="1040" height="1615" alt="demo_form ja" src="https://github.com/user-attachments/assets/1997c5d7-eb93-4370-b2ff-6e8da34e79a0" />
580
+
581
+ ### ExStruct JSON
582
+
583
+ (Truncated for brevity)
584
+
585
+ ```json
586
+ {
587
+ "book_name": "ja_form.xlsx",
588
+ "sheets": {
589
+ "Sheet1": {
590
+ "rows": [
591
+ { "r": 1, "c": { "0": "介護保険負担限度額認定申請書" } },
592
+ {
593
+ "r": 3,
594
+ "c": { "0": "(申請先)", "7": "     年    月    日" }
595
+ },
596
+ { "r": 4, "c": { "1": "X市長 " } },
597
+ ...
598
+ ],
599
+ "table_candidates": ["B25:C26", "C37:D50"],
600
+ "merged_cells": {
601
+ "schema": ["r1", "c1", "r2", "c2", "v"],
602
+ "items": [
603
+ [55, 5, 55, 10, "申請者が被保険者本人の場合には、下記について記載は不要です。"],
604
+ [54, 8, 54, 10, " "],
605
+ [51, 5, 52, 6, "有価証券"],
606
+ ...
607
+ ]
608
+ }
609
+ }
610
+ }
611
+ }
612
+ ```
613
+
614
+ ### ExStruct JSON -> Markdown via LLM reasoning
615
+
616
+ ```md
617
+ # Long-Term Care Insurance Burden Limit Certification Application
618
+
619
+ (Submitted to) Year Month Day
620
+ Mayor of City X
621
+
622
+ Attach the related documents below and apply for certification of the burden limit for food and housing expenses.
623
+
624
+ ---
625
+
626
+ ## Insured Person Information
627
+
628
+ | Item | Value |
629
+ | ---- | ----- |
630
+ | Furigana | |
631
+ | Name | |
632
+ | Insured Person Number | |
633
+ | Personal Number | |
634
+ | Date of Birth | Meiji / Taisho / Showa Year Month Day |
635
+ | Address | |
636
+ | Contact | |
637
+
638
+ ---
639
+
640
+ ## Long-Term Care Facility Entered / Hospitalized In
641
+
642
+ | Item | Value |
643
+ | ---- | ----- |
644
+ | Facility name / location | |
645
+ | Contact | |
646
+ | Date of entry / admission | Year Month Day |
647
+
648
+ If the applicant has not entered a care insurance facility, or uses short stay only, this section is not required.
649
+
650
+ ---
651
+
652
+ ## Presence of a Spouse
653
+
654
+ | Item | Value |
655
+ | ---- | ----- |
656
+ | Spouse | Yes / No |
657
+
658
+ If "No", the following spouse section is not required.
659
+
660
+ ---
661
+
662
+ ## Notes
663
+
664
+ 1. In this application, "spouse" includes a spouse living separately and a common-law partner.
665
+ 2. If you own multiple assets of the same kind, list all of them and attach copies of bankbooks or equivalent documents.
666
+ 3. If there is not enough space, write on the margin or on a separate sheet and attach it.
667
+ 4. If benefits are obtained through a false declaration, the paid amount and up to twice that amount as an additional charge may need to be repaid under Article 22, Paragraph 1 of the Long-Term Care Insurance Act.
668
+ ```
669
+
670
+ ## Discussion
671
+
672
+ The result above shows the following clearly:
673
+
674
+ **ExStruct JSON is already in a format that AI can understand semantically as-is.**
675
+
676
+ Other LLM inference samples built with this library are available in the following directories:
677
+
678
+ - [Basic Excel](sample/basic/)
679
+ - [Flowchart](sample/flowchart/)
680
+ - [Gantt Chart](sample/gantt_chart/)
681
+ - [Application forms with many merged cells](sample/forms_with_many_merged_cells/)
682
+
683
+ ### 4. Summary
684
+
685
+ This benchmark demonstrates that the library can:
686
+
687
+ - analyze tables, charts, and shapes (flowcharts) at the same time
688
+ - convert Excel's semantic structure into JSON
689
+ - let AI/LLMs read that JSON directly and reconstruct workbook content
690
+
691
+ In short, **exstruct = "an engine that converts Excel into a format AI can understand."**
692
+
693
+ ## Benchmark
694
+
695
+ <img width="1440" height="720" alt="markdown_quality" src="https://github.com/user-attachments/assets/537bbc8c-8e09-433d-a910-6521274d2df5" />
696
+
697
+ This repository includes benchmark reports focused on RAG/LLM preprocessing of Excel documents.
698
+ We track two perspectives: (1) core extraction accuracy and (2) reconstruction utility for downstream structure queries (RUB).
699
+ See `benchmark/REPORT.md` for the working summary and `benchmark/public/REPORT.md` for the public bundle.
700
+ Current results are based on n=12 cases and will be expanded further.
701
+
702
+ ## Notes
703
+
704
+ - Default JSON is compact to reduce token usage. Use `--pretty` / `pretty=True` when readability matters.
705
+ - The field name is `table_candidates` (replacing the old `tables`). Adjust downstream schemas accordingly.
706
+
707
+ ## Enterprise Use
708
+
709
+ ExStruct is intended primarily for **library** use, not as a service.
710
+
711
+ - no official support or SLA is provided
712
+ - long-term stability is prioritized over rapid feature growth
713
+ - enterprise use is expected to involve forking or internal customization
714
+
715
+ It is suitable for teams that:
716
+
717
+ - need transparency instead of black-box tooling
718
+ - are comfortable maintaining internal forks when needed
719
+
720
+ ## Print Areas and Auto Page-Break Areas (PrintArea / PrintAreaView)
721
+
722
+ - `SheetData.print_areas` contains print areas (cell coordinates) in `light` / `standard` / `verbose`.
723
+ - `SheetData.auto_print_areas` contains Excel COM-computed auto page-break areas only when auto page-break extraction is enabled (COM only).
724
+ - Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to export one file per print area. If no print areas exist, nothing is written.
725
+ - Use CLI `--auto-page-breaks-dir` (COM only), `DestinationOptions.auto_page_breaks_dir` (recommended), or `export_auto_page_breaks(...)` to export one file per auto page-break area. `export_auto_page_breaks(...)` raises `ValueError` when no auto page breaks exist.
726
+ - `PrintAreaView` includes rows and table candidates inside the area, plus shapes/charts that intersect the area. When shape size is unknown, point-based overlap is used. With `normalize=True`, row/column indices are rebased to the area origin.
727
+
728
+ ## Architecture
729
+
730
+ ExStruct adopts a pipeline-oriented architecture that separates extraction strategy (Backend), orchestration (Pipeline), and semantic modeling.
731
+
732
+ See: [dev-docs/architecture/pipeline.md](dev-docs/architecture/pipeline.md)
733
+
734
+ ## Contributing
735
+
736
+ If you plan to extend ExStruct internals, read the contributor architecture guide first.
737
+
738
+ See: [dev-docs/architecture/contributor-guide.md](dev-docs/architecture/contributor-guide.md)
739
+
740
+ ## Coverage Note
741
+
742
+ The cell-structure inference logic (`cells.py`) depends on heuristic rules and Excel-specific behavior. Full coverage is intentionally not pursued, because exhaustive tests would not reflect real-world reliability.
743
+
744
+ ## License
745
+
746
+ BSD-3-Clause. See `LICENSE` for details.
747
+
748
+ ## Documentation
749
+
750
+ - API reference (GitHub Pages): https://harumiweb.github.io/exstruct/
751
+ - JSON schemas are stored in `schemas/`, one file per model. Regenerate them with `python scripts/gen_json_schema.py` after model changes.
752
+
753
+ ## Star History
754
+
755
+ [![Star History Chart](https://api.star-history.com/image?repos=harumiWeb/exstruct&type=date&legend=top-left)](https://www.star-history.com/?repos=harumiWeb%2Fexstruct&type=date&legend=top-left)