exstruct 0.2.21__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: exstruct
3
- Version: 0.2.21
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
@@ -60,12 +60,12 @@ Description-Content-Type: text/markdown
60
60
 
61
61
  ![ExStruct Image](/docs/assets/icon.webp)
62
62
 
63
- ExStruct reads Excel workbooks and outputs structured data (tables, shapes, charts, 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), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
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, and table candidates per sheet.
68
- - **Output modes**: `light` (cells + table candidates only), `standard` (texted shapes + arrows, charts), `verbose` (all shapes with width/height). Verbose also emits cell hyperlinks.
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.
@@ -85,7 +85,8 @@ Optional extras:
85
85
  - All extras at once: `pip install exstruct[yaml,toon,render]`
86
86
 
87
87
  Platform note:
88
- - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates` safely.
88
+
89
+ - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates`.
89
90
 
90
91
  ## Quick Start (CLI)
91
92
 
@@ -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 from the models
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,19 +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 for extraction/output
124
- from exstruct import ExStructEngine, StructOptions, OutputOptions
125
+ # ExStructEngine: per-instance options (nested configs)
126
+ from exstruct import ExStructEngine, StructOptions, OutputOptions, FormatOptions, FilterOptions, DestinationOptions
125
127
 
126
128
  engine = ExStructEngine(
127
129
  options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
128
- output=OutputOptions(include_shapes=False, pretty=True),
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
+ ),
129
135
  )
130
136
  wb2 = engine.extract("input.xlsx")
131
- engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
137
+ engine.export(wb2, Path("out_filtered.json")) # drops shapes via filters
132
138
 
133
139
  # Enable hyperlinks in other modes
134
140
  engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
135
141
  with_links = engine_links.extract("input.xlsx")
142
+
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)
136
146
  ```
137
147
 
138
148
  **Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
@@ -152,11 +162,11 @@ set_table_detection_params(
152
162
 
153
163
  Use higher thresholds to reduce false positives; lower them if true tables are missed.
154
164
 
155
- ## Output Modes
156
-
157
- - **light**: cells + table candidates (no COM needed).
158
- - **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
159
- - **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
165
+ ## Output Modes
166
+
167
+ - **light**: cells + table candidates (no COM needed).
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.
160
170
 
161
171
  ## Error Handling / Fallbacks
162
172
 
@@ -185,6 +195,7 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
185
195
  (Screenshot below is the actual sample Excel sheet)
186
196
  ![Sample Excel](/docs/assets/demo_sheet.png)
187
197
  Sample workbook: `sample/sample.xlsx`
198
+ Sample workbook: `sample/sample.xlsx`
188
199
 
189
200
  ### 1. Input: Excel Sheet Overview
190
201
 
@@ -371,6 +382,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
371
382
  - Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
372
383
  - Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
373
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
+
374
391
  ## License
375
392
 
376
393
  BSD-3-Clause. See `LICENSE` for details.
@@ -378,18 +395,3 @@ BSD-3-Clause. See `LICENSE` for details.
378
395
  ## Documentation
379
396
 
380
397
  - API Reference (GitHub Pages): https://harumiweb.github.io/exstruct/
381
- # Engine option cheat sheet
382
-
383
- | Option class | Field | Meaning |
384
- | -------------- | ------------------- | ------- |
385
- | StructOptions | mode | "light"/"standard"/"verbose" |
386
- | | table_params | Dict passed to `set_table_detection_params` (table_score_threshold, density_min, coverage_min, min_nonempty_cells) |
387
- | | include_cell_links | Include cell hyperlinks in `rows[*].links` (None -> auto: verbose=True, others=False) |
388
- | OutputOptions | fmt | Default format ("json"/"yaml"/"yml"/"toon") |
389
- | | pretty / indent | Pretty-print JSON and control indent |
390
- | | include_rows | Include rows (False to drop) |
391
- | | include_shapes | Include shapes |
392
- | | include_charts | Include charts |
393
- | | include_tables | Include table_candidates |
394
- | | sheets_dir | Optional directory for per-sheet exports |
395
- | | stream | Default stream when output_path is None |
@@ -4,12 +4,12 @@
4
4
 
5
5
  ![ExStruct Image](/docs/assets/icon.webp)
6
6
 
7
- ExStruct reads Excel workbooks and outputs structured data (tables, shapes, charts, 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), with tunable detection heuristics and multiple output modes to fit LLM/RAG pipelines.
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, and table candidates per sheet.
12
- - **Output modes**: `light` (cells + table candidates only), `standard` (texted shapes + arrows, charts), `verbose` (all shapes with width/height). Verbose also emits cell hyperlinks.
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.
@@ -29,7 +29,8 @@ Optional extras:
29
29
  - All extras at once: `pip install exstruct[yaml,toon,render]`
30
30
 
31
31
  Platform note:
32
- - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates` safely.
32
+
33
+ - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates`.
33
34
 
34
35
  ## Quick Start (CLI)
35
36
 
@@ -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 from the models
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,19 +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 for extraction/output
68
- from exstruct import ExStructEngine, StructOptions, OutputOptions
69
+ # ExStructEngine: per-instance options (nested configs)
70
+ from exstruct import ExStructEngine, StructOptions, OutputOptions, FormatOptions, FilterOptions, DestinationOptions
69
71
 
70
72
  engine = ExStructEngine(
71
73
  options=StructOptions(mode="verbose"), # verbose includes hyperlinks by default
72
- output=OutputOptions(include_shapes=False, pretty=True),
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
+ ),
73
79
  )
74
80
  wb2 = engine.extract("input.xlsx")
75
- engine.export(wb2, Path("out_filtered.json")) # drops shapes via OutputOptions
81
+ engine.export(wb2, Path("out_filtered.json")) # drops shapes via filters
76
82
 
77
83
  # Enable hyperlinks in other modes
78
84
  engine_links = ExStructEngine(options=StructOptions(mode="standard", include_cell_links=True))
79
85
  with_links = engine_links.extract("input.xlsx")
86
+
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)
80
90
  ```
