exstruct 0.2.11__tar.gz → 0.2.51__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.
- {exstruct-0.2.11 → exstruct-0.2.51}/PKG-INFO +48 -41
- {exstruct-0.2.11 → exstruct-0.2.51}/README.md +47 -40
- exstruct-0.2.51/pyproject.toml +111 -0
- exstruct-0.2.51/src/exstruct/__init__.py +217 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/cli/main.py +6 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/core/cells.py +559 -470
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/core/charts.py +25 -13
- exstruct-0.2.51/src/exstruct/core/integrate.py +263 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/core/shapes.py +198 -177
- exstruct-0.2.51/src/exstruct/engine.py +489 -0
- exstruct-0.2.51/src/exstruct/io/__init__.py +444 -0
- exstruct-0.2.51/src/exstruct/models/__init__.py +259 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/models/maps.py +13 -13
- exstruct-0.2.51/src/exstruct/models/types.py +8 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/render/__init__.py +15 -14
- exstruct-0.2.11/pyproject.toml +0 -52
- exstruct-0.2.11/src/exstruct/__init__.py +0 -121
- exstruct-0.2.11/src/exstruct/core/integrate.py +0 -132
- exstruct-0.2.11/src/exstruct/engine.py +0 -245
- exstruct-0.2.11/src/exstruct/io/__init__.py +0 -187
- exstruct-0.2.11/src/exstruct/models/__init__.py +0 -179
- {exstruct-0.2.11 → exstruct-0.2.51}/LICENSE +0 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/core/__init__.py +0 -0
- {exstruct-0.2.11 → exstruct-0.2.51}/src/exstruct/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: exstruct
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.51
|
|
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
|
|
@@ -56,16 +56,16 @@ Description-Content-Type: text/markdown
|
|
|
56
56
|
|
|
57
57
|
# ExStruct — Excel Structured Extraction Engine
|
|
58
58
|
|
|
59
|
-
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml)
|
|
60
60
|
|
|
61
61
|

