From 7a97e9f027ee6565fce33da3df8e572934d34ff5 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 14 Oct 2025 22:49:30 +0200 Subject: [PATCH] PY-79486: (WIP) Fix backend call to detect modules, show icon for pythons. It is not possible to use topics to access the backend. Only RPC API must be used. Moreover, registry settings require restart. GitOrigin-RevId: 965ed41d17350ab0b24b36eb53edf23fba95c4af --- ...ntellij.python.sdkConfigurator.backend.xml | 4 -- .../backend/src/impl/backendLib.kt | 15 ++++- .../impl/platformBridge/ConfigureSDKAction.kt | 3 +- .../ModelRebuiltListenerImpl.kt | 5 +- .../impl/rpcBridge/BackendTopicListener.kt | 15 ----- .../impl/rpcBridge/SdkConfiguratorApiImpl.kt | 5 ++ ...intellij.python.sdkConfigurator.common.xml | 2 +- .../src/impl/SdkConfiguratorBackEndApi.kt | 16 ++++- .../common/src/impl/detectModulesImpl.kt | 10 ---- .../common/src/publicApi.kt | 16 ++--- ...PySdkConfiguratorFrontendBundle.properties | 5 +- .../frontend/src/components/ModuleList.kt | 60 ++++++++++++------- .../src/components/PythonsDropDown.kt | 31 +++++++++- .../frontend/src/components/tools.kt | 15 +++++ .../frontend/src/package-info.java | 3 + .../src/rpcBridge/FrontendTopicListener.kt | 3 +- .../frontend/src/rpcBridge/apiObtainer.kt | 9 --- .../frontend/src/swingBridge.kt | 9 ++- .../inspections/PyInterpreterInspection.java | 4 +- .../inspections/PyInterpreterInspectionEx.kt | 24 ++++++++ 20 files changed, 169 insertions(+), 85 deletions(-) delete mode 100644 python/python-sdk-configurator/backend/src/impl/rpcBridge/BackendTopicListener.kt delete mode 100644 python/python-sdk-configurator/common/src/impl/detectModulesImpl.kt create mode 100644 python/python-sdk-configurator/frontend/src/components/tools.kt delete mode 100644 python/python-sdk-configurator/frontend/src/rpcBridge/apiObtainer.kt diff --git a/python/python-sdk-configurator/backend/resources/intellij.python.sdkConfigurator.backend.xml b/python/python-sdk-configurator/backend/resources/intellij.python.sdkConfigurator.backend.xml index 09ccc3c3b20d..1ee5941f00c6 100644 --- a/python/python-sdk-configurator/backend/resources/intellij.python.sdkConfigurator.backend.xml +++ b/python/python-sdk-configurator/backend/resources/intellij.python.sdkConfigurator.backend.xml @@ -16,10 +16,6 @@ - - - diff --git a/python/python-sdk-configurator/backend/src/impl/backendLib.kt b/python/python-sdk-configurator/backend/src/impl/backendLib.kt index a395f5e66a6a..4646fb7a3c5f 100644 --- a/python/python-sdk-configurator/backend/src/impl/backendLib.kt +++ b/python/python-sdk-configurator/backend/src/impl/backendLib.kt @@ -30,9 +30,20 @@ import kotlinx.coroutines.withContext private val askUserMutex = Mutex() -// TODO: DOC -internal fun configureSdkAskingUser(project: Project) { +/** + * Same as [configureSdkAutomatically] but in a separate coroutine + */ +internal fun configureSdkAskingUserBg(project: Project) { project.service().scope.launch(Dispatchers.Default) { + configureSdkAskingUser(project) + } +} + +/** + * Ask user for list of modules and configure them + */ +internal suspend fun configureSdkAskingUser(project: Project) { + withContext(Dispatchers.Default) { askUserMutex.withLock { val moduleToSuggestedSdk = getModulesWithoutSDK(project) if (moduleToSuggestedSdk.modules.isNotEmpty()) { diff --git a/python/python-sdk-configurator/backend/src/impl/platformBridge/ConfigureSDKAction.kt b/python/python-sdk-configurator/backend/src/impl/platformBridge/ConfigureSDKAction.kt index fc39d7effc3e..ebc8fd653827 100644 --- a/python/python-sdk-configurator/backend/src/impl/platformBridge/ConfigureSDKAction.kt +++ b/python/python-sdk-configurator/backend/src/impl/platformBridge/ConfigureSDKAction.kt @@ -4,6 +4,7 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUser +import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUserBg import com.intellij.python.sdkConfigurator.common.enableSDKAutoConfigurator internal class ConfigureSDKAction : AnAction() { @@ -13,7 +14,7 @@ internal class ConfigureSDKAction : AnAction() { if (!enableSDKAutoConfigurator) { return } - configureSdkAskingUser(project) + configureSdkAskingUserBg(project) } override fun update(e: AnActionEvent) { diff --git a/python/python-sdk-configurator/backend/src/impl/platformBridge/ModelRebuiltListenerImpl.kt b/python/python-sdk-configurator/backend/src/impl/platformBridge/ModelRebuiltListenerImpl.kt index 520157dedc04..41a9fdde637f 100644 --- a/python/python-sdk-configurator/backend/src/impl/platformBridge/ModelRebuiltListenerImpl.kt +++ b/python/python-sdk-configurator/backend/src/impl/platformBridge/ModelRebuiltListenerImpl.kt @@ -3,9 +3,8 @@ package com.intellij.python.sdkConfigurator.backend.impl.platformBridge import com.intellij.openapi.extensions.ExtensionNotApplicableException import com.intellij.openapi.project.Project import com.intellij.python.pyproject.model.api.ModelRebuiltListener -import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUser +import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUserBg import com.intellij.python.sdkConfigurator.common.enableSDKAutoConfigurator -import kotlinx.coroutines.sync.Mutex internal class ModelRebuiltListenerImpl : ModelRebuiltListener { init { @@ -15,7 +14,7 @@ internal class ModelRebuiltListenerImpl : ModelRebuiltListener { } override fun modelRebuilt(project: Project) { - configureSdkAskingUser(project) + configureSdkAskingUserBg(project) } } diff --git a/python/python-sdk-configurator/backend/src/impl/rpcBridge/BackendTopicListener.kt b/python/python-sdk-configurator/backend/src/impl/rpcBridge/BackendTopicListener.kt deleted file mode 100644 index ed9bb9e76efd..000000000000 --- a/python/python-sdk-configurator/backend/src/impl/rpcBridge/BackendTopicListener.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.intellij.python.sdkConfigurator.backend.impl.rpcBridge - -import com.intellij.openapi.project.Project -import com.intellij.platform.rpc.topics.ProjectRemoteTopic -import com.intellij.platform.rpc.topics.ProjectRemoteTopicListener -import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUser -import com.intellij.python.sdkConfigurator.common.impl.DETECT_SDK_FOR_MODULES - -internal class BackendTopicListener : ProjectRemoteTopicListener { - override val topic: ProjectRemoteTopic = DETECT_SDK_FOR_MODULES - - override fun handleEvent(project: Project, event: Unit) { - configureSdkAskingUser(project) - } -} diff --git a/python/python-sdk-configurator/backend/src/impl/rpcBridge/SdkConfiguratorApiImpl.kt b/python/python-sdk-configurator/backend/src/impl/rpcBridge/SdkConfiguratorApiImpl.kt index 66dada0bf9c4..d5666cda6184 100644 --- a/python/python-sdk-configurator/backend/src/impl/rpcBridge/SdkConfiguratorApiImpl.kt +++ b/python/python-sdk-configurator/backend/src/impl/rpcBridge/SdkConfiguratorApiImpl.kt @@ -2,6 +2,7 @@ package com.intellij.python.sdkConfigurator.backend.impl.rpcBridge import com.intellij.platform.project.ProjectId import com.intellij.platform.project.findProject +import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAskingUser import com.intellij.python.sdkConfigurator.backend.impl.configureSdkAutomatically import com.intellij.python.sdkConfigurator.common.impl.ModuleName import com.intellij.python.sdkConfigurator.common.impl.SdkConfiguratorBackEndApi @@ -10,4 +11,8 @@ internal object SdkConfiguratorApiImpl : SdkConfiguratorBackEndApi { override suspend fun configureSdkAutomatically(projectId: ProjectId, onlyModules: Set) { configureSdkAutomatically(projectId.findProject(), onlyModules) } + + override suspend fun configureAskingUser(projectId: ProjectId) { + configureSdkAskingUser(projectId.findProject()) + } } \ No newline at end of file diff --git a/python/python-sdk-configurator/common/resources/intellij.python.sdkConfigurator.common.xml b/python/python-sdk-configurator/common/resources/intellij.python.sdkConfigurator.common.xml index f7b2a6632b72..22c04e273843 100644 --- a/python/python-sdk-configurator/common/resources/intellij.python.sdkConfigurator.common.xml +++ b/python/python-sdk-configurator/common/resources/intellij.python.sdkConfigurator.common.xml @@ -1,5 +1,5 @@ - + diff --git a/python/python-sdk-configurator/common/src/impl/SdkConfiguratorBackEndApi.kt b/python/python-sdk-configurator/common/src/impl/SdkConfiguratorBackEndApi.kt index ed834bda66c5..cc678e90d641 100644 --- a/python/python-sdk-configurator/common/src/impl/SdkConfiguratorBackEndApi.kt +++ b/python/python-sdk-configurator/common/src/impl/SdkConfiguratorBackEndApi.kt @@ -1,9 +1,11 @@ package com.intellij.python.sdkConfigurator.common.impl import com.intellij.platform.project.ProjectId +import com.intellij.platform.rpc.RemoteApiProviderService import com.intellij.platform.rpc.topics.ProjectRemoteTopic import fleet.rpc.RemoteApi import fleet.rpc.Rpc +import fleet.rpc.remoteApiDescriptor import kotlinx.serialization.Serializable /** @@ -12,9 +14,14 @@ import kotlinx.serialization.Serializable @Rpc interface SdkConfiguratorBackEndApi : RemoteApi { /*** - * Configure SDK for all modules in [projectId] if their names in [onlyModules] + * Configure SDK for all modules in [projectId] if their names in [onlyModules] unconditionally */ suspend fun configureSdkAutomatically(projectId: ProjectId, onlyModules: Set) + + /** + * Ask user about modules, then call [configureSdkAutomatically] + */ + suspend fun configureAskingUser(projectId: ProjectId) } typealias ModuleName = String @@ -29,4 +36,9 @@ val SHOW_SDK_CONFIG_UI_TOPIC: ProjectRemoteTopic = ProjectRemoteTopi */ @Serializable data class ModulesDTO(val modules: Map) { -} \ No newline at end of file +} + +/** + * [SdkConfiguratorBackEndApi] instance + */ +suspend fun SdkConfiguratorBackEndApi(): SdkConfiguratorBackEndApi = RemoteApiProviderService.resolve(remoteApiDescriptor()) \ No newline at end of file diff --git a/python/python-sdk-configurator/common/src/impl/detectModulesImpl.kt b/python/python-sdk-configurator/common/src/impl/detectModulesImpl.kt deleted file mode 100644 index f6f8a0f3b16f..000000000000 --- a/python/python-sdk-configurator/common/src/impl/detectModulesImpl.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.intellij.python.sdkConfigurator.common.impl - -import com.intellij.platform.rpc.topics.ProjectRemoteTopic -import kotlinx.serialization.builtins.serializer - -/** - * Backend listens for this topic to start SDK detection process - */ -val DETECT_SDK_FOR_MODULES: ProjectRemoteTopic = ProjectRemoteTopic("PySDKConfigurationDetectSDKTopic", Unit.serializer()) - diff --git a/python/python-sdk-configurator/common/src/publicApi.kt b/python/python-sdk-configurator/common/src/publicApi.kt index 059d91956a12..76689c4f8acf 100644 --- a/python/python-sdk-configurator/common/src/publicApi.kt +++ b/python/python-sdk-configurator/common/src/publicApi.kt @@ -2,8 +2,8 @@ package com.intellij.python.sdkConfigurator.common import com.intellij.openapi.project.Project import com.intellij.openapi.util.registry.Registry -import com.intellij.platform.rpc.topics.sendToClient -import com.intellij.python.sdkConfigurator.common.impl.DETECT_SDK_FOR_MODULES +import com.intellij.platform.project.projectId +import com.intellij.python.sdkConfigurator.common.impl.SdkConfiguratorBackEndApi /** @@ -11,14 +11,10 @@ import com.intellij.python.sdkConfigurator.common.impl.DETECT_SDK_FOR_MODULES */ val enableSDKAutoConfigurator: Boolean get() = Registry.`is`("intellij.python.sdkConfigurator.auto") + /** - * Check if [enableSDKAutoConfigurator] (return `false` if not) and start detecting process. - * it might ask user for list of modules and then detect them + * it might ask user for list of modules and then detect SDK for them */ -fun detectSdkForModulesIn(project: Project): Boolean { - if (!enableSDKAutoConfigurator) { - return false - } - DETECT_SDK_FOR_MODULES.sendToClient(project, Unit) - return true +suspend fun detectSdkForModulesIn(project: Project) { + SdkConfiguratorBackEndApi().configureAskingUser(project.projectId()) } diff --git a/python/python-sdk-configurator/frontend/resources/messages/PySdkConfiguratorFrontendBundle.properties b/python/python-sdk-configurator/frontend/resources/messages/PySdkConfiguratorFrontendBundle.properties index c9c6b99e6560..64ca45526a7e 100644 --- a/python/python-sdk-configurator/frontend/resources/messages/PySdkConfiguratorFrontendBundle.properties +++ b/python/python-sdk-configurator/frontend/resources/messages/PySdkConfiguratorFrontendBundle.properties @@ -1 +1,4 @@ -python.sdk.configurator.frontend.choose.modules.title=Choose Modules to Configure SDK For \ No newline at end of file +python.sdk.configurator.frontend.choose.modules.title=Configure Modules Environment +python.sdk.configurator.frontend.choose.modules.text=Pick the ones you want to use to run code and set up environment for them +python.sdk.configurator.frontend.choose.modules.project.structure=Project Structure +python.sdk.configurator.frontend.choose.modules.environment=Environment diff --git a/python/python-sdk-configurator/frontend/src/components/ModuleList.kt b/python/python-sdk-configurator/frontend/src/components/ModuleList.kt index ac261354a404..d1a0a68320cd 100644 --- a/python/python-sdk-configurator/frontend/src/components/ModuleList.kt +++ b/python/python-sdk-configurator/frontend/src/components/ModuleList.kt @@ -1,17 +1,18 @@ package com.intellij.python.sdkConfigurator.frontend.components -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableIntState -import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.snapshots.SnapshotStateSet import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.intellij.python.sdkConfigurator.frontend.ModuleInfo import kotlinx.collections.immutable.ImmutableMap -import org.jetbrains.jewel.ui.component.Checkbox +import org.jetbrains.annotations.Nls +import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.ui.component.CheckboxRow import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.VerticallyScrollableContainer @@ -21,23 +22,42 @@ internal fun ModuleList( moduleItems: ImmutableMap, checked: SnapshotStateSet, onCheckChange: (String, Boolean) -> Unit, + topLabel: @Nls String, + projectStructureLabel: @Nls String, + environmentLabel: @Nls String, ) { - VerticallyScrollableContainer { - Column(Modifier.width(500.dp)) { - for ((moduleName, moduleInfo) in moduleItems) { - val (parent, pythons) = moduleInfo - Row(Modifier.padding(2.dp), verticalAlignment = Alignment.CenterVertically) { - val checked = moduleName in checked - val elementToChange = parent ?: moduleName - Checkbox( - checked = checked, - onCheckedChange = { - onCheckChange(elementToChange, it) - }, - ) - Text(moduleName, Modifier.padding(start = 1.dp).clickable(true, onClick = { onCheckChange(elementToChange, !checked) })) - Spacer(Modifier.weight(1f)) - PythonsDropDown(pythons, Modifier.width(200.dp)) + val ts = JewelTheme.defaultTextStyle + val padding = 2.dp + val longestItemChars = remember { (listOf(projectStructureLabel) + moduleItems.keys).maxBy { it.length } } + val leftColumnMinSize = measureText(longestItemChars, ts) + val spaceBetweenCols = 16.dp + Column(Modifier.padding(padding), verticalArrangement = Arrangement.spacedBy(padding)) { + Text(topLabel, Modifier.padding(bottom = 10.dp)) + Row(Modifier, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) { + Text(projectStructureLabel, Modifier.width(leftColumnMinSize + spaceBetweenCols + padding + 26.dp)) //~ checkbox size + Text(environmentLabel, textAlign = TextAlign.End) + } + val moduleItems = remember { moduleItems.entries.sortedBy { it.key } } + VerticallyScrollableContainer { + Column(Modifier, horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(padding)) { + for ((moduleName, moduleInfo) in moduleItems) { + val (parent, pythons) = moduleInfo + Row(Modifier.padding(padding), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(spaceBetweenCols)) { + val checked = moduleName in checked + val elementToChange = parent ?: moduleName // TODO: move logic out of UI + CheckboxRow( + moduleName, + checked = checked, + onCheckedChange = { + onCheckChange(elementToChange, it) + }, + textStyle = ts, + textModifier = Modifier.width(leftColumnMinSize) + ) + if (parent == null) { + PythonsDropDown(pythons) + } + } } } } diff --git a/python/python-sdk-configurator/frontend/src/components/PythonsDropDown.kt b/python/python-sdk-configurator/frontend/src/components/PythonsDropDown.kt index 007e7f491d93..a499bf0951d2 100644 --- a/python/python-sdk-configurator/frontend/src/components/PythonsDropDown.kt +++ b/python/python-sdk-configurator/frontend/src/components/PythonsDropDown.kt @@ -1,13 +1,40 @@ package com.intellij.python.sdkConfigurator.frontend.components +import androidx.compose.foundation.layout.widthIn import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.unit.dp import kotlinx.collections.immutable.ImmutableList import org.jetbrains.jewel.foundation.ExperimentalJewelApi +import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.ui.component.ListComboBox +import org.jetbrains.jewel.ui.component.SimpleListItem +import org.jetbrains.jewel.ui.icons.AllIconsKeys.Language.Python +@OptIn(ExperimentalJewelApi::class) @Composable -internal fun PythonsDropDown(pythons: ImmutableList, modifier: Modifier = Modifier) { +internal fun PythonsDropDown(pythons: ImmutableList, grayedOut: Boolean = false, modifier: Modifier = Modifier) { + val ts = JewelTheme.defaultTextStyle + val longestPython = remember { pythons.maxBy { it.length } } + val padding = 100.dp + val width = measureText(longestPython, ts) + padding // Padding var i by remember { mutableIntStateOf(0) } - ListComboBox(pythons, i, { i = it }, modifier) + ListComboBox( + items = pythons, + selectedIndex = i, + modifier = modifier.widthIn(min = width, max = width + padding), + onSelectedItemChange = { i = it }, + itemKeys = { index, _ -> index }, + itemContent = { item, isSelected, isActive -> + SimpleListItem( + text = item, + selected = isSelected, + active = isActive, + icon = Python, + colorFilter = if (grayedOut) ColorFilter.tint(Color.Gray) else null, + ) + }, + ) } \ No newline at end of file diff --git a/python/python-sdk-configurator/frontend/src/components/tools.kt b/python/python-sdk-configurator/frontend/src/components/tools.kt new file mode 100644 index 000000000000..0a65e1c4fc5e --- /dev/null +++ b/python/python-sdk-configurator/frontend/src/components/tools.kt @@ -0,0 +1,15 @@ +package com.intellij.python.sdkConfigurator.frontend.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.unit.Dp + +@Composable +internal fun measureText(text: String, textStyle: TextStyle): Dp { + val textMeasurer = rememberTextMeasurer() + return with(LocalDensity.current) { + textMeasurer.measure(text, textStyle).size.width.toDp() + } +} \ No newline at end of file diff --git a/python/python-sdk-configurator/frontend/src/package-info.java b/python/python-sdk-configurator/frontend/src/package-info.java index 73502c3f5af2..19baa5e9a068 100644 --- a/python/python-sdk-configurator/frontend/src/package-info.java +++ b/python/python-sdk-configurator/frontend/src/package-info.java @@ -1,3 +1,6 @@ +/** + * Front-end implementation, do not access directly + */ @ApiStatus.Internal package com.intellij.python.sdkConfigurator.frontend; diff --git a/python/python-sdk-configurator/frontend/src/rpcBridge/FrontendTopicListener.kt b/python/python-sdk-configurator/frontend/src/rpcBridge/FrontendTopicListener.kt index 1c3746efe4d2..7bebcced34cc 100644 --- a/python/python-sdk-configurator/frontend/src/rpcBridge/FrontendTopicListener.kt +++ b/python/python-sdk-configurator/frontend/src/rpcBridge/FrontendTopicListener.kt @@ -9,6 +9,7 @@ import com.intellij.platform.rpc.topics.ProjectRemoteTopic import com.intellij.platform.rpc.topics.ProjectRemoteTopicListener import com.intellij.python.sdkConfigurator.common.impl.ModulesDTO import com.intellij.python.sdkConfigurator.common.impl.SHOW_SDK_CONFIG_UI_TOPIC +import com.intellij.python.sdkConfigurator.common.impl.SdkConfiguratorBackEndApi import com.intellij.python.sdkConfigurator.frontend.askUser import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -22,7 +23,7 @@ internal class FrontendTopicListener : ProjectRemoteTopicListener { // Ask user to choose modules, then ask backend to configure it askUser(project, event) { modulesChosenByUser -> scope.launch { - getBackendApi().configureSdkAutomatically(project.projectId(), modulesChosenByUser) + SdkConfiguratorBackEndApi().configureSdkAutomatically(project.projectId(), modulesChosenByUser) } } } diff --git a/python/python-sdk-configurator/frontend/src/rpcBridge/apiObtainer.kt b/python/python-sdk-configurator/frontend/src/rpcBridge/apiObtainer.kt deleted file mode 100644 index 491afe7a8e3a..000000000000 --- a/python/python-sdk-configurator/frontend/src/rpcBridge/apiObtainer.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.intellij.python.sdkConfigurator.frontend.rpcBridge - -import com.intellij.platform.rpc.RemoteApiProviderService -import com.intellij.python.sdkConfigurator.common.impl.SdkConfiguratorBackEndApi -import fleet.rpc.remoteApiDescriptor - - -internal suspend fun getBackendApi() = RemoteApiProviderService.resolve(remoteApiDescriptor()) - diff --git a/python/python-sdk-configurator/frontend/src/swingBridge.kt b/python/python-sdk-configurator/frontend/src/swingBridge.kt index dd2952f78fde..1dffc18e2ba9 100644 --- a/python/python-sdk-configurator/frontend/src/swingBridge.kt +++ b/python/python-sdk-configurator/frontend/src/swingBridge.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.python.sdkConfigurator.common.impl.ModuleName import com.intellij.python.sdkConfigurator.common.impl.ModulesDTO +import com.intellij.python.sdkConfigurator.frontend.PySdkConfiguratorFrontendBundle.message import com.intellij.python.sdkConfigurator.frontend.components.ModuleList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -28,7 +29,8 @@ internal suspend fun askUser(project: Project, modules: ModulesDTO, onResult: (S private class MyDialog(project: Project, private val viewModel: ModulesViewModel) : DialogWrapper(project) { init { - title = PySdkConfiguratorFrontendBundle.message("python.sdk.configurator.frontend.choose.modules.title") + title = message("python.sdk.configurator.frontend.choose.modules.title") + isResizable = false init() } @@ -36,7 +38,10 @@ private class MyDialog(project: Project, private val viewModel: ModulesViewModel override fun createCenterPanel(): JComponent { enableNewSwingCompositing() return compose(focusOnClickInside = true, content = { - ModuleList(viewModel.checkBoxItems, viewModel.checked, viewModel::clicked) + ModuleList(viewModel.checkBoxItems, viewModel.checked, viewModel::clicked, + topLabel = message("python.sdk.configurator.frontend.choose.modules.text"), + projectStructureLabel = message("python.sdk.configurator.frontend.choose.modules.project.structure"), + environmentLabel = message("python.sdk.configurator.frontend.choose.modules.environment")) }) } } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/inspections/PyInterpreterInspection.java b/python/src/com/jetbrains/python/inspections/PyInterpreterInspection.java index b0766eaaf1b5..38ad254f80e2 100644 --- a/python/src/com/jetbrains/python/inspections/PyInterpreterInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyInterpreterInspection.java @@ -58,7 +58,7 @@ import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static com.intellij.python.sdkConfigurator.common.PublicApiKt.detectSdkForModulesIn; +import static com.jetbrains.python.inspections.PyInterpreterInspectionExKt.detectSdkForModulesForJvmIn; import static com.jetbrains.python.inspections.PyInterpreterInspectionExKt.findAllSortedForModuleForJvm; @@ -343,7 +343,7 @@ public final class PyInterpreterInspection extends PyInspection { @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - if (!detectSdkForModulesIn(project)) { + if (!detectSdkForModulesForJvmIn(project)) { PyProjectSdkConfiguration.INSTANCE.configureSdkUsingCreateSdkInfo(myModule, myCreateSdkInfo); } } diff --git a/python/src/com/jetbrains/python/inspections/PyInterpreterInspectionEx.kt b/python/src/com/jetbrains/python/inspections/PyInterpreterInspectionEx.kt index 5c7b1ab208b9..b3bc445a5a82 100644 --- a/python/src/com/jetbrains/python/inspections/PyInterpreterInspectionEx.kt +++ b/python/src/com/jetbrains/python/inspections/PyInterpreterInspectionEx.kt @@ -1,13 +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.inspections +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service import com.intellij.openapi.module.Module import com.intellij.openapi.progress.runBlockingMaybeCancellable +import com.intellij.openapi.project.Project +import com.intellij.python.sdkConfigurator.common.detectSdkForModulesIn +import com.intellij.python.sdkConfigurator.common.enableSDKAutoConfigurator import com.intellij.util.concurrency.annotations.RequiresBackgroundThread import com.jetbrains.python.sdk.configuration.CreateSdkInfo import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import org.jetbrains.annotations.ApiStatus +/** + * To be used by [PyInterpreterInspection] only + */ +@ApiStatus.Internal +internal fun detectSdkForModulesForJvmIn(project: Project): Boolean { + if (!enableSDKAutoConfigurator) { + return false + } + project.service().scope.launch { + detectSdkForModulesIn(project) + } + return true +} + +@Service(Service.Level.PROJECT) +private class MyService(val scope: CoroutineScope) + /** * To be used by [PyInterpreterInspection] only */