mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-82244 Packages: Venv interpreter is not configured automatically
Signed-off-by: Nikita.Ashihmin <nikita.ashihmin@jetbrains.com> GitOrigin-RevId: 7dd5f77452afb28c500b70c525f7cdc007991a9c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d04453827d
commit
6b1720baee
+83
-82
@@ -3,7 +3,7 @@ package com.intellij.pycharm.community.ide.impl
|
||||
|
||||
import com.intellij.ide.trustedProjects.TrustedProjects
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.debug
|
||||
import com.intellij.openapi.module.Module
|
||||
@@ -36,7 +36,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
/**
|
||||
* @see [PyConfigureSdkOnWslTest]
|
||||
@@ -96,105 +95,107 @@ class PythonSdkConfigurator : DirectoryProjectConfigurator {
|
||||
project: Project,
|
||||
module: Module,
|
||||
extension: PyProjectSdkConfigurationExtension?,
|
||||
): Unit = reportRawProgress { indicator ->
|
||||
// please keep this method in sync with com.jetbrains.python.inspections.PyInterpreterInspection.Visitor.getSuitableSdkFix
|
||||
): Unit = withContext(Dispatchers.Default) {
|
||||
reportRawProgress { indicator ->
|
||||
// please keep this method in sync with com.jetbrains.python.inspections.PyInterpreterInspection.Visitor.getSuitableSdkFix
|
||||
|
||||
indicator.fraction(null)
|
||||
indicator.fraction(null)
|
||||
|
||||
val context = UserDataHolderBase()
|
||||
val context = UserDataHolderBase()
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.inner.venvs"))
|
||||
LOGGER.debug("Looking for inner virtual environments")
|
||||
detectAssociatedEnvironments(module, emptyList(), context).filter { it.isLocatedInsideModule(module) }.takeIf { it.isNotEmpty() }?.let {
|
||||
runInEdt { it.forEach { module.excludeInnerVirtualEnv(it) } }
|
||||
}
|
||||
|
||||
if (!TrustedProjects.isProjectTrusted(project)) {
|
||||
// com.jetbrains.python.inspections.PyInterpreterInspection will ask for confirmation
|
||||
LOGGER.info("Python interpreter has not been configured since project is not trusted")
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
val existingSdks = ProjectSdksModel().apply { reset(project) }.sdks.filter { it.sdkType is PythonSdkType }
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.previous.interpreter"))
|
||||
LOGGER.debug("Looking for the previously used interpreter")
|
||||
mostPreferred(filterAssociatedSdks(module, existingSdks))?.let {
|
||||
LOGGER.debug { "The previously used interpreter: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.related.venv"))
|
||||
LOGGER.debug("Looking for a virtual environment related to the project")
|
||||
detectAssociatedEnvironments(module, existingSdks, context).firstOrNull()?.let {
|
||||
LOGGER.debug { "Detected virtual environment related to the project: $it" }
|
||||
val newSdk = it.setupAssociated(existingSdks, module.basePath, true).orLogException(LOGGER) ?: return
|
||||
|
||||
LOGGER.debug { "Created virtual environment related to the project: $newSdk" }
|
||||
|
||||
runInEdt {
|
||||
SdkConfigurationUtil.addSdk(newSdk)
|
||||
setReadyToUseSdk(project, module, newSdk)
|
||||
indicator.text(PyBundle.message("looking.for.inner.venvs"))
|
||||
LOGGER.debug("Looking for inner virtual environments")
|
||||
detectAssociatedEnvironments(module, emptyList(), context).filter { it.isLocatedInsideModule(module) }.takeIf { it.isNotEmpty() }?.let {
|
||||
withContext(Dispatchers.EDT) { it.forEach { module.excludeInnerVirtualEnv(it) } }
|
||||
}
|
||||
|
||||
return@reportRawProgress
|
||||
}
|
||||
if (!TrustedProjects.isProjectTrusted(project)) {
|
||||
// com.jetbrains.python.inspections.PyInterpreterInspection will ask for confirmation
|
||||
LOGGER.info("Python interpreter has not been configured since project is not trusted")
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
val existingSdks = ProjectSdksModel().apply { reset(project) }.sdks.filter { it.sdkType is PythonSdkType }
|
||||
|
||||
if (extension != null) {
|
||||
indicator.text("")
|
||||
setSdkUsingExtension(module, extension) { extension.createAndAddSdkForConfigurator(module) }
|
||||
return@reportRawProgress
|
||||
}
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
if (PyCondaSdkCustomizer.instance.suggestSharedCondaEnvironments) {
|
||||
indicator.text(PyBundle.message("looking.for.shared.conda.environment"))
|
||||
mostPreferred(filterSharedCondaEnvs(module, existingSdks))?.let {
|
||||
indicator.text(PyBundle.message("looking.for.previous.interpreter"))
|
||||
LOGGER.debug("Looking for the previously used interpreter")
|
||||
mostPreferred(filterAssociatedSdks(module, existingSdks))?.let {
|
||||
LOGGER.debug { "The previously used interpreter: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
}
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.default.interpreter"))
|
||||
LOGGER.debug("Looking for the default interpreter setting for a new project")
|
||||
getDefaultProjectSdk()?.let {
|
||||
LOGGER.debug { "Default interpreter setting for a new project: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
indicator.text(PyBundle.message("looking.for.related.venv"))
|
||||
LOGGER.debug("Looking for a virtual environment related to the project")
|
||||
detectAssociatedEnvironments(module, existingSdks, context).firstOrNull()?.let {
|
||||
LOGGER.debug { "Detected virtual environment related to the project: $it" }
|
||||
val newSdk = it.setupAssociated(existingSdks, module.basePath, true).orLogException(LOGGER) ?: return@withContext
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
LOGGER.debug { "Created virtual environment related to the project: $newSdk" }
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.previous.system.interpreter"))
|
||||
LOGGER.debug("Looking for the previously used system-wide interpreter")
|
||||
mostPreferred(filterSystemWideSdks(existingSdks))?.let {
|
||||
LOGGER.debug { "Previously used system-wide interpreter: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
withContext(Dispatchers.EDT) {
|
||||
SdkConfigurationUtil.addSdk(newSdk)
|
||||
setReadyToUseSdk(project, module, newSdk)
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.system.interpreter"))
|
||||
LOGGER.debug("Looking for a system-wide interpreter")
|
||||
detectSystemWideSdks(module, existingSdks, context).firstOrNull()?.let {
|
||||
LOGGER.debug { "Detected system-wide interpreter: $it" }
|
||||
runInEdt {
|
||||
SdkConfigurationUtil.createAndAddSDK(it.homePath!!, PythonSdkType.getInstance())?.apply {
|
||||
LOGGER.debug { "Created system-wide interpreter: $this" }
|
||||
setReadyToUseSdk(project, module, this)
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
if (extension != null) {
|
||||
indicator.text("")
|
||||
setSdkUsingExtension(module, extension) { extension.createAndAddSdkForConfigurator(module) }
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
if (PyCondaSdkCustomizer.instance.suggestSharedCondaEnvironments) {
|
||||
indicator.text(PyBundle.message("looking.for.shared.conda.environment"))
|
||||
mostPreferred(filterSharedCondaEnvs(module, existingSdks))?.let {
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
}
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.default.interpreter"))
|
||||
LOGGER.debug("Looking for the default interpreter setting for a new project")
|
||||
getDefaultProjectSdk()?.let {
|
||||
LOGGER.debug { "Default interpreter setting for a new project: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.previous.system.interpreter"))
|
||||
LOGGER.debug("Looking for the previously used system-wide interpreter")
|
||||
mostPreferred(filterSystemWideSdks(existingSdks))?.let {
|
||||
LOGGER.debug { "Previously used system-wide interpreter: $it" }
|
||||
setReadyToUseSdk(project, module, it)
|
||||
return@reportRawProgress
|
||||
}
|
||||
|
||||
if (!coroutineContext.isActive) return@reportRawProgress
|
||||
|
||||
indicator.text(PyBundle.message("looking.for.system.interpreter"))
|
||||
LOGGER.debug("Looking for a system-wide interpreter")
|
||||
detectSystemWideSdks(module, existingSdks, context).firstOrNull()?.let {
|
||||
LOGGER.debug { "Detected system-wide interpreter: $it" }
|
||||
withContext(Dispatchers.EDT) {
|
||||
SdkConfigurationUtil.createAndAddSDK(it.homePath!!, PythonSdkType.getInstance())?.apply {
|
||||
LOGGER.debug { "Created system-wide interpreter: $this" }
|
||||
setReadyToUseSdk(project, module, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
@@ -26,7 +27,6 @@ import com.intellij.openapi.vfs.ex.temp.TempFileSystem
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.webcore.packaging.PackagesNotificationPanel
|
||||
import com.jetbrains.python.PyBundle
|
||||
import com.jetbrains.python.errorProcessing.PyResult
|
||||
@@ -200,7 +200,9 @@ fun createSdkByGenerateTask(
|
||||
}
|
||||
}
|
||||
else {
|
||||
suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
|
||||
runBlockingMaybeCancellable {
|
||||
suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
|
||||
}
|
||||
}
|
||||
return SdkConfigurationUtil.setupSdk(
|
||||
existingSdks.toTypedArray(),
|
||||
@@ -221,10 +223,7 @@ suspend fun createSdk(
|
||||
val homeFile = withContext(Dispatchers.IO) { StandardFileSystems.local().refreshAndFindFileByPath(sdkHomePath.pathString) }
|
||||
?: return PyResult.localizedError(PyBundle.message("python.sdk.directory.not.found", sdkHomePath.pathString))
|
||||
|
||||
val sdkName = suggestedSdkName ?: withContext(Dispatchers.IO) {
|
||||
suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
|
||||
}
|
||||
|
||||
val sdkName = suggestedSdkName ?: suggestAssociatedSdkName(homeFile.path, associatedProjectPath)
|
||||
val sdk = SdkConfigurationUtil.setupSdk(
|
||||
existingSdks.toTypedArray(),
|
||||
homeFile,
|
||||
@@ -289,25 +288,30 @@ fun PyDetectedSdk.setup(existingSdks: List<Sdk>): Sdk? {
|
||||
|
||||
// For Java only
|
||||
internal fun PyDetectedSdk.setupAssociatedLogged(existingSdks: List<Sdk>, associatedModulePath: String?, doAssociate: Boolean): Sdk? {
|
||||
return setupAssociated(existingSdks, associatedModulePath, doAssociate).orLogException(LOGGER)
|
||||
return runBlockingMaybeCancellable {
|
||||
setupAssociated(existingSdks, associatedModulePath, doAssociate).orLogException(LOGGER)
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
|
||||
fun PyDetectedSdk.setupAssociated(existingSdks: List<Sdk>, associatedModulePath: String?, doAssociate: Boolean): PyResult<Sdk> {
|
||||
suspend fun PyDetectedSdk.setupAssociated(
|
||||
existingSdks: List<Sdk>,
|
||||
associatedModulePath: String?,
|
||||
doAssociate: Boolean,
|
||||
): PyResult<Sdk> = withContext(Dispatchers.IO) {
|
||||
if (!sdkSeemsValid) {
|
||||
return PyResult.localizedError(PyBundle.message("python.sdk.error.invalid.interpreter.selected", homePath))
|
||||
return@withContext PyResult.localizedError(PyBundle.message("python.sdk.error.invalid.interpreter.selected", homePath))
|
||||
}
|
||||
|
||||
val homePath = this.homePath
|
||||
val homePath = homePath
|
||||
if (homePath == null) {
|
||||
// e.g. directory is not there anymore
|
||||
return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", null))
|
||||
return@withContext PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", null))
|
||||
}
|
||||
|
||||
val homeDir = this.homeDirectory
|
||||
val homeDir = homeDirectory
|
||||
if (homeDir == null) {
|
||||
return PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", null))
|
||||
return@withContext PyResult.localizedError(PyBundle.message("python.sdk.provided.path.is.invalid", null))
|
||||
}
|
||||
|
||||
val suggestedName = if (doAssociate) {
|
||||
@@ -332,7 +336,7 @@ fun PyDetectedSdk.setupAssociated(existingSdks: List<Sdk>, associatedModulePath:
|
||||
data,
|
||||
suggestedName)
|
||||
|
||||
return PyResult.success(sdk)
|
||||
PyResult.success(sdk)
|
||||
}
|
||||
|
||||
var Module.pythonSdk: Sdk?
|
||||
@@ -408,12 +412,11 @@ fun getInnerVirtualEnvRoot(sdk: Sdk): VirtualFile? {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresBackgroundThread(generateAssertion = false)
|
||||
internal fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?): String? {
|
||||
internal suspend fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?): String? = withContext(Dispatchers.IO) {
|
||||
// please don't forget to update com.jetbrains.python.inspections.PyInterpreterInspection.Visitor#getSuitableSdkFix
|
||||
// after changing this method
|
||||
|
||||
val baseSdkName = PythonSdkType.suggestBaseSdkName(sdkHome) ?: return null
|
||||
val baseSdkName = PythonSdkType.suggestBaseSdkName(sdkHome) ?: return@withContext null
|
||||
val venvRoot = PythonSdkUtil.getVirtualEnvRoot(sdkHome)?.path
|
||||
val condaRoot = CondaEnvSdkFlavor.getCondaEnvRoot(sdkHome)?.path
|
||||
val associatedName = when {
|
||||
@@ -424,9 +427,9 @@ internal fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?):
|
||||
PythonSdkUtil.isBaseConda(sdkHome) ->
|
||||
"base"
|
||||
else ->
|
||||
associatedPath?.let { PathUtil.getFileName(associatedPath) } ?: return null
|
||||
associatedPath?.let { PathUtil.getFileName(associatedPath) } ?: return@withContext null
|
||||
}
|
||||
return "$baseSdkName ($associatedName)"
|
||||
return@withContext "$baseSdkName ($associatedName)"
|
||||
}
|
||||
|
||||
internal val Sdk.isSystemWide: Boolean
|
||||
|
||||
@@ -20,8 +20,7 @@ suspend fun createSdk(
|
||||
existingSdks: Array<Sdk>,
|
||||
): Sdk {
|
||||
val newSdk = withContext(Dispatchers.IO) {
|
||||
// "suggest name" calls external process and can't be called from EDT
|
||||
val suggestedName = /*suggestedSdkName ?:*/ suggestAssociatedSdkName(pythonBinaryPath.path, projectPath?.toString())
|
||||
val suggestedName = suggestAssociatedSdkName(pythonBinaryPath.path, projectPath?.toString())
|
||||
SdkConfigurationUtil.setupSdk(existingSdks, pythonBinaryPath,
|
||||
PythonSdkType.getInstance(),
|
||||
null, suggestedName)
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.execution.target.TargetEnvironmentConfiguration
|
||||
import com.intellij.execution.target.joinTargetPaths
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
@@ -14,11 +15,7 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
import com.intellij.openapi.util.UserDataHolder
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.ui.dsl.builder.AlignX
|
||||
import com.intellij.ui.dsl.builder.bind
|
||||
import com.intellij.ui.dsl.builder.bindSelected
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.dsl.builder.selected
|
||||
import com.intellij.ui.dsl.builder.*
|
||||
import com.intellij.ui.layout.ComponentPredicate
|
||||
import com.intellij.ui.layout.not
|
||||
import com.intellij.util.PathUtil
|
||||
@@ -29,25 +26,19 @@ import com.jetbrains.python.icons.PythonIcons
|
||||
import com.jetbrains.python.pathValidation.PlatformAndRoot.Companion.getPlatformAndRoot
|
||||
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
|
||||
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory.Companion.extendWithTargetSpecificFields
|
||||
import com.jetbrains.python.sdk.PyDetectedSdk
|
||||
import com.jetbrains.python.sdk.PySdkSettings
|
||||
import com.jetbrains.python.sdk.PythonSdkType
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import com.jetbrains.python.sdk.*
|
||||
import com.jetbrains.python.sdk.add.ExistingPySdkComboBoxItem
|
||||
import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox
|
||||
import com.jetbrains.python.sdk.add.addBaseInterpretersAsync
|
||||
import com.jetbrains.python.sdk.add.addInterpretersAsync
|
||||
import com.jetbrains.python.sdk.configuration.createSdkForTarget
|
||||
import com.jetbrains.python.sdk.configuration.createVirtualEnvAndSdkSynchronously
|
||||
import com.jetbrains.python.sdk.detectVirtualEnvs
|
||||
import com.jetbrains.python.sdk.flavors.PyFlavorAndData
|
||||
import com.jetbrains.python.sdk.flavors.PyFlavorData
|
||||
import com.jetbrains.python.sdk.isAssociatedWithAnotherModule
|
||||
import com.jetbrains.python.sdk.isAssociatedWithModule
|
||||
import com.jetbrains.python.sdk.setupAssociated
|
||||
import com.jetbrains.python.target.PyTargetAwareAdditionalData
|
||||
import com.jetbrains.python.target.PythonLanguageRuntimeConfiguration
|
||||
import com.jetbrains.python.target.createDetectedSdk
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import java.awt.BorderLayout
|
||||
import java.util.function.Supplier
|
||||
|
||||
@@ -199,7 +190,9 @@ internal class PyAddVirtualEnvPanel(
|
||||
|
||||
val item = interpreterCombobox.selectedItem as ExistingPySdkComboBoxItem
|
||||
// there should *not* be other items other than `ExistingPySdkComboBoxItem`
|
||||
return configureExistingVirtualenvSdk(targetEnvironmentConfiguration, item.sdk)
|
||||
return runBlockingMaybeCancellable {
|
||||
configureExistingVirtualenvSdk(targetEnvironmentConfiguration, item.sdk)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +221,7 @@ internal class PyAddVirtualEnvPanel(
|
||||
isInheritSitePackages, false, targetPanelExtension)
|
||||
}
|
||||
|
||||
private fun configureExistingVirtualenvSdk(targetEnvironmentConfiguration: TargetEnvironmentConfiguration?, selectedSdk: Sdk): Sdk {
|
||||
private suspend fun configureExistingVirtualenvSdk(targetEnvironmentConfiguration: TargetEnvironmentConfiguration?, selectedSdk: Sdk): Sdk {
|
||||
if (targetEnvironmentConfiguration == null) {
|
||||
return when (selectedSdk) {
|
||||
is PyDetectedSdk -> selectedSdk.setupAssociated(existingSdks, newProjectPath ?: project?.basePath, true)
|
||||
|
||||
Reference in New Issue
Block a user