exstruct 0.2.1__tar.gz → 0.2.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: exstruct
3
- Version: 0.2.1
3
+ Version: 0.2.3
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
@@ -41,6 +41,7 @@ Requires-Dist: pydantic>=2.12.5
41
41
  Requires-Dist: scipy>=1.16.3
42
42
  Requires-Dist: xlwings>=0.33.16
43
43
  Requires-Dist: pypdfium2>=5.1.0 ; extra == 'render'
44
+ Requires-Dist: pillow>=12.0.0 ; extra == 'render'
44
45
  Requires-Dist: python-toon>=0.1.3 ; extra == 'toon'
45
46
  Requires-Dist: pyyaml>=6.0.3 ; extra == 'yaml'
46
47
  Requires-Python: >=3.11
@@ -55,14 +56,16 @@ Description-Content-Type: text/markdown
55
56
 
56
57
  # ExStruct — Excel Structured Extraction Engine
57
58
 
58
- <img width="3168" height="1344" alt="Gemini_Generated_Image_nlwx0bnlwx0bnlwx" src="https://github.com/user-attachments/assets/90231682-fb42-428e-bf01-4389e8116b65" />
59
+ [![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)
59
60
 
60
- ExStruct reads Excel workbooks and outputs structured data (tables, shapes, charts) as JSON by default, with optional YAML/TOON formats. It targets both COM/Excel environments (rich extraction) and non-COM environments (cells + table candidates), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
61
+ ![ExStruct Image](/docs/assets/icon.webp)
62
+
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.
61
64
 
62
65
  ## Features
63
66
 
64
- - **Excel → Structured JSON**: cells, shapes, charts, and table candidates per sheet.
65
- - **Output modes**: `light` (cells + table candidates only), `standard` (texted shapes + arrows, charts), `verbose` (all shapes with width/height).
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.
66
69
  - **Formats**: JSON (compact by default, `--pretty` available), YAML, TOON (optional dependencies).
67
70
  - **Table detection tuning**: adjust heuristics at runtime via API.
68
71
  - **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
@@ -78,51 +81,67 @@ Optional extras:
78
81
 
79
82
  - YAML: `pip install pyyaml`
80
83
  - TOON: `pip install python-toon`
81
- - Rendering (PDF/PNG): Excel + `pip install pypdfium2`
84
+ - Rendering (PDF/PNG): Excel + `pip install pypdfium2 pillow`
85
+ - All extras at once: `pip install exstruct[yaml,toon,render]`
82
86
 
83
- ## Quick Start (CLI)
84
-
85
- ```bash
86
- exstruct input.xlsx > output.json # compact JSON to stdout (default)
87
- exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
88
- exstruct input.xlsx --format yaml # YAML (needs pyyaml)
89
- exstruct input.xlsx --format toon # TOON (needs python-toon)
90
- exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
91
- exstruct input.xlsx --mode light # cells + table candidates only
92
- exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
93
- ```
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)
92
+
93
+ ```bash
94
+ exstruct input.xlsx > output.json # compact JSON to stdout (default)
95
+ exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
96
+ exstruct input.xlsx --format yaml # YAML (needs pyyaml)
97
+ exstruct input.xlsx --format toon # TOON (needs python-toon)
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)
100
+ exstruct input.xlsx --mode light # cells + table candidates only
101
+ exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
102
+ ```
94
103
 
95
104
  ## Quick Start (Python)
96
105
 
