PipxInterface/Pipx.py

changeset 2
26430067aa09
child 8
02b45cd11e64
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PipxInterface/Pipx.py	Mon Jun 24 17:13:07 2024 +0200
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the pipx GUI logic.
+"""
+
+import contextlib
+import json
+import os
+import sys
+import sysconfig
+
+from PyQt6.QtCore import QObject, QProcess
+
+from eric7 import Preferences
+from eric7.SystemUtilities import OSUtilities
+
+
+class Pipx(QObject):
+    """
+    Class implementing the pip GUI logic.
+    """
+
+    def __init__(self, parent=None):
+        """
+        Constructor
+
+        @param parent reference to the user interface object
+        @type QObject
+        """
+        super().__init__(parent)
+
+        self.__ui = parent
+
+    ############################################################################
+    ## Utility methods
+    ############################################################################
+
+    def getPipxVersion(self):
+        """
+        Public method to get the version of the installed pipx package.
+
+        @return string containing the pipx version number
+        @rtype str
+        """
+        from pipx.version import version
+
+        return version
+
+    def getPipxVersionTuple(self):
+        """
+        Public method to get the version tuple of the installed pipx package.
+
+        @return tuple containing the elements of the pipx version number
+        @rtype tuple of (int, int, int)
+        """
+        from pipx.version import version_tuple
+
+        return version_tuple
+
+    def getPipxPaths(self):
+        """
+        Public method to get the paths used by pipx.
+
+        @return dictionary containing the various pipx paths. The keys are
+            'venvsPath', 'appsPath' and 'manPath'.
+        @rtype dict[str, Path]
+        """
+        from pipx.paths import ctx
+
+        return {
+            "venvsPath": ctx.venvs,
+            "appsPath": ctx.bin_dir,
+            "manPath": ctx.man_dir,
+        }
+
+    def getPipxStrPaths(self):
+        """
+        Public method to get the paths used by pipx.
+
+        @return dictionary containing the various pipx paths. The keys are
+            'venvsPath', 'appsPath' and 'manPath'.
+        @rtype dict[str, str]
+        """
+        from pipx.paths import ctx
+
+        return {
+            "venvsPath": str(ctx.venvs),
+            "appsPath": str(ctx.bin_dir),
+            "manPath": str(ctx.man_dir),
+        }
+
+    def __getPipxExecutable(self):
+        """
+        Private method to get the path name of the pipx executable.
+
+        @return path name of the pipx executable
+        @rtype str
+        """
+        binDir = sysconfig.get_path("scripts")
+        pipx = os.path.join(binDir, "pipx")
+        if OSUtilities.isWindowsPlatform:
+            pipx += ".exe"
+
+        return pipx
+
+    def runProcess(self, args):
+        """
+        Public method to execute pipx with the given arguments.
+
+        @param args list of command line arguments for pipx
+        @type list of str
+        @return tuple containing a flag indicating success and the output
+            of the process
+        @rtype tuple of (bool, str)
+        """
+        ioEncoding = Preferences.getSystem("IOEncoding")
+
+        process = QProcess()
+        process.start(sys.executable, ["-m", "pipx"] + args)
+        procStarted = process.waitForStarted()
+        if procStarted:
+            finished = process.waitForFinished(30000)
+            if finished:
+                if process.exitCode() == 0:
+                    output = str(process.readAllStandardOutput(), ioEncoding, "replace")
+                    return True, output
+                else:
+                    error = str(process.readAllStandardError(), ioEncoding, "replace")
+                    msg = self.tr("<p>Message:{0}</p>").format(error) if error else ""
+                    return (
+                        False,
+                        self.tr("<p>pipx exited with an error ({0}).</p>{1}").format(
+                            process.exitCode(), msg
+                        ),
+                    )
+            else:
+                process.terminate()
+                process.waitForFinished(2000)
+                process.kill()
+                process.waitForFinished(3000)
+                return False, self.tr("pipx did not finish within 30 seconds.")
+
+        return False, self.tr("pipx could not be started.")
+
+    ############################################################################
+    ## Command methods
+    ############################################################################
+
+    def getInstalledPackages(self):
+        """
+        Public method to get the installed packages.
+
+        @return list of dictionaries containing the installed packages and apps
+        @rtype list of dict[str, str | list]
+        """
+        packages = []
+
+        ok, output = self.runProcess(["list", "--json"])
+        if ok:
+            if output:
+                with contextlib.suppress(json.JSONDecodeError):
+                    data = json.loads(output)
+                    for venvName in data["venvs"]:
+                        metadata = data["venvs"][venvName]["metadata"]
+                        package = {
+                            "name": venvName,
+                            "version": metadata["main_package"]["package_version"],
+                            "apps": [],
+                            "python": metadata["python_version"],
+                        }
+                        for appPath in metadata["main_package"]["app_paths"]:
+                            path = appPath["__Path__"]
+                            package["apps"].append((os.path.basename(path), path))
+                        packages.append(package)
+
+        return packages

eric ide

mercurial