|
13 | 13 | from __future__ import annotations |
14 | 14 |
|
15 | 15 | import json |
| 16 | +import os |
16 | 17 | from typing import Any, ClassVar |
17 | 18 |
|
18 | 19 | from modelchoice_mcp.store import STORE_SHEET_NAME, parse_store, reassemble_chunks |
@@ -59,6 +60,49 @@ def _book(self, workbook: str | None) -> Any: |
59 | 60 | return b |
60 | 61 | raise ModelChoiceNotFoundError(f"Workbook {workbook!r} is not open.") |
61 | 62 |
|
| 63 | + def open_workbook(self, path: str) -> dict[str, Any]: |
| 64 | + """Open a workbook from disk in the running Excel and report its |
| 65 | + sheets + any ModelChoice trees it contains. If a workbook with the |
| 66 | + same file name is already open, that one is used (Excel won't open two |
| 67 | + with the same name). Raises if Excel isn't running, the file is |
| 68 | + missing, or Excel can't open it.""" |
| 69 | + xw = self._load_xw() |
| 70 | + app = xw.apps.active |
| 71 | + if app is None: |
| 72 | + raise ExcelNotRunningError( |
| 73 | + "No running Excel instance found. Open Excel (with the ModelChoice " |
| 74 | + "add-in) first, then open the workbook." |
| 75 | + ) |
| 76 | + self._harden_attach(app) |
| 77 | + if not os.path.isfile(path): |
| 78 | + raise ModelChoiceNotFoundError(f"File not found: {path!r}.") |
| 79 | + name = os.path.basename(path) |
| 80 | + book = None |
| 81 | + for b in app.books: |
| 82 | + try: |
| 83 | + if str(b.name).lower() == name.lower(): |
| 84 | + book = b |
| 85 | + break |
| 86 | + except Exception: |
| 87 | + continue |
| 88 | + if book is None: |
| 89 | + try: |
| 90 | + book = app.books.open(path) |
| 91 | + except Exception as exc: |
| 92 | + raise ModelChoiceNotFoundError(f"Excel could not open {path!r}: {exc}") from exc |
| 93 | + wb_name = str(book.name) |
| 94 | + try: |
| 95 | + sheets = [s.name for s in book.sheets] |
| 96 | + except Exception: |
| 97 | + sheets = [] |
| 98 | + # ModelChoice tree sheets, if this is a ModelChoice workbook. |
| 99 | + try: |
| 100 | + raw = self.read_store_raw(wb_name) |
| 101 | + trees = list(parse_store(raw)) if raw else [] |
| 102 | + except Exception: |
| 103 | + trees = [] |
| 104 | + return {"workbook": wb_name, "sheets": sheets, "trees": trees} |
| 105 | + |
62 | 106 | @staticmethod |
63 | 107 | def _harden_attach(app: Any) -> None: |
64 | 108 | """Make the COM attach robust against a loaded ModelChoice add-in. |
|
0 commit comments