97
106
  ```python
98
107
  from pathlib import Path
99
- from exstruct import extract, export, set_table_detection_params
100
-
101
- # Tune table detection (optional)
102
- set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
103
-
104
- # Extract with modes: "light", "standard", "verbose"
105
- wb = extract("input.xlsx", mode="standard")
106
- export(wb, Path("out.json"), pretty=False) # compact JSON
107
-
108
- # Model helpers: iterate, index, and serialize directly from the models
109
- first_sheet = wb["Sheet1"] # __getitem__ access
110
- for name, sheet in wb: # __iter__ yields (name, SheetData)
111
- print(name, len(sheet.rows))
112
- wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
113
- first_sheet.save("sheet.json") # SheetData → file (by extension)
114
- print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
115
-
116
- # ExStructEngine: per-instance options for extraction/output
117
- from exstruct import ExStructEngine, StructOptions, OutputOptions
118
-
119
- engine = ExStructEngine(
120
- options=StructOptions(mode="standard"),
121
- output=OutputOptions(include_shapes=False, pretty=True),
122
- )
123
- wb2 = engine.extract("input.xlsx")
124
- engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
125
- ```
108
+ from exstruct import extract, export, set_table_detection_params
109
+
110
+ # Tune table detection (optional)
111
+ set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
112
+
113
+ # Extract with modes: "light", "standard", "verbose"
114
+ wb = extract("input.xlsx", mode="standard")
115
+ export(wb, Path("out.json"), pretty=False) # compact JSON
116
+
117
+ # Model helpers: iterate, index, and serialize directly
118
+ first_sheet = wb["Sheet1"] # __getitem__ access
119
+ for name, sheet in wb: # __iter__ yields (name, SheetData)
120
+ print(name, len(sheet.rows))
121
+ wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
122
+ first_sheet.save("sheet.json") # SheetData → file (by extension)
123
+ print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
124
+
125
+ # ExStructEngine: per-instance options for extraction/output
126
+ from exstruct import ExStructEngine, StructOptions, OutputOptions
127
+
128
+ engine = ExStructEngine(
129
+ options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
130
+ output=OutputOptions(include_shapes=False, pretty=True),
131
+ )
132
+ wb2 = engine.extract("input.xlsx")
133
+ engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
134
+
135
+ # Enable hyperlinks in other modes
136
+ engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
137
+ with_links = engine_links.extract("input.xlsx")
138
+
139
+ # Export per print area (if print areas exist)
140
+ from exstruct import export_print_areas_as
141
+ export_print_areas_as(wb, "areas", fmt="json", pretty=True)
142
+ ```
143
+
144
+ **Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
126
145
 
127
146
  ## Table Detection Tuning
128
147
 
@@ -142,8 +161,8 @@ Use higher thresholds to reduce false positives; lower them if true tables are m
142
161
  ## Output Modes
143
162
 
144
163
  - **light**: cells + table candidates (no COM needed).
145
- - **standard**: texted shapes + arrows, charts (COM if available), table candidates.
146
- - **verbose**: all shapes (with width/height), charts, table candidates.
164
+ - **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
165
+ - **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
147
166
 
148
167
  ## Error Handling / Fallbacks
149
168
 
@@ -170,7 +189,9 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
170
189
  - Flowchart built only with shapes
171
190
 
172
191
  (Screenshot below is the actual sample Excel sheet)
173
- <img width="1842" height="1242" alt="スクリーンショット 2025-12-04 221252" src="https://github.com/user-attachments/assets/37ffcb3d-121e-47c1-a59f-0497337c85d9" />
192
+ ![Sample Excel](/docs/assets/demo_sheet.png)
193
+ Sample workbook: `sample/sample.xlsx`
194
+ Sample workbook: `sample/sample.xlsx`
174
195
 
175
196
  ### 1. Input: Excel Sheet Overview
176
197
 
@@ -357,6 +378,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
357
378
  - Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
358
379
  - Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
359
380
 
381
+ ## Print Areas (PrintArea / PrintAreaView)
382
+
383
+ - `SheetData.print_areas` holds print areas (cell coordinates) in light/standard/verbose.
384
+ - Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to write one file per print area (nothing is written if none exist).
385
+ - `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.
386
+
360
387
  ## License
361
388
 
362
389
  BSD-3-Clause. See `LICENSE` for details.
@@ -1,13 +1,15 @@
1
1
  # ExStruct — Excel Structured Extraction Engine
2
2
 
3
- <img width="3168" height="1344" alt="Gemini_Generated_Image_nlwx0bnlwx0bnlwx" src="https://github.com/user-attachments/assets/90231682-fb42-428e-bf01-4389e8116b65" />
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)
4
4
 
5
- ExStruct reads Excel workbooks and outputs structured data (tables, shapes, charts) as JSON by default, with optional YAML/TOON formats. It targets both COM/Excel environments (rich extraction) and non-COM environments (cells + table candidates), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
5
+ ![ExStruct Image](/docs/assets/icon.webp)
6
+
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.
6
8
 
7
9
  ## Features
8
10
 
9
- - **Excel → Structured JSON**: cells, shapes, charts, and table candidates per sheet.
10
- - **Output modes**: `light` (cells + table candidates only), `standard` (texted shapes + arrows, charts), `verbose` (all shapes with width/height).
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.
11
13
  - **Formats**: JSON (compact by default, `--pretty` available), YAML, TOON (optional dependencies).
12
14
  - **Table detection tuning**: adjust heuristics at runtime via API.
13
15
  - **CLI rendering** (Excel required): optional PDF and per-sheet PNGs.
@@ -23,51 +25,67 @@ Optional extras:
23
25
 
24
26
  - YAML: `pip install pyyaml`
