diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java index 9a2249d5cab6..1d5ace2b194e 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java +++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java @@ -3,9 +3,7 @@ package com.jetbrains.python.packaging; import com.intellij.execution.ExecutionException; import com.intellij.openapi.Disposable; -import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.util.Key; import com.intellij.util.messages.Topic; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -18,7 +16,6 @@ import java.util.List; */ @Deprecated(forRemoval = true) public abstract class PyPackageManager implements Disposable { - public static final Key RUNNING_PACKAGING_TASKS = Key.create("PyPackageRequirementsInspection.RunningPackagingTasks"); public static final String USE_USER_SITE = "--user"; @Topic.AppLevel @@ -62,8 +59,6 @@ public abstract class PyPackageManager implements Disposable { public abstract boolean hasManagement() throws ExecutionException; - public abstract void install(@NotNull String requirementString) throws ExecutionException; - public abstract void install(@Nullable List requirements, @NotNull List extraArgs) throws ExecutionException; public abstract void uninstall(@NotNull List packages) throws ExecutionException; @@ -76,8 +71,6 @@ public abstract class PyPackageManager implements Disposable { public abstract @NotNull List refreshAndGetPackages(boolean alwaysRefresh) throws ExecutionException; - public abstract @Nullable List getRequirements(@NotNull Module module); - public interface Listener { void packagesRefreshed(@NotNull Sdk sdk); } diff --git a/python/src/com/jetbrains/python/newProject/DeprecatedUtils.java b/python/src/com/jetbrains/python/newProject/DeprecatedUtils.java index 665ae8a6a5b9..112a9f3af969 100644 --- a/python/src/com/jetbrains/python/newProject/DeprecatedUtils.java +++ b/python/src/com/jetbrains/python/newProject/DeprecatedUtils.java @@ -2,35 +2,20 @@ package com.jetbrains.python.newProject; import com.intellij.execution.ExecutionException; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Pair; import com.jetbrains.python.PyBundle; -import com.jetbrains.python.PyPsiPackageUtil; -import com.jetbrains.python.packaging.PyPackage; -import com.jetbrains.python.packaging.PyPackageManager; -import com.jetbrains.python.packaging.PyPackageUtil; -import com.jetbrains.python.packaging.PyPackagesNotificationPanel; import com.jetbrains.python.packaging.ui.PyPackageManagementService; import com.jetbrains.python.sdk.PreferredSdkComparator; import com.jetbrains.python.sdk.PySdkExtKt; import com.jetbrains.python.sdk.PythonSdkType; -import com.jetbrains.python.sdk.PythonSdkUtil; import one.util.streamex.StreamEx; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; /** @@ -43,20 +28,6 @@ import java.util.concurrent.Future; public final class DeprecatedUtils { private DeprecatedUtils() { } - /** - * @param sdkAndException if you have SDK and execution exception provide them here (both must not be null). - */ - private static void reportPackageInstallationFailure(final @NotNull String frameworkName, - final @Nullable Pair sdkAndException) { - - final PyPackageManagementService.PyPackageInstallationErrorDescription errorDescription = - getErrorDescription(sdkAndException, frameworkName); - final Application app = ApplicationManager.getApplication(); - app.invokeLater(() -> { - PyPackagesNotificationPanel.showPackageInstallationError(PyBundle.message("python.new.project.install.failed.title", frameworkName), - errorDescription); - }); - } private static @NotNull PyPackageManagementService.PyPackageInstallationErrorDescription getErrorDescription(final @Nullable Pair sdkAndException, @NotNull String packageName) { @@ -80,90 +51,6 @@ public final class DeprecatedUtils { //TODO: Support for plugin also - /** - * Installs framework and runs callback on success. - * Installation runs in modal dialog and callback is posted to AWT thread. - *

- * If "forceInstallFramework" is passed then installs framework in any case. - * If SDK is remote then checks if it has interpreter and installs if missing - * - * @param frameworkName user-readable framework name (i.e. "Django") - * @param requirement name of requirement to install (i.e. "django") - * @param forceInstallFramework pass true if you are sure required framework is missing - * @param callback to be called after installation (or instead of is framework is installed) on AWT thread - * @return future to be used instead of callback. - */ - public static @NotNull Future installFrameworkIfNeeded(final @NotNull Project project, - final @NotNull String frameworkName, - final @NotNull String requirement, - final @NotNull Sdk sdk, - final boolean forceInstallFramework, - final @Nullable Runnable callback) { - - var future = new CompletableFuture(); - - // For remote SDK we are not sure if framework exists or not, so we'll check it anyway - if (forceInstallFramework || PythonSdkUtil.isRemote(sdk)) { - - ProgressManager.getInstance() - .run(new Task.Modal(project, PyBundle.message("python.install.framework.ensure.installed", frameworkName), false) { - @Override - public void run(final @NotNull ProgressIndicator indicator) { - installPackages(frameworkName, forceInstallFramework, indicator, requirement, sdk); - } - - @Override - public void onThrowable(@NotNull Throwable error) { - future.completeExceptionally(error); - } - - @Override - public void onSuccess() { - future.complete(null); - // Installed / checked successfully, call callback on AWT - if (callback != null) { - callback.run(); - } - } - }); - } - else { - future.complete(null); - // No need to install, but still need to call callback on AWT - if (callback != null) { - assert SwingUtilities.isEventDispatchThread(); - callback.run(); - } - } - return future; - } - - private static void installPackages(final @NotNull String frameworkName, - boolean forceInstallFramework, - @NotNull ProgressIndicator indicator, - final @NotNull String requirement, - final @NotNull Sdk sdk) { - final PyPackageManager packageManager = PyPackageManager.getInstance(sdk); - boolean installed = false; - if (!forceInstallFramework) { - // First check if we need to do it - indicator.setText(PyBundle.message("python.install.framework.checking.is.installed", frameworkName)); - final List packages = PyPackageUtil.refreshAndGetPackagesModally(sdk); - installed = PyPsiPackageUtil.findPackage(packages, requirement) != null; - } - - if (!installed) { - indicator.setText(PyBundle.message("python.install.framework.installing", frameworkName)); - try { - packageManager.install(requirement); - packageManager.refresh(); - } - catch (final ExecutionException e) { - reportPackageInstallationFailure(requirement, Pair.create(sdk, e)); - } - } - } - // TODO: Migrate to interpreter service public static @NotNull List getValidPythonSdks(@NotNull List existingSdks) { return StreamEx diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerBridge.kt b/python/src/com/jetbrains/python/packaging/PyPackageManagerBridge.kt index f81a3b0b2844..67450a4be800 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerBridge.kt +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerBridge.kt @@ -3,7 +3,6 @@ package com.jetbrains.python.packaging import com.intellij.execution.ExecutionException import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.module.Module import com.intellij.openapi.progress.runBlockingMaybeCancellable import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.getOpenedProjects @@ -68,9 +67,5 @@ internal open class PyPackageManagerBridge(sdk: Sdk) : PyTargetEnvironmentPackag return packageManagerUI.manager.listInstalledPackagesSnapshot().map { PyPackage(it.name, it.version) } } - override fun getRequirements(module: Module): List? { - return packageManager.getDependencyManager()?.getDependencies() - } - private fun guessProject() = getOpenedProjects().firstOrNull() ?: ProjectManager.getInstance().defaultProject } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index bcd3ba2db959..a13534536318 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -41,7 +41,7 @@ import static com.jetbrains.python.sdk.PySdkExtKt.showSdkExecutionException; * @deprecated This class and all its inheritors are deprecated. Everything should work via {@link PyTargetEnvironmentPackageManager} */ @Deprecated(forRemoval = true) -public class PyPackageManagerImpl extends PyPackageManagerImplBase { +public abstract class PyPackageManagerImpl extends PyPackageManagerImplBase { private static final Logger LOG = Logger.getInstance(PyPackageManagerImpl.class); @Override @@ -61,11 +61,6 @@ public class PyPackageManagerImpl extends PyPackageManagerImplBase { super(sdk); } - @Override - public void install(@NotNull String requirementString) throws ExecutionException { - install(Collections.singletonList(PyRequirementParser.fromLine(requirementString)), Collections.emptyList()); - } - @Override public void install(@Nullable List requirements, @NotNull List extraArgs) throws ExecutionException { install(requirements, extraArgs, null); diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java index 3c601894be95..3152d7fdd823 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImplBase.java @@ -5,7 +5,6 @@ import com.intellij.execution.ExecutionException; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.text.StringUtil; @@ -31,7 +30,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.net.URI; import java.net.URISyntaxException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; @@ -166,13 +168,6 @@ public abstract class PyPackageManagerImplBase extends PyPackageManager { return PythonSdkType.getLanguageLevelForSdk(sdk); } - @Override - public @Nullable List getRequirements(@NotNull Module module) { - return Optional - .ofNullable(PyPackageUtil.getRequirementsFromTxt(module)) - .orElseGet(() -> PyPackageUtil.findSetupPyRequires(module)); - } - @Override public @NotNull List refreshAndGetPackages(boolean alwaysRefresh) throws ExecutionException { final List currentPackages = myPackagesCache; diff --git a/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java b/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java index cd68f1bdee18..aa524acc56da 100644 --- a/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java +++ b/python/src/com/jetbrains/python/packaging/PyTargetEnvironmentPackageManager.java @@ -69,11 +69,6 @@ public abstract class PyTargetEnvironmentPackageManager extends PyPackageManager super(sdk); } - @Override - public void install(@NotNull String requirementString) throws ExecutionException { - install(Collections.singletonList(PyRequirementParser.fromLine(requirementString)), Collections.emptyList()); - } - @Override public void install(@Nullable List requirements, @NotNull List extraArgs) throws ExecutionException { install(requirements, extraArgs, null); diff --git a/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUI.kt b/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUI.kt index e019854be237..d255e98f7a15 100644 --- a/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUI.kt +++ b/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUI.kt @@ -46,7 +46,7 @@ class PythonPackageManagerUI(val manager: PythonPackageManager, val sink: ErrorS /** * @return List of all installed packages or null if the operation was failed. */ - suspend fun installPackagesBackground( + suspend fun installPackagesRequestBackground( installRequest: PythonPackageInstallRequest, options: List = emptyList(), ): List? { diff --git a/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUiExtensions.kt b/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUiExtensions.kt index 28d6e397451e..c8710b94a584 100644 --- a/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUiExtensions.kt +++ b/python/src/com/jetbrains/python/packaging/management/ui/PythonPackageManagerUiExtensions.kt @@ -68,8 +68,23 @@ suspend fun PythonPackageManagerUI.installPyRequirementsBackground( val specifications = packages.mapNotNull { manager.findPackageSpecificationWithVersionSpec(it.name, it.versionSpecs.firstOrNull()) } - return installPackagesBackground(PythonPackageInstallRequest.ByRepositoryPythonPackageSpecifications(specifications), - options = options) + return installPackagesRequestBackground(PythonPackageInstallRequest.ByRepositoryPythonPackageSpecifications(specifications), + options = options) +} + + +@ApiStatus.Internal +suspend fun PythonPackageManagerUI.installPackagesBackground( + packages: List, + options: List = emptyList(), +): List? { + //Wait here to load spec + manager.waitForInit() + val specifications = packages.mapNotNull { + manager.findPackageSpecificationWithVersionSpec(it, null) + } + return installPackagesRequestBackground(PythonPackageInstallRequest.ByRepositoryPythonPackageSpecifications(specifications), + options = options) } /** diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt index 2f1e08c1f906..c61774bcc4bd 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt @@ -51,7 +51,7 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou internal var currentSdk: Sdk? = null private lateinit var managerUI: PythonPackageManagerUI - private val manager: PythonPackageManager? + private val manager: PythonPackageManager get() = managerUI.manager @@ -128,7 +128,7 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou suspend fun installPackage(installRequest: PythonPackageInstallRequest, options: List = emptyList()) { PythonPackagesToolwindowStatisticsCollector.installPackageEvent.log(project) - managerUI.installPackagesBackground(installRequest, options)?.let { + managerUI.installPackagesRequestBackground(installRequest, options)?.let { handleActionCompleted(message("python.packaging.notification.installed", installRequest.title)) } } @@ -136,7 +136,7 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou suspend fun installPackage(pkg: PythonPackage, options: List = emptyList()) { val installRequest = manager?.findPackageSpecification(pkg.name, pkg.version)?.toInstallRequest() ?: return PythonPackagesToolwindowStatisticsCollector.installPackageEvent.log(project) - managerUI.installPackagesBackground(installRequest, options)?.let { + managerUI.installPackagesRequestBackground(installRequest, options)?.let { handleActionCompleted(message("python.packaging.notification.installed", installRequest.title)) } } diff --git a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.kt b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.kt index b1f890ebb727..0defc1bea4cf 100644 --- a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.kt +++ b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.project.Project import com.intellij.util.concurrency.annotations.RequiresBackgroundThread import com.jetbrains.python.extensions.getSdk import com.jetbrains.python.packaging.PyPIPackageCache -import com.jetbrains.python.packaging.PyPackageManager import com.jetbrains.python.packaging.management.PythonPackageManager import com.jetbrains.python.packaging.normalizePackageName import com.jetbrains.python.sdk.PythonSdkAdditionalData @@ -49,7 +48,8 @@ internal class PyPackageVersionUsagesCollector : ProjectUsagesCollector() { val sdk = module.getSdk() ?: continue if (!PythonSdkUtil.isPythonSdk(sdk)) continue val usageData = getPythonSpecificInfo(sdk) - PyPackageManager.getInstance(sdk).getRequirements(module).orEmpty() + val requirements = PythonPackageManager.forSdk(project, sdk).getDependencyManager()?.getDependencies().orEmpty() + requirements .filter { pypiPackages.containsPackage(it.name) } .forEach { req -> ProgressManager.checkCanceled()