From 2127d2c9042a8141f9fb4f37567af964124ed429 Mon Sep 17 00:00:00 2001 From: forbes Date: Wed, 4 Mar 2026 13:50:37 -0600 Subject: [PATCH] =?UTF-8?q?feat(sdk):=20addon=20load=20timing=20diagnostic?= =?UTF-8?q?s=20=E2=80=94=20addon=5Fdiagnostics()=20(#390)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add kindred_sdk.addon_diagnostics() returning per-addon load state, timing, and error info as a list of dicts. Reads name, state, load_time_ms, and error from AddonManifest via AddonRegistry. Add _print_load_summary() to addon_loader.py that prints a formatted summary table to the console after each load phase (Init.py and InitGui.py), replacing interleaved individual log lines with a consolidated view. Closes #390 --- mods/sdk/kindred_sdk/__init__.py | 2 ++ mods/sdk/kindred_sdk/registry.py | 32 ++++++++++++++++++++++++++++++++ src/Mod/Create/addon_loader.py | 23 +++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/mods/sdk/kindred_sdk/__init__.py b/mods/sdk/kindred_sdk/__init__.py index a0b881c3cf..afe75b959f 100644 --- a/mods/sdk/kindred_sdk/__init__.py +++ b/mods/sdk/kindred_sdk/__init__.py @@ -25,6 +25,7 @@ from kindred_sdk.origin import ( unregister_origin, ) from kindred_sdk.registry import ( + addon_diagnostics, addon_resource, addon_version, is_addon_loaded, @@ -38,6 +39,7 @@ from kindred_sdk.version import SDK_VERSION __all__ = [ "SDK_VERSION", "active_origin", + "addon_diagnostics", "addon_resource", "addon_version", "available_contexts", diff --git a/mods/sdk/kindred_sdk/registry.py b/mods/sdk/kindred_sdk/registry.py index e1e22f65ef..c362286a48 100644 --- a/mods/sdk/kindred_sdk/registry.py +++ b/mods/sdk/kindred_sdk/registry.py @@ -97,3 +97,35 @@ def addon_resource(name: str, relative_path: str) -> str: f"Resource not found: {resolved} (addon '{name}', path '{relative_path}')" ) return resolved + + +def addon_diagnostics() -> list[dict]: + """Return load diagnostics for all discovered addons. + + Each entry is a dict with keys: + + - ``name`` — addon name + - ``state`` — load state (``"loaded"``, ``"failed"``, ``"skipped"``, etc.) + - ``load_time_ms`` — cumulative load time (Init.py + InitGui.py) + - ``error`` — error message string, or ``None`` if no error + + Addons are returned in registry order. + + >>> import kindred_sdk as sdk + >>> sdk.addon_diagnostics() + [{'name': 'sdk', 'state': 'loaded', 'load_time_ms': 12.0, 'error': None}, ...] + """ + registry = _get_registry() + if registry is None: + return [] + result = [] + for m in registry.all(): + result.append( + { + "name": m.name, + "state": m.state.value, + "load_time_ms": m.load_time_ms, + "error": m.error or None, + } + ) + return result diff --git a/src/Mod/Create/addon_loader.py b/src/Mod/Create/addon_loader.py index 10417de2df..d1eea81cc6 100644 --- a/src/Mod/Create/addon_loader.py +++ b/src/Mod/Create/addon_loader.py @@ -488,6 +488,25 @@ def _get_create_version() -> str: return "0.0.0" +def _print_load_summary(registry: AddonRegistry, phase: str): + """Print a formatted addon load summary table to the console.""" + addons = registry.all() + if not addons: + return + + max_name = max(len(m.name) for m in addons) + lines = [f"Create: Addon load summary ({phase})"] + for m in addons: + state_str = m.state.value.upper() + time_str = f"{m.load_time_ms:.0f}ms" if m.load_time_ms > 0 else "-" + line = f" {m.name:<{max_name}} {state_str:<12} {time_str:>6}" + if m.error: + line += f" ({m.error})" + lines.append(line) + + FreeCAD.Console.PrintLog("\n".join(lines) + "\n") + + def load_addons(gui: bool = False): """Load Kindred addons from mods/. @@ -520,6 +539,8 @@ def load_addons(gui: bool = False): for m in ordered: _load_addon(m, gui=False) + + _print_load_summary(_registry, "Init.py") else: # GUI phase: reuse registry, load InitGui.py in load order if _registry is None: @@ -531,6 +552,8 @@ def load_addons(gui: bool = False): for m in _registry.loaded(): _load_addon(m, gui=True) + _print_load_summary(_registry, "InitGui.py") + def getAddonRegistry() -> Optional[AddonRegistry]: """Return the addon registry singleton, or None if not yet initialized.