feat(sdk): addon asset path resolution — addon_resource() (#389)
Some checks failed
Build and Test / build (pull_request) Has been cancelled

Add kindred_sdk.addon_resource(name, relative_path) that resolves
bundled asset paths relative to an addon's root directory. Looks up
the addon manifest from AddonRegistry for the install root, joins
the relative path, and validates existence on disk.

Raises LookupError if the addon is not registered, FileNotFoundError
if the resolved path does not exist.

Closes #389
This commit is contained in:
forbes
2026-03-04 13:46:25 -06:00
parent e0653ed2a9
commit 85ae0effc9
2 changed files with 53 additions and 1 deletions

View File

@@ -24,7 +24,12 @@ from kindred_sdk.origin import (
set_active_origin,
unregister_origin,
)
from kindred_sdk.registry import addon_version, is_addon_loaded, loaded_addons
from kindred_sdk.registry import (
addon_resource,
addon_version,
is_addon_loaded,
loaded_addons,
)
from kindred_sdk.statusbar import register_status_widget
from kindred_sdk.theme import get_theme_tokens, load_palette
from kindred_sdk.toolbar import register_toolbar
@@ -33,6 +38,7 @@ from kindred_sdk.version import SDK_VERSION
__all__ = [
"SDK_VERSION",
"active_origin",
"addon_resource",
"addon_version",
"available_contexts",
"context_history",

View File

@@ -3,6 +3,8 @@
# Thin wrappers around FreeCAD.KindredAddons (AddonRegistry) so addons
# use a stable SDK import instead of reaching into FreeCAD internals.
import os
import FreeCAD
@@ -51,3 +53,47 @@ def loaded_addons() -> list[str]:
if registry is None:
return []
return [m.name for m in registry.loaded()]
def addon_resource(name: str, relative_path: str) -> str:
"""Resolve a bundled asset path for an addon.
Parameters
----------
name : str
Addon name as declared in its ``package.xml`` (e.g. ``"silo"``).
relative_path : str
Path relative to the addon's root directory
(e.g. ``"icons/silo_commit.svg"``).
Returns
-------
str
Absolute path to the resolved file.
Raises
------
LookupError
If the addon is not registered.
FileNotFoundError
If the resolved path does not exist on disk.
>>> import kindred_sdk as sdk
>>> sdk.addon_resource("silo", "icons/silo_commit.svg")
'/home/.../mods/silo/freecad/icons/silo_commit.svg'
"""
registry = _get_registry()
if registry is None:
raise LookupError(
f"Addon registry not initialized; cannot resolve resource for '{name}'"
)
manifest = registry.get(name)
if manifest is None:
raise LookupError(f"Addon '{name}' is not registered")
resolved = os.path.join(manifest.addon_root, relative_path)
if not os.path.exists(resolved):
raise FileNotFoundError(
f"Resource not found: {resolved} (addon '{name}', path '{relative_path}')"
)
return resolved