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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: exstruct
3
- Version: 0.2.11
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
- [![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) [![CI](https://github.com/harumiWeb/exstruct/actions/workflows/ci.yml/badge.svg)](https://github.com/harumiWeb/exstruct/actions/workflows/ci.yml)
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)
60
60
 
61
61
  ![ExStruct Image](/docs/assets/icon.webp)
62
62
 
63
- 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.
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).
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
- - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates` safely.
89
-
90
- ## Quick Start (CLI)
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 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,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 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
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
- engine = ExStructEngine(
127
- options=StructOptions(mode="standard"),
128
- output=OutputOptions(include_shapes=False, pretty=True),
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
  ![Sample Excel](/docs/assets/demo_sheet.png)
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
- [![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) [![CI](https://github.com/harumiWeb/exstruct/actions/workflows/ci.yml/badge.svg)](https://github.com/harumiWeb/exstruct/actions/workflows/ci.yml)
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
5
  ![ExStruct Image](/docs/assets/icon.webp)
6
6
 
7
- 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.
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).
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
- - Full extraction (shapes/charts) targets Windows + Excel (COM via xlwings). On other platforms, use `mode=light` to get cells + `table_candidates` safely.
33
-
34
- ## Quick Start (CLI)
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 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,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 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
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
- engine = ExStructEngine(
71
- options=StructOptions(mode="standard"),
72
- output=OutputOptions(include_shapes=False, pretty=True),
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
  ![Sample Excel](/docs/assets/demo_sheet.png)
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: