Merge pull request 'feat(sdk): addon load timing diagnostics — addon_diagnostics() (#390)' (#402) from feat/sdk-addon-diagnostics into main
Some checks failed
Build and Test / build (push) Has been cancelled

Reviewed-on: #402
This commit was merged in pull request #402.
This commit is contained in:
2026-03-04 19:51:35 +00:00
3 changed files with 57 additions and 0 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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.