mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 09:19:13 +07:00
cleanup python package manager internal interface. squash redundant test python package manager implementations.
GitOrigin-RevId: e1f80d690a5c67868312e626e79d7fbd73e06808
This commit is contained in:
committed by
intellij-monorepo-bot
parent
677e708e7e
commit
e9f5ddd211
@@ -414,8 +414,8 @@ The Python plug-in provides smart editing for Python scripts. The feature set of
|
||||
<applicationService serviceInterface="com.jetbrains.python.codeInsight.PyCustomMemberProvider"
|
||||
serviceImplementation="com.jetbrains.python.codeInsight.PyCustomMemberProviderImpl"/>
|
||||
|
||||
<projectService serviceInterface="com.jetbrains.python.packaging.common.PackageManagerHolder"
|
||||
serviceImplementation="com.jetbrains.python.packaging.common.PackageManagerHolderImpl"/>
|
||||
<projectService serviceInterface="com.jetbrains.python.packaging.management.PythonPackageManagerService"
|
||||
serviceImplementation="com.jetbrains.python.packaging.management.PythonPackageManagerServiceImpl"/>
|
||||
|
||||
<qualifiedNameProvider implementation="com.jetbrains.python.actions.PyQualifiedNameProvider"/>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.packaging.common.PackageManagerHolder;
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManagerService;
|
||||
import com.jetbrains.python.packaging.ui.PyPackageManagementService;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.sdk.PythonSdkUtil;
|
||||
@@ -89,7 +89,7 @@ public class PyPackageManagersImpl extends PyPackageManagers {
|
||||
LOG.assertTrue(!Disposer.isDisposed((Disposable)sdk),
|
||||
"Requesting a package service for an already disposed SDK " + sdk + " (" + sdk.getClass() + ")");
|
||||
}
|
||||
return project.getService(PackageManagerHolder.class).bridgeForSdk(project, sdk);
|
||||
return project.getService(PythonPackageManagerService.class).bridgeForSdk(project, sdk);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,79 +1,21 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.packaging.common
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.writeIntentReadAction
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.NlsContexts
|
||||
import com.intellij.webcore.packaging.PackagesNotificationPanel
|
||||
import com.jetbrains.python.packaging.PyExecutionException
|
||||
import com.jetbrains.python.packaging.PyPIPackageRanking
|
||||
import com.jetbrains.python.packaging.PyPackagesNotificationPanel
|
||||
import com.jetbrains.python.packaging.bridge.PythonPackageManagementServiceBridge
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManager
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManagerProvider
|
||||
import com.jetbrains.python.packaging.ui.PyPackageManagementService
|
||||
import com.jetbrains.python.sdk.PythonSdkAdditionalData
|
||||
import com.jetbrains.python.sdk.getOrCreateAdditionalData
|
||||
import com.jetbrains.python.statistics.PyPackagesUsageCollector
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
|
||||
interface PackageManagerHolder {
|
||||
fun forSdk(project: Project, sdk: Sdk): PythonPackageManager
|
||||
|
||||
/**
|
||||
* Provides an implementation bridge for Python package management operations
|
||||
* specific to the given project and SDK. The bridge serves as a connection point
|
||||
* to enable advanced management tasks, potentially extending or adapting functionalities
|
||||
* provided by the [PythonPackageManager].
|
||||
*/
|
||||
fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge
|
||||
|
||||
fun getServiceScope(): CoroutineScope
|
||||
}
|
||||
|
||||
class PackageManagerHolderImpl(private val serviceScope: CoroutineScope) : PackageManagerHolder, Disposable {
|
||||
private val cache = ConcurrentHashMap<UUID, PythonPackageManager>()
|
||||
|
||||
private val bridgeCache = ConcurrentHashMap<UUID, PythonPackageManagementServiceBridge>()
|
||||
|
||||
/**
|
||||
* Requires Sdk to be Python Sdk and have PythonSdkAdditionalData.
|
||||
*/
|
||||
override fun forSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
val cacheKey = (sdk.getOrCreateAdditionalData()).uuid
|
||||
|
||||
return cache.computeIfAbsent(cacheKey) {
|
||||
PythonPackageManagerProvider.EP_NAME.extensionList
|
||||
.firstNotNullOf { it.createPackageManagerForSdk(project, sdk) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge {
|
||||
val cacheKey = (sdk.sdkAdditionalData as PythonSdkAdditionalData).uuid
|
||||
return bridgeCache.computeIfAbsent(cacheKey) {
|
||||
val bridge = PythonPackageManagementServiceBridge(project, sdk)
|
||||
Disposer.register(this@PackageManagerHolderImpl, bridge)
|
||||
bridge
|
||||
}
|
||||
}
|
||||
|
||||
override fun getServiceScope(): CoroutineScope = serviceScope
|
||||
|
||||
override fun dispose() {
|
||||
cache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ApiStatus.Experimental
|
||||
interface PythonPackageManagementListener {
|
||||
|
||||
@@ -15,12 +15,14 @@ class CompositePythonPackageManager(
|
||||
) : PythonPackageManager(project, sdk) {
|
||||
@Volatile
|
||||
override var installedPackages: List<PythonPackage> = emptyList()
|
||||
|
||||
// TODO: composite one
|
||||
override var repositoryManager: PythonRepositoryManager = managers.first().repositoryManager
|
||||
|
||||
private fun isInRepository(repositoryManager: PythonRepositoryManager, pkgName: String) =
|
||||
repositoryManager.allPackages().contains(pkgName)
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> {
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> {
|
||||
val exceptionList = mutableListOf<Throwable>()
|
||||
for (manager in managers) {
|
||||
repositoryManager = manager.repositoryManager
|
||||
@@ -28,17 +30,15 @@ class CompositePythonPackageManager(
|
||||
|
||||
if (!isInRepository(repositoryManager, specification.name)) continue
|
||||
val executionResult = manager.installPackage(specification, options)
|
||||
val executionOutcome = executionResult.getOrElse { exceptionList.add(it) }
|
||||
|
||||
if (executionResult.isSuccess) {
|
||||
return Result.success(executionOutcome.toString())
|
||||
}
|
||||
executionResult
|
||||
.onSuccess { return Result.success(Unit) }
|
||||
.onFailure { exceptionList.add(it) }
|
||||
}
|
||||
return Result.failure(exceptionList.last())
|
||||
|
||||
return Result.failure(exceptionList.lastOrNull() ?: RuntimeException("No package managers found for package $specification"))
|
||||
}
|
||||
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> {
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> {
|
||||
val exceptionList = mutableListOf<Throwable>()
|
||||
|
||||
for (manager in managers) {
|
||||
@@ -47,33 +47,32 @@ class CompositePythonPackageManager(
|
||||
|
||||
if (!isInRepository(repositoryManager, specification.name)) continue
|
||||
val executionResult = manager.updatePackage(specification)
|
||||
val executionOutcome = executionResult.getOrElse { exceptionList.add(it) }
|
||||
|
||||
if (executionResult.isSuccess) {
|
||||
return Result.success(executionOutcome.toString())
|
||||
}
|
||||
executionResult
|
||||
.onSuccess { return Result.success(Unit) }
|
||||
.onFailure { exceptionList.add(it) }
|
||||
}
|
||||
|
||||
return Result.failure(exceptionList.last())
|
||||
return Result.failure(exceptionList.lastOrNull() ?: RuntimeException("No package managers found for package $specification"))
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> {
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> {
|
||||
val exceptionList = mutableListOf<Throwable>()
|
||||
|
||||
for (manager in managers) {
|
||||
repositoryManager = manager.repositoryManager
|
||||
installedPackages = manager.installedPackages
|
||||
|
||||
if (!isInRepository(repositoryManager, pkg.name)) continue
|
||||
if (!isInRepository(repositoryManager, pkg.name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val executionResult = manager.uninstallPackage(pkg)
|
||||
val executionOutcome = executionResult.getOrElse { exceptionList.add(it) }
|
||||
if (executionResult.isSuccess) {
|
||||
return Result.success(executionOutcome.toString())
|
||||
}
|
||||
executionResult
|
||||
.onSuccess { return Result.success(Unit) }
|
||||
.onFailure { exceptionList.add(it) }
|
||||
}
|
||||
|
||||
return Result.failure(exceptionList.last())
|
||||
return Result.failure(exceptionList.lastOrNull() ?: RuntimeException("No package managers found for package $pkg"))
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
@@ -83,15 +82,11 @@ class CompositePythonPackageManager(
|
||||
repositoryManager = manager.repositoryManager
|
||||
installedPackages = manager.installedPackages
|
||||
|
||||
val executionResult = manager.reloadPackages()
|
||||
val executionOutcome = executionResult.getOrElse {
|
||||
exceptionList.add(it)
|
||||
emptyList()
|
||||
}
|
||||
if (executionResult.isSuccess) {
|
||||
return Result.success(executionOutcome)
|
||||
}
|
||||
manager.reloadPackages()
|
||||
.onSuccess { return Result.success(it) }
|
||||
.onFailure { exceptionList.add(it) }
|
||||
}
|
||||
return Result.failure(exceptionList.last())
|
||||
|
||||
return Result.failure(exceptionList.lastOrNull() ?: RuntimeException("No package managers found"))
|
||||
}
|
||||
}
|
||||
@@ -32,25 +32,28 @@ class CondaPackageManager(project: Project, sdk: Sdk) : PythonPackageManager(pro
|
||||
override var installedPackages: List<PythonPackage> = emptyList()
|
||||
override val repositoryManager = CondaRepositoryManger(project, sdk)
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> =
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> =
|
||||
try {
|
||||
Result.success(runConda("install", specification.buildInstallationString() + "-y" + options, message("conda.packaging.install.progress", specification.name)))
|
||||
runConda("install", specification.buildInstallationString() + "-y" + options, message("conda.packaging.install.progress", specification.name))
|
||||
Result.success(Unit)
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> =
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> =
|
||||
try {
|
||||
Result.success(runConda("update", listOf(specification.name, "-y"), message("conda.packaging.update.progress", specification.name)))
|
||||
runConda("update", listOf(specification.name, "-y"), message("conda.packaging.update.progress", specification.name))
|
||||
Result.success(Unit)
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> =
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> =
|
||||
try {
|
||||
Result.success(runConda("uninstall", listOf(pkg.name, "-y"), message("conda.packaging.uninstall.progress", pkg.name)))
|
||||
runConda("uninstall", listOf(pkg.name, "-y"), message("conda.packaging.uninstall.progress", pkg.name))
|
||||
Result.success(Unit)
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
|
||||
@@ -73,9 +73,9 @@ abstract class PythonPackageManager(val project: Project, val sdk: Sdk) {
|
||||
return Result.success(packages)
|
||||
}
|
||||
|
||||
protected abstract suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String>
|
||||
protected abstract suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String>
|
||||
protected abstract suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String>
|
||||
protected abstract suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit>
|
||||
protected abstract suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit>
|
||||
protected abstract suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit>
|
||||
protected abstract suspend fun reloadPackagesCommand(): Result<List<PythonPackage>>
|
||||
|
||||
internal suspend fun refreshPaths() {
|
||||
@@ -93,9 +93,9 @@ abstract class PythonPackageManager(val project: Project, val sdk: Sdk) {
|
||||
|
||||
companion object {
|
||||
fun forSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
val packageManagerHolder = project.service<PackageManagerHolder>()
|
||||
val manager = packageManagerHolder.forSdk(project, sdk)
|
||||
packageManagerHolder.getServiceScope().launch(Dispatchers.IO) {
|
||||
val pythonPackageManagerService = project.service<PythonPackageManagerService>()
|
||||
val manager = pythonPackageManagerService.forSdk(project, sdk)
|
||||
pythonPackageManagerService.getServiceScope().launch(Dispatchers.IO) {
|
||||
manager.repositoryManager.initCaches()
|
||||
}
|
||||
return manager
|
||||
|
||||
+17
@@ -4,6 +4,8 @@ package com.jetbrains.python.packaging.management
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.bridge.PythonPackageManagementServiceBridge
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@@ -19,4 +21,19 @@ interface PythonPackageManagerProvider {
|
||||
companion object {
|
||||
val EP_NAME = ExtensionPointName.create<PythonPackageManagerProvider>("Pythonid.pythonPackageManagerProvider")
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
interface PythonPackageManagerService {
|
||||
fun forSdk(project: Project, sdk: Sdk): PythonPackageManager
|
||||
|
||||
/**
|
||||
* Provides an implementation bridge for Python package management operations
|
||||
* specific to the given project and SDK. The bridge serves as a connection point
|
||||
* to enable advanced management tasks, potentially extending or adapting functionalities
|
||||
* provided by the [PythonPackageManager].
|
||||
*/
|
||||
fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge
|
||||
|
||||
fun getServiceScope(): CoroutineScope
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// 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.openapi.Disposable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.jetbrains.python.packaging.bridge.PythonPackageManagementServiceBridge
|
||||
import com.jetbrains.python.sdk.PythonSdkAdditionalData
|
||||
import com.jetbrains.python.sdk.getOrCreateAdditionalData
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class PythonPackageManagerServiceImpl(private val serviceScope: CoroutineScope) : PythonPackageManagerService, Disposable {
|
||||
private val cache = ConcurrentHashMap<UUID, PythonPackageManager>()
|
||||
|
||||
private val bridgeCache = ConcurrentHashMap<UUID, PythonPackageManagementServiceBridge>()
|
||||
|
||||
/**
|
||||
* Requires Sdk to be Python Sdk and have PythonSdkAdditionalData.
|
||||
*/
|
||||
override fun forSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
val cacheKey = (sdk.getOrCreateAdditionalData()).uuid
|
||||
|
||||
return cache.computeIfAbsent(cacheKey) {
|
||||
PythonPackageManagerProvider.EP_NAME.extensionList
|
||||
.firstNotNullOf { it.createPackageManagerForSdk(project, sdk) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge {
|
||||
val cacheKey = (sdk.sdkAdditionalData as PythonSdkAdditionalData).uuid
|
||||
return bridgeCache.computeIfAbsent(cacheKey) {
|
||||
val bridge = PythonPackageManagementServiceBridge(project, sdk)
|
||||
Disposer.register(this@PythonPackageManagerServiceImpl, bridge)
|
||||
bridge
|
||||
}
|
||||
}
|
||||
|
||||
override fun getServiceScope(): CoroutineScope = serviceScope
|
||||
|
||||
override fun dispose() {
|
||||
cache.clear()
|
||||
}
|
||||
}
|
||||
@@ -19,31 +19,40 @@ open class PipPythonPackageManager(project: Project, sdk: Sdk) : PythonPackageMa
|
||||
override var installedPackages: List<PythonPackage> = emptyList()
|
||||
override val repositoryManager: PythonRepositoryManager = PipRepositoryManager(project, sdk)
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> =
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> {
|
||||
try {
|
||||
Result.success(runPackagingTool("install", specification.buildInstallationString() + options, PyBundle.message("python.packaging.install.progress", specification.name)))
|
||||
runPackagingTool("install", specification.buildInstallationString() + options, PyBundle.message("python.packaging.install.progress", specification.name))
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
return Result.failure(ex)
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> =
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> {
|
||||
try {
|
||||
Result.success(runPackagingTool("install", listOf("--upgrade") + specification.buildInstallationString(), PyBundle.message("python.packaging.update.progress", specification.name)))
|
||||
runPackagingTool("install", listOf("--upgrade") + specification.buildInstallationString(), PyBundle.message("python.packaging.update.progress", specification.name))
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
return Result.failure(ex)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> =
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> {
|
||||
try {
|
||||
Result.success(runPackagingTool("uninstall", listOf(pkg.name), PyBundle.message("python.packaging.uninstall.progress", pkg.name)))
|
||||
runPackagingTool("uninstall", listOf(pkg.name), PyBundle.message("python.packaging.uninstall.progress", pkg.name))
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
return Result.failure(ex)
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> =
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
try {
|
||||
val output = runPackagingTool("list", emptyList(), PyBundle.message("python.packaging.list.progress"))
|
||||
val packages = output.lineSequence()
|
||||
@@ -54,9 +63,11 @@ open class PipPythonPackageManager(project: Project, sdk: Sdk) : PythonPackageMa
|
||||
}
|
||||
.sortedWith(compareBy(PythonPackage::name))
|
||||
.toList()
|
||||
Result.success(packages)
|
||||
|
||||
return Result.success(packages)
|
||||
}
|
||||
catch (ex: ExecutionException) {
|
||||
Result.failure(ex)
|
||||
return Result.failure(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,26 @@ class PoetryPackageManager(project: Project, sdk: Sdk) : PythonPackageManager(pr
|
||||
@Volatile
|
||||
private var outdatedPackages: Map<String, PythonOutdatedPackage> = emptyMap()
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> =
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> {
|
||||
poetryInstallPackage(sdk, specification.getVersionForPoetry(), options)
|
||||
.onFailure { return Result.failure(it) }
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> =
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> {
|
||||
poetryInstallPackage(sdk, specification.getVersionForPoetry(), emptyList())
|
||||
.onFailure { return Result.failure(it) }
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> = poetryUninstallPackage(sdk, pkg.name)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> {
|
||||
poetryUninstallPackage(sdk, pkg.name)
|
||||
.onFailure { return Result.failure(it) }
|
||||
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
val (installed, _) = poetryListPackages(sdk).getOrElse {
|
||||
|
||||
@@ -21,7 +21,7 @@ internal class UvPackageManager(project: Project, sdk: Sdk, private val uv: UvLo
|
||||
@Volatile
|
||||
var outdatedPackages: Map<String, PythonOutdatedPackage> = emptyMap()
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> {
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> {
|
||||
val result = if (sdk.uvUsePackageManagement) {
|
||||
uv.installPackage(specification, emptyList())
|
||||
}
|
||||
@@ -34,19 +34,19 @@ internal class UvPackageManager(project: Project, sdk: Sdk, private val uv: UvLo
|
||||
}
|
||||
|
||||
// FIXME: refactor command return value, it's not used
|
||||
return Result.success("")
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> {
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> {
|
||||
installPackageCommand(specification, emptyList()).getOrElse {
|
||||
return Result.failure(it)
|
||||
}
|
||||
|
||||
// FIXME: refactor command return value, it's not used
|
||||
return Result.success("")
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> {
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> {
|
||||
val result = if (sdk.uvUsePackageManagement) {
|
||||
uv.uninstallPackage(pkg)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ internal class UvPackageManager(project: Project, sdk: Sdk, private val uv: UvLo
|
||||
}
|
||||
|
||||
// FIXME: refactor command return value, it's not used
|
||||
return Result.success("")
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
|
||||
+4
-4
@@ -7,8 +7,8 @@ import com.intellij.testFramework.ServiceContainerUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.fixtures.PyInspectionTestCase;
|
||||
import com.jetbrains.python.packaging.PyRequirement;
|
||||
import com.jetbrains.python.packaging.common.PackageManagerHolder;
|
||||
import com.jetbrains.python.packaging.mocks.MockPackageManagerHolder;
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManagerService;
|
||||
import com.jetbrains.python.packaging.management.TestPythonPackageManagerService;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.sdk.PythonSdkUtil;
|
||||
import com.jetbrains.python.sdk.pipenv.PipenvFilesUtilsKt;
|
||||
@@ -31,8 +31,8 @@ public class PyPackageRequirementsInspectionTest extends PyInspectionTestCase {
|
||||
|
||||
ServiceContainerUtil.replaceService(
|
||||
myFixture.getProject(),
|
||||
PackageManagerHolder.class,
|
||||
new MockPackageManagerHolder(),
|
||||
PythonPackageManagerService.class,
|
||||
new TestPythonPackageManagerService(),
|
||||
myFixture.getProject()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// 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.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.bridge.PythonPackageManagementServiceBridge
|
||||
import com.jetbrains.python.packaging.common.PythonPackage
|
||||
import com.jetbrains.python.packaging.common.PythonPackageDetails
|
||||
import com.jetbrains.python.packaging.common.PythonPackageSpecification
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@TestOnly
|
||||
class TestPythonPackageManager(project: Project, sdk: Sdk) : PythonPackageManager(project, sdk) {
|
||||
|
||||
override var installedPackages: List<PythonPackage> = DEFAULT_PACKAGES.toMutableList()
|
||||
|
||||
private var packageNames: List<String> = emptyList()
|
||||
private var packageDetails: PythonPackageDetails? = null
|
||||
|
||||
override val repositoryManager: PythonRepositoryManager
|
||||
get() = TestPythonRepositoryManager(project, sdk).withPackageNames(packageNames).withPackageDetails(packageDetails)
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<Unit> {
|
||||
return if (repositoryManager.allPackages().contains(specification.name)) {
|
||||
installedPackages += PythonPackage(specification.name, specification.versionSpecs.orEmpty(), false)
|
||||
Result.success(Unit)
|
||||
} else {
|
||||
Result.failure(Exception(PACKAGE_INSTALL_FAILURE_MESSAGE))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<Unit> {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<Unit> {
|
||||
val packageToRemove = findPackageByName(pkg.name)
|
||||
return if (packageToRemove != null) {
|
||||
installedPackages -= packageToRemove
|
||||
Result.success(Unit)
|
||||
} else {
|
||||
Result.failure(Exception(PACKAGE_UNINSTALL_FAILURE_MESSAGE))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
return Result.success(installedPackages)
|
||||
}
|
||||
|
||||
private fun findPackageByName(name: String): PythonPackage? {
|
||||
return installedPackages.find { it.name == name }
|
||||
}
|
||||
|
||||
fun withPackageNames(packageNames: List<String>): TestPythonPackageManager {
|
||||
this.packageNames = packageNames
|
||||
return this
|
||||
}
|
||||
|
||||
fun withPackageDetails(details: PythonPackageDetails?): TestPythonPackageManager {
|
||||
this.packageDetails = details
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_PACKAGES = listOf(
|
||||
PythonPackage(PIP_PACKAGE, EMPTY_STRING, false),
|
||||
PythonPackage(SETUP_TOOLS_PACKAGE, EMPTY_STRING, false)
|
||||
)
|
||||
|
||||
private const val PIP_PACKAGE = "pip"
|
||||
private const val SETUP_TOOLS_PACKAGE = "setuptools"
|
||||
private const val PACKAGE_INSTALL_FAILURE_MESSAGE = "Failed to install package"
|
||||
private const val PACKAGE_UNINSTALL_FAILURE_MESSAGE = "No such package found"
|
||||
private const val EMPTY_STRING = ""
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
class TestPythonPackageManagerService(): PythonPackageManagerService {
|
||||
|
||||
override fun forSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
return TestPythonPackageManager(project, sdk)
|
||||
}
|
||||
|
||||
override fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge {
|
||||
return PythonPackageManagementServiceBridge(project, sdk)
|
||||
}
|
||||
|
||||
override fun getServiceScope(): CoroutineScope {
|
||||
return CoroutineScope(Job())
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
class TestPackageManagerProvider : PythonPackageManagerProvider {
|
||||
private var packageNames: List<String> = emptyList()
|
||||
private var packageDetails: PythonPackageDetails? = null
|
||||
|
||||
fun withPackageNames(packageNames: List<String>): TestPackageManagerProvider {
|
||||
this.packageNames = packageNames
|
||||
return this
|
||||
}
|
||||
|
||||
fun withPackageDetails(details: PythonPackageDetails): TestPackageManagerProvider {
|
||||
this.packageDetails = details
|
||||
return this
|
||||
}
|
||||
|
||||
override fun createPackageManagerForSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
return TestPythonPackageManager(project, sdk).withPackageNames(packageNames).withPackageDetails(packageDetails)
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
// Copyright 2000-2023 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.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.common.PythonPackageDetails
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@TestOnly
|
||||
class TestPackageManagerProvider : PythonPackageManagerProvider {
|
||||
private var packageNames: List<String> = emptyList()
|
||||
private var packageDetails: PythonPackageDetails? = null
|
||||
|
||||
fun withPackageNames(packageNames: List<String>): TestPackageManagerProvider {
|
||||
this.packageNames = packageNames
|
||||
return this
|
||||
}
|
||||
|
||||
fun withPackageDetails(details: PythonPackageDetails): TestPackageManagerProvider {
|
||||
this.packageDetails = details
|
||||
return this
|
||||
}
|
||||
|
||||
override fun createPackageManagerForSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
return TestPythonPackageManager(project, sdk).withPackageNames(packageNames).withPackageDetails(packageDetails)
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2000-2023 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.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.common.PythonPackage
|
||||
import com.jetbrains.python.packaging.common.PythonPackageDetails
|
||||
import com.jetbrains.python.packaging.common.PythonPackageSpecification
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@TestOnly
|
||||
class TestPythonPackageManager(project: Project, sdk: Sdk) : PythonPackageManager(project, sdk) {
|
||||
private var packageNames: List<String> = emptyList()
|
||||
private var packageDetails: PythonPackageDetails? = null
|
||||
|
||||
override var installedPackages: List<PythonPackage> = emptyList()
|
||||
get() = TODO("Not yet implemented")
|
||||
override val repositoryManager: PythonRepositoryManager
|
||||
get() = TestPythonRepositoryManager(project, sdk).withPackageNames(packageNames).withPackageDetails(packageDetails)
|
||||
|
||||
fun withPackageNames(packageNames: List<String>): TestPythonPackageManager {
|
||||
this.packageNames = packageNames
|
||||
return this
|
||||
}
|
||||
|
||||
fun withPackageDetails(details: PythonPackageDetails?): TestPythonPackageManager {
|
||||
this.packageDetails = details
|
||||
return this
|
||||
}
|
||||
|
||||
override suspend fun reloadPackages(): Result<List<PythonPackage>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
-2
@@ -59,10 +59,8 @@ class TestPythonRepositoryManager(project: Project, sdk: Sdk) : PythonRepository
|
||||
}
|
||||
|
||||
override suspend fun refreshCashes() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun initCaches() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.packaging.mocks
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.common.PythonPackage
|
||||
import com.jetbrains.python.packaging.common.PythonPackageSpecification
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManager
|
||||
import com.jetbrains.python.packaging.management.PythonRepositoryManager
|
||||
import com.jetbrains.python.packaging.pip.PipRepositoryManager
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@TestOnly
|
||||
class MockPythonPackageManager(project: Project, sdk: Sdk) : PythonPackageManager(project, sdk) {
|
||||
|
||||
override var installedPackages: List<PythonPackage> = DEFAULT_PACKAGES.toMutableList()
|
||||
|
||||
override val repositoryManager: PythonRepositoryManager = PipRepositoryManager(project, sdk)
|
||||
|
||||
override suspend fun installPackageCommand(specification: PythonPackageSpecification, options: List<String>): Result<String> {
|
||||
return if (repositoryManager.allPackages().contains(specification.name)) {
|
||||
installedPackages += PythonPackage(specification.name, specification.versionSpecs.orEmpty(), false)
|
||||
Result.success(PACKAGE_INSTALLED_MESSAGE)
|
||||
} else {
|
||||
Result.failure(Exception(PACKAGE_INSTALL_FAILURE_MESSAGE))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updatePackageCommand(specification: PythonPackageSpecification): Result<String> {
|
||||
return Result.success(PACKAGE_UPDATED_MESSAGE)
|
||||
}
|
||||
|
||||
override suspend fun uninstallPackageCommand(pkg: PythonPackage): Result<String> {
|
||||
val packageToRemove = findPackageByName(pkg.name)
|
||||
return if (packageToRemove != null) {
|
||||
installedPackages -= packageToRemove
|
||||
Result.success(PACKAGE_UNINSTALLED_MESSAGE)
|
||||
} else {
|
||||
Result.failure(Exception(PACKAGE_UNINSTALL_FAILURE_MESSAGE))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reloadPackagesCommand(): Result<List<PythonPackage>> {
|
||||
return Result.success(installedPackages)
|
||||
}
|
||||
|
||||
private fun findPackageByName(name: String): PythonPackage? {
|
||||
return installedPackages.find { it.name == name }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_PACKAGES = listOf(
|
||||
PythonPackage(PIP_PACKAGE, EMPTY_STRING, false),
|
||||
PythonPackage(SETUP_TOOLS_PACKAGE, EMPTY_STRING, false)
|
||||
)
|
||||
|
||||
private const val PIP_PACKAGE = "pip"
|
||||
private const val SETUP_TOOLS_PACKAGE = "setuptools"
|
||||
private const val PACKAGE_INSTALLED_MESSAGE = "Successfully installed package"
|
||||
private const val PACKAGE_INSTALL_FAILURE_MESSAGE = "Failed to install package"
|
||||
private const val PACKAGE_UPDATED_MESSAGE = "Successfully updated package"
|
||||
private const val PACKAGE_UNINSTALLED_MESSAGE = "Successfully uninstalled package"
|
||||
private const val PACKAGE_UNINSTALL_FAILURE_MESSAGE = "No such package found"
|
||||
private const val EMPTY_STRING = ""
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.packaging.mocks
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.bridge.PythonPackageManagementServiceBridge
|
||||
import com.jetbrains.python.packaging.common.PackageManagerHolder
|
||||
import com.jetbrains.python.packaging.management.PythonPackageManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
|
||||
@TestOnly
|
||||
class MockPackageManagerHolder() : PackageManagerHolder {
|
||||
|
||||
override fun forSdk(project: Project, sdk: Sdk): PythonPackageManager {
|
||||
return MockPythonPackageManager(project, sdk)
|
||||
}
|
||||
|
||||
override fun bridgeForSdk(project: Project, sdk: Sdk): PythonPackageManagementServiceBridge {
|
||||
return PythonPackageManagementServiceBridge(project, sdk)
|
||||
}
|
||||
|
||||
override fun getServiceScope(): CoroutineScope {
|
||||
return CoroutineScope(Job())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user