|
|
62
62
|
|
|
63
|
-
ExStruct reads Excel workbooks and outputs structured data (
|
|
63
|
+
ExStruct reads Excel workbooks and outputs structured data (cells, table candidates, shapes, charts, print areas/views, hyperlinks) as JSON by default, with optional YAML/TOON formats. It targets both COM/Excel environments (rich extraction) and non-COM environments (cells + table candidates + print areas), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
|
|
64
64
|
|
|
65
65
|
## Features
|
|
66
66
|
|
|
67
|
-
- **Excel → Structured JSON**: cells, shapes, charts,
|
|
68
|
-
- **Output modes**: `light` (cells + table candidates
|
|
67
|
+
- **Excel → Structured JSON**: cells, shapes, charts, table candidates, and print areas/views per sheet.
|
|
68
|
+
- **Output modes**: `light` (cells + table candidates + print areas; no COM, shapes/charts empty), `standard` (texted shapes + arrows, charts, print areas), `verbose` (all shapes with width/height, charts with size, print areas). Verbose also emits cell hyperlinks. Size output is flag-controlled.
|
|
69
69
|
- **Formats**: JSON (compact by default, `--pretty` available), YAML, TOON (optional dependencies).
|
|
70
70
|
- **Table detection tuning**: adjust heuristics at runtime via API.
|
|
71
71
|
- **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
|
|
@@ -77,17 +77,18 @@ ExStruct reads Excel workbooks and outputs structured data (tables, shapes, char
|
|
|
77
77
|
pip install exstruct
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
Optional extras:
|
|
81
|
-
|
|
82
|
-
- YAML: `pip install pyyaml`
|
|
83
|
-
- TOON: `pip install python-toon`
|
|
84
|
-
- Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow`
|
|
85
|
-
- All extras at once: `pip install exstruct[yaml,toon,render]`
|
|
86
|
-
|
|
87
|
-
Platform note:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
Optional extras:
|
|
81
|
+
|
|
82
|
+
- YAML: `pip install pyyaml`
|
|
83
|
+
- TOON: `pip install python-toon`
|
|
84
|
+
- Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow`
|
|
85
|
+
- All extras at once: `pip install exstruct[yaml,toon,render]`
|
|
86
|
+
|
|
87
|
+
Platform note:
|
|
88
|
+
|
|
89
|
+
- Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates`.
|
|
90
|
+
|
|
91
|
+
## Quick Start (CLI)
|
|
91
92
|
|
|
92
93
|
```bash
|
|
93
94
|
exstruct input.xlsx > output.json # compact JSON to stdout (default)
|
|
@@ -95,6 +96,7 @@ exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
|
|
|
95
96
|
exstruct input.xlsx --format yaml # YAML (needs pyyaml)
|
|
96
97
|
exstruct input.xlsx --format toon # TOON (needs python-toon)
|
|
97
98
|
exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
|
|
99
|
+
exstruct input.xlsx --print-areas-dir areas/ # split per print area (if any)
|
|
98
100
|
exstruct input.xlsx --mode light # cells + table candidates only
|
|
99
101
|
exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
|
|
100
102
|
```
|
|
@@ -112,7 +114,7 @@ set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
|
|
|
112
114
|
wb = extract("input.xlsx", mode="standard")
|
|
113
115
|
export(wb, Path("out.json"), pretty=False) # compact JSON
|
|
114
116
|
|
|
115
|
-
# Model helpers: iterate, index, and serialize directly
|
|
117
|
+
# Model helpers: iterate, index, and serialize directly
|
|
116
118
|
first_sheet = wb["Sheet1"] # __getitem__ access
|
|
117
119
|
for name, sheet in wb: # __iter__ yields (name, SheetData)
|
|
118
120
|
print(name, len(sheet.rows))
|
|
@@ -120,15 +122,27 @@ wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
|
|
|
120
122
|
first_sheet.save("sheet.json") # SheetData → file (by extension)
|
|
121
123
|
print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
|
|
122
124
|
|
|
123
|
-
# ExStructEngine: per-instance options
|
|
124
|
-
from exstruct import ExStructEngine, StructOptions, OutputOptions
|
|
125
|
+
# ExStructEngine: per-instance options (nested configs)
|
|
126
|
+
from exstruct import ExStructEngine, StructOptions, OutputOptions, FormatOptions, FilterOptions, DestinationOptions
|
|
127
|
+
|
|
128
|
+
engine = ExStructEngine(
|
|
129
|
+
options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
|
|
130
|
+
output=OutputOptions(
|
|
131
|
+
format=FormatOptions(pretty=True),
|
|
132
|
+
filters=FilterOptions(include_shapes=False), # drop shapes in output
|
|
133
|
+
destinations=DestinationOptions(sheets_dir=Path("out_sheets")), # also write per-sheet files
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
wb2 = engine.extract("input.xlsx")
|
|
137
|
+
engine.export(wb2, Path("out_filtered.json")) # drops shapes via filters
|
|
138
|
+
|
|
139
|
+
# Enable hyperlinks in other modes
|
|
140
|
+
engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
|
|
141
|
+
with_links = engine_links.extract("input.xlsx")
|
|
125
142
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
wb2 = engine.extract("input.xlsx")
|
|
131
|
-
engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
|
|
143
|
+
# Export per print area (if print areas exist)
|
|
144
|
+
from exstruct import export_print_areas_as
|
|
145
|
+
export_print_areas_as(wb, "areas", fmt="json", pretty=True)
|
|
132
146
|
```
|
|
133
147
|
|
|
134
148
|
**Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
|
|
@@ -151,8 +165,8 @@ Use higher thresholds to reduce false positives; lower them if true tables are m
|
|
|
151
165
|
## Output Modes
|
|
152
166
|
|
|
153
167
|
- **light**: cells + table candidates (no COM needed).
|
|
154
|
-
- **standard**: texted shapes + arrows, charts (COM if available), table candidates.
|
|
155
|
-
- **verbose**: all shapes (with width/height), charts, table candidates.
|
|
168
|
+
- **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
|
|
169
|
+
- **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
|
|
156
170
|
|
|
157
171
|
## Error Handling / Fallbacks
|
|
158
172
|
|
|
@@ -181,6 +195,7 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
|
|
|
181
195
|
(Screenshot below is the actual sample Excel sheet)
|
|
182
196
|

|
|
183
197
|
Sample workbook: `sample/sample.xlsx`
|
|
198
|
+
Sample workbook: `sample/sample.xlsx`
|
|
184
199
|
|
|
185
200
|
### 1. Input: Excel Sheet Overview
|
|
186
201
|
|
|
@@ -367,6 +382,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
|
|
|
367
382
|
- Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
|
|
368
383
|
- Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
|
|
369
384
|
|
|
385
|
+
## Print Areas (PrintArea / PrintAreaView)
|
|
386
|
+
|
|
387
|
+
- `SheetData.print_areas` holds print areas (cell coordinates) in light/standard/verbose.
|
|
388
|
+
- Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to write one file per print area (nothing is written if none exist).
|
|
389
|
+
- `PrintAreaView` includes rows and table candidates inside the area, plus shapes/charts that overlap the area (size-less shapes are treated as points). `normalize=True` rebases row/col indices to the area origin.
|
|
390
|
+
|
|
370
391
|
## License
|
|
371
392
|
|
|
372
393
|
BSD-3-Clause. See `LICENSE` for details.
|
|
@@ -374,17 +395,3 @@ BSD-3-Clause. See `LICENSE` for details.
|
|
|
374
395
|
## Documentation
|
|
375
396
|
|
|
376
397
|
- API Reference (GitHub Pages): https://harumiweb.github.io/exstruct/
|
|
377
|
-
# Engine option cheat sheet
|
|
378
|
-
|
|
379
|
-
| Option class | Field | Meaning |
|
|
380
|
-
| -------------- | ------------------- | ------- |
|
|
381
|
-
| StructOptions | mode | "light"/"standard"/"verbose" |
|
|
382
|
-
| | table_params | Dict passed to `set_table_detection_params` (table_score_threshold, density_min, coverage_min, min_nonempty_cells) |
|
|
383
|
-
| OutputOptions | fmt | Default format ("json"/"yaml"/"yml"/"toon") |
|
|
384
|
-
| | pretty / indent | Pretty-print JSON and control indent |
|
|
385
|
-
| | include_rows | Include rows (False to drop) |
|
|
386
|
-
| | include_shapes | Include shapes |
|
|
387
|
-
| | include_charts | Include charts |
|
|
388
|
-
| | include_tables | Include table_candidates |
|
|
389
|
-
| | sheets_dir | Optional directory for per-sheet exports |
|
|
390
|
-
| | stream | Default stream when output_path is None |
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# ExStruct — Excel Structured Extraction Engine
|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml)
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
ExStruct reads Excel workbooks and outputs structured data (
|
|
7
|
+
ExStruct reads Excel workbooks and outputs structured data (cells, table candidates, shapes, charts, print areas/views, hyperlinks) as JSON by default, with optional YAML/TOON formats. It targets both COM/Excel environments (rich extraction) and non-COM environments (cells + table candidates + print areas), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Excel → Structured JSON**: cells, shapes, charts,
|
|
12
|
-
- **Output modes**: `light` (cells + table candidates
|
|
11
|
+
- **Excel → Structured JSON**: cells, shapes, charts, table candidates, and print areas/views per sheet.
|
|
12
|
+
- **Output modes**: `light` (cells + table candidates + print areas; no COM, shapes/charts empty), `standard` (texted shapes + arrows, charts, print areas), `verbose` (all shapes with width/height, charts with size, print areas). Verbose also emits cell hyperlinks. Size output is flag-controlled.
|
|
13
13
|
- **Formats**: JSON (compact by default, `--pretty` available), YAML, TOON (optional dependencies).
|
|
14
14
|
- **Table detection tuning**: adjust heuristics at runtime via API.
|
|
15
15
|
- **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
|
|
@@ -21,17 +21,18 @@ ExStruct reads Excel workbooks and outputs structured data (tables, shapes, char
|
|
|
21
21
|
pip install exstruct
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Optional extras:
|
|
25
|
-
|
|
26
|
-
- YAML: `pip install pyyaml`
|
|
27
|
-
- TOON: `pip install python-toon`
|
|
28
|
-
- Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow`
|
|
29
|
-
- All extras at once: `pip install exstruct[yaml,toon,render]`
|
|
30
|
-
|
|
31
|
-
Platform note:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
Optional extras:
|
|
25
|
+
|
|
26
|
+
- YAML: `pip install pyyaml`
|
|
27
|
+
- TOON: `pip install python-toon`
|
|
28
|
+
- Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow`
|
|
29
|
+
- All extras at once: `pip install exstruct[yaml,toon,render]`
|
|
30
|
+
|
|
31
|
+
Platform note:
|
|
32
|
+
|
|
33
|
+
- Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates`.
|
|
34
|
+
|
|
35
|
+
## Quick Start (CLI)
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
38
|
exstruct input.xlsx > output.json # compact JSON to stdout (default)
|
|
@@ -39,6 +40,7 @@ exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
|
|
|
39
40
|
exstruct input.xlsx --format yaml # YAML (needs pyyaml)
|
|
40
41
|
exstruct input.xlsx --format toon # TOON (needs python-toon)
|
|
41
42
|
exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
|
|
43
|
+
exstruct input.xlsx --print-areas-dir areas/ # split per print area (if any)
|
|
42
44
|
exstruct input.xlsx --mode light # cells + table candidates only
|
|
43
45
|
exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
|
|
44
46
|
```
|
|
@@ -56,7 +58,7 @@ set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
|
|
|
56
58
|
wb = extract("input.xlsx", mode="standard")
|
|
57
59
|
export(wb, Path("out.json"), pretty=False) # compact JSON
|
|
58
60
|
|
|
59
|
-
# Model helpers: iterate, index, and serialize directly
|
|
61
|
+
# Model helpers: iterate, index, and serialize directly
|
|
60
62
|
first_sheet = wb["Sheet1"] # __getitem__ access
|
|
61
63
|
for name, sheet in wb: # __iter__ yields (name, SheetData)
|
|
62
64
|
print(name, len(sheet.rows))
|
|
@@ -64,15 +66,27 @@ wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
|
|
|
64
66
|
first_sheet.save("sheet.json") # SheetData → file (by extension)
|
|
65
67
|
print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
|
|
66
68
|
|
|
67
|
-
# ExStructEngine: per-instance options
|
|
68
|
-
from exstruct import ExStructEngine, StructOptions, OutputOptions
|
|
69
|
+
# ExStructEngine: per-instance options (nested configs)
|
|
70
|
+
from exstruct import ExStructEngine, StructOptions, OutputOptions, FormatOptions, FilterOptions, DestinationOptions
|
|
71
|
+
|
|
72
|
+
engine = ExStructEngine(
|
|
73
|
+
options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
|
|
74
|
+
output=OutputOptions(
|
|
75
|
+
format=FormatOptions(pretty=True),
|
|
76
|
+
filters=FilterOptions(include_shapes=False), # drop shapes in output
|
|
77
|
+
destinations=DestinationOptions(sheets_dir=Path("out_sheets")), # also write per-sheet files
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
wb2 = engine.extract("input.xlsx")
|
|
81
|
+
engine.export(wb2, Path("out_filtered.json")) # drops shapes via filters
|
|
82
|
+
|
|
83
|
+
# Enable hyperlinks in other modes
|
|
84
|
+
engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
|
|
85
|
+
with_links = engine_links.extract("input.xlsx")
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
wb2 = engine.extract("input.xlsx")
|
|
75
|
-
engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
|
|
87
|
+
# Export per print area (if print areas exist)
|
|
88
|
+
from exstruct import export_print_areas_as
|
|
89
|
+
export_print_areas_as(wb, "areas", fmt="json", pretty=True)
|
|
76
90
|
```
|
|
77
91
|
|
|
78
92
|
**Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
|
|
@@ -95,8 +109,8 @@ Use higher thresholds to reduce false positives; lower them if true tables are m
|
|
|
95
109
|
## Output Modes
|
|
96
110
|
|
|
97
111
|
- **light**: cells + table candidates (no COM needed).
|
|
98
|
-
- **standard**: texted shapes + arrows, charts (COM if available), table candidates.
|
|
99
|
-
- **verbose**: all shapes (with width/height), charts, table candidates.
|
|
112
|
+
- **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
|
|
113
|
+
- **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
|
|
100
114
|
|
|
101
115
|
## Error Handling / Fallbacks
|
|
102
116
|
|
|
@@ -125,6 +139,7 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
|
|
|
125
139
|
(Screenshot below is the actual sample Excel sheet)
|
|
126
140
|

|
|
127
141
|
Sample workbook: `sample/sample.xlsx`
|
|
142
|
+
Sample workbook: `sample/sample.xlsx`
|
|
128
143
|
|
|
129
144
|
### 1. Input: Excel Sheet Overview
|
|
130
145
|
|
|
@@ -311,6 +326,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
|
|
|
311
326
|
- Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
|
|
312
327
|
- Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
|
|
313
328
|
|
|
329
|
+
## Print Areas (PrintArea / PrintAreaView)
|
|
330
|
+
|
|
331
|
+
- `SheetData.print_areas` holds print areas (cell coordinates) in light/standard/verbose.
|
|
332
|
+
- Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to write one file per print area (nothing is written if none exist).
|
|
333
|
+
- `PrintAreaView` includes rows and table candidates inside the area, plus shapes/charts that overlap the area (size-less shapes are treated as points). `normalize=True` rebases row/col indices to the area origin.
|
|
334
|
+
|
|
314
335
|
## License
|
|
315
336
|
|
|
316
337
|
BSD-3-Clause. See `LICENSE` for details.
|
|
@@ -318,17 +339,3 @@ BSD-3-Clause. See `LICENSE` for details.
|
|
|
318
339
|
## Documentation
|
|
319
340
|
|
|
320
341
|
- API Reference (GitHub Pages): https://harumiweb.github.io/exstruct/
|
|
321
|
-
# Engine option cheat sheet
|
|
322
|
-
|
|
323
|
-
| Option class | Field | Meaning |
|
|
324
|
-
| -------------- | ------------------- | ------- |
|
|
325
|
-
| StructOptions | mode | "light"/"standard"/"verbose" |
|
|
326
|
-
| | table_params | Dict passed to `set_table_detection_params` (table_score_threshold, density_min, coverage_min, min_nonempty_cells) |
|
|
327
|
-
| OutputOptions | fmt | Default format ("json"/"yaml"/"yml"/"toon") |
|
|
328
|
-
| | pretty / indent | Pretty-print JSON and control indent |
|
|
329
|
-
| | include_rows | Include rows (False to drop) |
|
|
330
|
-
| | include_shapes | Include shapes |
|
|
331
|
-
| | include_charts | Include charts |
|
|
332
|
-
| | include_tables | Include table_candidates |
|
|
333
|
-
| | sheets_dir | Optional directory for per-sheet exports |
|
|
334
|
-
| | stream | Default stream when output_path is None |
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "exstruct"
|
|
3
|
+
version = "0.2.51"
|
|
4
|
+
description = "Excel to structured JSON (tables, shapes, charts) for LLM/RAG pipelines"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { file = "LICENSE" }
|
|
7
|
+
keywords = ["excel", "structure", "data", "exstruct"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "harumiWeb", email = "ganaharumi@outlook.jp" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"numpy>=2.3.5",
|
|
14
|
+
"openpyxl>=3.1.5",
|
|
15
|
+
"pandas>=2.3.3",
|
|
16
|
+
"pydantic>=2.12.5",
|
|
17
|
+
"scipy>=1.16.3",
|
|
18
|
+
"xlwings>=0.33.16",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["uv_build>=0.8.4,<0.9.0"]
|
|
23
|
+
build-backend = "uv_build"
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"mkdocs-material>=9.7.0",
|
|
28
|
+
"mypy>=1.19.0",
|
|
29
|
+
"pytest>=9.0.1",
|
|
30
|
+
"pytest-cov>=7.0.0",
|
|
31
|
+
"pytest-mock>=3.15.1",
|
|
32
|
+
"ruff>=0.14.8",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
yaml = ["pyyaml>=6.0.3"]
|
|
37
|
+
toon = ["python-toon>=0.1.3"]
|
|
38
|
+
render = ["pypdfium2>=5.1.0", "Pillow>=12.0.0"]
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
exstruct = "exstruct.cli.main:main"
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://harumiweb.github.io/exstruct/"
|
|
45
|
+
Repository = "https://github.com/harumiWeb/exstruct"
|
|
46
|
+
Issues = "https://github.com/harumiWeb/exstruct/issues"
|
|
47
|
+
Documentation = "https://harumiweb.github.io/exstruct/"
|
|
48
|
+
|
|
49
|
+
[tool.coverage.run]
|
|
50
|
+
omit = [
|
|
51
|
+
"tests/*",
|
|
52
|
+
"*/test_*.py",
|
|
53
|
+
"*/gen_py/*",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
target-version = "py311"
|
|
58
|
+
src = ["exstruct"]
|
|
59
|
+
|
|
60
|
+
select = [
|
|
61
|
+
"E", # pycodestyle errors
|
|
62
|
+
"W", # pycodestyle warnings
|
|
63
|
+
"F", # pyflakes
|
|
64
|
+
"I", # import sorting
|
|
65
|
+
"UP", # pyupgrade
|
|
66
|
+
"B", # flake8-bugbear
|
|
67
|
+
"N", # naming
|
|
68
|
+
"C90", # complexity
|
|
69
|
+
"A", # flake8-builtins
|
|
70
|
+
"ANN", # type annotations
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
ignore = [
|
|
74
|
+
"E501", # 行長は許容(Excel JSON は長くなりがち)
|
|
75
|
+
"B008", # Pydantic の default_factory を誤検知するため
|
|
76
|
+
"ANN101", # self に型を要求されてしまうため
|
|
77
|
+
"ANN102", # cls も同様
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
fix = true
|
|
81
|
+
|
|
82
|
+
# 型ヒントのスタイル
|
|
83
|
+
[tool.ruff.lint]
|
|
84
|
+
extend-select = ["ANN"]
|
|
85
|
+
|
|
86
|
+
# import の並び替え設定
|
|
87
|
+
[tool.ruff.isort]
|
|
88
|
+
combine-as-imports = true
|
|
89
|
+
known-first-party = ["exstruct"]
|
|
90
|
+
force-sort-within-sections = true
|
|
91
|
+
|
|
92
|
+
# 複雑度チェック(関数の最大複雑度)
|
|
93
|
+
[tool.ruff.mccabe]
|
|
94
|
+
max-complexity = 12
|
|
95
|
+
|
|
96
|
+
[tool.ruff.per-file-ignores]
|
|
97
|
+
"tests/**/*.py" = ["N802", "N803", "N806"]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
[tool.mypy]
|
|
101
|
+
packages = ["exstruct"]
|
|
102
|
+
python_version = "3.11"
|
|
103
|
+
|
|
104
|
+
# 外部ライブラリは一切チェックしない
|
|
105
|
+
ignore_missing_imports = true
|
|
106
|
+
|
|
107
|
+
# 自作コードは厳密にチェックする
|
|
108
|
+
strict = true
|
|
109
|
+
|
|
110
|
+
# Pydantic v2 向け
|
|
111
|
+
plugins = ["pydantic.mypy"]
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Literal, TextIO
|
|
5
|
+
|
|
6
|
+
from .core.cells import set_table_detection_params
|
|
7
|
+
from .core.integrate import extract_workbook
|
|
8
|
+
from .engine import ExStructEngine, OutputOptions, StructOptions
|
|
9
|
+
from .io import (
|
|
10
|
+
save_as_json,
|
|
11
|
+
save_as_toon,
|
|
12
|
+
save_as_yaml,
|
|
13
|
+
save_print_area_views,
|
|
14
|
+
save_sheets,
|
|
15
|
+
serialize_workbook,
|
|
16
|
+
)
|
|
17
|
+
from .models import (
|
|
18
|
+
CellRow,
|
|
19
|
+
Chart,
|
|
20
|
+
ChartSeries,
|
|
21
|
+
PrintArea,
|
|
22
|
+
PrintAreaView,
|
|
23
|
+
Shape,
|
|
24
|
+
SheetData,
|
|
25
|
+
WorkbookData,
|
|
26
|
+
)
|
|
27
|
+
from .render import export_pdf, export_sheet_images
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"extract",
|
|
31
|
+
"export",
|
|
32
|
+
"export_sheets",
|
|
33
|
+
"export_sheets_as",
|
|
34
|
+
"export_print_areas_as",
|
|
35
|
+
"export_pdf",
|
|
36
|
+
"export_sheet_images",
|
|
37
|
+
"process_excel",
|
|
38
|
+
"ExtractionMode",
|
|
39
|
+
"CellRow",
|
|
40
|
+
"Shape",
|
|
41
|
+
"ChartSeries",
|
|
42
|
+
"Chart",
|
|
43
|
+
"SheetData",
|
|
44
|
+
"WorkbookData",
|
|
45
|
+
"PrintArea",
|
|
46
|
+
"PrintAreaView",
|
|
47
|
+
"set_table_detection_params",
|
|
48
|
+
"extract_workbook",
|
|
49
|
+
"ExStructEngine",
|
|
50
|
+
"StructOptions",
|
|
51
|
+
"OutputOptions",
|
|
52
|
+
"serialize_workbook",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
ExtractionMode = Literal["light", "standard", "verbose"]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> WorkbookData:
|
|
60
|
+
"""
|
|
61
|
+
Extract an Excel workbook into WorkbookData.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
file_path: Path to .xlsx/.xlsm/.xls.
|
|
65
|
+
mode: "light" / "standard" / "verbose"
|
|
66
|
+
- light: cells + table detection only (no COM, shapes/charts empty). Print areas via openpyxl.
|
|
67
|
+
- standard: texted shapes + arrows + charts (COM if available), print areas included. Shape/chart size is kept but hidden by default in output.
|
|
68
|
+
- verbose: all shapes (including textless) with size, charts with size.
|
|
69
|
+
"""
|
|
70
|
+
include_links = True if mode == "verbose" else False
|
|
71
|
+
engine = ExStructEngine(
|
|
72
|
+
options=StructOptions(mode=mode, include_cell_links=include_links)
|
|
73
|
+
)
|
|
74
|
+
return engine.extract(file_path, mode=mode)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def export(
|
|
78
|
+
data: WorkbookData,
|
|
79
|
+
path: str | Path,
|
|
80
|
+
fmt: Literal["json", "yaml", "yml", "toon"] | None = None,
|
|
81
|
+
*,
|
|
82
|
+
pretty: bool = False,
|
|
83
|
+
indent: int | None = None,
|
|
84
|
+
) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Save WorkbookData to a file (format inferred from extension).
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
data: WorkbookData from `extract` or similar
|
|
90
|
+
path: destination path; extension is used to infer format
|
|
91
|
+
fmt: explicitly set format if desired (json/yaml/yml/toon)
|
|
92
|
+
pretty: pretty-print JSON
|
|
93
|
+
indent: JSON indent width (defaults to 2 when pretty=True and indent is None)
|
|
94
|
+
"""
|
|
95
|
+
dest = Path(path)
|
|
96
|
+
format_hint = (fmt or dest.suffix.lstrip(".") or "json").lower()
|
|
97
|
+
match format_hint:
|
|
98
|
+
case "json":
|
|
99
|
+
save_as_json(data, dest, pretty=pretty, indent=indent)
|
|
100
|
+
case "yaml" | "yml":
|
|
101
|
+
save_as_yaml(data, dest)
|
|
102
|
+
case "toon":
|
|
103
|
+
save_as_toon(data, dest)
|
|
104
|
+
case _:
|
|
105
|
+
raise ValueError(f"Unsupported export format: {format_hint}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def export_sheets(data: WorkbookData, dir_path: str | Path) -> dict[str, Path]:
|
|
109
|
+
"""
|
|
110
|
+
Export each sheet as an individual JSON file.
|
|
111
|
+
|
|
112
|
+
- Payload: {book_name, sheet_name, sheet: SheetData}
|
|
113
|
+
- Returns: {sheet_name: Path}
|
|
114
|
+
"""
|
|
115
|
+
return save_sheets(data, Path(dir_path), fmt="json")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def export_sheets_as(
|
|
119
|
+
data: WorkbookData,
|
|
120
|
+
dir_path: str | Path,
|
|
121
|
+
fmt: Literal["json", "yaml", "yml", "toon"] = "json",
|
|
122
|
+
*,
|
|
123
|
+
pretty: bool = False,
|
|
124
|
+
indent: int | None = None,
|
|
125
|
+
) -> dict[str, Path]:
|
|
126
|
+
"""Export each sheet in the given format (json/yaml/toon); returns sheet name to path map."""
|
|
127
|
+
return save_sheets(data, Path(dir_path), fmt=fmt, pretty=pretty, indent=indent)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def export_print_areas_as(
|
|
131
|
+
data: WorkbookData,
|
|
132
|
+
dir_path: str | Path,
|
|
133
|
+
fmt: Literal["json", "yaml", "yml", "toon"] = "json",
|
|
134
|
+
*,
|
|
135
|
+
pretty: bool = False,
|
|
136
|
+
indent: int | None = None,
|
|
137
|
+
normalize: bool = False,
|
|
138
|
+
) -> dict[str, Path]:
|
|
139
|
+
"""
|
|
140
|
+
Export each print area as a PrintAreaView.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
data: WorkbookData that contains print areas
|
|
144
|
+
dir_path: output directory
|
|
145
|
+
fmt: json/yaml/yml/toon
|
|
146
|
+
pretty/indent: JSON formatting options
|
|
147
|
+
normalize: rebase row/col indices to the print-area origin when True
|
|
148
|
+
Returns:
|
|
149
|
+
dict mapping area key to path (e.g., "Sheet1#1": /.../Sheet1_area1_...json)
|
|
150
|
+
"""
|
|
151
|
+
return save_print_area_views(
|
|
152
|
+
data,
|
|
153
|
+
Path(dir_path),
|
|
154
|
+
fmt=fmt,
|
|
155
|
+
pretty=pretty,
|
|
156
|
+
indent=indent,
|
|
157
|
+
normalize=normalize,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def process_excel(
|
|
162
|
+
file_path: Path,
|
|
163
|
+
output_path: Path | None = None,
|
|
164
|
+
out_fmt: str = "json",
|
|
165
|
+
image: bool = False,
|
|
166
|
+
pdf: bool = False,
|
|
167
|
+
dpi: int = 72,
|
|
168
|
+
mode: ExtractionMode = "standard",
|
|
169
|
+
pretty: bool = False,
|
|
170
|
+
indent: int | None = None,
|
|
171
|
+
sheets_dir: Path | None = None,
|
|
172
|
+
print_areas_dir: Path | None = None,
|
|
173
|
+
stream: TextIO | None = None,
|
|
174
|
+
) -> None:
|
|
175
|
+
"""
|
|
176
|
+
Convenience wrapper: extract → serialize (file or stdout) → optional PDF/PNG.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
file_path: input Excel
|
|
180
|
+
output_path: None for stdout; otherwise, write to file
|
|
181
|
+
out_fmt: json/yaml/yml/toon
|
|
182
|
+
image/pdf: True to also output PNG/PDF (requires Excel + pypdfium2)
|
|
183
|
+
dpi: DPI for image output
|
|
184
|
+
mode: light/standard/verbose (same meaning as `extract`)
|
|
185
|
+
pretty/indent: JSON formatting
|
|
186
|
+
sheets_dir: directory to write per-sheet files
|
|
187
|
+
print_areas_dir: directory to write per-print-area files
|
|
188
|
+
stream: IO override when output_path is None
|
|
189
|
+
"""
|
|
190
|
+
engine = ExStructEngine(
|
|
191
|
+
options=StructOptions(mode=mode),
|
|
192
|
+
output=OutputOptions(
|
|
193
|
+
fmt=out_fmt,
|
|
194
|
+
pretty=pretty,
|
|
195
|
+
indent=indent,
|
|
196
|
+
sheets_dir=sheets_dir,
|
|
197
|
+
print_areas_dir=print_areas_dir,
|
|
198
|
+
include_print_areas=None if mode == "light" else True,
|
|
199
|
+
include_shape_size=True if mode == "verbose" else False,
|
|
200
|
+
include_chart_size=True if mode == "verbose" else False,
|
|
201
|
+
stream=stream,
|
|
202
|
+
),
|
|
203
|
+
)
|
|
204
|
+
engine.process(
|
|
205
|
+
file_path=file_path,
|
|
206
|
+
output_path=output_path,
|
|
207
|
+
out_fmt=out_fmt,
|
|
208
|
+
image=image,
|
|
209
|
+
pdf=pdf,
|
|
210
|
+
dpi=dpi,
|
|
211
|
+
mode=mode,
|
|
212
|
+
pretty=pretty,
|
|
213
|
+
indent=indent,
|
|
214
|
+
sheets_dir=sheets_dir,
|
|
215
|
+
print_areas_dir=print_areas_dir,
|
|
216
|
+
stream=stream,
|
|
217
|
+
)
|
|
@@ -57,6 +57,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
57
57
|
type=Path,
|
|
58
58
|
help="Optional directory to write one file per sheet (format follows --format).",
|
|
59
59
|
)
|
|
60
|
+
parser.add_argument(
|
|
61
|
+
"--print-areas-dir",
|
|
62
|
+
type=Path,
|
|
63
|
+
help="Optional directory to write one file per print area (format follows --format).",
|
|
64
|
+
)
|
|
60
65
|
return parser
|
|
61
66
|
|
|
62
67
|
|
|
@@ -80,6 +85,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
80
85
|
mode=args.mode,
|
|
81
86
|
pretty=args.pretty,
|
|
82
87
|
sheets_dir=args.sheets_dir,
|
|
88
|
+
print_areas_dir=args.print_areas_dir,
|
|
83
89
|
)
|
|
84
90
|
return 0
|
|
85
91
|
except Exception as e:
|