--- a/PipxInterface/Pipx.py Thu Jun 27 17:54:24 2024 +0200 +++ b/PipxInterface/Pipx.py Fri Jun 28 16:25:21 2024 +0200 @@ -11,12 +11,12 @@ import json import os import pathlib -##import sys import sysconfig from PyQt6.QtCore import QObject, QProcess from eric7 import Preferences +from eric7.EricWidgets import EricMessageBox from eric7.SystemUtilities import OSUtilities from .PipxExecDialog import PipxExecDialog @@ -166,6 +166,43 @@ return jsonDict ############################################################################ + ## pipx interpreter list function (modified from original to work here) + ############################################################################ + + def getPipxInterpretersList(self): + """ + Public method returning a list all standalone interpreters. + + @return dictionary containing data of standalone interpreters + @rtype dict + """ + from pipx.commands.interpreter import ( + get_installed_standalone_interpreters, + get_venvs_using_standalone_interpreter, + get_interpreter_users, + ) + from pipx.paths import ctx + from pipx.venv import VenvContainer + + interpreters = get_installed_standalone_interpreters() + venvs = get_venvs_using_standalone_interpreter(VenvContainer(ctx.venvs)) + + interpretersDict = { + "path": str(ctx.standalone_python_cachedir), + "interpreters": {}, + } + for interpreter in interpreters: + usedBy = get_interpreter_users(interpreter, venvs) + interpretersDict["interpreters"][interpreter.name] = { + "used": bool(usedBy), + "used_by": [ + (p.main_package.package, p.main_package.package_version) + for p in usedBy + ], + } + return interpretersDict + + ############################################################################ ## Command methods ############################################################################ @@ -176,6 +213,8 @@ @return list of dictionaries containing the installed packages and apps @rtype list of dict[str, str | list] """ + from pipx.paths import ctx + packages = [] ok, output = self.runPipxProcess(["list", "--json"]) @@ -190,6 +229,13 @@ "version": metadata["main_package"]["package_version"], "apps": [], "python": metadata["python_version"], + "is_standalone": ( + str(metadata["source_interpreter"]).startswith( + str(ctx.standalone_python_cachedir.resolve()) + ) + if metadata["source_interpreter"] + else False + ), } for appPath in metadata["main_package"]["app_paths"]: package["apps"].append((appPath.name, str(appPath))) @@ -203,7 +249,7 @@ interpreterVersion="", fetchMissingInterpreter=False, forceVenvModification=False, - systemSitePackages=False + systemSitePackages=False, ): """ Public method to install a list of packages with the given options. @@ -247,7 +293,7 @@ interpreterVersion="", fetchMissingInterpreter=False, forceVenvModification=False, - systemSitePackages=False + systemSitePackages=False, ): """ Public method to install all packages define by a given spec metadata file @@ -391,3 +437,100 @@ res = dia.startProcess(self.__getPipxExecutable(), args) if res: dia.exec() + + def checkPackageOutdated(self, package): + """ + Public method to check, if a given package is outdated. + + @param package name of the package + @type str + @return latest version in case the package is outdated and None otherwise + @rtype str or None + """ + args = ["runpip", package, "list", "--outdated", "--format", "json"] + if Preferences.getPip("PipSearchIndex"): + indexUrl = Preferences.getPip("PipSearchIndex") + "/simple" + args += ["--index-url", indexUrl] + ok, output = self.runPipxProcess(args) + if not ok: + EricMessageBox.information( + None, + self.tr("Check Outdated Package"), + self.tr( + "<p>The status of package <b>{0}</b> could not be determined.</p>" + "<p>Reason: {1}</p>" + ).format(package, output), + ) + return None + + outdatedList = json.loads(output) + # check if the main package is in the list + for outdatedPackage in outdatedList: + if outdatedPackage["name"] == package: + return outdatedPackage["latest_version"] + + return None + + def upgradePackage(self, package): + """ + Public method to upgrade the given package. + + @param package name of the package + @type str + """ + args = ["upgrade"] + if Preferences.getPip("PipSearchIndex"): + indexUrl = Preferences.getPip("PipSearchIndex") + "/simple" + args += ["--index-url", indexUrl] + args.append(package) + dia = PipxExecDialog(self.tr("Upgrade Package")) + res = dia.startProcess(self.__getPipxExecutable(), args) + if res: + dia.exec() + + def upgradeAllPackages(self): + """ + Public method to upgrade all package. + """ + args = ["upgrade-all"] + dia = PipxExecDialog(self.tr("Upgrade All Packages")) + res = dia.startProcess(self.__getPipxExecutable(), args) + if res: + dia.exec() + + def upgradeSharedLibraries(self): + """ + Public method to upgrade shared libraries. + """ + args = ["upgrade-shared"] + dia = PipxExecDialog(self.tr("Upgrade Shared Libraries")) + res = dia.startProcess(self.__getPipxExecutable(), args) + if res: + dia.exec() + + def upgradeInterpreters(self, dialogParent=None): + """ + Public method to upgrade the installed interpreters to the latest available + micro/patch version + + @param dialogParent parent widget of the execution dialog + @type QWidget + """ + args = ["interpreter", "upgrade"] + dia = PipxExecDialog(self.tr("Upgrade Interpreters"), parent=dialogParent) + res = dia.startProcess(self.__getPipxExecutable(), args) + if res: + dia.exec() + + def pruneInterpreters(self, dialogParent=None): + """ + Public method to prune unused interpreters. + + @param dialogParent parent widget of the execution dialog + @type QWidget + """ + args = ["interpreter", "prune"] + dia = PipxExecDialog(self.tr("Prune Unused Interpreters"), parent=dialogParent) + res = dia.startProcess(self.__getPipxExecutable(), args) + if res: + dia.exec()