From 2012e105fe7a8cbdb0ef4c7f6422daed7e70e70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 2 Jan 2026 17:32:13 -0800 Subject: [PATCH] Improve error UX with notifications - Add error notifications when Python executable not found - Add error notifications when SDK creation fails - Add error notifications when module not found (for module-level setting) - Refactor to use sealed class SetSdkResult for type-safe error handling - Show clear error messages to help users understand failures --- .../actions/ConfigurePythonActionAbstract.kt | 57 +++++++++++++++++-- .../actions/ConfigurePythonActionModule.kt | 8 ++- .../actions/ConfigurePythonActionProject.kt | 4 +- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt index 3eeb8e6..5ff9ea8 100644 --- a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt +++ b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionAbstract.kt @@ -37,7 +37,13 @@ abstract class ConfigurePythonActionAbstract : AnAction() { e.getData(CommonDataKeys.VIRTUAL_FILE)?.let { if (it.isDirectory) it else it.parent } ?: return - val pythonExecutable = PythonSdkUtil.getPythonExecutable(selectedPath.path) ?: return + + val pythonExecutable = PythonSdkUtil.getPythonExecutable(selectedPath.path) + if (pythonExecutable == null) { + notifyError(project, "No Python executable found in ${selectedPath.name}") + return + } + val sdk: Sdk = PyConfigurableInterpreterList .getInstance(project) @@ -45,24 +51,65 @@ abstract class ConfigurePythonActionAbstract : AnAction() { .projectSdks .values .firstOrNull { it.homePath == pythonExecutable } - ?: (SdkConfigurationUtil.createAndAddSDK(pythonExecutable, PythonSdkType.getInstance()) ?: return) + ?: run { + val newSdk = SdkConfigurationUtil.createAndAddSDK(pythonExecutable, PythonSdkType.getInstance()) + if (newSdk == null) { + notifyError(project, "Failed to create SDK from $pythonExecutable") + return + } + newSdk + } + + when (val result = setSdk(project, selectedPath, sdk)) { + is SetSdkResult.Success -> notifySuccess(project, result.target, sdk) + is SetSdkResult.Error -> notifyError(project, result.message) + } + } - val notificationFor = setSdk(project, selectedPath, sdk) ?: return + private fun notifySuccess( + project: Project, + target: String, + sdk: Sdk, + ) { NotificationGroupManager .getInstance() .getNotificationGroup("Python SDK change") .createNotification( "Python SDK Updated", - "Updated SDK for $notificationFor to:\n${sdk.name} " + + "Updated SDK for $target to:\n${sdk.name} " + "of type ${sdk.interpreterType.toString().lowercase()} " + sdk.executionType.toString().lowercase(), NotificationType.INFORMATION, ).notify(project) } + private fun notifyError( + project: Project, + message: String, + ) { + NotificationGroupManager + .getInstance() + .getNotificationGroup("Python SDK change") + .createNotification( + "Python SDK Error", + message, + NotificationType.ERROR, + ).notify(project) + } + protected abstract fun setSdk( project: Project, selectedPath: VirtualFile, sdk: Sdk, - ): String? + ): SetSdkResult + + sealed class SetSdkResult { + data class Success( + val target: String, + ) : SetSdkResult() + + data class Error( + val message: String, + ) : SetSdkResult() + } } diff --git a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionModule.kt b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionModule.kt index 46ff5b7..394885d 100644 --- a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionModule.kt +++ b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionModule.kt @@ -11,9 +11,11 @@ class ConfigurePythonActionModule : ConfigurePythonActionAbstract() { project: Project, selectedPath: VirtualFile, sdk: Sdk, - ): String? { - val module = ProjectFileIndex.getInstance(project).getModuleForFile(selectedPath, false) ?: return null + ): SetSdkResult { + val module = + ProjectFileIndex.getInstance(project).getModuleForFile(selectedPath, false) + ?: return SetSdkResult.Error("No module found for ${selectedPath.name}") ModuleRootModificationUtil.setModuleSdk(module, sdk) - return "module ${module.name}" + return SetSdkResult.Success("module ${module.name}") } } diff --git a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionProject.kt b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionProject.kt index ec481df..06eb39c 100644 --- a/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionProject.kt +++ b/src/main/kotlin/com/github/pyvenvmanage/actions/ConfigurePythonActionProject.kt @@ -10,8 +10,8 @@ class ConfigurePythonActionProject : ConfigurePythonActionAbstract() { project: Project, selectedPath: VirtualFile, sdk: Sdk, - ): String { + ): SetSdkResult { SdkConfigurationUtil.setDirectoryProjectSdk(project, sdk) - return "project ${project.name}" + return SetSdkResult.Success("project ${project.name}") } }