[python] PY-83881 Provide python info during environment detection

GitOrigin-RevId: 4382680255fc78925c4b23ce825a2894114040c5
This commit is contained in:
Alexey Katsman
2025-11-03 12:05:45 +00:00
committed by intellij-monorepo-bot
parent 4025d5d1d3
commit 1ac353ef9a
23 changed files with 147 additions and 73 deletions
+3
View File
@@ -69,6 +69,7 @@ jvm_library(
"//python/python-exec-service:community-execService",
"//python/python-sdk-configurator/common",
"//python/python-sdk-ui:sdk-ui",
"//python/python-exec-service/execService.python",
],
runtime_deps = ["//python/python-features-trainer:featuresTrainer"],
plugins = ["@lib//:compose-plugin"]
@@ -144,6 +145,8 @@ jvm_library(
"//python/python-exec-service:community-execService_test_lib",
"//python/python-sdk-configurator/common",
"//python/python-sdk-ui:sdk-ui",
"//python/python-exec-service/execService.python",
"//python/python-exec-service/execService.python:execService.python_test_lib",
],
plugins = ["@lib//:compose-plugin"]
)
@@ -83,5 +83,6 @@
<orderEntry type="module" module-name="intellij.python.community.execService" />
<orderEntry type="module" module-name="intellij.python.sdkConfigurator.common" />
<orderEntry type="module" module-name="intellij.python.sdk.ui" />
<orderEntry type="module" module-name="intellij.python.community.execService.python" />
</component>
</module>
@@ -8,6 +8,7 @@
<module name="intellij.platform.ide.nonModalWelcomeScreen.backend"/>
<module name="intellij.python.sdkConfigurator.common"/>
<module name="intellij.python.sdk.ui"/>
<module name="intellij.python.community.execService.python"/>
</dependencies>
<projectListeners>
@@ -16,6 +16,7 @@ import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationC
import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationCollector.InputData
import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationCollector.Source
import com.intellij.pycharm.community.ide.impl.configuration.ui.PyAddNewCondaEnvFromFilePanel
import com.intellij.pycharm.community.ide.impl.findEnvOrNull
import com.intellij.python.community.execService.BinOnEel
import com.intellij.python.sdk.ui.icons.PythonSdkUIIcons
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
@@ -23,7 +24,6 @@ import com.jetbrains.python.PyBundle
import com.jetbrains.python.PyToolUIInfo
import com.jetbrains.python.configuration.PyConfigurableInterpreterList
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.errorProcessing.emit
import com.jetbrains.python.getOrNull
import com.jetbrains.python.onSuccess
import com.jetbrains.python.packaging.conda.environmentYml.CondaEnvironmentYmlSdkUtils
@@ -37,6 +37,7 @@ import com.jetbrains.python.sdk.basePath
import com.jetbrains.python.sdk.conda.PyCondaSdkCustomizer
import com.jetbrains.python.sdk.conda.createCondaSdkAlongWithNewEnv
import com.jetbrains.python.sdk.conda.createCondaSdkFromExistingEnv
import com.jetbrains.python.sdk.conda.execution.CondaExecutor
import com.jetbrains.python.sdk.conda.suggestCondaPath
import com.jetbrains.python.sdk.configuration.*
import com.jetbrains.python.sdk.findAmongRoots
@@ -78,10 +79,16 @@ class PyEnvironmentYmlSdkConfiguration : PyProjectSdkConfigurationExtension {
}
val canManage = condaPath != null
val intentionName = PyCharmCommunityCustomizationBundle.message("sdk.create.condaenv.suggestion")
val envNotFound = EnvCheckerResult.EnvNotFound(intentionName)
when {
canManage && checkExistence && getCondaEnvIdentity(module, condaPath.path) != null -> EnvCheckerResult.EnvFound("", intentionName)
canManage -> EnvCheckerResult.EnvNotFound(intentionName)
canManage && checkExistence -> {
getCondaEnvIdentity(module, condaPath.path)?.let { env ->
val binaryToExec = BinOnEel(Path.of(condaPath.path))
CondaExecutor.getPythonInfo(binaryToExec, env).findEnvOrNull(intentionName)
} ?: envNotFound
}
canManage -> envNotFound
else -> EnvCheckerResult.CannotConfigure
}
}
@@ -55,7 +55,7 @@ class PyHatchSdkConfiguration : PyProjectTomlConfigurationExtension {
canManage && checkExistence -> {
val defaultEnv = hatchService.findDefaultVirtualEnvironmentOrNull().getOrLogException(LOGGER)?.pythonVirtualEnvironment
when (defaultEnv) {
is PythonVirtualEnvironment.Existing -> EnvCheckerResult.EnvFound("", intentionName)
is PythonVirtualEnvironment.Existing -> EnvCheckerResult.EnvFound(defaultEnv.pythonInfo, intentionName)
is PythonVirtualEnvironment.NotExisting, null -> envNotFound
}
}
@@ -16,6 +16,8 @@ import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBund
import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationCollector.InputData
import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationCollector.PipEnvResult
import com.intellij.pycharm.community.ide.impl.configuration.PySdkConfigurationCollector.Source
import com.intellij.pycharm.community.ide.impl.findEnvOrNull
import com.intellij.python.community.execService.ZeroCodeStdoutParserTransformer
import com.intellij.python.community.impl.pipenv.pipenvPath
import com.intellij.python.sdk.ui.icons.PythonSdkUIIcons
import com.intellij.ui.IdeBorderFactory
@@ -72,10 +74,19 @@ class PyPipfileSdkConfiguration : PyProjectSdkConfigurationExtension {
when {
canManage && checkExistence -> {
PropertiesComponent.getInstance().pipenvPath = pipEnvExecutable.pathString
val envPath = runPipEnv(module.basePath?.toNioPathOrNull(), "--venv").mapSuccess { Path.of(it) }.successOrNull
val envPath = runPipEnv(
module.basePath?.toNioPathOrNull(),
"--venv",
transformer = ZeroCodeStdoutParserTransformer { PyResult.success(Path.of(it)) }
).successOrNull
val path = envPath?.resolvePythonBinary()
val envExists = path?.let { LocalFileSystem.getInstance().refreshAndFindFileByPath(it.pathString) != null } ?: false
if (envExists) EnvCheckerResult.EnvFound("", intentionName) else envNotFound
val envExists = path?.let {
LocalFileSystem.getInstance().refreshAndFindFileByPath(it.pathString) != null
} ?: false
if (envExists) {
path.findEnvOrNull(intentionName) ?: envNotFound
}
else envNotFound
}
canManage -> envNotFound
else -> EnvCheckerResult.CannotConfigure
@@ -11,6 +11,7 @@ import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.intellij.platform.util.progress.reportRawProgress
import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBundle
import com.intellij.pycharm.community.ide.impl.findEnvOrNull
import com.intellij.python.pyproject.PyProjectToml
import com.intellij.python.sdk.ui.icons.PythonSdkUIIcons
import com.jetbrains.python.PyBundle
@@ -78,7 +79,7 @@ class PyPoetrySdkConfiguration : PyProjectTomlConfigurationExtension {
val envPath = runPoetry(basePath, "env", "info", "-p")
.mapSuccess { it.toNioPathOrNull() }
.getOr { return@reportRawProgress envNotFound }
envPath?.resolvePythonBinary()?.let { EnvCheckerResult.EnvFound("", intentionName) } ?: return@reportRawProgress envNotFound
envPath?.resolvePythonBinary()?.findEnvOrNull(intentionName) ?: return@reportRawProgress envNotFound
}
canManage -> envNotFound
else -> EnvCheckerResult.CannotConfigure
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.UserDataHolderBase
import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.openapi.vfs.readText
import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBundle
import com.intellij.pycharm.community.ide.impl.findEnvOrNull
import com.intellij.python.pyproject.PyProjectToml
import com.intellij.python.pyproject.model.api.SuggestedSdk
import com.intellij.python.pyproject.model.api.suggestSdk
@@ -88,10 +89,14 @@ class PyUvSdkConfiguration : PyProjectTomlConfigurationExtension {
else true to module.name
val intentionName = PyCharmCommunityCustomizationBundle.message("sdk.set.up.uv.environment", projectName)
val envNotFound = EnvCheckerResult.EnvNotFound(intentionName)
return when {
checkExistence && getUvEnv(if (checkToml) module else module.getSdkAssociatedModule()) != null -> EnvCheckerResult.EnvFound("", intentionName)
canManage -> EnvCheckerResult.EnvNotFound(intentionName)
checkExistence -> {
val detectedSdk = getUvEnv(if (checkToml) module else module.getSdkAssociatedModule())
detectedSdk?.findEnvOrNull(intentionName) ?: if (canManage) envNotFound else EnvCheckerResult.CannotConfigure
}
canManage -> envNotFound
else -> EnvCheckerResult.CannotConfigure
}
}
@@ -118,8 +123,8 @@ class PyUvSdkConfiguration : PyProjectTomlConfigurationExtension {
getUvEnv(sdkAssociatedModule)?.homePath?.toNioPathOrNull()?.let {
setupExistingEnvAndSdk(it, workingDir, false, workingDir, existingSdks)
} ?: run {
logger.error("Can't find existing uv environment in project, but it was expected. " +
"Probably it was deleted. New environment will be created")
logger.warn("Can't find existing uv environment in project, but it was expected. " +
"Probably it was deleted. New environment will be created")
setupNewUvSdkAndEnv(workingDir, existingSdks, null)
}
}
@@ -6,6 +6,7 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.UserDataHolderBase
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBundle
import com.intellij.pycharm.community.ide.impl.findEnvOrNull
import com.jetbrains.python.PyBundle
import com.jetbrains.python.PyToolUIInfo
import com.jetbrains.python.errorProcessing.MessageError
@@ -38,7 +39,7 @@ class PyVenvSdkConfiguration : PyProjectSdkConfigurationExtension {
): EnvCheckerResult = withBackgroundProgress(module.project, PyBundle.message("python.sdk.validating.environment")) {
withContext(Dispatchers.IO) {
getVirtualEnv(module)?.let {
EnvCheckerResult.EnvFound("", PyCharmCommunityCustomizationBundle.message("sdk.use.existing.venv", it.name))
it.findEnvOrNull(PyCharmCommunityCustomizationBundle.message("sdk.use.existing.venv", it.name))
} ?: EnvCheckerResult.CannotConfigure
}
}
@@ -0,0 +1,22 @@
// 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
import com.intellij.codeInspection.util.IntentionName
import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.python.community.execService.python.validatePythonAndGetInfo
import com.jetbrains.python.PythonBinary
import com.jetbrains.python.PythonInfo
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.orLogExceptionAsWarn
import com.jetbrains.python.sdk.asBinToExecute
import com.jetbrains.python.sdk.configuration.EnvCheckerResult
internal suspend fun PythonBinary.findEnvOrNull(@IntentionName intentionName: String): EnvCheckerResult.EnvFound? =
validatePythonAndGetInfo().findEnvOrNull(intentionName)
internal suspend fun Sdk.findEnvOrNull(@IntentionName intentionName: String): EnvCheckerResult.EnvFound? =
asBinToExecute().validatePythonAndGetInfo().findEnvOrNull(intentionName)
internal fun PyResult<PythonInfo>.findEnvOrNull(@IntentionName intentionName: String): EnvCheckerResult.EnvFound? =
orLogExceptionAsWarn(fileLogger())?.let { EnvCheckerResult.EnvFound(it, intentionName) }