Files
openide/python/testSrc/com/jetbrains/TestTargetTools.kt
Ilya.Kazakevich 2e14347844 Python: extract python-specific extensions from exec service to simplify API and make it extendable for intepreters.
Use `ExecService` `api.kt` to exec any binary and extensions from `execService.python/api.kt` for python-specific things (i.e helpers)

GitOrigin-RevId: bb217798a9d1ee886c4b12220ec1f66a5ef08336
2025-06-07 22:05:56 +00:00

74 lines
3.2 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.jetbrains
import com.intellij.execution.processTools.getBareExecutionResult
import com.intellij.execution.processTools.getResultStdoutStr
import com.intellij.execution.processTools.mapFlat
import com.intellij.execution.target.*
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.util.concurrency.ThreadingAssertions
import com.jetbrains.python.PYTHON_VERSION_ARG
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
import com.jetbrains.python.sdk.configureBuilderToRunPythonOnTarget
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.sdk.getOrCreateAdditionalData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.junit.Assert
internal suspend fun getPythonVersion(sdk: Sdk, request: TargetEnvironmentRequest): String? {
val commandLineBuilder = TargetedCommandLineBuilder(request)
sdk.configureBuilderToRunPythonOnTarget(commandLineBuilder)
val flavor = sdk.getOrCreateAdditionalData().flavor
return getPythonVersion(commandLineBuilder, flavor, request)
}
internal suspend fun getPythonVersion(commandLineBuilder: TargetedCommandLineBuilder,
flavor: PythonSdkFlavor<*>,
request: TargetEnvironmentRequest): String? {
commandLineBuilder.addParameter(PYTHON_VERSION_ARG)
val commandLine = commandLineBuilder.build()
val result = request
.prepareEnvironment(TargetProgressIndicator.EMPTY)
.createProcess(commandLine).getBareExecutionResult()
// Conda python may send version to stderr, check both
val err = result.stdErr.decodeToString()
val out = result.stdOut.decodeToString()
Assert.assertEquals(err, 0, result.exitCode)
val versionString = out.ifBlank { err }.trim()
return PythonSdkFlavor.getVersionStringFromOutput(versionString)
}
/**
* @return path to python binary on target
*/
suspend fun Sdk.getPythonBinaryPath(project: Project): Result<FullPathOnTarget> {
return getCommandOutput(project, EmptyProgressIndicator(), "import sys; print(sys.executable)").map { it.trim() }
}
/**
* Runs python [command] and returns stdout or error
*/
private suspend fun Sdk.getCommandOutput(project: Project, indicator: ProgressIndicator, command: String): Result<String> {
ThreadingAssertions.assertBackgroundThread()
val pyRequest = PythonInterpreterTargetEnvironmentFactory.findPythonTargetInterpreter(sdk = this, project)
val targetEnvRequest = pyRequest.targetEnvironmentRequest
val cmdBuilder = TargetedCommandLineBuilder(targetEnvRequest)
configureBuilderToRunPythonOnTarget(cmdBuilder)
cmdBuilder.addParameter("-c")
cmdBuilder.addParameter(command)
val cmd = cmdBuilder.build()
val environment = targetEnvRequest.prepareEnvironment(TargetProgressIndicatorAdapter(indicator))
return withContext(Dispatchers.IO) {
environment.createProcessWithResult(cmd).mapFlat { it.getResultStdoutStr() }
}
}