Python: move PyError and ErrorSink into api to reuse it in modules

GitOrigin-RevId: 44eeac6d4a44a4ce095a1b4aed1cccca61a4efbb
This commit is contained in:
Ilya.Kazakevich
2025-01-29 02:33:56 +00:00
committed by intellij-monorepo-bot
parent cd5f782c15
commit 4678462b27
28 changed files with 202 additions and 197 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.pycharm.community.ide.impl.newProjectWizard.impl.emptyProject
import com.intellij.openapi.application.EDT
@@ -10,7 +10,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.python.newProjectWizard.PyV3ProjectTypeSpecificSettings
import com.intellij.pycharm.community.ide.impl.newProjectWizard.welcome.PyWelcome
import com.jetbrains.python.Result
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.PyError
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -0,0 +1,41 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.errorProcessing
import kotlinx.coroutines.flow.FlowCollector
/**
* [emit] user-readable errors here.
*
* This class should be used by the topmost classes, tightly coupled to the UI.
* For the most business-logic and backend functions please return [com.jetbrains.python.Result] or error.
*
* Please do not report *all* exceptions here: This is *not* the class for NPEs and AOOBs:
* do not pass exceptions caught by `catch(e: Exception)` or `runCatching`: only report exceptions user interested in.
* `IOException` or `ExecutionException` are generally ok.
*
* There will be unified sink soon to show and log errors.
* Currently, only [com.jetbrains.python.util.ShowingMessageErrorSync] is a well-known implementation
*
* Example:
* ```kotlin
* suspend fun someLogic(): Result<@NlsSafe String, IOException> = withContext(Dispatchers.IO) {
* try {
* Result.success(Path.of("1.txt").readText())
* }
* catch (e: IOException) {
* Result.failure(e)
* }
* }
*
* suspend fun ui(errorSink: ErrorSink) {
* someLogic()
* .onSuccess {
* Messages.showInfoMessage("..", it)
* }
* .onFailure {
* errorSink.emit(it.localizedMessage)
* }
* }
* ```
*/
typealias ErrorSink = FlowCollector<PyError>
@@ -0,0 +1,58 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.errorProcessing
import com.intellij.openapi.util.NlsSafe
import com.jetbrains.python.execution.PyExecutionFailure
import com.jetbrains.python.execution.userMessage
import com.jetbrains.python.packaging.PyExecutionException
import org.jetbrains.annotations.Nls
sealed class PyError(val message: @NlsSafe String) {
/**
* Some "business" error: just a message to be displayed to a user
*/
class Message(message: @NlsSafe String) : PyError(message)
/**
* Some process can't be executed. To be displayed specially.
*/
data class ExecException(val execFailure: PyExecutionFailure) : PyError(execFailure.userMessage)
override fun toString(): String = message
}
suspend fun ErrorSink.emit(@NlsSafe message: String) {
emit(PyError.Message(message))
}
suspend fun ErrorSink.emit(e: PyExecutionException) {
emit(PyError.ExecException(e))
}
@Deprecated("Migrate to native python result")
fun <T> Result<T>.asPythonResult(): com.jetbrains.python.Result<T, PyError> =
com.jetbrains.python.Result.Companion.success(getOrElse {
return if (it is PyExecutionException) {
failure(it)
}
else {
failure(it.localizedMessage)
}
}
)
@Deprecated("Use python result, not kotlin result")
fun <S, E> com.jetbrains.python.Result<S, E>.asKotlinResult(): Result<S> = when (this) {
is com.jetbrains.python.Result.Failure -> Result.failure(
when (val r = error) {
is Throwable -> r
is PyError.Message -> Exception(r.message)
is PyError.ExecException -> Exception(r.execFailure.userMessage)
else -> Exception(r.toString())
}
)
is com.jetbrains.python.Result.Success -> Result.success(result)
}
fun failure(message: @Nls String): com.jetbrains.python.Result.Failure<PyError.Message> = com.jetbrains.python.Result.Companion.failure(PyError.Message(message))
fun failure(failure: PyExecutionFailure): com.jetbrains.python.Result.Failure<PyError.ExecException> = com.jetbrains.python.Result.failure(PyError.ExecException(failure))
@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Experimental
package com.jetbrains.python.errorProcessing;
import org.jetbrains.annotations.ApiStatus;
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.newProjectWizard
import com.intellij.openapi.GitRepositoryInitializer
@@ -13,7 +13,7 @@ import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.add.v2.PySdkCreator
import com.jetbrains.python.sdk.pythonSdk
import com.jetbrains.python.sdk.setAssociationToModule
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.PyError
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.newProjectWizard
import com.intellij.facet.ui.ValidationResult
@@ -21,10 +21,8 @@ import com.jetbrains.python.newProjectWizard.impl.PyV3GeneratorPeer
import com.jetbrains.python.newProjectWizard.impl.PyV3UIServicesProd
import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows.Companion.validatePath
import com.jetbrains.python.onFailure
import com.jetbrains.python.packaging.PyExecutionException
import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMode
import com.jetbrains.python.statistics.version
import com.jetbrains.python.util.PyError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -1,11 +1,11 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.newProjectWizard
import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.python.Result
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.PyError
import org.jetbrains.annotations.CheckReturnValue
/**
@@ -1,8 +1,8 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.newProjectWizard
import com.intellij.openapi.project.Project
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.CoroutineScope
import javax.swing.JComponent
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.newProjectWizard.impl
import com.intellij.ide.projectView.impl.AbstractProjectViewPane
@@ -7,7 +7,7 @@ import com.intellij.openapi.project.Project
import com.intellij.ui.tree.ui.DefaultTreeUI.AUTO_EXPAND_ALLOWED
import com.intellij.util.ui.showingScope
import com.jetbrains.python.newProjectWizard.PyV3UIServices
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.util.ShowingMessageErrorSync
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.application.EDT
@@ -22,9 +22,9 @@ import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.asPythonResult
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.asPythonResult
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.observable.properties.ObservableMutableProperty
@@ -19,9 +19,9 @@ import com.jetbrains.python.sdk.flavors.conda.NewCondaEnvRequest
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.ui.flow.bindText
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.asPythonResult
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.asPythonResult
internal class CondaNewEnvironmentCreator(model: PythonMutableTargetAddInterpreterModel) : PythonNewEnvironmentCreator(model) {
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.module.Module
@@ -14,7 +14,7 @@ import com.jetbrains.python.sdk.PySdkUtil
import com.jetbrains.python.sdk.PythonSdkUtil
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import org.jetbrains.annotations.ApiStatus.Internal
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.module.Module
@@ -21,9 +21,9 @@ import com.jetbrains.python.sdk.*
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.emit
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.emit
import kotlinx.coroutines.flow.first
import org.jetbrains.annotations.ApiStatus.Internal
import java.nio.file.Path
@@ -19,7 +19,7 @@ import com.jetbrains.python.sdk.baseDir
import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.poetry.*
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.application.EDT
@@ -27,9 +27,9 @@ import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMethod.SELECT_E
import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.PYTHON
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.failure
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.failure
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.module.Module
@@ -14,8 +14,8 @@ import com.jetbrains.python.sdk.poetry.pyProjectToml
import com.jetbrains.python.sdk.poetry.setupPoetrySdkUnderProgress
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.statistics.version
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.asPythonResult
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.asPythonResult
import java.nio.file.Path
import kotlin.io.path.pathString
@@ -1,11 +1,11 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.python.Result
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.PyError
interface PySdkCreator {
/**
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.observable.util.and
@@ -13,7 +13,7 @@ import com.jetbrains.python.PyBundle.message
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.add.v2.PythonSupportedEnvironmentManagers.*
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.flow.Flow
import java.nio.file.Path
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.projectRoots.Sdk
@@ -8,7 +8,7 @@ import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.sdk.VirtualEnvReader
import com.jetbrains.python.sdk.rootManager
import com.jetbrains.python.sdk.service.PySdkService.Companion.pySdkService
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@@ -33,10 +33,10 @@ import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMode.*
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterTarget
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.util.ShowingMessageErrorSync
import com.jetbrains.python.util.asPythonResult
import com.jetbrains.python.errorProcessing.asPythonResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.projectRoots.Sdk
@@ -11,8 +11,8 @@ import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
import com.jetbrains.python.sdk.ModuleOrProject
import com.jetbrains.python.statistics.InterpreterCreationMode
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
class PythonExistingEnvironmentSelector(model: PythonAddInterpreterModel) : PythonExistingEnvironmentConfigurator(model) {
@@ -14,9 +14,9 @@ import com.jetbrains.python.sdk.uv.pyProjectToml
import com.jetbrains.python.sdk.uv.setupUvSdkUnderProgress
import com.jetbrains.python.statistics.InterpreterType
import com.jetbrains.python.statistics.version
import com.jetbrains.python.util.PyError
import com.jetbrains.python.util.asPythonResult
import com.jetbrains.python.util.failure
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.errorProcessing.asPythonResult
import com.jetbrains.python.errorProcessing.failure
import java.nio.file.Path
import kotlin.io.path.pathString
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.execution.target.TargetEnvironmentConfiguration
@@ -24,8 +24,8 @@ import com.jetbrains.python.sdk.pipenv.PIPENV_ICON
import com.jetbrains.python.sdk.poetry.POETRY_ICON
import com.jetbrains.python.sdk.uv.UV_ICON
import com.jetbrains.python.statistics.InterpreterTarget
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import kotlinx.coroutines.CoroutineScope
import javax.swing.Icon
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.execution.target.TargetEnvironmentConfiguration
@@ -23,8 +23,8 @@ import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
import com.jetbrains.python.sdk.pipenv.getPipEnvExecutable
import com.jetbrains.python.sdk.poetry.getPoetryExecutable
import com.jetbrains.python.sdk.uv.impl.getUvExecutable
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.util.emit
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.emit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.openapi.application.writeAction
@@ -21,7 +21,7 @@ import com.jetbrains.python.sdk.createSdk
import com.jetbrains.python.sdk.excludeInnerVirtualEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaCommand
import com.jetbrains.python.sdk.persist
import com.jetbrains.python.util.PyError
import com.jetbrains.python.errorProcessing.PyError
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Path
@@ -46,13 +46,13 @@ suspend fun PythonMutableTargetAddInterpreterModel.setupVirtualenv(venvPath: Pat
inheritSitePackages = state.inheritSitePackages.get())
}
catch (e: PyExecutionException) {
return com.jetbrains.python.util.failure(e)
return com.jetbrains.python.errorProcessing.failure(e)
}
if (targetEnvironmentConfiguration != null) error("Remote targets aren't supported")
val venvPython = VirtualEnvReader.Instance.findPythonInPythonRoot(venvPath)
if (venvPython == null) {
return com.jetbrains.python.util.failure(message("commandLine.directoryCantBeAccessed", venvPath))
return com.jetbrains.python.errorProcessing.failure(message("commandLine.directoryCantBeAccessed", venvPath))
}
val homeFile =
@@ -61,7 +61,7 @@ suspend fun PythonMutableTargetAddInterpreterModel.setupVirtualenv(venvPath: Pat
VfsUtil.findFile(venvPython, true)
}
if (homeFile == null) {
return com.jetbrains.python.util.failure(message("commandLine.directoryCantBeAccessed", venvPath))
return com.jetbrains.python.errorProcessing.failure(message("commandLine.directoryCantBeAccessed", venvPath))
}
val newSdk = createSdk(homeFile, projectPath, existingSdks.toTypedArray())
@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk.add.v2
import com.intellij.icons.AllIcons
@@ -40,7 +40,7 @@ import com.jetbrains.python.sdk.installer.CondaInstallManager
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
import com.jetbrains.python.util.ErrorSink
import com.jetbrains.python.errorProcessing.ErrorSink
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.flow.SharedFlow
@@ -1,134 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.util
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.NlsSafe
import com.jetbrains.python.PyBundle
import com.jetbrains.python.Result
import com.jetbrains.python.Result.Failure
import com.jetbrains.python.Result.Success
import com.jetbrains.python.execution.PyExecutionFailure
import com.jetbrains.python.execution.userMessage
import com.jetbrains.python.packaging.PyExecutionException
import com.jetbrains.python.showProcessExecutionErrorDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.Nls
/**
* [FlowCollector.emit] user-readable errors here.
*
* This class should be used by the topmost classes, tightly coupled to the UI.
* For the most business-logic and backend functions please return [com.jetbrains.python.Result] or error.
*
* Please do not report *all* exceptions here: This is *not* the class for NPEs and AOOBs:
* do not pass exceptions caught by `catch(e: Exception)` or `runCatching`: only report exceptions user interested in.
* `IOException` or `ExecutionException` are generally ok.
*
* There will be unified sink soon to show and log errors.
* Currently, only [ShowingMessageErrorSync] is a well-known implementation
*
* Example:
* ```kotlin
* suspend fun someLogic(): Result<@NlsSafe String, IOException> = withContext(Dispatchers.IO) {
* try {
* Result.success(Path.of("1.txt").readText())
* }
* catch (e: IOException) {
* Result.failure(e)
* }
* }
*
* suspend fun ui(errorSink: ErrorSink) {
* someLogic()
* .onSuccess {
* Messages.showInfoMessage("..", it)
* }
* .onFailure {
* errorSink.emit(it.localizedMessage)
* }
* }
* ```
*/
typealias ErrorSink = FlowCollector<PyError>
sealed class PyError(val message: @NlsSafe String) {
/**
* Some "business" error: just a message to be displayed to a user
*/
class Message(message: @NlsSafe String) : PyError(message)
/**
* Some process can't be executed. To be displayed specially.
*/
data class ExecException(val execFailure: PyExecutionFailure) : PyError(execFailure.userMessage)
override fun toString(): String = message
}
/**
* Displays error with a message box and writes it to a log.
*/
internal object ShowingMessageErrorSync : ErrorSink {
override suspend fun emit(error: PyError) {
withContext(Dispatchers.EDT + ModalityState.any().asContextElement()) {
thisLogger().warn(error.message)
// Platform doesn't allow dialogs without lock for now, fix later
writeIntentReadAction {
when (val e = error) {
is PyError.ExecException -> {
showProcessExecutionErrorDialog(null, e.execFailure)
}
is PyError.Message -> {
Messages.showErrorDialog(error.message, PyBundle.message("python.error"))
}
}
}
}
}
}
suspend fun ErrorSink.emit(@NlsSafe message: String) {
emit(PyError.Message(message))
}
suspend fun ErrorSink.emit(e: PyExecutionException) {
emit(PyError.ExecException(e))
}
fun failure(message: @Nls String): Failure<PyError.Message> = Result.failure(PyError.Message(message))
fun failure(failure: PyExecutionFailure): Failure<PyError.ExecException> = Result.failure(PyError.ExecException(failure))
@Deprecated("Migrate to native python result")
fun <T> kotlin.Result<T>.asPythonResult(): Result<T, PyError> =
Result.success(getOrElse {
return if (it is PyExecutionException) {
failure(it)
}
else {
failure(it.localizedMessage)
}
}
)
@Deprecated("Use python result, not kotlin result")
fun <S, E> Result<S, E>.asKotlinResult(): kotlin.Result<S> = when (this) {
is Failure -> kotlin.Result.failure(
when (val r = error) {
is Throwable -> r
is PyError.Message -> Exception(r.message)
is PyError.ExecException -> Exception(r.execFailure.userMessage)
else -> Exception(r.toString())
}
)
is Success -> kotlin.Result.success(result)
}
@@ -0,0 +1,37 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.util
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.ui.Messages
import com.jetbrains.python.PyBundle
import com.jetbrains.python.errorProcessing.ErrorSink
import com.jetbrains.python.errorProcessing.PyError
import com.jetbrains.python.showProcessExecutionErrorDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
/**
* Displays error with a message box and writes it to a log.
*/
internal object ShowingMessageErrorSync : ErrorSink {
override suspend fun emit(error: PyError) {
withContext(Dispatchers.EDT + ModalityState.any().asContextElement()) {
thisLogger().warn(error.message)
// Platform doesn't allow dialogs without lock for now, fix later
writeIntentReadAction {
when (val e = error) {
is PyError.ExecException -> {
showProcessExecutionErrorDialog(null, e.execFailure)
}
is PyError.Message -> {
Messages.showErrorDialog(error.message, PyBundle.message("python.error"))
}
}
}
}
}
}