cleanup python package manager internal interface. squash redundant test python package manager implementations.

GitOrigin-RevId: e1f80d690a5c67868312e626e79d7fbd73e06808
This commit is contained in:
Aleksandr Sorotskii
2025-01-29 19:52:47 +00:00
committed by intellij-monorepo-bot
parent 677e708e7e
commit e9f5ddd211
18 changed files with 271 additions and 303 deletions
@@ -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
@@ -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
}
@@ -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>> {
@@ -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)
}
}
@@ -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")
}
}
@@ -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())
}
}