25
27
  - TOON: `pip install python-toon`
26
- - Rendering (PDF/PNG): Excel + `pip install pypdfium2`
27
-
28
- ## Quick Start (CLI)
29
-
30
- ```bash
31
- exstruct input.xlsx > output.json # compact JSON to stdout (default)
32
- exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
33
- exstruct input.xlsx --format yaml # YAML (needs pyyaml)
34
- exstruct input.xlsx --format toon # TOON (needs python-toon)
35
- exstruct input.xlsx --sheets-dir sheets/ # split per sheet in chosen format
36
- exstruct input.xlsx --mode light # cells + table candidates only
37
- exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
38
- ```
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)
36
+
37
+ ```bash
38
+ exstruct input.xlsx > output.json # compact JSON to stdout (default)
39
+ exstruct input.xlsx -o out.json --pretty # pretty JSON to a file
40
+ exstruct input.xlsx --format yaml # YAML (needs pyyaml)
41
+ exstruct input.xlsx --format toon # TOON (needs python-toon)
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)
44
+ exstruct input.xlsx --mode light # cells + table candidates only
45
+ exstruct input.xlsx --pdf --image # PDF and PNGs (Excel required)
46
+ ```
39
47
 
40
48
  ## Quick Start (Python)
41
49
 
42
50
  ```python
43
51
  from pathlib import Path
44
- from exstruct import extract, export, set_table_detection_params
45
-
46
- # Tune table detection (optional)
47
- set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
48
-
49
- # Extract with modes: "light", "standard", "verbose"
50
- wb = extract("input.xlsx", mode="standard")
51
- export(wb, Path("out.json"), pretty=False) # compact JSON
52
-
53
- # Model helpers: iterate, index, and serialize directly from the models
54
- first_sheet = wb["Sheet1"] # __getitem__ access
55
- for name, sheet in wb: # __iter__ yields (name, SheetData)
56
- print(name, len(sheet.rows))
57
- wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
58
- first_sheet.save("sheet.json") # SheetData → file (by extension)
59
- print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
60
-
61
- # ExStructEngine: per-instance options for extraction/output
62
- from exstruct import ExStructEngine, StructOptions, OutputOptions
63
-
64
- engine = ExStructEngine(
65
- options=StructOptions(mode="standard"),
66
- output=OutputOptions(include_shapes=False, pretty=True),
67
- )
68
- wb2 = engine.extract("input.xlsx")
69
- engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
70
- ```
52
+ from exstruct import extract, export, set_table_detection_params
53
+
54
+ # Tune table detection (optional)
55
+ set_table_detection_params(table_score_threshold=0.3, density_min=0.04)
56
+
57
+ # Extract with modes: "light", "standard", "verbose"
58
+ wb = extract("input.xlsx", mode="standard")
59
+ export(wb, Path("out.json"), pretty=False) # compact JSON
60
+
61
+ # Model helpers: iterate, index, and serialize directly
62
+ first_sheet = wb["Sheet1"] # __getitem__ access
63
+ for name, sheet in wb: # __iter__ yields (name, SheetData)
64
+ print(name, len(sheet.rows))
65
+ wb.save("out.json", pretty=True) # WorkbookData → file (by extension)
66
+ first_sheet.save("sheet.json") # SheetData → file (by extension)
67
+ print(first_sheet.to_yaml()) # YAML text (requires pyyaml)
68
+
69
+ # ExStructEngine: per-instance options for extraction/output
70
+ from exstruct import ExStructEngine, StructOptions, OutputOptions
71
+
72
+ engine = ExStructEngine(
73
+ options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
74
+ output=OutputOptions(include_shapes=False, pretty=True),
75
+ )
76
+ wb2 = engine.extract("input.xlsx")
77
+ engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
78
+
79
+ # Enable hyperlinks in other modes
80
+ engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
81
+ with_links = engine_links.extract("input.xlsx")
82
+
83
+ # Export per print area (if print areas exist)
84
+ from exstruct import export_print_areas_as
85
+ export_print_areas_as(wb, "areas", fmt="json", pretty=True)
86
+ ```
87
+
88
+ **Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
71
89
 
72
90
  ## Table Detection Tuning
73
91
 
@@ -87,8 +105,8 @@ Use higher thresholds to reduce false positives; lower them if true tables are m
87
105
  ## Output Modes
88
106
 
89
107
  - **light**: cells + table candidates (no COM needed).
90
- - **standard**: texted shapes + arrows, charts (COM if available), table candidates.
91
- - **verbose**: all shapes (with width/height), charts, table candidates.
108
+ - **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
109
+ - **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
92
110
 
93
111
  ## Error Handling / Fallbacks
94
112
 
@@ -115,7 +133,9 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
115
133
  - Flowchart built only with shapes
116
134
 
117
135
  (Screenshot below is the actual sample Excel sheet)
118
- <img width="1842" height="1242" alt="スクリーンショット 2025-12-04 221252" src="https://github.com/user-attachments/assets/37ffcb3d-121e-47c1-a59f-0497337c85d9" />
136
+ ![Sample Excel](/docs/assets/demo_sheet.png)
137
+ Sample workbook: `sample/sample.xlsx`
138
+ Sample workbook: `sample/sample.xlsx`
119
139
 
120
140
  ### 1. Input: Excel Sheet Overview
121
141
 
@@ -302,6 +322,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
302
322
  - Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
303
323
  - Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
304
324
 
325
+ ## Print Areas (PrintArea / PrintAreaView)
326
+
327
+ - `SheetData.print_areas` holds print areas (cell coordinates) in light/standard/verbose.
328
+ - Use `export_print_areas_as(...)` or CLI `--print-areas-dir` to write one file per print area (nothing is written if none exist).
329
+ - `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.
330
+
305
331
  ## License
