mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
There was a problem with detecting system-wide pythons, which relied on binary not being a part of conda env or virtualenv. But it led to unrelated Hatch and Poetry pythons automatically configured as interpreters in new projects. Another problem is that free-threaded python was chosen as default interpreter with highest priority because of the newest version. This change uses SystemPythonService to detect system pythons properly, also free-threaded python used as a default interpreter only if it's the only available option. Merge-request: IJ-MR-179008 Merged-by: Alexey Katsman <alexey.katsman@jetbrains.com> GitOrigin-RevId: 73bc98aed2918c44832b57f22b86c9c7d17a4301
67 lines
3.6 KiB
Kotlin
67 lines
3.6 KiB
Kotlin
// 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.python.community.execService.python.impl
|
|
|
|
import com.intellij.openapi.diagnostic.fileLogger
|
|
import com.intellij.openapi.util.NlsSafe
|
|
import com.intellij.platform.eel.provider.utils.EelProcessExecutionResult
|
|
import com.intellij.platform.eel.provider.utils.stderrString
|
|
import com.intellij.platform.eel.provider.utils.stdoutString
|
|
import com.intellij.python.community.execService.*
|
|
import com.intellij.python.community.execService.impl.transformerToHandler
|
|
import com.intellij.python.community.execService.python.advancedApi.ExecutablePython
|
|
import com.intellij.python.community.execService.python.advancedApi.executePythonAdvanced
|
|
import com.intellij.python.community.execService.python.impl.PyExecPythonBundle.message
|
|
import com.jetbrains.python.PYTHON_VERSION_ARG
|
|
import com.jetbrains.python.PythonInfo
|
|
import com.jetbrains.python.Result
|
|
import com.jetbrains.python.errorProcessing.PyResult
|
|
import com.jetbrains.python.errorProcessing.getOr
|
|
import com.jetbrains.python.onFailure
|
|
import com.jetbrains.python.psi.LanguageLevel
|
|
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor.getLanguageLevelFromVersionStringStaticSafe
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.withContext
|
|
import org.jetbrains.annotations.ApiStatus
|
|
import kotlin.io.path.pathString
|
|
import kotlin.time.Duration.Companion.minutes
|
|
|
|
@ApiStatus.Internal
|
|
internal suspend fun ExecService.validatePythonAndGetInfoImpl(python: ExecutablePython): PyResult<PythonInfo> = withContext(Dispatchers.IO) {
|
|
val options = ExecOptions(timeout = 1.minutes)
|
|
|
|
val smokeTestOutput = executePythonAdvanced(python, Args("-c", "print(1)"), processInteractiveHandler = transformerToHandler(null, ZeroCodeStdoutTransformer), options = options).getOr(message("python.cannot.exec", python.userReadableName)) { return@withContext it }.trim()
|
|
if (smokeTestOutput != "1") {
|
|
return@withContext PyResult.localizedError(message("python.get.version.error", python.userReadableName, smokeTestOutput))
|
|
}
|
|
|
|
val versionOutput: EelProcessExecutionResult = executePythonAdvanced(python, options = options, args = Args(PYTHON_VERSION_ARG), processInteractiveHandler = transformerToHandler<EelProcessExecutionResult>(null) { r ->
|
|
if (r.exitCode == 0) Result.success(r) else Result.failure(message("python.get.version.error", python.userReadableName, r.exitCode))
|
|
}).getOr { return@withContext it }
|
|
// Python 2 might return version as stderr, see https://bugs.python.org/issue18338
|
|
val versionString = versionOutput.stdoutString.let { it.ifBlank { versionOutput.stderrString } }
|
|
val languageLevel = getLanguageLevelFromVersionStringStaticSafe(versionString.trim())
|
|
if (languageLevel == null) {
|
|
return@withContext PyResult.localizedError(message("python.get.version.wrong.version", python.userReadableName, versionString))
|
|
}
|
|
|
|
val freeThreaded = if (languageLevel.isAtLeast(LanguageLevel.PYTHON313)) {
|
|
val gilEnabledOutput = executePythonAdvanced(
|
|
python,
|
|
Args("-c", "import sys; print(sys._is_gil_enabled())"),
|
|
processInteractiveHandler = transformerToHandler(null, ZeroCodeStdoutTransformer),
|
|
options = options
|
|
).onFailure { fileLogger().warn(it.toString()) }.successOrNull?.trim()
|
|
gilEnabledOutput == "False"
|
|
}
|
|
else false
|
|
|
|
return@withContext Result.success(PythonInfo(languageLevel, freeThreaded))
|
|
}
|
|
|
|
private val ExecutablePython.userReadableName: @NlsSafe String
|
|
get() =
|
|
(listOf(when (binary) {
|
|
is BinOnEel -> binary.path.pathString
|
|
is BinOnTarget -> binary
|
|
}) + args).joinToString(" ")
|