diff --git a/python/pluginResources/intellij.python.community.impl.xml b/python/pluginResources/intellij.python.community.impl.xml
index 864350b4ff30..d8df1637eecc 100644
--- a/python/pluginResources/intellij.python.community.impl.xml
+++ b/python/pluginResources/intellij.python.community.impl.xml
@@ -572,10 +572,6 @@
-
-
diff --git a/python/python-exec-service/src/com/intellij/python/community/execService/api.kt b/python/python-exec-service/src/com/intellij/python/community/execService/api.kt
index a7ade91de516..83c286dc479f 100644
--- a/python/python-exec-service/src/com/intellij/python/community/execService/api.kt
+++ b/python/python-exec-service/src/com/intellij/python/community/execService/api.kt
@@ -185,7 +185,7 @@ open class ZeroCodeStdoutParserTransformer(val stdoutParser: (String) -> Resu
* @property[env] Environment variables to be applied with the process run
* @property[timeout] Process gets killed after this timeout
* @property[processDescription] optional description to be displayed to user
- * [tty] Much like [com.intellij.platform.eel.EelExecApi.Pty]
+ * @property[tty] Much like [com.intellij.platform.eel.EelExecApi.Pty]
*/
data class ExecOptions(
override val env: Map = emptyMap(),
diff --git a/python/src/com/jetbrains/python/PythonHelper.java b/python/src/com/jetbrains/python/PythonHelper.java
index 8922a1dab412..781b8218a80a 100644
--- a/python/src/com/jetbrains/python/PythonHelper.java
+++ b/python/src/com/jetbrains/python/PythonHelper.java
@@ -22,13 +22,14 @@ import java.util.stream.Collectors;
import static com.intellij.python.community.helpersLocator.PythonHelpersLocator.*;
import static com.intellij.python.community.impl.venv.VenvKt.LEGACY_VIRTUALENV_ZIPAPP_NAME;
import static com.intellij.python.community.impl.venv.VenvKt.VIRTUALENV_ZIPAPP_NAME;
+import static com.jetbrains.python.packaging.pip.PipPackageManagerEngine.PACKAGING_TOOL_NAME;
public enum PythonHelper implements HelperPackage {
GENERATOR3("generator3/__main__.py"),
REMOTE_SYNC("remote_sync.py"),
// Packaging tools
- PACKAGING_TOOL("packaging_tool.py"),
+ PACKAGING_TOOL(PACKAGING_TOOL_NAME),
VIRTUALENV_ZIPAPP(VIRTUALENV_ZIPAPP_NAME),
LEGACY_VIRTUALENV_ZIPAPP(LEGACY_VIRTUALENV_ZIPAPP_NAME), // virtualenv used to create virtual environments for python 2.7, 3.6, 3.7
diff --git a/python/src/com/jetbrains/python/packaging/management/PyPackageProcessHandler.kt b/python/src/com/jetbrains/python/packaging/management/PyPackageProcessHandler.kt
deleted file mode 100644
index e71ed23b3273..000000000000
--- a/python/src/com/jetbrains/python/packaging/management/PyPackageProcessHandler.kt
+++ /dev/null
@@ -1,41 +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.packaging.management
-
-import com.intellij.execution.process.CapturingAnsiEscapesAwareProcessHandler
-import com.intellij.execution.process.CapturingProcessAdapter
-import com.intellij.execution.process.ProcessOutput
-import com.intellij.execution.process.ProcessOutputTypes
-import com.intellij.openapi.util.Key
-
-internal class PyPackageProcessHandler : CapturingAnsiEscapesAwareProcessHandler {
- constructor(process: Process, commandLine: String) : super(process, commandLine)
-
- var lastLine: String = ""
- private set
-
- var lastLineNotifier: ((String) -> Unit)? = null
-
- override fun createProcessAdapter(processOutput: ProcessOutput): CapturingProcessAdapter? {
- return PackageProcessAdapter(processOutput)
- }
-
- private inner class PackageProcessAdapter(processOutput: ProcessOutput) : AnsiEscapesAwareAdapter(processOutput) {
- override fun addToOutput(text: String, outputType: Key<*>) {
- super.addToOutput(text, outputType)
-
- when {
- outputType === ProcessOutputTypes.STDOUT -> {
- lastLine = output.stdoutLines.lastOrNull { it.isNotBlank() } ?: ""
-
- }
- outputType === ProcessOutputTypes.STDERR -> {
- lastLine = output.stderrLines.lastOrNull { it.isNotBlank() } ?: ""
- }
- }
- lastLine = lastLine.trim()
- if (lastLine.isBlank())
- return
- lastLineNotifier?.invoke(lastLine)
- }
- }
-}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/packaging/management/PythonPackageManagerRunner.kt b/python/src/com/jetbrains/python/packaging/management/PythonPackageManagerRunner.kt
deleted file mode 100644
index 7d2fbfc25ba6..000000000000
--- a/python/src/com/jetbrains/python/packaging/management/PythonPackageManagerRunner.kt
+++ /dev/null
@@ -1,32 +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.packaging.management
-
-import com.intellij.execution.process.ProcessOutput
-import com.intellij.openapi.progress.ProgressManager
-import com.intellij.openapi.progress.coroutineToIndicator
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import org.jetbrains.annotations.ApiStatus
-
-@ApiStatus.Internal
-internal object PythonPackageManagerRunner {
- suspend fun runProcess(
- process: Process,
- command: String,
- ): ProcessOutput {
- val handler = PyPackageProcessHandler(process, command)
-
- return runProcessInternal(handler)
- }
-
- private suspend fun runProcessInternal(processHandler: PyPackageProcessHandler): ProcessOutput = withContext(Dispatchers.IO) {
- coroutineToIndicator {
- val progressIndicator = ProgressManager.getInstance().progressIndicator
- processHandler.lastLineNotifier = { line: String ->
- @Suppress("HardCodedStringLiteral")
- progressIndicator.text = line.trim()
- }
- processHandler.runProcessWithProgressIndicator(progressIndicator, 10 * 60 * 1000)
- }
- }
-}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/packaging/pip/PipPackageManagerEngine.kt b/python/src/com/jetbrains/python/packaging/pip/PipPackageManagerEngine.kt
index d8037104edd6..491223643578 100644
--- a/python/src/com/jetbrains/python/packaging/pip/PipPackageManagerEngine.kt
+++ b/python/src/com/jetbrains/python/packaging/pip/PipPackageManagerEngine.kt
@@ -1,23 +1,14 @@
// 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.packaging.pip
-import com.intellij.execution.target.TargetProgressIndicator
-import com.intellij.execution.target.local.LocalTargetEnvironmentRequest
-import com.intellij.execution.target.value.targetPath
import com.intellij.openapi.diagnostic.thisLogger
-import com.intellij.openapi.progress.EmptyProgressIndicator
-import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.projectRoots.Sdk
-import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.util.io.IdeUtilIoBundle
-import com.jetbrains.python.sdk.impl.PySdkBundle
-import com.jetbrains.python.PythonHelper
+import com.intellij.python.community.execService.ExecService
+import com.intellij.python.community.execService.python.HelperName
import com.jetbrains.python.errorProcessing.PyResult
import com.jetbrains.python.onFailure
-import com.jetbrains.python.packaging.PyExecutionException
import com.jetbrains.python.packaging.PyPIPackageUtil
import com.jetbrains.python.packaging.common.PythonOutdatedPackage
import com.jetbrains.python.packaging.common.PythonPackage
@@ -25,16 +16,11 @@ import com.jetbrains.python.packaging.common.PythonRepositoryPackageSpecificatio
import com.jetbrains.python.packaging.management.PythonPackageInstallRequest
import com.jetbrains.python.packaging.management.PythonPackageManager
import com.jetbrains.python.packaging.management.PythonPackageManagerEngine
-import com.jetbrains.python.packaging.management.PythonPackageManagerRunner
import com.jetbrains.python.packaging.utils.PyProxyUtils
-import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
-import com.jetbrains.python.run.buildTargetedCommandLine
-import com.jetbrains.python.run.ensureProjectSdkAndModuleDirsAreOnTarget
-import com.jetbrains.python.run.prepareHelperScriptExecution
+import com.jetbrains.python.sdk.executeHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.ApiStatus
-import kotlin.math.min
@ApiStatus.Internal
@@ -95,91 +81,22 @@ class PipPackageManagerEngine(
return PyResult.success(packages)
}
- @ApiStatus.Internal
suspend fun runPackagingTool(operation: String, arguments: List): PyResult = withContext(Dispatchers.IO) {
- // todo[akniazev]: check for package management tools
- val helpersAwareTargetRequest = PythonInterpreterTargetEnvironmentFactory.findPythonTargetInterpreter(sdk, project)
- val targetEnvironmentRequest = helpersAwareTargetRequest.targetEnvironmentRequest
- val pythonExecution = prepareHelperScriptExecution(PythonHelper.PACKAGING_TOOL, helpersAwareTargetRequest)
-
- if (targetEnvironmentRequest is LocalTargetEnvironmentRequest) {
- if (Registry.`is`("python.packaging.tool.use.project.location.as.working.dir")) {
- project.guessProjectDir()?.toNioPath()?.let {
- pythonExecution.workingDir = targetPath(it)
- }
- }
- }
- else {
- if (Registry.`is`("python.packaging.tool.upload.project")) {
- project.guessProjectDir()?.toNioPath()?.let {
- targetEnvironmentRequest.ensureProjectSdkAndModuleDirsAreOnTarget(project)
- pythonExecution.workingDir = targetPath(it)
- }
- }
- }
-
- pythonExecution.addParameter(operation)
+ val parameters = mutableListOf(operation)
if (operation == "install") {
PyProxyUtils.proxyString?.let {
- pythonExecution.addParameter("--proxy")
- pythonExecution.addParameter(it)
+ parameters += "--proxy"
+ parameters += it
}
}
-
- arguments.forEach(pythonExecution::addParameter)
-
- // // todo[akniazev]: add extra args to package specification
-
- val targetProgressIndicator = TargetProgressIndicator.EMPTY
- val targetEnvironment = targetEnvironmentRequest.prepareEnvironment(targetProgressIndicator)
-
- targetEnvironment.uploadVolumes.entries.forEach { (_, value) ->
- value.upload(".", targetProgressIndicator)
- }
-
- val targetedCommandLine = pythonExecution.buildTargetedCommandLine(targetEnvironment, sdk, emptyList())
-
- val indicator = ProgressManager.getInstance().progressIndicator ?: EmptyProgressIndicator()
- // from targets package manager
- // TODO [targets] Apply environment variables: setPythonUnbuffered(...), setPythonDontWriteBytecode(...), resetHomePathChanges(...)
- // TODO [targets] Apply flavor from PythonSdkFlavor.getFlavor(mySdk)
- // TODO [targets] check askForSudo
-
- val process = targetEnvironment.createProcess(targetedCommandLine, indicator)
-
- val commandLine = targetedCommandLine.collectCommandsSynchronously()
- val commandLineString = commandLine.joinToString(" ")
+ parameters += arguments
thisLogger().debug("Running python packaging tool. Operation: $operation")
-
- val result = PythonPackageManagerRunner.runProcess(
- process,
- commandLineString
+ ExecService().executeHelper(
+ sdk,
+ PACKAGING_TOOL_NAME,
+ parameters,
)
- if (result.isCancelled) {
- return@withContext PyResult.localizedError(IdeUtilIoBundle.message("run.canceled.by.user.message"))
- }
-
- result.checkSuccess(thisLogger())
- val exitCode = result.exitCode
- val helperPath = commandLine.firstOrNull() ?: ""
- val args: List = commandLine.subList(min(1, commandLine.size), commandLine.size)
- if (exitCode != 0) {
- val message = if (result.stdout.isBlank() && result.stderr.isBlank()) PySdkBundle.message(
- "python.conda.permission.denied")
- else PySdkBundle.message("python.sdk.packaging.non.zero.exit.code", exitCode)
- PyExecutionException(message, commandLine[0], args, result).let {
- return@withContext PyResult.failure(it.pyError)
- }
- }
-
- if (result.isTimeout) {
- PyExecutionException.createForTimeout(PySdkBundle.message("python.sdk.packaging.timed.out"), helperPath, args).let {
- return@withContext PyResult.failure(it.pyError)
- }
- }
-
- return@withContext PyResult.success(result.stdout)
}
@@ -235,4 +152,8 @@ class PipPackageManagerEngine(
return PyResult.success(Unit)
}
-}
\ No newline at end of file
+
+ companion object {
+ const val PACKAGING_TOOL_NAME: HelperName = "packaging_tool.py"
+ }
+}