306
332
 
307
333
  BSD-3-Clause. See `LICENSE` for details.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "exstruct"
3
- version = "0.2.1"
3
+ version = "0.2.3"
4
4
  description = "Excel to structured JSON (tables, shapes, charts) for LLM/RAG pipelines"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -33,7 +33,7 @@ dev = [
33
33
  [project.optional-dependencies]
34
34
  yaml = ["pyyaml>=6.0.3"]
35
35
  toon = ["python-toon>=0.1.3"]
36
- render = ["pypdfium2>=5.1.0"]
36
+ render = ["pypdfium2>=5.1.0", "Pillow>=12.0.0"]
37
37
 
38
38
  [project.scripts]
39
39
  exstruct = "exstruct.cli.main:main"
@@ -43,3 +43,10 @@ Homepage = "https://harumiweb.github.io/exstruct/"
43
43
  Repository = "https://github.com/harumiWeb/exstruct"
44
44
  Issues = "https://github.com/harumiWeb/exstruct/issues"
45
45
  Documentation = "https://harumiweb.github.io/exstruct/"
46
+
47
+ [tool.coverage.run]
48
+ omit = [
49
+ "tests/*",
50
+ "*/test_*.py",
51
+ "*/gen_py/*",
52
+ ]
@@ -0,0 +1,215 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Literal, Optional, 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
+ "ExStructEngine",
49
+ "StructOptions",
50
+ "OutputOptions",
51
+ ]
52
+
53
+
54
+ ExtractionMode = Literal["light", "standard", "verbose"]
55
+
56
+
57
+ def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> WorkbookData:
58
+ """
59
+ Extract an Excel workbook into WorkbookData.
60
+
61
+ Args:
62
+ file_path: Path to .xlsx/.xlsm/.xls.
63
+ mode: "light" / "standard" / "verbose"
64
+ - light: cells + table detection only (no COM, shapes/charts empty). Print areas via openpyxl.
65
+ - standard: texted shapes + arrows + charts (COM if available), print areas included. Shape/chart size is kept but hidden by default in output.
66
+ - verbose: all shapes (including textless) with size, charts with size.
67
+ """
68
+ include_links = True if mode == "verbose" else False
69
+ engine = ExStructEngine(
70
+ options=StructOptions(mode=mode, include_cell_links=include_links)
71
+ )
72
+ return engine.extract(file_path, mode=mode)
73
+
74
+
75
+ def export(
76
+ data: WorkbookData,
77
+ path: str | Path,
78
+ fmt: Optional[Literal["json", "yaml", "yml", "toon"]] = None,
79
+ *,
80
+ pretty: bool = False,
81
+ indent: int | None = None,
82
+ ) -> None:
83
+ """
84
+ Save WorkbookData to a file (format inferred from extension).
85
+
86
+ Args:
87
+ data: WorkbookData from `extract` or similar
88
+ path: destination path; extension is used to infer format
89
+ fmt: explicitly set format if desired (json/yaml/yml/toon)
90
+ pretty: pretty-print JSON
91
+ indent: JSON indent width (defaults to 2 when pretty=True and indent is None)
92
+ """
93
+ dest = Path(path)
94
+ format_hint = (fmt or dest.suffix.lstrip(".") or "json").lower()
95
+ match format_hint:
96
+ case "json":
97
+ save_as_json(data, dest, pretty=pretty, indent=indent)
98
+ case "yaml" | "yml":
99
+ save_as_yaml(data, dest)
100
+ case "toon":
101
+ save_as_toon(data, dest)
102
+ case _:
103
+ raise ValueError(f"Unsupported export format: {format_hint}")
104
+
105
+
106
+ def export_sheets(data: WorkbookData, dir_path: str | Path) -> dict[str, Path]:
107
+ """
108
+ Export each sheet as an individual JSON file.
109
+
110
+ - Payload: {book_name, sheet_name, sheet: SheetData}
111
+ - Returns: {sheet_name: Path}
112
+ """
113
+ return save_sheets(data, Path(dir_path), fmt="json")
114
+
115
+
116
+ def export_sheets_as(
117
+ data: WorkbookData,
118
+ dir_path: str | Path,
119
+ fmt: Literal["json", "yaml", "yml", "toon"] = "json",
120
+ *,
121
+ pretty: bool = False,
122
+ indent: int | None = None,
123
+ ) -> dict[str, Path]:
124
+ """Export each sheet in the given format (json/yaml/toon); returns sheet name to path map."""
125
+ return save_sheets(data, Path(dir_path), fmt=fmt, pretty=pretty, indent=indent)
126
+
127
+
128
+ def export_print_areas_as(
129
+ data: WorkbookData,
130
+ dir_path: str | Path,
131
+ fmt: Literal["json", "yaml", "yml", "toon"] = "json",
132
+ *,
133
+ pretty: bool = False,
134
+ indent: int | None = None,
135
+ normalize: bool = False,
136
+ ) -> dict[str, Path]:
137
+ """
138
+ Export each print area as a PrintAreaView.
139
+
140
+ Args:
141
+ data: WorkbookData that contains print areas
142
+ dir_path: output directory
143
+ fmt: json/yaml/yml/toon
144
+ pretty/indent: JSON formatting options
145
+ normalize: rebase row/col indices to the print-area origin when True
146
+ Returns:
147
+ dict mapping area key to path (e.g., "Sheet1#1": /.../Sheet1_area1_...json)
148
+ """
149
+ return save_print_area_views(
150
+ data,
151
+ Path(dir_path),
152
+ fmt=fmt,
153
+ pretty=pretty,
154
+ indent=indent,
155
+ normalize=normalize,
156
+ )
157
+
158
+
159
+ def process_excel(
160
+ file_path: Path,
161
+ output_path: Path | None = None,
162
+ out_fmt: str = "json",
163
+ image: bool = False,
164
+ pdf: bool = False,
165
+ dpi: int = 72,
166
+ mode: ExtractionMode = "standard",
167
+ pretty: bool = False,
168
+ indent: int | None = None,
169
+ sheets_dir: Path | None = None,
170
+ print_areas_dir: Path | None = None,
171
+ stream: TextIO | None = None,
172
+ ) -> None:
173
+ """
174
+ Convenience wrapper: extract → serialize (file or stdout) → optional PDF/PNG.
175
+
176
+ Args:
177
+ file_path: input Excel
178
+ output_path: None for stdout; otherwise, write to file
179
+ out_fmt: json/yaml/yml/toon
180
+ image/pdf: True to also output PNG/PDF (requires Excel + pypdfium2)
181
+ dpi: DPI for image output
182
+ mode: light/standard/verbose (same meaning as `extract`)
183
+ pretty/indent: JSON formatting
184
+ sheets_dir: directory to write per-sheet files
185
+ print_areas_dir: directory to write per-print-area files
186
+ stream: IO override when output_path is None
187
+ """
188
+ engine = ExStructEngine(
189
+ options=StructOptions(mode=mode),
190
+ output=OutputOptions(
191
+ fmt=out_fmt,
192
+ pretty=pretty,
193
+ indent=indent,
194
+ sheets_dir=sheets_dir,
195
+ print_areas_dir=print_areas_dir,
196
+ include_print_areas=None if mode == "light" else True,
197
+ include_shape_size=True if mode == "verbose" else False,
198
+ include_chart_size=True if mode == "verbose" else False,
199
+ stream=stream,
200
+ ),
201
+ )
202
+ engine.process(
203
+ file_path=file_path,
204
+ output_path=output_path,
205
+ out_fmt=out_fmt,
206
+ image=image,
207
+ pdf=pdf,
208
+ dpi=dpi,
209
+ mode=mode,
210
+ pretty=pretty,
211
+ indent=indent,
212
+ sheets_dir=sheets_dir,
213
+ print_areas_dir=print_areas_dir,
214
+ stream=stream,
215
+ )
@@ -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: