diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/conda/PyEnvironmentYmlSdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/conda/PyEnvironmentYmlSdkConfiguration.kt index 28286144b039..a8be546839d0 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/conda/PyEnvironmentYmlSdkConfiguration.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/conda/PyEnvironmentYmlSdkConfiguration.kt @@ -63,7 +63,7 @@ import kotlin.io.path.name @ApiStatus.Internal class PyEnvironmentYmlSdkConfiguration : PyProjectSdkConfigurationExtension { - override val toolId: ToolId = ToolId("Conda") + override val toolId: ToolId = CONDA_TOOL_ID override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module): CreateSdkInfo? = prepareSdkCreator( { checkManageableEnv(module, it) } diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPipfileSdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPipfileSdkConfiguration.kt index b67b306e11d3..7c0bab2aad64 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPipfileSdkConfiguration.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyPipfileSdkConfiguration.kt @@ -52,7 +52,7 @@ private val LOGGER = Logger.getInstance(PyPipfileSdkConfiguration::class.java) @ApiStatus.Internal class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension { - override val toolId: ToolId = ToolId("pipenv") + override val toolId: ToolId = PIPENV_TOOL_ID override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module): CreateSdkInfo? = prepareSdkCreator( { checkManageableEnv(module, it) } diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyVenvSdkConfiguration.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyVenvSdkConfiguration.kt index d6bc5b791afa..3aedbcfa057b 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyVenvSdkConfiguration.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/configuration/PyVenvSdkConfiguration.kt @@ -26,7 +26,7 @@ class PyVenvSdkConfiguration : PyProjectSdkConfigurationExtension { private val existingSdks by lazy { PythonSdkUtil.getAllSdks() } private val context = UserDataHolderBase() - override val toolId: ToolId = ToolId("Venv") + override val toolId: ToolId = VENV_TOOL_ID override suspend fun checkEnvironmentAndPrepareSdkCreator(module: Module): CreateSdkInfo? = prepareSdkCreator( { checkManageableEnv(module) } diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties index 9b206b515469..7302af390413 100644 --- a/python/pluginResources/messages/PyBundle.properties +++ b/python/pluginResources/messages/PyBundle.properties @@ -587,6 +587,8 @@ sdk.create.custom.uv=uv sdk.create.custom.hatch=Hatch sdk.create.custom.python=Python +sdk.create.check.environments=Checking Existing Environments + sdk.rendering.detected.grey.text=system sdk.rendering.installable.grey.text=download and install diff --git a/python/python-sdk/src/com/jetbrains/python/sdk/configuration/PyProjectSdkConfigurationExtension.kt b/python/python-sdk/src/com/jetbrains/python/sdk/configuration/PyProjectSdkConfigurationExtension.kt index 9f23d6cae0e1..ea68b186259b 100644 --- a/python/python-sdk/src/com/jetbrains/python/sdk/configuration/PyProjectSdkConfigurationExtension.kt +++ b/python/python-sdk/src/com/jetbrains/python/sdk/configuration/PyProjectSdkConfigurationExtension.kt @@ -75,3 +75,12 @@ interface PyProjectSdkConfigurationExtension { * [createSdkInfo] with [toolId] that created it */ data class CreateSdkInfoWithTool(val createSdkInfo: CreateSdkInfo, val toolId: ToolId) + +@ApiStatus.Internal +val VENV_TOOL_ID: ToolId = ToolId("Venv") + +@ApiStatus.Internal +val CONDA_TOOL_ID: ToolId = ToolId("Conda") + +@ApiStatus.Internal +val PIPENV_TOOL_ID: ToolId = ToolId("pipenv") diff --git a/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt b/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt index 15cce080e6d3..e31d6335a966 100644 --- a/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt +++ b/python/src/com/jetbrains/python/sdk/add/v2/FileSystem.kt @@ -57,6 +57,7 @@ internal class VenvAlreadyExistsError
( sealed interface FileSystem
{ val isReadOnly: Boolean val isBrowseable: Boolean + val isLocal: Boolean fun parsePath(raw: String): PyResult
fun validateExecutable(path: P): PyResult {
) : FileSystem {
get() = !PythonInterpreterTargetEnvironmentFactory.isMutable(targetEnvironmentConfiguration)
override val isBrowseable: Boolean
get() = targetEnvironmentConfiguration.getTargetType() is BrowsableTargetEnvironmentType
+ override val isLocal: Boolean = false
private val systemPythonCache = ArrayList (
fun onShown(scope: CoroutineScope) {
newInterpreterCreators.values.forEach { it.onShown(scope) }
existingInterpreterSelectors.values.forEach { it.onShown(scope) }
+
+ scope.launch(Dispatchers.Default) {
+ val createSdkInfoWithTool = withModalProgress(ModalTaskOwner.guess(), message("sdk.create.check.environments"), TaskCancellation.cancellable()) {
+ module?.let { PyProjectSdkConfigurationExtension.findAllSortedForModule(it) }?.firstOrNull()
+ } ?: return@launch
+
+ val (manager, configurators) = when (createSdkInfoWithTool.createSdkInfo) {
+ is CreateSdkInfo.WillCreateEnv -> {
+ selectionMethod.set(PythonInterpreterSelectionMethod.CREATE_NEW)
+ newInterpreterManager to newInterpreterCreators
+ }
+ is CreateSdkInfo.ExistingEnv -> {
+ selectionMethod.set(PythonInterpreterSelectionMethod.SELECT_EXISTING)
+ existingInterpreterManager to existingInterpreterSelectors
+ }
+ }
+
+ val tool = PythonSupportedEnvironmentManagers.entries.singleOrNull { it.toolId == createSdkInfoWithTool.toolId } ?: return@launch
+ if (tool in configurators) {
+ manager.set(tool)
+ }
+ else {
+ selectionMethod.set(PythonInterpreterSelectionMethod.CREATE_NEW)
+ newInterpreterManager.set(tool)
+ }
+ }
}
fun createStatisticsInfo(): InterpreterStatisticsInfo {
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/common.kt b/python/src/com/jetbrains/python/sdk/add/v2/common.kt
index 05bdd27ca017..d4320a8017e8 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/common.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/common.kt
@@ -25,13 +25,17 @@ import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.TaskCancellation
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.python.common.tools.ToolId
import com.intellij.python.community.execService.Args
import com.intellij.python.community.execService.BinaryToExec
import com.intellij.python.community.execService.ExecService
import com.intellij.python.community.execService.execGetStdout
+import com.intellij.python.community.impl.poetry.common.POETRY_TOOL_ID
import com.intellij.python.community.impl.poetry.common.icons.PythonCommunityImplPoetryCommonIcons
+import com.intellij.python.community.impl.uv.common.UV_TOOL_ID
import com.intellij.python.community.impl.uv.common.icons.PythonCommunityImplUVCommonIcons
import com.intellij.python.hatch.icons.PythonHatchIcons
+import com.intellij.python.hatch.impl.HATCH_TOOL_ID
import com.intellij.ui.dsl.builder.Align
import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.builder.Row
@@ -44,6 +48,9 @@ import com.jetbrains.python.parser.icons.PythonParserIcons
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
import com.jetbrains.python.sdk.*
+import com.jetbrains.python.sdk.configuration.CONDA_TOOL_ID
+import com.jetbrains.python.sdk.configuration.PIPENV_TOOL_ID
+import com.jetbrains.python.sdk.configuration.VENV_TOOL_ID
import com.jetbrains.python.sdk.flavors.PyFlavorAndData
import com.jetbrains.python.sdk.flavors.PyFlavorData
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor
@@ -137,17 +144,18 @@ abstract class PythonExistingEnvironmentConfigurator (model: Pyth
enum class PythonSupportedEnvironmentManagers(
+ val toolId: ToolId,
val nameKey: String,
val icon: Icon,
val isFSSupported: (FileSystem<*>) -> Boolean = { (it as? FileSystem.Eel)?.eelApi == localEel },
) {
- VIRTUALENV("sdk.create.custom.virtualenv", PythonIcons.Python.Virtualenv, { true }),
- CONDA("sdk.create.custom.conda", PythonIcons.Python.Anaconda, { true }),
- POETRY("sdk.create.custom.poetry", PythonCommunityImplPoetryCommonIcons.Poetry),
- PIPENV("sdk.create.custom.pipenv", PIPENV_ICON),
- UV("sdk.create.custom.uv", PythonCommunityImplUVCommonIcons.UV),
- HATCH("sdk.create.custom.hatch", PythonHatchIcons.Logo, { it is FileSystem.Eel }),
- PYTHON("sdk.create.custom.python", PythonParserIcons.PythonFile, { true })
+ VIRTUALENV(VENV_TOOL_ID, "sdk.create.custom.virtualenv", PythonIcons.Python.Virtualenv, { true }),
+ CONDA(CONDA_TOOL_ID, "sdk.create.custom.conda", PythonIcons.Python.Anaconda, { true }),
+ POETRY(POETRY_TOOL_ID, "sdk.create.custom.poetry", PythonCommunityImplPoetryCommonIcons.Poetry),
+ PIPENV(PIPENV_TOOL_ID, "sdk.create.custom.pipenv", PIPENV_ICON),
+ UV(UV_TOOL_ID, "sdk.create.custom.uv", PythonCommunityImplUVCommonIcons.UV),
+ HATCH(HATCH_TOOL_ID, "sdk.create.custom.hatch", PythonHatchIcons.Logo, { it is FileSystem.Eel }),
+ PYTHON(VENV_TOOL_ID, "sdk.create.custom.python", PythonParserIcons.PythonFile, { true })
}
enum class PythonInterpreterSelectionMode(val nameKey: String) {
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaExistingEnvironmentSelector.kt b/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaExistingEnvironmentSelector.kt
index 696ad1251dcb..bde31c2c3bbd 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaExistingEnvironmentSelector.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaExistingEnvironmentSelector.kt
@@ -109,7 +109,9 @@ internal class CondaExistingEnvironmentSelector (model: PythonAdd
scope.launch(Dispatchers.EDT) {
model.condaViewModel.condaEnvironmentsResult.collectLatest { environmentsResult ->
envComboBox.removeAllItems()
- environmentsResult?.successOrNull?.forEach(envComboBox::addItem)
+ val environments = environmentsResult?.successOrNull ?: return@collectLatest
+ environments.forEach(envComboBox::addItem)
+ model.condaViewModel.updateSelection(environments)
}
}
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaViewModel.kt b/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaViewModel.kt
index 00e1ca6451be..7e8d511083ff 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaViewModel.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/conda/CondaViewModel.kt
@@ -8,10 +8,16 @@ import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.diagnostic.rethrowControlFlowException
import com.intellij.openapi.observable.properties.ObservableMutableProperty
import com.intellij.openapi.observable.properties.PropertyGraph
+import com.intellij.openapi.util.io.toNioPathOrNull
+import com.intellij.openapi.vfs.isFile
+import com.intellij.openapi.vfs.refreshAndFindVirtualFileOrDirectory
import com.intellij.platform.eel.provider.localEel
import com.jetbrains.python.PyBundle.message
import com.jetbrains.python.conda.loadLocalPythonCondaPath
import com.jetbrains.python.errorProcessing.PyResult
+import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows
+import com.jetbrains.python.packaging.conda.environmentYml.CondaEnvironmentYmlSdkUtils
+import com.jetbrains.python.packaging.conda.environmentYml.format.CondaEnvironmentYmlParser
import com.jetbrains.python.sdk.add.v2.*
import com.jetbrains.python.sdk.conda.TargetEnvironmentRequestCommandExecutor
import com.jetbrains.python.sdk.conda.suggestCondaPath
@@ -20,14 +26,17 @@ import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import java.nio.file.Path
private val LOG: Logger = fileLogger()
class CondaViewModel (
val fileSystem: FileSystem ,
propertyGraph: PropertyGraph,
+ val projectPathFlows: ProjectPathFlows,
) : PythonToolViewModel {
val condaExecutable: ObservableMutableProperty (
}
}
- /**
- * Returns error or `null` if no error
- */
+ suspend fun updateSelection(environments: List (
withContext(Dispatchers.UI) {
baseCondaEnv.set(baseConda)
- selectedCondaEnv.set(environments.firstOrNull())
}
+
return@withContext PyResult.success(environments)
}
}
diff --git a/python/src/com/jetbrains/python/sdk/add/v2/models.kt b/python/src/com/jetbrains/python/sdk/add/v2/models.kt
index a865e970ace5..a238409035b3 100644
--- a/python/src/com/jetbrains/python/sdk/add/v2/models.kt
+++ b/python/src/com/jetbrains/python/sdk/add/v2/models.kt
@@ -55,7 +55,7 @@ abstract class PythonAddInterpreterModel (
val navigator: PythonNewEnvironmentDialogNavigator = PythonNewEnvironmentDialogNavigator()
open val state: AddInterpreterState = AddInterpreterState(propertyGraph)
- val condaViewModel: CondaViewModel = CondaViewModel(fileSystem, propertyGraph)
+ val condaViewModel: CondaViewModel = CondaViewModel(fileSystem, propertyGraph, projectPathFlows)
val uvViewModel: UvViewModel = UvViewModel(fileSystem, propertyGraph)
val pipenvViewModel: PipenvViewModel = PipenvViewModel(fileSystem, propertyGraph)
val poetryViewModel: PoetryViewModel = PoetryViewModel(fileSystem, propertyGraph)
> = withContext(Dispatchers.IO) {
val executable = condaExecutable.get()
if (executable == null) return@withContext PyResult.localizedError(message("python.sdk.conda.no.exec"))
@@ -108,8 +144,8 @@ class CondaViewModel