exstruct 0.4.2__tar.gz → 0.5.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 (62) hide show
  1. {exstruct-0.4.2 → exstruct-0.5.0}/PKG-INFO +49 -5
  2. {exstruct-0.4.2 → exstruct-0.5.0}/README.md +46 -2
  3. {exstruct-0.4.2 → exstruct-0.5.0}/pyproject.toml +14 -6
  4. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/__init__.py +18 -2
  5. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/cli/main.py +6 -0
  6. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/engine.py +11 -2
  7. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/errors.py +2 -2
  8. exstruct-0.5.0/src/exstruct/mcp/__init__.py +145 -0
  9. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/mcp/chunk_reader.py +450 -413
  10. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/mcp/extract_runner.py +296 -309
  11. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/mcp/io.py +71 -61
  12. exstruct-0.5.0/src/exstruct/mcp/op_schema.py +405 -0
  13. exstruct-0.5.0/src/exstruct/mcp/patch/__init__.py +13 -0
  14. exstruct-0.5.0/src/exstruct/mcp/patch/engine/__init__.py +6 -0
  15. exstruct-0.5.0/src/exstruct/mcp/patch/engine/base.py +34 -0
  16. exstruct-0.5.0/src/exstruct/mcp/patch/engine/openpyxl_engine.py +18 -0
  17. exstruct-0.5.0/src/exstruct/mcp/patch/engine/xlwings_engine.py +19 -0
  18. exstruct-0.5.0/src/exstruct/mcp/patch/internal.py +3930 -0
  19. exstruct-0.5.0/src/exstruct/mcp/patch/models.py +1427 -0
  20. exstruct-0.5.0/src/exstruct/mcp/patch/normalize.py +181 -0
  21. exstruct-0.5.0/src/exstruct/mcp/patch/ops/__init__.py +6 -0
  22. exstruct-0.5.0/src/exstruct/mcp/patch/ops/common.py +7 -0
  23. exstruct-0.5.0/src/exstruct/mcp/patch/ops/openpyxl_ops.py +29 -0
  24. exstruct-0.5.0/src/exstruct/mcp/patch/ops/xlwings_ops.py +26 -0
  25. exstruct-0.5.0/src/exstruct/mcp/patch/runtime.py +153 -0
  26. exstruct-0.5.0/src/exstruct/mcp/patch/service.py +325 -0
  27. exstruct-0.5.0/src/exstruct/mcp/patch/specs.py +57 -0
  28. exstruct-0.5.0/src/exstruct/mcp/patch/types.py +52 -0
  29. exstruct-0.5.0/src/exstruct/mcp/patch_runner.py +74 -0
  30. exstruct-0.5.0/src/exstruct/mcp/server.py +798 -0
  31. exstruct-0.5.0/src/exstruct/mcp/shared/__init__.py +23 -0
  32. exstruct-0.5.0/src/exstruct/mcp/shared/a1.py +82 -0
  33. exstruct-0.5.0/src/exstruct/mcp/shared/output_path.py +85 -0
  34. exstruct-0.5.0/src/exstruct/mcp/sheet_reader.py +472 -0
  35. exstruct-0.5.0/src/exstruct/mcp/tools.py +783 -0
  36. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/mcp/validate_input.py +76 -76
  37. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/models/__init__.py +156 -1
  38. exstruct-0.4.2/src/exstruct/mcp/__init__.py +0 -59
  39. exstruct-0.4.2/src/exstruct/mcp/server.py +0 -312
  40. exstruct-0.4.2/src/exstruct/mcp/tools.py +0 -203
  41. {exstruct-0.4.2 → exstruct-0.5.0}/LICENSE +0 -0
  42. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/cli/availability.py +0 -0
  43. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/__init__.py +0 -0
  44. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/backends/__init__.py +0 -0
  45. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/backends/base.py +0 -0
  46. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/backends/com_backend.py +0 -0
  47. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/backends/openpyxl_backend.py +0 -0
  48. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/cells.py +0 -0
  49. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/charts.py +0 -0
  50. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/integrate.py +0 -0
  51. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/logging_utils.py +0 -0
  52. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/modeling.py +0 -0
  53. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/pipeline.py +0 -0
  54. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/ranges.py +0 -0
  55. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/shapes.py +0 -0
  56. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/core/workbook.py +0 -0
  57. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/io/__init__.py +0 -0
  58. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/io/serialize.py +0 -0
  59. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/models/maps.py +0 -0
  60. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/models/types.py +0 -0
  61. {exstruct-0.4.2 → exstruct-0.5.0}/src/exstruct/py.typed +0 -0
  62. {exstruct-0.4.2 → exstruct-0.5.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.4.2
3
+ Version: 0.5.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
@@ -43,9 +43,9 @@ Requires-Dist: pyyaml>=6.0.3 ; extra == 'all'
43
43
  Requires-Dist: python-toon>=0.1.3 ; extra == 'all'
44
44
  Requires-Dist: pypdfium2>=5.1.0 ; extra == 'all'
45
45
  Requires-Dist: pillow>=12.0.0 ; extra == 'all'
46
- Requires-Dist: mcp>=1.6.0,<2.0.0 ; extra == 'all'
46
+ Requires-Dist: mcp>=1.25.0,<2.0.0 ; extra == 'all'
47
47
  Requires-Dist: httpx>=0.27,<1.0 ; extra == 'all'
48
- Requires-Dist: mcp>=1.6.0,<2.0.0 ; extra == 'mcp'
48
+ Requires-Dist: mcp>=1.25.0,<2.0.0 ; extra == 'mcp'
49
49
  Requires-Dist: httpx>=0.27,<1.0 ; extra == 'mcp'
50
50
  Requires-Dist: pypdfium2>=5.1.0 ; extra == 'render'
51
51
  Requires-Dist: pillow>=12.0.0 ; extra == 'render'
@@ -65,7 +65,8 @@ Description-Content-Type: text/markdown
65
65
 
66
66
  # ExStruct — Excel Structured Extraction Engine
67
67
 
68
- [![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)
68
+ [![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)
69
+
69
70
 
70
71
  ![ExStruct Image](docs/assets/icon.webp)
71
72
 
@@ -84,6 +85,15 @@ ExStruct reads Excel workbooks and outputs structured data (cells, table candida
84
85
  - **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
85
86
  - **Graceful fallback**: if Excel COM is unavailable, extraction falls back to cells + table candidates without crashing.
86
87
 
88
+ ## Benchmark
89
+
90
+ ![Benchmark Chart](benchmark/public/plots/markdown_quality.png)
91
+
92
+ This repository includes benchmark reports focused on RAG/LLM preprocessing of Excel documents.
93
+ We track two perspectives: (1) core extraction accuracy and (2) reconstruction utility for downstream structure queries (RUB).
94
+ See `benchmark/REPORT.md` for the working summary and `benchmark/public/REPORT.md` for the public bundle.
95
+ Current results are based on n=12 cases and will be expanded.
96
+
87
97
  ## Installation
88
98
 
89
99
  ```bash
@@ -111,15 +121,34 @@ exstruct input.xlsx --format toon # TOON (needs python-toon)
111
121
  exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
112
122
  exstruct input.xlsx --auto-page-breaks-dir auto_areas/ # COM only; option appears when available
113
123
  exstruct input.xlsx --print-areas-dir areas/ # split per print area (if any)
124
+ exstruct input.xlsx --alpha-col # output column keys as A, B, ..., AA
114
125
  exstruct input.xlsx --mode light # cells + table candidates only
115
126
  exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
116
127
  ```
117
128
 
118
129
  Auto page-break exports are available via API and CLI when Excel/COM is available; the CLI exposes `--auto-page-breaks-dir` only in COM-capable environments.
130
+ By default, CLI keeps legacy 0-based numeric string column keys (`"0"`, `"1"`, ...). Use `--alpha-col` to emit Excel-style column keys (`"A"`, `"B"`, ...).
131
+ Note: MCP `exstruct_extract` defaults to `options.alpha_col=true`, while CLI defaults to `false` unless `--alpha-col` is specified.
119
132
 
120
133
  ## MCP Server (stdio)
121
134
 
122
- Install the MCP extras and run the stdio server:
135
+ ### Quick Start with uvx (recommended)
136
+
137
+ Run directly without installation:
138
+
139
+ ```bash
140
+ uvx --from 'exstruct[mcp]' exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
141
+ ```
142
+
143
+ Benefits:
144
+ - No `pip install` required
145
+ - Automatic dependency management
146
+ - Environment isolation
147
+ - Easy version pinning: `uvx --from 'exstruct[mcp]==0.4.4' exstruct-mcp`
148
+
149
+ ### Traditional Installation
150
+
151
+ Alternatively, install with pip:
123
152
 
124
153
  ```bash
125
154
  pip install exstruct[mcp]
@@ -129,13 +158,28 @@ exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict re
129
158
  Available tools:
130
159
 
131
160
  - `exstruct_extract`
161
+ - `exstruct_make`
162
+ - `exstruct_patch`
132
163
  - `exstruct_read_json_chunk`
164
+ - `exstruct_read_range`
165
+ - `exstruct_read_cells`
166
+ - `exstruct_read_formulas`
133
167
  - `exstruct_validate_input`
134
168
 
135
169
  Notes:
136
170
 
171
+ - In MCP, `exstruct_extract` defaults to `options.alpha_col=true` (column keys: `A`, `B`, ...). Set `options.alpha_col=false` for legacy 0-based numeric string keys.
137
172
  - Logs go to stderr (and optionally `--log-file`) to avoid contaminating stdio responses.
138
173
  - On Windows with Excel, standard/verbose can use COM for richer extraction. On non-Windows, COM is unavailable and extraction uses openpyxl-based fallbacks.
174
+ - `exstruct_patch` supports `backend` selection:
175
+ - `auto` (default): prefer COM when available, otherwise openpyxl
176
+ - `com`: force COM (rejects `dry_run` / `return_inverse_ops` / `preflight_formula_check`)
177
+ - `openpyxl`: force openpyxl (`.xls` is not supported)
178
+ - `exstruct_patch` response includes `engine` (`com` or `openpyxl`) to show the actual backend used. `restore_design_snapshot` remains openpyxl-only.
179
+ - `exstruct_make` creates a new workbook and applies `ops` in one call (`out_path` required, `ops` optional).
180
+ - Supports `.xlsx` / `.xlsm` / `.xls`
181
+ - Initial sheet is normalized to `Sheet1`
182
+ - `.xls` requires COM and rejects `backend=openpyxl`
139
183
 
140
184
  MCP Setup Guide for Each AI Agent:
141
185
 
@@ -1,6 +1,7 @@
1
1
  # ExStruct — Excel Structured Extraction Engine
2
2
 
3
- [![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)
3
+ [![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)
4
+
4
5
 
5
6
  ![ExStruct Image](docs/assets/icon.webp)
6
7
 
@@ -19,6 +20,15 @@ ExStruct reads Excel workbooks and outputs structured data (cells, table candida
19
20
  - **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
20
21
  - **Graceful fallback**: if Excel COM is unavailable, extraction falls back to cells + table candidates without crashing.
21
22
 
23
+ ## Benchmark
24
+
25
+ ![Benchmark Chart](benchmark/public/plots/markdown_quality.png)
26
+
27
+ This repository includes benchmark reports focused on RAG/LLM preprocessing of Excel documents.
28
+ We track two perspectives: (1) core extraction accuracy and (2) reconstruction utility for downstream structure queries (RUB).
29
+ See `benchmark/REPORT.md` for the working summary and `benchmark/public/REPORT.md` for the public bundle.
30
+ Current results are based on n=12 cases and will be expanded.
31
+
22
32
  ## Installation
23
33
 
24
34
  ```bash
@@ -46,15 +56,34 @@ exstruct input.xlsx --format toon # TOON (needs python-toon)
46
56
  exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
47
57
  exstruct input.xlsx --auto-page-breaks-dir auto_areas/ # COM only; option appears when available
48
58
  exstruct input.xlsx --print-areas-dir areas/ # split per print area (if any)
59
+ exstruct input.xlsx --alpha-col # output column keys as A, B, ..., AA
49
60
  exstruct input.xlsx --mode light # cells + table candidates only
50
61
  exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
51
62
  ```
52
63
 
53
64
  Auto page-break exports are available via API and CLI when Excel/COM is available; the CLI exposes `--auto-page-breaks-dir` only in COM-capable environments.
65
+ By default, CLI keeps legacy 0-based numeric string column keys (`"0"`, `"1"`, ...). Use `--alpha-col` to emit Excel-style column keys (`"A"`, `"B"`, ...).
66
+ Note: MCP `exstruct_extract` defaults to `options.alpha_col=true`, while CLI defaults to `false` unless `--alpha-col` is specified.
54
67
 
55
68
  ## MCP Server (stdio)
56
69
 
57
- Install the MCP extras and run the stdio server:
70
+ ### Quick Start with uvx (recommended)
71
+
72
+ Run directly without installation:
73
+
74
+ ```bash
75
+ uvx --from 'exstruct[mcp]' exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict rename
76
+ ```
77
+
78
+ Benefits:
79
+ - No `pip install` required
80
+ - Automatic dependency management
81
+ - Environment isolation
82
+ - Easy version pinning: `uvx --from 'exstruct[mcp]==0.4.4' exstruct-mcp`
83
+
84
+ ### Traditional Installation
85
+
86
+ Alternatively, install with pip:
58
87
 
59
88
  ```bash
60
89
  pip install exstruct[mcp]
@@ -64,13 +93,28 @@ exstruct-mcp --root C:\data --log-file C:\logs\exstruct-mcp.log --on-conflict re
64
93
  Available tools:
65
94
 
66
95
  - `exstruct_extract`
96
+ - `exstruct_make`
97
+ - `exstruct_patch`
67
98
  - `exstruct_read_json_chunk`
99
+ - `exstruct_read_range`
100
+ - `exstruct_read_cells`
101
+ - `exstruct_read_formulas`
68
102
  - `exstruct_validate_input`
69
103
 
70
104
  Notes:
71
105
 
106
+ - In MCP, `exstruct_extract` defaults to `options.alpha_col=true` (column keys: `A`, `B`, ...). Set `options.alpha_col=false` for legacy 0-based numeric string keys.
72
107
  - Logs go to stderr (and optionally `--log-file`) to avoid contaminating stdio responses.
73
108
  - On Windows with Excel, standard/verbose can use COM for richer extraction. On non-Windows, COM is unavailable and extraction uses openpyxl-based fallbacks.
109
+ - `exstruct_patch` supports `backend` selection:
110
+ - `auto` (default): prefer COM when available, otherwise openpyxl
111
+ - `com`: force COM (rejects `dry_run` / `return_inverse_ops` / `preflight_formula_check`)
112
+ - `openpyxl`: force openpyxl (`.xls` is not supported)
113
+ - `exstruct_patch` response includes `engine` (`com` or `openpyxl`) to show the actual backend used. `restore_design_snapshot` remains openpyxl-only.
114
+ - `exstruct_make` creates a new workbook and applies `ops` in one call (`out_path` required, `ops` optional).
115
+ - Supports `.xlsx` / `.xlsm` / `.xls`
116
+ - Initial sheet is normalized to `Sheet1`
117
+ - `.xls` requires COM and rejects `backend=openpyxl`
74
118
 
75
119
  MCP Setup Guide for Each AI Agent:
76
120
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "exstruct"
3
- version = "0.4.2"
3
+ version = "0.5.0"
4
4
  description = "Excel to structured JSON (tables, shapes, charts) for LLM/RAG pipelines"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -42,14 +42,14 @@ all = [
42
42
  "python-toon>=0.1.3",
43
43
  "pypdfium2>=5.1.0",
44
44
  "Pillow>=12.0.0",
45
- "mcp>=1.6.0,<2.0.0",
45
+ "mcp>=1.25.0,<2.0.0",
46
46
  "httpx>=0.27,<1.0",
47
47
  ]
48
48
  yaml = ["pyyaml>=6.0.3"]
49
49
  toon = ["python-toon>=0.1.3"]
50
50
  render = ["pypdfium2>=5.1.0", "Pillow>=12.0.0"]
51
51
  mcp = [
52
- "mcp>=1.6.0,<2.0.0",
52
+ "mcp>=1.25.0,<2.0.0",
53
53
  "httpx>=0.27,<1.0",
54
54
  ]
55
55
 
@@ -68,12 +68,14 @@ omit = [
68
68
  "tests/*",
69
69
  "*/test_*.py",
70
70
  "*/gen_py/*",
71
+ "src/exstruct/mcp/patch/engine/base.py",
71
72
  ]
72
73
 
73
74
  [tool.ruff]
74
75
  target-version = "py311"
75
76
  src = ["exstruct"]
76
77
  fix = true
78
+ exclude = ["benchmark/**"]
77
79
 
78
80
  # 静的解析ルール
79
81
  [tool.ruff.lint]
@@ -113,6 +115,7 @@ max-complexity = 12
113
115
  [tool.mypy]
114
116
  packages = ["exstruct"]
115
117
  python_version = "3.11"
118
+ exclude = "benchmark/.*"
116
119
 
117
120
  # 外部ライブラリの型情報がない場合は無視
118
121
  ignore_missing_imports = true
@@ -134,10 +137,15 @@ ruff = "ruff check ."
134
137
  ruff-fix = "ruff check . --fix"
135
138
  mypy = "mypy src/exstruct --strict"
136
139
  precommit-run = "pre-commit run -a"
137
- test = "pytest -vv --cov=exstruct --cov-report=term-missing --cov-report=xml" # uv sync --extra render --extra toon
138
- test-unit = "pytest -vv -m \"not com and not render\" --cov=exstruct --cov-report=term-missing --cov-report=xml"
139
- test-com = "pytest -vv -m \"com\" --cov=exstruct --cov-report=term-missing --cov-report=xml"
140
+ test = "pytest -vv --cov=exstruct --cov-report=term-missing --cov-report=xml --cov-fail-under=80" # uv sync --extra render --extra toon
141
+ test-unit = "pytest -vv -m \"not com and not render\" --cov=exstruct --cov-report=term-missing --cov-report=xml --cov-fail-under=80"
142
+ test-com = "pytest -vv -m \"com\" --cov=exstruct --cov-report=term-missing --cov-report=xml --cov-fail-under=80"
140
143
  codecov-unit = "codecov-cli upload-process -f coverage.xml -F unit -C %CODECOV_SHA% -t %CODECOV_TOKEN%"
141
144
  codecov-com = "codecov-cli upload-process -f coverage.xml -F com -C %CODECOV_SHA% -t %CODECOV_TOKEN%"
142
145
  docs = "mkdocs serve"
143
146
  build-docs = "mkdocs build && python scripts/gen_json_schema.py && python scripts/gen_model_docs.py"
147
+
148
+ [tool.uv.workspace]
149
+ members = [
150
+ "benchmark",
151
+ ]
@@ -41,6 +41,10 @@ from .models import (
41
41
  Shape,
42
42
  SheetData,
43
43
  WorkbookData,
44
+ col_index_to_alpha,
45
+ convert_row_keys_to_alpha,
46
+ convert_sheet_keys_to_alpha,
47
+ convert_workbook_keys_to_alpha,
44
48
  )
45
49
  from .render import export_pdf, export_sheet_images
46
50
 
@@ -82,19 +86,26 @@ __all__ = [
82
86
  "ColorsOptions",
83
87
  "serialize_workbook",
84
88
  "export_auto_page_breaks",
89
+ "col_index_to_alpha",
90
+ "convert_row_keys_to_alpha",
91
+ "convert_sheet_keys_to_alpha",
92
+ "convert_workbook_keys_to_alpha",
85
93
  ]
86
94
 
87
95
 
88
96
  ExtractionMode = Literal["light", "standard", "verbose"]
89
97
 
90
98
 
91
- def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> WorkbookData:
99
+ def extract(
100
+ file_path: str | Path, mode: ExtractionMode = "standard", *, alpha_col: bool = False
101
+ ) -> WorkbookData:
92
102
  """
93
103
  Extracts an Excel workbook into a WorkbookData structure.
94
104
 
95
105
  Parameters:
96
106
  file_path (str | Path): Path to the workbook file (.xlsx, .xlsm, .xls).
97
107
  mode (ExtractionMode): Extraction detail level. "light" includes cells and table detection only (no COM, shapes/charts empty; print areas via openpyxl). "standard" includes texted shapes, arrows, charts (COM if available) and print areas. "verbose" also includes shape/chart sizes, cell link map, colors map, and formulas map.
108
+ alpha_col: When True, convert CellRow column keys to Excel-style ABC names (A, B, ..., Z, AA, ...) instead of 0-based numeric strings.
98
109
 
99
110
  Returns:
100
111
  WorkbookData: Parsed workbook representation containing sheets, rows, shapes, charts, and print areas.
@@ -108,6 +119,7 @@ def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> Workboo
108
119
  include_cell_links=include_links,
109
120
  include_colors_map=include_colors_map,
110
121
  include_formulas_map=include_formulas_map,
122
+ alpha_col=alpha_col,
111
123
  )
112
124
  )
113
125
  return engine.extract(file_path, mode=mode)
@@ -317,6 +329,8 @@ def process_excel(
317
329
  print_areas_dir: str | Path | None = None,
318
330
  auto_page_breaks_dir: str | Path | None = None,
319
331
  stream: TextIO | None = None,
332
+ *,
333
+ alpha_col: bool = False,
320
334
  ) -> None:
321
335
  """
322
336
  Convenience wrapper: extract -> serialize (file or stdout) -> optional PDF/PNG.
@@ -335,6 +349,8 @@ def process_excel(
335
349
  print_areas_dir: Directory to write per-print-area files (string or Path).
336
350
  auto_page_breaks_dir: Directory to write per-auto-page-break files (COM only).
337
351
  stream: IO override when output_path is None.
352
+ alpha_col: When True, convert CellRow column keys to Excel-style
353
+ ABC names (A, B, ...) instead of 0-based numeric strings.
338
354
 
339
355
  Raises:
340
356
  ValueError: If an unsupported format or mode is given.
@@ -353,7 +369,7 @@ def process_excel(
353
369
  >>> process_excel(Path("input.xlsx"), output_path=Path("out.json"), pdf=True) # doctest: +SKIP
354
370
  """
355
371
  engine = ExStructEngine(
356
- options=StructOptions(mode=mode),
372
+ options=StructOptions(mode=mode, alpha_col=alpha_col),
357
373
  output=OutputOptions(
358
374
  format=FormatOptions(fmt=out_fmt, pretty=pretty, indent=indent),
359
375
  filters=FilterOptions(
@@ -109,6 +109,11 @@ def build_parser(
109
109
  availability if availability is not None else get_com_availability()
110
110
  )
111
111
  _add_auto_page_breaks_argument(parser, resolved_availability)
112
+ parser.add_argument(
113
+ "--alpha-col",
114
+ action="store_true",
115
+ help="Output column keys as Excel-style ABC names (A, B, ..., Z, AA, ...) instead of 0-based indices.",
116
+ )
112
117
  return parser
113
118
 
114
119
 
@@ -143,6 +148,7 @@ def main(argv: list[str] | None = None) -> int:
143
148
  sheets_dir=args.sheets_dir,
144
149
  print_areas_dir=args.print_areas_dir,
145
150
  auto_page_breaks_dir=getattr(args, "auto_page_breaks_dir", None),
151
+ alpha_col=args.alpha_col,
146
152
  )
147
153
  return 0
148
154
  except Exception as e:
@@ -17,7 +17,7 @@ from .io import (
17
17
  save_sheets,
18
18
  serialize_workbook,
19
19
  )
20
- from .models import SheetData, WorkbookData
20
+ from .models import SheetData, WorkbookData, convert_workbook_keys_to_alpha
21
21
  from .render import export_pdf, export_sheet_images
22
22
 
23
23
  ExtractionMode = Literal["light", "standard", "verbose"]
@@ -76,6 +76,8 @@ class StructOptions:
76
76
  include_merged_cells: Whether to extract merged cell ranges.
77
77
  include_merged_values_in_rows: Whether to keep merged values in rows.
78
78
  colors: Color extraction options.
79
+ alpha_col: When True, convert CellRow column keys to Excel-style
80
+ ABC names (A, B, ..., Z, AA, ...) instead of 0-based numeric strings.
79
81
  """
80
82
 
81
83
  mode: ExtractionMode = "standard"
@@ -88,6 +90,7 @@ class StructOptions:
88
90
  include_merged_cells: bool | None = None # None -> auto: light=False, others=True
89
91
  include_merged_values_in_rows: bool = True
90
92
  colors: ColorsOptions = field(default_factory=ColorsOptions)
93
+ alpha_col: bool = False
91
94
 
92
95
 
93
96
  class FormatOptions(BaseModel):
@@ -314,6 +317,9 @@ class ExStructEngine:
314
317
  merged_cells=sheet.merged_cells
315
318
  if self.output.filters.include_merged_cells
316
319
  else None,
320
+ merged_ranges=sheet.merged_ranges
321
+ if self.output.filters.include_merged_cells
322
+ else [],
317
323
  )
318
324
 
319
325
  def _filter_workbook(
@@ -383,7 +389,7 @@ class ExStructEngine:
383
389
  )
384
390
  normalized_file_path = self._ensure_path(file_path)
385
391
  with self._table_params_scope():
386
- return extract_workbook(
392
+ workbook = extract_workbook(
387
393
  normalized_file_path,
388
394
  mode=chosen_mode,
389
395
  include_cell_links=self.options.include_cell_links,
@@ -396,6 +402,9 @@ class ExStructEngine:
396
402
  include_merged_cells=self.options.include_merged_cells,
397
403
  include_merged_values_in_rows=self.options.include_merged_values_in_rows,
398
404
  )
405
+ if self.options.alpha_col:
406
+ workbook = convert_workbook_keys_to_alpha(workbook)
407
+ return workbook
399
408
 
400
409
  def serialize(
401
410
  self,
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from enum import Enum
5
+ from enum import StrEnum
6
6
 
7
7
 
8
8
  class ExstructError(Exception):
@@ -37,7 +37,7 @@ class PrintAreaError(ExstructError, ValueError):
37
37
  """Raised when print-area specific processing fails (also a ValueError for compatibility)."""
38
38
 
39
39
 
40
- class FallbackReason(str, Enum):
40
+ class FallbackReason(StrEnum):
41
41
  """Reason codes for extraction fallbacks."""
42
42
 
43
43
  LIGHT_MODE = "light_mode"
@@ -0,0 +1,145 @@
1
+ """MCP server integration for ExStruct."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .chunk_reader import (
6
+ ReadJsonChunkFilter,
7
+ ReadJsonChunkRequest,
8
+ ReadJsonChunkResult,
9
+ read_json_chunk,
10
+ )
11
+ from .extract_runner import (
12
+ ExtractOptions,
13
+ ExtractRequest,
14
+ ExtractResult,
15
+ WorkbookMeta,
16
+ run_extract,
17
+ )
18
+ from .io import PathPolicy
19
+ from .patch_runner import (
20
+ FormulaIssue,
21
+ MakeRequest,
22
+ PatchDiffItem,
23
+ PatchErrorDetail,
24
+ PatchOp,
25
+ PatchRequest,
26
+ PatchResult,
27
+ PatchValue,
28
+ run_make,
29
+ run_patch,
30
+ )
31
+ from .sheet_reader import (
32
+ CellReadItem,
33
+ FormulaReadItem,
34
+ ReadCellsRequest,
35
+ ReadCellsResult,
36
+ ReadFormulasRequest,
37
+ ReadFormulasResult,
38
+ ReadRangeRequest,
39
+ ReadRangeResult,
40
+ read_cells,
41
+ read_formulas,
42
+ read_range,
43
+ )
44
+ from .tools import (
45
+ DescribeOpToolInput,
46
+ DescribeOpToolOutput,
47
+ ExtractToolInput,
48
+ ExtractToolOutput,
49
+ ListOpsToolOutput,
50
+ MakeToolInput,
51
+ MakeToolOutput,
52
+ PatchToolInput,
53
+ PatchToolOutput,
54
+ ReadCellsToolInput,
55
+ ReadCellsToolOutput,
56
+ ReadFormulasToolInput,
57
+ ReadFormulasToolOutput,
58
+ ReadJsonChunkToolInput,
59
+ ReadJsonChunkToolOutput,
60
+ ReadRangeToolInput,
61
+ ReadRangeToolOutput,
62
+ ValidateInputToolInput,
63
+ ValidateInputToolOutput,
64
+ run_describe_op_tool,
65
+ run_extract_tool,
66
+ run_list_ops_tool,
67
+ run_make_tool,
68
+ run_patch_tool,
69
+ run_read_cells_tool,
70
+ run_read_formulas_tool,
71
+ run_read_json_chunk_tool,
72
+ run_read_range_tool,
73
+ run_validate_input_tool,
74
+ )
75
+ from .validate_input import (
76
+ ValidateInputRequest,
77
+ ValidateInputResult,
78
+ validate_input,
79
+ )
80
+
81
+ __all__ = [
82
+ "DescribeOpToolInput",
83
+ "DescribeOpToolOutput",
84
+ "ExtractRequest",
85
+ "ExtractResult",
86
+ "ExtractOptions",
87
+ "ExtractToolInput",
88
+ "ExtractToolOutput",
89
+ "FormulaIssue",
90
+ "FormulaReadItem",
91
+ "ListOpsToolOutput",
92
+ "MakeRequest",
93
+ "MakeToolInput",
94
+ "MakeToolOutput",
95
+ "PatchDiffItem",
96
+ "PatchErrorDetail",
97
+ "PatchOp",
98
+ "PatchRequest",
99
+ "PatchResult",
100
+ "PatchToolInput",
101
+ "PatchToolOutput",
102
+ "PatchValue",
103
+ "PathPolicy",
104
+ "ReadCellsRequest",
105
+ "ReadCellsResult",
106
+ "ReadCellsToolInput",
107
+ "ReadCellsToolOutput",
108
+ "ReadFormulasRequest",
109
+ "ReadFormulasResult",
110
+ "ReadFormulasToolInput",
111
+ "ReadFormulasToolOutput",
112
+ "ReadJsonChunkFilter",
113
+ "ReadJsonChunkRequest",
114
+ "ReadJsonChunkResult",
115
+ "ReadJsonChunkToolInput",
116
+ "ReadJsonChunkToolOutput",
117
+ "ReadRangeRequest",
118
+ "ReadRangeResult",
119
+ "ReadRangeToolInput",
120
+ "ReadRangeToolOutput",
121
+ "CellReadItem",
122
+ "ValidateInputRequest",
123
+ "ValidateInputResult",
124
+ "ValidateInputToolInput",
125
+ "ValidateInputToolOutput",
126
+ "WorkbookMeta",
127
+ "read_json_chunk",
128
+ "validate_input",
129
+ "run_extract",
130
+ "run_describe_op_tool",
131
+ "run_extract_tool",
132
+ "run_list_ops_tool",
133
+ "run_make",
134
+ "run_make_tool",
135
+ "run_patch",
136
+ "run_patch_tool",
137
+ "read_cells",
138
+ "read_formulas",
139
+ "run_read_json_chunk_tool",
140
+ "read_range",
141
+ "run_read_cells_tool",
142
+ "run_read_formulas_tool",
143
+ "run_read_range_tool",
144
+ "run_validate_input_tool",
145
+ ]