from __future__ import annotations import importlib.util import tomllib from pathlib import Path from types import ModuleType from typing import Any from Core import Config CachedSaraTagCore: ModuleType | None = None CachedSaraTagCoreLoaded = False def GetSaraTagCore() -> ModuleType | None: """Load SaraTag's Core.py directly by file path, under a private module name, so it never collides with SaraView's own Core module in sys.modules. Cached after the first successful load. """ global CachedSaraTagCore, CachedSaraTagCoreLoaded if CachedSaraTagCoreLoaded: return CachedSaraTagCore CachedSaraTagCoreLoaded = True SaraTagConfig = Config.get("SaraTag", {}) if not SaraTagConfig.get("Enabled", False): return None CoreModulePath = SaraTagConfig.get("CoreModulePath") if not CoreModulePath: return None CoreFilePath = Path(CoreModulePath).expanduser().resolve() / "Core.py" if not CoreFilePath.is_file(): return None ModuleSpec = importlib.util.spec_from_file_location("SaraTagCore", CoreFilePath) if ModuleSpec is None or ModuleSpec.loader is None: return None SaraTagCoreModule = importlib.util.module_from_spec(ModuleSpec) ModuleSpec.loader.exec_module(SaraTagCoreModule) CachedSaraTagCore = SaraTagCoreModule return CachedSaraTagCore def ReadBookForFile(FilePath: Path) -> dict[str, Any] | None: """Return a file's resolved Book (tag values + Lexicon definitions), or None if SaraTag integration is disabled or the file has no Book. """ SaraTagCore = GetSaraTagCore() if SaraTagCore is None: return None BookPath = SaraTagCore.GetBookPath(FilePath) if not BookPath.is_file(): return None with BookPath.open("rb") as BookFile: Metadata = tomllib.load(BookFile) ParentValue = Metadata.get("Parent") Definitions: dict[str, Any] = {} if isinstance(ParentValue, str): try: LexiconPath = SaraTagCore.ResolveBookLexiconPath(FilePath.parent, ParentValue) Definitions = SaraTagCore.ResolveLexiconTags(LexiconPath) except Exception: Definitions = {} Tags = {Key: Value for Key, Value in Metadata.items() if Key != "Parent"} return {"Parent": ParentValue, "Tags": Tags, "Definitions": Definitions}