diff --git a/src/scope/core/plugins/__init__.py b/src/scope/core/plugins/__init__.py index a681707d7..fcf208413 100644 --- a/src/scope/core/plugins/__init__.py +++ b/src/scope/core/plugins/__init__.py @@ -3,6 +3,7 @@ from .hookspecs import hookimpl from .manager import ( FailedPluginInfo, + PluginBundledError, PluginDependencyError, PluginInstallError, PluginInUseError, @@ -32,4 +33,5 @@ "PluginNameCollisionError", "PluginDependencyError", "PluginInstallError", + "PluginBundledError", ] diff --git a/src/scope/core/plugins/manager.py b/src/scope/core/plugins/manager.py index 87ee5a48a..399bea71e 100644 --- a/src/scope/core/plugins/manager.py +++ b/src/scope/core/plugins/manager.py @@ -80,6 +80,12 @@ class PluginInstallError(Exception): pass +class PluginBundledError(PluginInstallError): + """Attempted to uninstall a bundled (built-in) plugin.""" + + pass + + @dataclass(frozen=True) class FailedPluginInfo: """Information about a plugin entry point that failed to load.""" @@ -1360,7 +1366,7 @@ def _uninstall_plugin_sync( # Prevent uninstalling bundled plugins if plugin_info.get("bundled"): - raise PluginInstallError( + raise PluginBundledError( f"Plugin '{name}' is bundled and cannot be uninstalled" ) diff --git a/src/scope/server/app.py b/src/scope/server/app.py index 470771551..564a392a1 100644 --- a/src/scope/server/app.py +++ b/src/scope/server/app.py @@ -2957,6 +2957,7 @@ async def uninstall_plugin( cloud-hosted scope backend. """ from scope.core.plugins import ( + PluginBundledError, PluginInstallError, PluginNotFoundError, get_plugin_manager, @@ -2991,6 +2992,12 @@ async def uninstall_plugin( status_code=404, detail=f"Plugin '{name}' not found", ) from e + except PluginBundledError as e: + logger.warning(f"Plugin uninstall rejected (bundled plugin): {name} - {e}") + raise HTTPException( + status_code=400, + detail=str(e), + ) from e except PluginInstallError as e: logger.error(f"Plugin uninstall failed: {name} - {e}") raise HTTPException(