Warn and reset instead of exiting when a kit manifest is missing
A kit with no manifest under the Sedona home folder called sys.exit(1), tearing down the whole app over one unopenable file. schema now raises MissingManifestError instead, collecting every unresolved kit first so one dialog names them all rather than the user fixing them one reopen at a time. describe_missing_manifests builds the body, pointing at the configured Sedona home and at Preferences. open_file catches it, reports it, and calls the new reset_to_startup_state to return to the just-launched state: no file, empty tree, empty sheet, cleared registries and undo stack. The generic except now resets too, since a half-parsed file previously left current_file_path and a stale root behind. Placing a palette component hits the same loader, where a full reset would be too destructive: it rolls back the <kit> entry it just added, rebuilds the previous registry, and abandons only that placement. schema no longer imports sys or tkinter, so it reports nothing itself and stays testable without a display. base_window_title moves to app_state so the reset can restore the title without duplicating it. README: document the new behaviour, drop the fixed gap, and correct the stale "no undo, no keyboard shortcuts for save" claim. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,47 @@
|
||||
"""Kit manifest loading, slot inheritance, and which slots are worth showing."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from tkinter import messagebox
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import app_state
|
||||
|
||||
|
||||
class MissingManifestError(Exception):
|
||||
"""A kit the file needs has no manifest under the Sedona home folder.
|
||||
|
||||
Raised rather than handled here, so the caller decides what to abandon: opening a
|
||||
file abandons the whole load, placing a palette component only abandons that
|
||||
component. Carrying the kit names lets either one name them in its own wording.
|
||||
"""
|
||||
|
||||
def __init__(self, kit_names, unresolved_type=None):
|
||||
self.kit_names = sorted(set(kit_names))
|
||||
self.unresolved_type = unresolved_type
|
||||
super().__init__(", ".join(self.kit_names))
|
||||
|
||||
|
||||
def describe_missing_manifests(error):
|
||||
"""The body of the dialog both callers show, pointing at the folder to check."""
|
||||
kit_list = "\n".join(f" • {name}" for name in error.kit_names)
|
||||
home = app_state.SEDONA_HOME or "(not set)"
|
||||
|
||||
lines = ["No manifest was found for:", "", kit_list, "", f"Sedona home folder:\n {home}", ""]
|
||||
|
||||
if error.unresolved_type:
|
||||
lines.append(
|
||||
f"Type '{error.unresolved_type}' inherits from a kit that is not in the "
|
||||
"file's schema block, so its slots cannot be resolved."
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
lines.append(
|
||||
"Check that the Sedona home folder is the right one and that it holds "
|
||||
"manifests/<kit>/<kit>-<checksum>.xml for each kit listed above. "
|
||||
"Preferences → Sedona home folder points it somewhere else."
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def read_summary_facet(slot_element):
|
||||
"""Reads a slot's '@summary' facet. Absent means summary, matching manifest convention."""
|
||||
facets = slot_element.find("facets")
|
||||
@@ -23,8 +57,7 @@ def get_slots_with_inheritance(type_name, kit_schemas):
|
||||
"""Recursively resolves the slots for a given type by traversing its base chain."""
|
||||
if type_name not in kit_schemas:
|
||||
kit_prefix = type_name.split("::")[0] if "::" in type_name else type_name
|
||||
messagebox.showerror("Schema Warning", f"Kit {kit_prefix} is not in Schema selection!")
|
||||
sys.exit(1)
|
||||
raise MissingManifestError([kit_prefix], unresolved_type=type_name)
|
||||
|
||||
type_element = kit_schemas[type_name]
|
||||
base_type = type_element.get("base")
|
||||
@@ -93,6 +126,7 @@ def load_schema_kits_and_manifests():
|
||||
return
|
||||
|
||||
manifest_paths = []
|
||||
missing_kits = []
|
||||
for kit in schema_elem.findall("kit"):
|
||||
name = kit.get("name")
|
||||
checksum = kit.get("checksum")
|
||||
@@ -117,8 +151,12 @@ def load_schema_kits_and_manifests():
|
||||
if manifest_path:
|
||||
manifest_paths.append(manifest_path)
|
||||
else:
|
||||
messagebox.showerror("Schema Warning", f"Kit {name} is not in Schema selection!")
|
||||
sys.exit(1)
|
||||
# Every missing kit is collected before reporting, so one dialog names them
|
||||
# all rather than the user fixing them one reopen at a time.
|
||||
missing_kits.append(name)
|
||||
|
||||
if missing_kits:
|
||||
raise MissingManifestError(missing_kits)
|
||||
|
||||
compile_schema_registry(manifest_paths)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user