exstruct 0.1.0__py3-none-any.whl

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/__init__.py ADDED
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Literal, Optional
5
+
6
+ from .core.integrate import extract_workbook
7
+ from .core.cells import set_table_detection_params
8
+ from .io import save_as_json, save_as_toon, save_as_yaml, save_sheets
9
+ from .models import CellRow, Chart, ChartSeries, Shape, SheetData, WorkbookData
10
+ from .render import export_pdf, export_sheet_images
11
+
12
+ __all__ = [
13
+ "extract",
14
+ "export",
15
+ "export_sheets",
16
+ "export_pdf",
17
+ "export_sheet_images",
18
+ "process_excel",
19
+ "ExtractionMode",
20
+ "CellRow",
21
+ "Shape",
22
+ "ChartSeries",
23
+ "Chart",
24
+ "SheetData",
25
+ "WorkbookData",
26
+ "set_table_detection_params",
27
+ ]
28
+
29
+
30
+ ExtractionMode = Literal["light", "standard", "verbose"]
31
+
32
+
33
+ def extract(file_path: str | Path, mode: ExtractionMode = "standard") -> WorkbookData:
34
+ """Extract workbook semantic structure and return WorkbookData."""
35
+ if mode not in ("light", "standard", "verbose"):
36
+ raise ValueError(f"Unsupported mode: {mode}")
37
+ return extract_workbook(Path(file_path), mode=mode)
38
+
39
+
40
+ def export(
41
+ data: WorkbookData,
42
+ path: str | Path,
43
+ fmt: Optional[Literal["json", "yaml", "yml", "toon"]] = None,
44
+ *,
45
+ pretty: bool = False,
46
+ indent: int | None = None,
47
+ ) -> None:
48
+ """Export WorkbookData to supported file formats (json/yaml/toon)."""
49
+ dest = Path(path)
50
+ format_hint = (fmt or dest.suffix.lstrip(".") or "json").lower()
51
+ match format_hint:
52
+ case "json":
53
+ save_as_json(data, dest, pretty=pretty, indent=indent)
54
+ case "yaml" | "yml":
55
+ save_as_yaml(data, dest)
56
+ case "toon":
57
+ save_as_toon(data, dest)
58
+ case _:
59
+ raise ValueError(f"Unsupported export format: {format_hint}")
60
+
61
+
62
+ def export_sheets(data: WorkbookData, dir_path: str | Path) -> dict[str, Path]:
63
+ """
64
+ Export each sheet as a JSON file (book_name + SheetData) into a directory.
65
+ Returns a mapping of sheet name to written path.
66
+ """
67
+ return save_sheets(data, Path(dir_path), fmt="json")
68
+
69
+
70
+ def export_sheets_as(
71
+ data: WorkbookData,
72
+ dir_path: str | Path,
73
+ fmt: Literal["json", "yaml", "yml", "toon"] = "json",
74
+ *,
75
+ pretty: bool = False,
76
+ indent: int | None = None,
77
+ ) -> dict[str, Path]:
78
+ """
79
+ Export each sheet in the given format (json/yaml/toon), including book_name and SheetData; returns sheet name → path map.
80
+ """
81
+ return save_sheets(data, Path(dir_path), fmt=fmt, pretty=pretty, indent=indent)
82
+
83
+
84
+ def process_excel(
85
+ file_path: Path,
86
+ output_path: Path,
87
+ out_fmt: str = "json",
88
+ image: bool = False,
89
+ pdf: bool = False,
90
+ dpi: int = 72,
91
+ mode: ExtractionMode = "standard",
92
+ pretty: bool = False,
93
+ indent: int | None = None,
94
+ ) -> None:
95
+ """Convenience wrapper for CLI: export workbook and optionally PDF/PNG images (Excel required for rendering)."""
96
+ if mode not in ("light", "standard", "verbose"):
97
+ raise ValueError(f"Unsupported mode: {mode}")
98
+ workbook_model = extract(file_path, mode=mode)
99
+ match out_fmt:
100
+ case "json":
101
+ save_as_json(workbook_model, output_path, pretty=pretty, indent=indent)
102
+ case "yaml" | "yml":
103
+ save_as_yaml(workbook_model, output_path)
104
+ case "toon":
105
+ save_as_toon(workbook_model, output_path)
106
+ case _:
107
+ raise ValueError(f"Unsupported export format: {out_fmt}")
108
+
109
+ if pdf or image:
110
+ pdf_path = output_path.with_suffix(".pdf")
111
+ export_pdf(file_path, pdf_path)
112
+ if image:
113
+ images_dir = output_path.parent / f"{output_path.stem}_images"
114
+ export_sheet_images(file_path, images_dir, dpi=dpi)
115
+
116
+ print(f"{file_path.name} -> {output_path} completed.")
exstruct/cli/main.py ADDED
@@ -0,0 +1,93 @@
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 (defaults to <input>.json)",
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
+ return parser
56
+
57
+
58
+ def main(argv: list[str] | None = None) -> int:
59
+ parser = build_parser()
60
+ args = parser.parse_args(argv)
61
+
62
+ input_path: Path = args.input
63
+ if not input_path.exists():
64
+ print(f"File not found: {input_path}")
65
+ return 0
66
+
67
+ suffix = ".json"
68
+ if args.format in ("yaml", "yml"):
69
+ suffix = ".yaml"
70
+ elif args.format == "toon":
71
+ suffix = ".toon"
72
+
73
+ output_path: Path = args.output or input_path.with_suffix(suffix)
74
+
75
+ try:
76
+ process_excel(
77
+ file_path=input_path,
78
+ output_path=output_path,
79
+ out_fmt=args.format,
80
+ image=args.image,
81
+ pdf=args.pdf,
82
+ dpi=args.dpi,
83
+ mode=args.mode,
84
+ pretty=args.pretty,
85
+ )
86
+ return 0
87
+ except Exception as e:
88
+ print(f"Error: {e}")
89
+ return 1
90
+
91
+
92
+ if __name__ == "__main__":
93
+ raise SystemExit(main())
File without changes