81
91
 
82
92
  **Note (non-COM environments):** If Excel COM is unavailable, extraction still runs and returns cells + `table_candidates`; `shapes`/`charts` will be empty.
@@ -96,11 +106,11 @@ set_table_detection_params(
96
106
 
97
107
  Use higher thresholds to reduce false positives; lower them if true tables are missed.
98
108
 
99
- ## Output Modes
100
-
101
- - **light**: cells + table candidates (no COM needed).
102
- - **standard**: texted shapes + arrows, charts (COM if available), table candidates. Hyperlinks are off unless `include_cell_links=True`.
103
- - **verbose**: all shapes (with width/height), charts, table candidates, and cell hyperlinks.
109
+ ## Output Modes
110
+
111
+ - **light**: cells + table candidates (no COM needed).
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.
104
114
 
105
115
  ## Error Handling / Fallbacks
106
116
 
@@ -129,6 +139,7 @@ To show how well exstruct can structure Excel, we parse a workbook that combines
129
139
  (Screenshot below is the actual sample Excel sheet)
130
140
  ![Sample Excel](/docs/assets/demo_sheet.png)
131
141
  Sample workbook: `sample/sample.xlsx`
142
+ Sample workbook: `sample/sample.xlsx`
132
143
 
133
144
  ### 1. Input: Excel Sheet Overview
134
145
 
@@ -315,6 +326,12 @@ In short, **exstruct = “an engine that converts Excel into a format AI can und
315
326
  - Default JSON is compact to reduce tokens; use `--pretty` or `pretty=True` when readability matters.
316
327
  - Field `table_candidates` replaces `tables`; adjust downstream consumers accordingly.
317
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
+
318
335
  ## License
319
336
 
320
337
  BSD-3-Clause. See `LICENSE` for details.
@@ -322,18 +339,3 @@ BSD-3-Clause. See `LICENSE` for details.
322
339
  ## Documentation
323
340
 
324
341
  - API Reference (GitHub Pages): https://harumiweb.github.io/exstruct/
325
- # Engine option cheat sheet
326
-
327
- | Option class | Field | Meaning |
328
- | -------------- | ------------------- | ------- |
329
- | StructOptions | mode | "light"/"standard"/"verbose" |
330
- | | table_params | Dict passed to `set_table_detection_params` (table_score_threshold, density_min, coverage_min, min_nonempty_cells) |
331
- | | include_cell_links | Include cell hyperlinks in `rows[*].links` (None -> auto: verbose=True, others=False) |
332
- | OutputOptions | fmt | Default format ("json"/"yaml"/"yml"/"toon") |
333
- | | pretty / indent | Pretty-print JSON and control indent |
334
- | | include_rows | Include rows (False to drop) |
335
- | | include_shapes | Include shapes |
336
- | | include_charts | Include charts |
337
- | | include_tables | Include table_candidates |
338
- | | sheets_dir | Optional directory for per-sheet exports |
339
- | | 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: