exstruct 0.2.61__tar.gz → 0.2.62__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.61 → exstruct-0.2.62}/PKG-INFO +2 -2
- {exstruct-0.2.61 → exstruct-0.2.62}/README.md +1 -1
- {exstruct-0.2.61 → exstruct-0.2.62}/pyproject.toml +2 -1
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/__init__.py +125 -20
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/cli/main.py +97 -97
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/core/integrate.py +10 -8
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/engine.py +141 -56
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/errors.py +35 -35
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/models/__init__.py +107 -47
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/render/__init__.py +118 -107
- {exstruct-0.2.61 → exstruct-0.2.62}/LICENSE +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/core/__init__.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/core/cells.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/core/charts.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/core/shapes.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/io/__init__.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/models/maps.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/src/exstruct/models/types.py +0 -0
- {exstruct-0.2.61 → exstruct-0.2.62}/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.62
|
|
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
|
|
@@ -55,7 +55,7 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
|
|
56
56
|
# ExStruct — Excel Structured Extraction Engine
|
|
57
57
|
|
|
58
|
-
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml)
|
|
58
|
+
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml) [](https://app.codacy.com/gh/harumiWeb/exstruct/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
59
59
|
|
|
60
60
|

|
|
61
61
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ExStruct — Excel Structured Extraction Engine
|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml)
|
|
3
|
+
[](https://pypi.org/project/exstruct/) [](https://pepy.tech/projects/exstruct)  [](https://github.com/harumiWeb/exstruct/actions/workflows/pytest.yml) [](https://app.codacy.com/gh/harumiWeb/exstruct/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "exstruct"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.62"
|
|
4
4
|
description = "Excel to structured JSON (tables, shapes, charts) for LLM/RAG pipelines"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -25,6 +25,7 @@ build-backend = "uv_build"
|
|
|
25
25
|
[dependency-groups]
|
|
26
26
|
dev = [
|
|
27
27
|
"mkdocs-material>=9.7.0",
|
|
28
|
+
"mkdocstrings-python>=2.0.1",
|
|
28
29
|
"mypy>=1.19.0",
|
|
29
30
|
"pre-commit>=4.5.0",
|
|
30
31
|
"pytest>=9.0.1",
|
|
@@ -94,6 +94,20 @@ def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> Workboo
|
|
|
94
94
|
- light: cells + table detection only (no COM, shapes/charts empty). Print areas via openpyxl.
|
|
95
95
|
- standard: texted shapes + arrows + charts (COM if available), print areas included. Shape/chart size is kept but hidden by default in output.
|
|
96
96
|
- verbose: all shapes (including textless) with size, charts with size.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
WorkbookData containing sheets, rows, shapes, charts, and print areas.
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
ValueError: If an invalid mode is provided.
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
Extract with hyperlinks (verbose) and inspect table candidates:
|
|
106
|
+
|
|
107
|
+
>>> from exstruct import extract
|
|
108
|
+
>>> wb = extract("input.xlsx", mode="verbose")
|
|
109
|
+
>>> wb.sheets["Sheet1"].table_candidates
|
|
110
|
+
['A1:B5']
|
|
97
111
|
"""
|
|
98
112
|
include_links = True if mode == "verbose" else False
|
|
99
113
|
engine = ExStructEngine(
|
|
@@ -119,6 +133,17 @@ def export(
|
|
|
119
133
|
fmt: explicitly set format if desired (json/yaml/yml/toon)
|
|
120
134
|
pretty: pretty-print JSON
|
|
121
135
|
indent: JSON indent width (defaults to 2 when pretty=True and indent is None)
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
ValueError: If the format is unsupported.
|
|
139
|
+
|
|
140
|
+
Examples:
|
|
141
|
+
Write pretty JSON and YAML (requires pyyaml):
|
|
142
|
+
|
|
143
|
+
>>> from exstruct import export, extract
|
|
144
|
+
>>> wb = extract("input.xlsx")
|
|
145
|
+
>>> export(wb, "out.json", pretty=True)
|
|
146
|
+
>>> export(wb, "out.yaml", fmt="yaml") # doctest: +SKIP
|
|
122
147
|
"""
|
|
123
148
|
dest = Path(path)
|
|
124
149
|
format_hint = (fmt or dest.suffix.lstrip(".") or "json").lower()
|
|
@@ -139,6 +164,20 @@ def export_sheets(data: WorkbookData, dir_path: str | Path) -> dict[str, Path]:
|
|
|
139
164
|
|
|
140
165
|
- Payload: {book_name, sheet_name, sheet: SheetData}
|
|
141
166
|
- Returns: {sheet_name: Path}
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
data: WorkbookData to split by sheet.
|
|
170
|
+
dir_path: Output directory.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Mapping from sheet name to written JSON path.
|
|
174
|
+
|
|
175
|
+
Examples:
|
|
176
|
+
>>> from exstruct import export_sheets, extract
|
|
177
|
+
>>> wb = extract("input.xlsx")
|
|
178
|
+
>>> paths = export_sheets(wb, "out_sheets")
|
|
179
|
+
>>> "Sheet1" in paths
|
|
180
|
+
True
|
|
142
181
|
"""
|
|
143
182
|
return save_sheets(data, Path(dir_path), fmt="json")
|
|
144
183
|
|
|
@@ -151,7 +190,29 @@ def export_sheets_as(
|
|
|
151
190
|
pretty: bool = False,
|
|
152
191
|
indent: int | None = None,
|
|
153
192
|
) -> dict[str, Path]:
|
|
154
|
-
"""
|
|
193
|
+
"""
|
|
194
|
+
Export each sheet in the given format (json/yaml/toon); returns sheet name to path map.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
data: WorkbookData to split by sheet.
|
|
198
|
+
dir_path: Output directory.
|
|
199
|
+
fmt: Output format; inferred defaults to json.
|
|
200
|
+
pretty: Pretty-print JSON.
|
|
201
|
+
indent: JSON indent width (defaults to 2 when pretty=True and indent is None).
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Mapping from sheet name to written file path.
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
ValueError: If an unsupported format is passed.
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
Export per sheet as YAML (requires pyyaml):
|
|
211
|
+
|
|
212
|
+
>>> from exstruct import export_sheets_as, extract
|
|
213
|
+
>>> wb = extract("input.xlsx")
|
|
214
|
+
>>> _ = export_sheets_as(wb, "out_yaml", fmt="yaml") # doctest: +SKIP
|
|
215
|
+
"""
|
|
155
216
|
return save_sheets(data, Path(dir_path), fmt=fmt, pretty=pretty, indent=indent)
|
|
156
217
|
|
|
157
218
|
|
|
@@ -171,10 +232,21 @@ def export_print_areas_as(
|
|
|
171
232
|
data: WorkbookData that contains print areas
|
|
172
233
|
dir_path: output directory
|
|
173
234
|
fmt: json/yaml/yml/toon
|
|
174
|
-
pretty
|
|
235
|
+
pretty: Pretty-print JSON output.
|
|
236
|
+
indent: JSON indent width (defaults to 2 when pretty is True and indent is None).
|
|
175
237
|
normalize: rebase row/col indices to the print-area origin when True
|
|
238
|
+
|
|
176
239
|
Returns:
|
|
177
240
|
dict mapping area key to path (e.g., "Sheet1#1": /.../Sheet1_area1_...json)
|
|
241
|
+
|
|
242
|
+
Examples:
|
|
243
|
+
Export print areas when present:
|
|
244
|
+
|
|
245
|
+
>>> from exstruct import export_print_areas_as, extract
|
|
246
|
+
>>> wb = extract("input.xlsx", mode="standard")
|
|
247
|
+
>>> paths = export_print_areas_as(wb, "areas")
|
|
248
|
+
>>> isinstance(paths, dict)
|
|
249
|
+
True
|
|
178
250
|
"""
|
|
179
251
|
return save_print_area_views(
|
|
180
252
|
data,
|
|
@@ -202,8 +274,23 @@ def export_auto_page_breaks(
|
|
|
202
274
|
data: WorkbookData containing auto_print_areas (COM extraction with auto breaks enabled)
|
|
203
275
|
dir_path: output directory
|
|
204
276
|
fmt: json/yaml/yml/toon
|
|
205
|
-
pretty
|
|
277
|
+
pretty: Pretty-print JSON output.
|
|
278
|
+
indent: JSON indent width (defaults to 2 when pretty is True and indent is None).
|
|
206
279
|
normalize: rebase row/col indices to the area origin when True
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
dict mapping area key to path (e.g., "Sheet1#1": /.../Sheet1_auto_page1_...json)
|
|
283
|
+
|
|
284
|
+
Raises:
|
|
285
|
+
PrintAreaError: If no auto page-break areas are present.
|
|
286
|
+
|
|
287
|
+
Examples:
|
|
288
|
+
>>> from exstruct import export_auto_page_breaks, extract
|
|
289
|
+
>>> wb = extract("input.xlsx", mode="standard")
|
|
290
|
+
>>> try:
|
|
291
|
+
... export_auto_page_breaks(wb, "auto_areas")
|
|
292
|
+
... except PrintAreaError:
|
|
293
|
+
... pass
|
|
207
294
|
"""
|
|
208
295
|
if not any(sheet.auto_print_areas for sheet in data.sheets.values()):
|
|
209
296
|
message = "No auto page-break areas found. Enable COM-based auto page breaks before exporting."
|
|
@@ -220,8 +307,8 @@ def export_auto_page_breaks(
|
|
|
220
307
|
|
|
221
308
|
|
|
222
309
|
def process_excel(
|
|
223
|
-
file_path: Path,
|
|
224
|
-
output_path: Path | None = None,
|
|
310
|
+
file_path: str | Path,
|
|
311
|
+
output_path: str | Path | None = None,
|
|
225
312
|
out_fmt: str = "json",
|
|
226
313
|
image: bool = False,
|
|
227
314
|
pdf: bool = False,
|
|
@@ -229,26 +316,44 @@ def process_excel(
|
|
|
229
316
|
mode: ExtractionMode = "standard",
|
|
230
317
|
pretty: bool = False,
|
|
231
318
|
indent: int | None = None,
|
|
232
|
-
sheets_dir: Path | None = None,
|
|
233
|
-
print_areas_dir: Path | None = None,
|
|
234
|
-
auto_page_breaks_dir: Path | None = None,
|
|
319
|
+
sheets_dir: str | Path | None = None,
|
|
320
|
+
print_areas_dir: str | Path | None = None,
|
|
321
|
+
auto_page_breaks_dir: str | Path | None = None,
|
|
235
322
|
stream: TextIO | None = None,
|
|
236
323
|
) -> None:
|
|
237
324
|
"""
|
|
238
|
-
Convenience wrapper: extract
|
|
325
|
+
Convenience wrapper: extract -> serialize (file or stdout) -> optional PDF/PNG.
|
|
239
326
|
|
|
240
327
|
Args:
|
|
241
|
-
file_path:
|
|
242
|
-
output_path: None for stdout; otherwise, write to file
|
|
243
|
-
out_fmt: json/yaml/yml/toon
|
|
244
|
-
image
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
328
|
+
file_path: Input Excel workbook (path string or Path).
|
|
329
|
+
output_path: None for stdout; otherwise, write to file (string or Path).
|
|
330
|
+
out_fmt: json/yaml/yml/toon.
|
|
331
|
+
image: True to also output PNGs (requires Excel + COM + pypdfium2).
|
|
332
|
+
pdf: True to also output PDF (requires Excel + COM + pypdfium2).
|
|
333
|
+
dpi: DPI for image output.
|
|
334
|
+
mode: light/standard/verbose (same meaning as `extract`).
|
|
335
|
+
pretty: Pretty-print JSON.
|
|
336
|
+
indent: JSON indent width.
|
|
337
|
+
sheets_dir: Directory to write per-sheet files (string or Path).
|
|
338
|
+
print_areas_dir: Directory to write per-print-area files (string or Path).
|
|
339
|
+
auto_page_breaks_dir: Directory to write per-auto-page-break files (COM only).
|
|
340
|
+
stream: IO override when output_path is None.
|
|
341
|
+
|
|
342
|
+
Raises:
|
|
343
|
+
ValueError: If an unsupported format or mode is given.
|
|
344
|
+
PrintAreaError: When exporting auto page breaks without available data.
|
|
345
|
+
RenderError: When rendering fails (Excel/COM/pypdfium2 issues).
|
|
346
|
+
|
|
347
|
+
Examples:
|
|
348
|
+
Extract and write JSON to stdout, plus per-sheet files:
|
|
349
|
+
|
|
350
|
+
>>> from pathlib import Path
|
|
351
|
+
>>> from exstruct import process_excel
|
|
352
|
+
>>> process_excel(Path("input.xlsx"), output_path=None, sheets_dir=Path("sheets"))
|
|
353
|
+
|
|
354
|
+
Render PDF only (COM + Excel required):
|
|
355
|
+
|
|
356
|
+
>>> process_excel(Path("input.xlsx"), output_path=Path("out.json"), pdf=True) # doctest: +SKIP
|
|
252
357
|
"""
|
|
253
358
|
engine = ExStructEngine(
|
|
254
359
|
options=StructOptions(mode=mode),
|
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from exstruct import process_excel
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
10
|
-
parser = argparse.ArgumentParser(
|
|
11
|
-
description="Dev-only CLI stub for ExStruct extraction."
|
|
12
|
-
)
|
|
13
|
-
parser.add_argument("input", type=Path, help="Excel file (.xlsx/.xlsm/.xls)")
|
|
14
|
-
parser.add_argument(
|
|
15
|
-
"-o",
|
|
16
|
-
"--output",
|
|
17
|
-
type=Path,
|
|
18
|
-
help="Output path. If omitted, writes to stdout.",
|
|
19
|
-
)
|
|
20
|
-
parser.add_argument(
|
|
21
|
-
"-f",
|
|
22
|
-
"--format",
|
|
23
|
-
default="json",
|
|
24
|
-
choices=["json", "yaml", "yml", "toon"],
|
|
25
|
-
help="Export format",
|
|
26
|
-
)
|
|
27
|
-
parser.add_argument(
|
|
28
|
-
"--image",
|
|
29
|
-
action="store_true",
|
|
30
|
-
help="(placeholder) Render PNG alongside JSON",
|
|
31
|
-
)
|
|
32
|
-
parser.add_argument(
|
|
33
|
-
"--pdf",
|
|
34
|
-
action="store_true",
|
|
35
|
-
help="(placeholder) Render PDF alongside JSON",
|
|
36
|
-
)
|
|
37
|
-
parser.add_argument(
|
|
38
|
-
"--dpi",
|
|
39
|
-
type=int,
|
|
40
|
-
default=144,
|
|
41
|
-
help="DPI for image rendering (placeholder)",
|
|
42
|
-
)
|
|
43
|
-
parser.add_argument(
|
|
44
|
-
"-m",
|
|
45
|
-
"--mode",
|
|
46
|
-
default="standard",
|
|
47
|
-
choices=["light", "standard", "verbose"],
|
|
48
|
-
help="Extraction detail level",
|
|
49
|
-
)
|
|
50
|
-
parser.add_argument(
|
|
51
|
-
"--pretty",
|
|
52
|
-
action="store_true",
|
|
53
|
-
help="Pretty-print JSON output (indent=2). Default is compact JSON.",
|
|
54
|
-
)
|
|
55
|
-
parser.add_argument(
|
|
56
|
-
"--sheets-dir",
|
|
57
|
-
type=Path,
|
|
58
|
-
help="Optional directory to write one file per sheet (format follows --format).",
|
|
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
|
-
)
|
|
65
|
-
return parser
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def main(argv: list[str] | None = None) -> int:
|
|
69
|
-
parser = build_parser()
|
|
70
|
-
args = parser.parse_args(argv)
|
|
71
|
-
|
|
72
|
-
input_path: Path = args.input
|
|
73
|
-
if not input_path.exists():
|
|
74
|
-
print(f"File not found: {input_path}")
|
|
75
|
-
return 0
|
|
76
|
-
|
|
77
|
-
try:
|
|
78
|
-
process_excel(
|
|
79
|
-
file_path=input_path,
|
|
80
|
-
output_path=args.output,
|
|
81
|
-
out_fmt=args.format,
|
|
82
|
-
image=args.image,
|
|
83
|
-
pdf=args.pdf,
|
|
84
|
-
dpi=args.dpi,
|
|
85
|
-
mode=args.mode,
|
|
86
|
-
pretty=args.pretty,
|
|
87
|
-
sheets_dir=args.sheets_dir,
|
|
88
|
-
print_areas_dir=args.print_areas_dir,
|
|
89
|
-
)
|
|
90
|
-
return 0
|
|
91
|
-
except Exception as e:
|
|
92
|
-
print(f"Error: {e}")
|
|
93
|
-
return 1
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if __name__ == "__main__":
|
|
97
|
-
raise SystemExit(main())
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from exstruct import process_excel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
10
|
+
parser = argparse.ArgumentParser(
|
|
11
|
+
description="Dev-only CLI stub for ExStruct extraction."
|
|
12
|
+
)
|
|
13
|
+
parser.add_argument("input", type=Path, help="Excel file (.xlsx/.xlsm/.xls)")
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"-o",
|
|
16
|
+
"--output",
|
|
17
|
+
type=Path,
|
|
18
|
+
help="Output path. If omitted, writes to stdout.",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"-f",
|
|
22
|
+
"--format",
|
|
23
|
+
default="json",
|
|
24
|
+
choices=["json", "yaml", "yml", "toon"],
|
|
25
|
+
help="Export format",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--image",
|
|
29
|
+
action="store_true",
|
|
30
|
+
help="(placeholder) Render PNG alongside JSON",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--pdf",
|
|
34
|
+
action="store_true",
|
|
35
|
+
help="(placeholder) Render PDF alongside JSON",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--dpi",
|
|
39
|
+
type=int,
|
|
40
|
+
default=144,
|
|
41
|
+
help="DPI for image rendering (placeholder)",
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"-m",
|
|
45
|
+
"--mode",
|
|
46
|
+
default="standard",
|
|
47
|
+
choices=["light", "standard", "verbose"],
|
|
48
|
+
help="Extraction detail level",
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"--pretty",
|
|
52
|
+
action="store_true",
|
|
53
|
+
help="Pretty-print JSON output (indent=2). Default is compact JSON.",
|
|
54
|
+
)
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
"--sheets-dir",
|
|
57
|
+
type=Path,
|
|
58
|
+
help="Optional directory to write one file per sheet (format follows --format).",
|
|
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
|
+
)
|
|
65
|
+
return parser
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def main(argv: list[str] | None = None) -> int:
|
|
69
|
+
parser = build_parser()
|
|
70
|
+
args = parser.parse_args(argv)
|
|
71
|
+
|
|
72
|
+
input_path: Path = args.input
|
|
73
|
+
if not input_path.exists():
|
|
74
|
+
print(f"File not found: {input_path}", flush=True)
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
process_excel(
|
|
79
|
+
file_path=input_path,
|
|
80
|
+
output_path=args.output,
|
|
81
|
+
out_fmt=args.format,
|
|
82
|
+
image=args.image,
|
|
83
|
+
pdf=args.pdf,
|
|
84
|
+
dpi=args.dpi,
|
|
85
|
+
mode=args.mode,
|
|
86
|
+
pretty=args.pretty,
|
|
87
|
+
sheets_dir=args.sheets_dir,
|
|
88
|
+
print_areas_dir=args.print_areas_dir,
|
|
89
|
+
)
|
|
90
|
+
return 0
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Error: {e}", flush=True)
|
|
93
|
+
return 1
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
raise SystemExit(main())
|
|
@@ -288,7 +288,7 @@ def integrate_sheet_content(
|
|
|
288
288
|
|
|
289
289
|
|
|
290
290
|
def extract_workbook( # noqa: C901
|
|
291
|
-
file_path: Path,
|
|
291
|
+
file_path: str | Path,
|
|
292
292
|
mode: Literal["light", "standard", "verbose"] = "standard",
|
|
293
293
|
*,
|
|
294
294
|
include_cell_links: bool = False,
|
|
@@ -299,21 +299,23 @@ def extract_workbook( # noqa: C901
|
|
|
299
299
|
if mode not in _ALLOWED_MODES:
|
|
300
300
|
raise ValueError(f"Unsupported mode: {mode}")
|
|
301
301
|
|
|
302
|
+
normalized_file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
303
|
+
|
|
302
304
|
cell_data = (
|
|
303
|
-
extract_sheet_cells_with_links(
|
|
305
|
+
extract_sheet_cells_with_links(normalized_file_path)
|
|
304
306
|
if include_cell_links
|
|
305
|
-
else extract_sheet_cells(
|
|
307
|
+
else extract_sheet_cells(normalized_file_path)
|
|
306
308
|
)
|
|
307
309
|
print_area_data: dict[str, list[PrintArea]] = {}
|
|
308
310
|
if include_print_areas:
|
|
309
|
-
print_area_data = _extract_print_areas_openpyxl(
|
|
311
|
+
print_area_data = _extract_print_areas_openpyxl(normalized_file_path)
|
|
310
312
|
auto_page_break_data: dict[str, list[PrintArea]] = {}
|
|
311
313
|
|
|
312
314
|
def _cells_and_tables_only(reason: str) -> WorkbookData:
|
|
313
315
|
sheets: dict[str, SheetData] = {}
|
|
314
316
|
for sheet_name, rows in cell_data.items():
|
|
315
317
|
try:
|
|
316
|
-
tables = detect_tables_openpyxl(
|
|
318
|
+
tables = detect_tables_openpyxl(normalized_file_path, sheet_name)
|
|
317
319
|
except Exception:
|
|
318
320
|
tables = []
|
|
319
321
|
sheets[sheet_name] = SheetData(
|
|
@@ -330,7 +332,7 @@ def extract_workbook( # noqa: C901
|
|
|
330
332
|
"%s Falling back to cells+tables only; shapes and charts will be empty.",
|
|
331
333
|
reason,
|
|
332
334
|
)
|
|
333
|
-
return WorkbookData(book_name=
|
|
335
|
+
return WorkbookData(book_name=normalized_file_path.name, sheets=sheets)
|
|
334
336
|
|
|
335
337
|
if mode == "light":
|
|
336
338
|
return _cells_and_tables_only("Light mode selected.")
|
|
@@ -341,7 +343,7 @@ def extract_workbook( # noqa: C901
|
|
|
341
343
|
)
|
|
342
344
|
|
|
343
345
|
try:
|
|
344
|
-
wb, close_app = _open_workbook(
|
|
346
|
+
wb, close_app = _open_workbook(normalized_file_path)
|
|
345
347
|
except Exception as e:
|
|
346
348
|
return _cells_and_tables_only(f"xlwings/Excel COM is unavailable. ({e!r})")
|
|
347
349
|
|
|
@@ -369,7 +371,7 @@ def extract_workbook( # noqa: C901
|
|
|
369
371
|
if include_auto_page_breaks
|
|
370
372
|
else None,
|
|
371
373
|
)
|
|
372
|
-
return WorkbookData(book_name=
|
|
374
|
+
return WorkbookData(book_name=normalized_file_path.name, sheets=merged)
|
|
373
375
|
except Exception as e:
|
|
374
376
|
logger.warning(
|
|
375
377
|
"Shape extraction failed; falling back to cells+tables. (%r)", e
|