mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-85634 Adapt PyInterpreterInspection to Kotlin style
GitOrigin-RevId: 0587f6995f91295de62a8046e8fb7baae1cf1a3d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9069551acf
commit
3221788f65
+10
-14
@@ -6,7 +6,6 @@ import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.ide.actions.ShowSettingsUtilImpl
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.options.ConfigurableGroup
|
||||
import com.intellij.openapi.options.ex.ConfigurableExtensionPointUtil
|
||||
import com.intellij.openapi.options.ex.ConfigurableVisitor
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -17,16 +16,12 @@ import com.intellij.util.PlatformUtils
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
|
||||
class InterpreterSettingsQuickFix(private val myModule: Module?) : LocalQuickFix {
|
||||
override fun getFamilyName(): String {
|
||||
return if (PlatformUtils.isPyCharm())
|
||||
PyPsiBundle.message("INSP.interpreter.interpreter.settings")
|
||||
else
|
||||
PyPsiBundle.message("INSP.interpreter.configure.python.interpreter")
|
||||
}
|
||||
override fun getFamilyName(): String = if (PlatformUtils.isPyCharm())
|
||||
PyPsiBundle.message("INSP.interpreter.interpreter.settings")
|
||||
else
|
||||
PyPsiBundle.message("INSP.interpreter.configure.python.interpreter")
|
||||
|
||||
override fun startInWriteAction(): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
showPythonInterpreterSettings(project, myModule)
|
||||
@@ -36,8 +31,8 @@ class InterpreterSettingsQuickFix(private val myModule: Module?) : LocalQuickFix
|
||||
fun showPythonInterpreterSettings(project: Project, module: Module?) {
|
||||
val id = "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
|
||||
val group = ConfigurableExtensionPointUtil.getConfigurableGroup(project, true)
|
||||
if (ConfigurableVisitor.findById(id, mutableListOf<ConfigurableGroup?>(group)) != null) {
|
||||
ShowSettingsUtilImpl.Companion.showSettingsDialog(project, id, null)
|
||||
if (ConfigurableVisitor.findById(id, listOf(group)) != null) {
|
||||
ShowSettingsUtilImpl.showSettingsDialog(project, id, null)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,8 +46,9 @@ class InterpreterSettingsQuickFix(private val myModule: Module?) : LocalQuickFix
|
||||
}
|
||||
|
||||
private fun justOneModuleInheritingSdk(project: Project, module: Module): Boolean {
|
||||
return ProjectRootManager.getInstance(project).getProjectSdk() == null &&
|
||||
ModuleRootManager.getInstance(module).isSdkInherited() && ModuleManager.Companion.getInstance(project).modules.size < 2
|
||||
return ProjectRootManager.getInstance(project).projectSdk == null &&
|
||||
ModuleRootManager.getInstance(module).isSdkInherited &&
|
||||
ModuleManager.getInstance(project).modules.size < 2
|
||||
}
|
||||
}
|
||||
}
|
||||
+176
-259
@@ -9,19 +9,20 @@ import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.util.InspectionMessage
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
|
||||
import com.intellij.openapi.util.Condition
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.python.sdkConfigurator.common.detectSdkForModulesIn
|
||||
import com.intellij.python.sdkConfigurator.common.enableSDKAutoConfigurator
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.toArray
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
import com.jetbrains.python.PythonIdeLanguageCustomization
|
||||
import com.jetbrains.python.inspections.PyInspection
|
||||
@@ -31,302 +32,218 @@ import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.psi.PyFile
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
import com.jetbrains.python.sdk.PyDetectedSdk
|
||||
import com.jetbrains.python.sdk.PySdkPopupFactory
|
||||
import com.jetbrains.python.sdk.PythonSdkType
|
||||
import com.jetbrains.python.sdk.*
|
||||
import com.jetbrains.python.sdk.conda.PyCondaSdkCustomizer
|
||||
import com.jetbrains.python.sdk.configuration.CreateSdkInfoWithTool
|
||||
import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration
|
||||
import com.jetbrains.python.sdk.detectSystemWideSdks
|
||||
import com.jetbrains.python.sdk.detectVirtualEnvs
|
||||
import com.jetbrains.python.sdk.filterAssociatedSdks
|
||||
import com.jetbrains.python.sdk.filterSharedCondaEnvs
|
||||
import com.jetbrains.python.sdk.filterSystemWideSdks
|
||||
import com.jetbrains.python.sdk.guessedLanguageLevel
|
||||
import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension
|
||||
import com.jetbrains.python.sdk.legacy.PythonSdkUtil
|
||||
import com.jetbrains.python.sdk.mostPreferred
|
||||
import com.jetbrains.python.sdk.setupSdkLaunch
|
||||
import com.jetbrains.python.ui.PyUiUtil
|
||||
import one.util.streamex.StreamEx
|
||||
import java.io.File
|
||||
import java.util.function.Function
|
||||
import java.util.regex.Matcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private val NAME: Pattern = Pattern.compile("Python (?<version>\\d\\.\\d+)\\s*(\\((?<name>.+?)\\))?")
|
||||
|
||||
class PyInterpreterInspection : PyInspection() {
|
||||
override fun buildVisitor(
|
||||
holder: ProblemsHolder,
|
||||
isOnTheFly: Boolean,
|
||||
session: LocalInspectionToolSession
|
||||
): PsiElementVisitor {
|
||||
return Visitor(holder, PyInspectionVisitor.getContext(session))
|
||||
}
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor =
|
||||
PyInterpreterInspectionVisitor(holder, PyInspectionVisitor.getContext(session))
|
||||
}
|
||||
|
||||
class Visitor(
|
||||
holder: ProblemsHolder?,
|
||||
context: TypeEvalContext
|
||||
) : PyInspectionVisitor(holder, context) {
|
||||
override fun visitPyFile(node: PyFile) {
|
||||
if (isFileIgnored(node)) return
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(node)
|
||||
val sdk = PyBuiltinCache.Companion.findSdkForFile(node)
|
||||
val pyCharm = PythonIdeLanguageCustomization.isMainlyPythonIde()
|
||||
class PyInterpreterInspectionVisitor(
|
||||
holder: ProblemsHolder?,
|
||||
context: TypeEvalContext,
|
||||
) : PyInspectionVisitor(holder, context) {
|
||||
|
||||
val fixes: MutableList<LocalQuickFix?> = ArrayList<LocalQuickFix?>()
|
||||
if (sdk == null) {
|
||||
val message: @InspectionMessage String
|
||||
if (pyCharm) {
|
||||
message = PyPsiBundle.message("INSP.interpreter.no.python.interpreter.configured.for.project")
|
||||
}
|
||||
else {
|
||||
message = PyPsiBundle.message("INSP.interpreter.no.python.interpreter.configured.for.module")
|
||||
}
|
||||
registerProblemWithCommonFixes(node, message, module, fixes, pyCharm)
|
||||
}
|
||||
}
|
||||
override fun visitPyFile(node: PyFile) {
|
||||
if (isFileIgnored(node)) return
|
||||
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(node)
|
||||
val sdk = PyBuiltinCache.findSdkForFile(node)
|
||||
val pyCharm = PythonIdeLanguageCustomization.isMainlyPythonIde()
|
||||
|
||||
private fun registerProblemWithCommonFixes(
|
||||
node: PyFile,
|
||||
@InspectionMessage message: @InspectionMessage String,
|
||||
module: Module?,
|
||||
fixes: MutableList<LocalQuickFix?>,
|
||||
pyCharm: Boolean
|
||||
) {
|
||||
if (module != null && pyCharm) {
|
||||
val sdkName = ProjectRootManager.getInstance(node.getProject()).getProjectSdkName()
|
||||
ContainerUtil.addIfNotNull<LocalQuickFix?>(fixes, getSuitableSdkFix(sdkName, module))
|
||||
}
|
||||
if (module != null && pyCharm) {
|
||||
fixes.add(ConfigureInterpreterFix())
|
||||
if (sdk == null) {
|
||||
val message = if (pyCharm) {
|
||||
PyPsiBundle.message("INSP.interpreter.no.python.interpreter.configured.for.project")
|
||||
}
|
||||
else {
|
||||
fixes.add(InterpreterSettingsQuickFix(module))
|
||||
PyPsiBundle.message("INSP.interpreter.no.python.interpreter.configured.for.module")
|
||||
}
|
||||
registerProblemWithCommonFixes(node, message, module, pyCharm)
|
||||
}
|
||||
}
|
||||
|
||||
registerProblem(node, message, *fixes.toArray<LocalQuickFix?>(LocalQuickFix.EMPTY_ARRAY))
|
||||
private fun registerProblemWithCommonFixes(node: PyFile, @InspectionMessage message: String, module: Module?, pyCharm: Boolean) {
|
||||
val fixes = buildList {
|
||||
if (module != null && pyCharm) {
|
||||
val sdkName = ProjectRootManager.getInstance(node.project).projectSdkName
|
||||
getSuitableSdkFix(sdkName, module)?.let { add(it) }
|
||||
add(ConfigureInterpreterFix())
|
||||
}
|
||||
else {
|
||||
add(InterpreterSettingsQuickFix(module))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun getSuitableSdkFix(name: String?, module: Module): LocalQuickFix? {
|
||||
// this method is based on com.jetbrains.python.sdk.PySdkExtKt.suggestAssociatedSdkName
|
||||
// please keep it in sync with the mentioned method and com.jetbrains.python.PythonSdkConfigurator.configureSdk
|
||||
registerProblem(node, message, *fixes.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
val existingSdks: List<Sdk> = existingSdks
|
||||
private fun getSuitableSdkFix(name: String?, module: Module): LocalQuickFix? {
|
||||
// this method is based on com.jetbrains.python.sdk.PySdkExtKt.suggestAssociatedSdkName
|
||||
// please keep it in sync with the mentioned method and com.jetbrains.python.PythonSdkConfigurator.configureSdk
|
||||
|
||||
val associatedSdk = mostPreferred(filterAssociatedSdks(module, existingSdks))
|
||||
if (associatedSdk != null) return UseExistingInterpreterFix(associatedSdk, module)
|
||||
val existingSdks = getExistingSdks()
|
||||
|
||||
val context = UserDataHolderBase()
|
||||
val associatedSdk = mostPreferred(filterAssociatedSdks(module, existingSdks))
|
||||
if (associatedSdk != null) return UseExistingInterpreterFix(associatedSdk, module)
|
||||
|
||||
val createSdkInfos: List<CreateSdkInfoWithTool> = findAllSortedForModuleForJvm(module)
|
||||
if (!createSdkInfos.isEmpty()) {
|
||||
return UseProvidedInterpreterFix(module, createSdkInfos.first())
|
||||
val context = UserDataHolderBase()
|
||||
val createSdkInfo = runBlockingMaybeCancellable {
|
||||
PyProjectSdkConfigurationExtension.findAllSortedForModule(module).firstOrNull()
|
||||
}
|
||||
if (createSdkInfo != null) return UseProvidedInterpreterFix(module, createSdkInfo)
|
||||
|
||||
if (name != null) {
|
||||
val matcher = NAME.matcher(name)
|
||||
if (matcher.matches()) {
|
||||
val venvName = matcher.group("name")
|
||||
if (venvName != null) {
|
||||
val detectedAssociatedViaRootNameEnv = detectAssociatedViaRootNameEnv(venvName, module, existingSdks, context)
|
||||
if (detectedAssociatedViaRootNameEnv != null) {
|
||||
return UseDetectedInterpreterFix(detectedAssociatedViaRootNameEnv, existingSdks, true, module)
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
val matcher: Matcher = NAME.matcher(name)
|
||||
if (matcher.matches()) {
|
||||
val venvName = matcher.group("name")
|
||||
if (venvName != null) {
|
||||
val detectedAssociatedViaRootNameEnv: PyDetectedSdk? = detectAssociatedViaRootNameEnv(venvName, module, existingSdks, context)
|
||||
if (detectedAssociatedViaRootNameEnv != null) {
|
||||
return UseDetectedInterpreterFix(detectedAssociatedViaRootNameEnv, existingSdks, true, module)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val detectedSystemWideSdk: PyDetectedSdk? = detectSystemWideSdk(matcher.group("version"), module, existingSdks, context)
|
||||
if (detectedSystemWideSdk != null) {
|
||||
return UseDetectedInterpreterFix(detectedSystemWideSdk, existingSdks, false, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PyCondaSdkCustomizer.Companion.instance.suggestSharedCondaEnvironments) {
|
||||
val sharedCondaEnv = mostPreferred(filterSharedCondaEnvs(module, existingSdks))
|
||||
if (sharedCondaEnv != null) {
|
||||
return UseExistingInterpreterFix(sharedCondaEnv, module)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: We should use SystemPythonService here as well, postponing as it's quite unlikely we get here (although we can)
|
||||
val systemWideSdk = mostPreferred(filterSystemWideSdks(existingSdks))
|
||||
if (systemWideSdk != null) {
|
||||
return UseExistingInterpreterFix(systemWideSdk, module)
|
||||
}
|
||||
|
||||
val configurator = PyCondaSdkCustomizer.Companion.instance.fallbackConfigurator
|
||||
if (configurator != null) {
|
||||
val fallbackCreateSdkInfo =
|
||||
PyCondaSdkCustomizer.Companion.checkEnvironmentAndPrepareSdkCreatorBlocking(configurator, module)
|
||||
if (fallbackCreateSdkInfo != null) {
|
||||
return UseProvidedInterpreterFix(module, fallbackCreateSdkInfo)
|
||||
}
|
||||
}
|
||||
|
||||
val detectedSystemWideSdk = ContainerUtil.getFirstItem<PyDetectedSdk>(detectSystemWideSdks(module, existingSdks))
|
||||
}
|
||||
else {
|
||||
val detectedSystemWideSdk = detectSystemWideSdk(matcher.group("version"), module, existingSdks, context)
|
||||
if (detectedSystemWideSdk != null) {
|
||||
return UseDetectedInterpreterFix(detectedSystemWideSdk, existingSdks, false, module)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private val existingSdks: List<Sdk>
|
||||
get() {
|
||||
val model = ProjectSdksModel()
|
||||
model.reset(null)
|
||||
return ContainerUtil.filter(model.getSdks(),
|
||||
Condition { it.getSdkType() is PythonSdkType })
|
||||
}
|
||||
|
||||
private fun detectAssociatedViaRootNameEnv(
|
||||
associatedName: String,
|
||||
module: Module,
|
||||
existingSdks: List<Sdk>,
|
||||
context: UserDataHolderBase
|
||||
): PyDetectedSdk? {
|
||||
return Companion.findAssociatedViaRootNameEnv(
|
||||
associatedName,
|
||||
detectVirtualEnvs(module, existingSdks, context),
|
||||
Function { sdk: PyDetectedSdk? -> getVirtualEnvRootName(sdk!!) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun detectSystemWideSdk(
|
||||
version: String,
|
||||
module: Module,
|
||||
existingSdks: List<Sdk>,
|
||||
context: UserDataHolderBase
|
||||
): PyDetectedSdk? {
|
||||
val parsedVersion: LanguageLevel = LanguageLevel.fromPythonVersion(version)!!
|
||||
|
||||
if (parsedVersion.toString() == version) {
|
||||
return ContainerUtil.find<PyDetectedSdk>(
|
||||
detectSystemWideSdks(module, existingSdks, context),
|
||||
Condition { sdk: PyDetectedSdk -> sdk.guessedLanguageLevel == parsedVersion }
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun findAssociatedViaRootNameEnv(
|
||||
associatedName: String,
|
||||
envs: List<PyDetectedSdk>,
|
||||
envRootName: Function<PyDetectedSdk?, String?>
|
||||
): PyDetectedSdk? {
|
||||
return StreamEx
|
||||
.of(envs)
|
||||
.filter { sdk: PyDetectedSdk -> associatedName == envRootName.apply(sdk) }
|
||||
.max(compareBy<PyDetectedSdk> { it.guessedLanguageLevel }.thenBy { it.homePath })
|
||||
.orElse(null)
|
||||
}
|
||||
|
||||
private fun getVirtualEnvRootName(sdk: PyDetectedSdk): String? {
|
||||
val path = sdk.getHomePath()
|
||||
return if (path == null) null else getEnvRootName(PythonSdkUtil.getVirtualEnvRoot(path))
|
||||
}
|
||||
|
||||
private fun getEnvRootName(envRoot: File?): String? {
|
||||
return if (envRoot == null) null else PathUtil.getFileName(envRoot.getPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigureInterpreterFix : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return PyPsiBundle.message("INSP.interpreter.configure.python.interpreter")
|
||||
if (PyCondaSdkCustomizer.instance.suggestSharedCondaEnvironments) {
|
||||
val sharedCondaEnv = mostPreferred(filterSharedCondaEnvs(module, existingSdks))
|
||||
if (sharedCondaEnv != null) return UseExistingInterpreterFix(sharedCondaEnv, module)
|
||||
}
|
||||
|
||||
// TODO: We should use SystemPythonService here as well, postponing as it's quite unlikely we get here (although we can)
|
||||
val systemWideSdk = mostPreferred(filterSystemWideSdks(existingSdks))
|
||||
if (systemWideSdk != null) return UseExistingInterpreterFix(systemWideSdk, module)
|
||||
|
||||
val configurator = PyCondaSdkCustomizer.instance.fallbackConfigurator
|
||||
if (configurator != null) {
|
||||
val fallbackCreateSdkInfo = PyCondaSdkCustomizer.checkEnvironmentAndPrepareSdkCreatorBlocking(configurator, module)
|
||||
if (fallbackCreateSdkInfo != null) return UseProvidedInterpreterFix(module, fallbackCreateSdkInfo)
|
||||
}
|
||||
|
||||
val detectedSystemWideSdk = detectSystemWideSdks(module, existingSdks).firstOrNull()
|
||||
if (detectedSystemWideSdk != null) return UseDetectedInterpreterFix(detectedSystemWideSdk, existingSdks, false, module)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getExistingSdks(): List<Sdk> {
|
||||
val model = ProjectSdksModel()
|
||||
model.reset(null)
|
||||
return model.sdks.filter { it.sdkType is PythonSdkType }
|
||||
}
|
||||
|
||||
private fun detectAssociatedViaRootNameEnv(
|
||||
associatedName: String, module: Module, existingSdks: List<Sdk>, context: UserDataHolderBase,
|
||||
): PyDetectedSdk? = findAssociatedViaRootNameEnv(associatedName, detectVirtualEnvs(module, existingSdks, context))
|
||||
|
||||
private fun detectSystemWideSdk(version: String, module: Module, existingSdks: List<Sdk>, context: UserDataHolderBase): PyDetectedSdk? {
|
||||
val parsedVersion = LanguageLevel.fromPythonVersion(version)!!
|
||||
|
||||
return if (parsedVersion.toString() == version) {
|
||||
detectSystemWideSdks(module, existingSdks, context).firstOrNull { it.guessedLanguageLevel == parsedVersion }
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
private fun findAssociatedViaRootNameEnv(associatedName: String, envs: List<PyDetectedSdk>): PyDetectedSdk? =
|
||||
envs.filter { associatedName == getVirtualEnvRootName(it) }
|
||||
.maxWithOrNull(compareBy<PyDetectedSdk> { it.guessedLanguageLevel }.thenBy { it.homePath })
|
||||
|
||||
private fun getVirtualEnvRootName(sdk: PyDetectedSdk): String? {
|
||||
val file = sdk.homePath?.let { PythonSdkUtil.getVirtualEnvRoot(it) } ?: return null
|
||||
return PathUtil.getFileName(file.path)
|
||||
}
|
||||
|
||||
private fun isFileIgnored(pyFile: PyFile): Boolean =
|
||||
PyInspectionExtension.EP_NAME.extensionList.any { it.ignoreInterpreterWarnings(pyFile) }
|
||||
|
||||
|
||||
class ConfigureInterpreterFix : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): String = PyPsiBundle.message("INSP.interpreter.configure.python.interpreter")
|
||||
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val element = descriptor.psiElement ?: return
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return
|
||||
PySdkPopupFactory.createAndShow(module)
|
||||
}
|
||||
}
|
||||
|
||||
private class UseProvidedInterpreterFix(private val myModule: Module, private val myCreateSdkInfo: CreateSdkInfoWithTool) : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): String = PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter")
|
||||
|
||||
@IntentionName
|
||||
override fun getName(): String = myCreateSdkInfo.createSdkInfo.intentionName
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
if (!enableSDKAutoConfigurator) {
|
||||
return PyProjectSdkConfiguration.configureSdkUsingCreateSdkInfo(myModule, myCreateSdkInfo)
|
||||
}
|
||||
|
||||
override fun startInWriteAction(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val element = descriptor.getPsiElement()
|
||||
if (element == null) return
|
||||
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element)
|
||||
if (module == null) return
|
||||
|
||||
PySdkPopupFactory.Companion.createAndShow(module)
|
||||
project.service<MyService>().scope.launch {
|
||||
detectSdkForModulesIn(project)
|
||||
}
|
||||
}
|
||||
|
||||
private class UseProvidedInterpreterFix(
|
||||
private val myModule: Module,
|
||||
private val myCreateSdkInfo: CreateSdkInfoWithTool
|
||||
) : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter")
|
||||
}
|
||||
override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo {
|
||||
// The quick fix doesn't change the code and is suggested on a file level
|
||||
return IntentionPreviewInfo.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
@IntentionName
|
||||
override fun getName(): @IntentionName String {
|
||||
return myCreateSdkInfo.createSdkInfo.intentionName
|
||||
}
|
||||
private abstract class UseInterpreterFix<T : Sdk>(protected val mySdk: T) : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): String = PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter")
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
if (!detectSdkForModulesForJvmIn(project)) {
|
||||
PyProjectSdkConfiguration.configureSdkUsingCreateSdkInfo(myModule, myCreateSdkInfo)
|
||||
}
|
||||
}
|
||||
@IntentionName
|
||||
override fun getName(): String = PyPsiBundle.message("INSP.interpreter.use.interpreter", PySdkPopupFactory.shortenNameInPopup(mySdk, 75))
|
||||
|
||||
override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo {
|
||||
// The quick fix doesn't change the code and is suggested on a file level
|
||||
return IntentionPreviewInfo.EMPTY
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
}
|
||||
|
||||
private class UseExistingInterpreterFix(existingSdk: Sdk, private val myModule: Module) : UseInterpreterFix<Sdk>(existingSdk) {
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
PyUiUtil.clearFileLevelInspectionResults(descriptor.psiElement.containingFile)
|
||||
project.service<MyService>().scope.launch {
|
||||
PyProjectSdkConfiguration.setReadyToUseSdk(project, myModule, mySdk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class UseInterpreterFix<T : Sdk> protected constructor(protected val mySdk: T) : LocalQuickFix {
|
||||
@IntentionFamilyName
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter")
|
||||
}
|
||||
|
||||
@IntentionName
|
||||
override fun getName(): @IntentionName String {
|
||||
return PyPsiBundle.message("INSP.interpreter.use.interpreter", PySdkPopupFactory.Companion.shortenNameInPopup(mySdk!!, 75))
|
||||
}
|
||||
|
||||
override fun startInWriteAction(): Boolean {
|
||||
return false
|
||||
private class UseDetectedInterpreterFix(
|
||||
detectedSdk: PyDetectedSdk,
|
||||
private val myExistingSdks: List<Sdk>,
|
||||
private val doAssociate: Boolean,
|
||||
private val myModule: Module,
|
||||
) : UseInterpreterFix<PyDetectedSdk>(detectedSdk) {
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
PyUiUtil.clearFileLevelInspectionResults(descriptor.psiElement.containingFile)
|
||||
project.service<MyService>().scope.launch {
|
||||
mySdk.setupSdk(myModule, myExistingSdks, doAssociate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UseExistingInterpreterFix(existingSdk: Sdk, private val myModule: Module) : UseInterpreterFix<Sdk>(existingSdk) {
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
PyUiUtil.clearFileLevelInspectionResults(descriptor.getPsiElement().getContainingFile())
|
||||
ApplicationManager.getApplication().executeOnPooledThread(
|
||||
Runnable {
|
||||
PyProjectSdkConfiguration.setReadyToUseSdkSync(project, myModule, mySdk)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private class UseDetectedInterpreterFix(
|
||||
detectedSdk: PyDetectedSdk,
|
||||
private val myExistingSdks: List<Sdk>,
|
||||
private val doAssociate: Boolean,
|
||||
private val myModule: Module
|
||||
) : UseInterpreterFix<PyDetectedSdk>(detectedSdk) {
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
PyUiUtil.clearFileLevelInspectionResults(descriptor.getPsiElement().getContainingFile())
|
||||
mySdk.setupSdkLaunch(myModule, myExistingSdks, doAssociate)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val NAME: Pattern = Pattern.compile("Python (?<version>\\d\\.\\d+)\\s*(\\((?<name>.+?)\\))?")
|
||||
|
||||
private fun isFileIgnored(pyFile: PyFile): Boolean {
|
||||
return PyInspectionExtension.EP_NAME.extensionList.stream().anyMatch { ep: PyInspectionExtension? ->
|
||||
ep!!.ignoreInterpreterWarnings(pyFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Service(Service.Level.PROJECT)
|
||||
private class MyService(val scope: CoroutineScope)
|
||||
@@ -1,42 +0,0 @@
|
||||
// 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.interpreter
|
||||
|
||||
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.CreateSdkInfoWithTool
|
||||
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<MyService>().scope.launch {
|
||||
detectSdkForModulesIn(project)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
private class MyService(val scope: CoroutineScope)
|
||||
|
||||
/**
|
||||
* To be used by [PyInterpreterInspection] only
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@RequiresBackgroundThread
|
||||
internal fun findAllSortedForModuleForJvm(module: Module): List<CreateSdkInfoWithTool> = runBlockingMaybeCancellable {
|
||||
PyProjectSdkConfigurationExtension.findAllSortedForModule(module)
|
||||
}
|
||||
Reference in New Issue
Block a user