src/eric7/VirtualEnv/VirtualenvManager.py

branch
eric7
changeset 10194
2c26b4fe25db
parent 9653
e67609152c5e
child 10195
d763674ac9a3
--- a/src/eric7/VirtualEnv/VirtualenvManager.py	Tue Sep 05 14:17:29 2023 +0200
+++ b/src/eric7/VirtualEnv/VirtualenvManager.py	Wed Sep 06 10:28:50 2023 +0200
@@ -22,6 +22,8 @@
 from eric7.SystemUtilities import FileSystemUtilities, PythonUtilities
 from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
 
+from .VirtualenvMeta import VirtualenvMetaData
+
 
 class VirtualenvManager(QObject):
     """
@@ -85,27 +87,17 @@
         #                   setting
         #   description     a description of the environment
         #
-        envsToDelete = []
         for venvName in environments:
             environment = environments[venvName]
+            environment["name"] = venvName
             if ("is_remote" in environment and environment["is_remote"]) or os.access(
                 environment["interpreter"], os.X_OK
             ):
                 if "is_global" not in environment:
                     environment["is_global"] = environment["path"] == ""
-                if "is_conda" not in environment:
-                    environment["is_conda"] = False
-                if "is_remote" not in environment:
-                    environment["is_remote"] = False
-                if "exec_path" not in environment:
-                    environment["exec_path"] = ""
-                if "description" not in environment:
-                    environment["description"] = ""
-                self.__virtualEnvironments[venvName] = environment
-
-        # now remove unsupported environments
-        for venvName in envsToDelete:
-            del environments[venvName]
+                self.__virtualEnvironments[venvName] = VirtualenvMetaData.from_dict(
+                    environment
+                )
 
         # check, if the interpreter used to run eric is in the environments
         defaultPy = PythonUtilities.getPythonExecutable()
@@ -120,16 +112,13 @@
                     break
             if not found:
                 # add an environment entry for the default interpreter
-                self.__virtualEnvironments[VirtualenvManager.DefaultKey] = {
-                    "path": "",
-                    "interpreter": defaultPy,
-                    "variant": 3,
-                    "is_global": True,
-                    "is_conda": False,
-                    "is_remote": False,
-                    "exec_path": "",
-                    "description": "",
-                }
+                self.__virtualEnvironments[
+                    VirtualenvManager.DefaultKey
+                ] = VirtualenvMetaData(
+                    name=VirtualenvManager.DefaultKey,
+                    interpreter=defaultPy,
+                    is_globa=True,
+                )
 
         self.__saveSettings()
 
@@ -142,7 +131,10 @@
         )
 
         Preferences.getSettings().setValue(
-            "PyVenv/VirtualEnvironments", json.dumps(self.__virtualEnvironments)
+            "PyVenv/VirtualEnvironments",
+            json.dumps(
+                {env.name: env.as_dict() for env in self.__virtualEnvironments.values()}
+            ),
         )
         Preferences.syncPreferences()
 
@@ -162,9 +154,9 @@
         having an interpreter matching sys.executable (i.e. the one used to
         execute eric with)
 
-        @return tuple containing the environment name and a dictionary
-            containing a copy of the default virtual environment
-        @rtype tuple of (str, dict)
+        @return tuple containing the environment name and a copy of the metadata
+            of the default virtual environment
+        @rtype tuple of (str, VirtualenvMetaData)
         """
         if VirtualenvManager.DefaultKey in self.__virtualEnvironments:
             return (
@@ -181,14 +173,14 @@
 
         @param interpreter path of the interpreter
         @type str
-        @return tuple containing the environment name and a dictionary
-            containing a copy of the default virtual environment
-        @rtype tuple of (str, dict)
+        @return tuple containing the environment name and a copy of the metadata
+            of the virtual environment the interpreter belongs to
+        @rtype tuple of (str, VirtualenvMetaData)
         """
         py = FileSystemUtilities.normcaseabspath(interpreter.replace("w.exe", ".exe"))
         for venvName in self.__virtualEnvironments:
             if py == FileSystemUtilities.normcaseabspath(
-                self.__virtualEnvironments[venvName]["interpreter"]
+                self.__virtualEnvironments[venvName].interpreter
             ):
                 return (venvName, copy.copy(self.__virtualEnvironments[venvName]))
 
@@ -223,10 +215,12 @@
                 )
                 if ok and "--dry-run" not in resultDict["arguments"]:
                     self.addVirtualEnv(
-                        resultDict["logicalName"],
-                        prefix,
-                        venvInterpreter=interpreter,
-                        isConda=True,
+                        VirtualenvMetaData(
+                            name=resultDict["logicalName"],
+                            path=prefix,
+                            interpreter=interpreter,
+                            is_conda=True,
+                        )
                     )
             else:
                 # now do the call
@@ -262,155 +256,78 @@
             dia.start(args)
             dia.exec()
 
-    def addVirtualEnv(
-        self,
-        venvName,
-        venvDirectory,
-        venvInterpreter="",
-        isGlobal=False,
-        isConda=False,
-        isRemote=False,
-        execPath="",
-        description="",
-    ):
+    def addVirtualEnv(self, metadata):
         """
         Public method to add a virtual environment.
 
-        @param venvName logical name for the virtual environment
-        @type str
-        @param venvDirectory directory of the virtual environment
-        @type str
-        @param venvInterpreter interpreter of the virtual environment
-        @type str
-        @param isGlobal flag indicating a global environment
-        @type bool
-        @param isConda flag indicating an Anaconda virtual environment
-        @type bool
-        @param isRemote flag indicating a remotely accessed environment
-        @type bool
-        @param execPath search path string to be prepended to the PATH
-            environment variable
-        @type str
-        @param description descriptive text for the environment
-        @type str
+        @param metadata object containing the metadata of the virtual environment
+        @type VirtualenvMetaData
         """
         from .VirtualenvInterpreterSelectionDialog import (
             VirtualenvInterpreterSelectionDialog,
         )
         from .VirtualenvNameDialog import VirtualenvNameDialog
 
-        if venvName in self.__virtualEnvironments:
+        if metadata.name in self.__virtualEnvironments:
             ok = EricMessageBox.yesNo(
                 None,
                 self.tr("Add Virtual Environment"),
                 self.tr(
                     """A virtual environment named <b>{0}</b> exists"""
                     """ already. Shall it be replaced?"""
-                ).format(venvName),
+                ).format(metadata.name),
                 icon=EricMessageBox.Warning,
             )
             if not ok:
                 dlg = VirtualenvNameDialog(
-                    list(self.__virtualEnvironments.keys()), venvName
+                    list(self.__virtualEnvironments.keys()), metadata.name
                 )
                 if dlg.exec() != QDialog.DialogCode.Accepted:
                     return
 
-                venvName = dlg.getName()
-
-        if not venvInterpreter:
-            dlg = VirtualenvInterpreterSelectionDialog(venvName, venvDirectory)
-            if dlg.exec() == QDialog.DialogCode.Accepted:
-                venvInterpreter = dlg.getData()
+                metadata.name = dlg.getName()
 
-        if venvInterpreter:
-            self.__virtualEnvironments[venvName] = {
-                "path": venvDirectory,
-                "interpreter": venvInterpreter,
-                "variant": 3,  # always 3
-                "is_global": isGlobal,
-                "is_conda": isConda,
-                "is_remote": isRemote,
-                "exec_path": execPath,
-                "description": description,
-            }
+        if not metadata.interpreter:
+            dlg = VirtualenvInterpreterSelectionDialog(metadata.name, metadata.path)
+            if dlg.exec() == QDialog.DialogCode.Accepted:
+                metadata.interpreter = dlg.getData()
 
+        if metadata.interpreter:
+            self.__virtualEnvironments[metadata.name] = metadata
             self.__saveSettings()
 
             self.virtualEnvironmentAdded.emit()
             self.virtualEnvironmentsListChanged.emit()
 
-    def setVirtualEnv(
-        self,
-        venvName,
-        venvDirectory,
-        venvInterpreter,
-        isGlobal,
-        isConda,
-        isRemote,
-        execPath,
-        description,
-    ):
+    def setVirtualEnv(self, metadata):
         """
         Public method to change a virtual environment.
 
-        @param venvName logical name of the virtual environment
-        @type str
-        @param venvDirectory directory of the virtual environment
-        @type str
-        @param venvInterpreter interpreter of the virtual environment
-        @type str
-        @param isGlobal flag indicating a global environment
-        @type bool
-        @param isConda flag indicating an Anaconda virtual environment
-        @type bool
-        @param isRemote flag indicating a remotely accessed environment
-        @type bool
-        @param execPath search path string to be prepended to the PATH
-            environment variable
-        @type str
-        @param description descriptive text for the environment
-        @type str
+        @param metadata object containing the metadata of the virtual environment
+        @type VirtualenvMetaData
         """
-        if venvName not in self.__virtualEnvironments:
+        if metadata.name not in self.__virtualEnvironments:
             EricMessageBox.yesNo(
                 None,
                 self.tr("Change Virtual Environment"),
                 self.tr(
                     """A virtual environment named <b>{0}</b> does not"""
                     """ exist. Aborting!"""
-                ).format(venvName),
+                ).format(metadata.name),
                 icon=EricMessageBox.Warning,
             )
             return
 
-        self.__virtualEnvironments[venvName] = {
-            "path": venvDirectory,
-            "interpreter": venvInterpreter,
-            "variant": 3,  # always 3
-            "is_global": isGlobal,
-            "is_conda": isConda,
-            "is_remote": isRemote,
-            "exec_path": execPath,
-            "description": description,
-        }
-
+        self.__virtualEnvironments[metadata.name] = metadata
         self.__saveSettings()
 
-        self.virtualEnvironmentChanged.emit(venvName)
+        self.virtualEnvironmentChanged.emit(metadata.name)
         self.virtualEnvironmentsListChanged.emit()
 
     def renameVirtualEnv(
         self,
         oldVenvName,
-        venvName,
-        venvDirectory,
-        venvInterpreter,
-        isGlobal,
-        isConda,
-        isRemote,
-        execPath,
-        description,
+        metadata,
     ):
         """
         Public method to substitute a virtual environment entry with a new
@@ -418,23 +335,8 @@
 
         @param oldVenvName old name of the virtual environment
         @type str
-        @param venvName logical name for the virtual environment
-        @type str
-        @param venvDirectory directory of the virtual environment
-        @type str
-        @param venvInterpreter interpreter of the virtual environment
-        @type str
-        @param isGlobal flag indicating a global environment
-        @type bool
-        @param isConda flag indicating an Anaconda virtual environment
-        @type bool
-        @param isRemote flag indicating a remotely accessed environment
-        @type bool
-        @param execPath search path string to be prepended to the PATH
-            environment variable
-        @type str
-        @param description descriptive text for the environment
-        @type str
+        @param metadata object containing the metadata of the virtual environment
+        @type VirtualenvMetaData
         """
         if oldVenvName not in self.__virtualEnvironments:
             EricMessageBox.yesNo(
@@ -449,16 +351,7 @@
             return
 
         del self.__virtualEnvironments[oldVenvName]
-        self.addVirtualEnv(
-            venvName,
-            venvDirectory,
-            venvInterpreter=venvInterpreter,
-            isGlobal=isGlobal,
-            isConda=isConda,
-            isRemote=isRemote,
-            execPath=execPath,
-            description=description,
-        )
+        self.addVirtualEnv(metadata)
 
     def deleteVirtualEnvs(self, venvNames):
         """
@@ -470,11 +363,11 @@
         venvMessages = []
         for venvName in venvNames:
             if venvName in self.__virtualEnvironments and bool(
-                self.__virtualEnvironments[venvName]["path"]
+                self.__virtualEnvironments[venvName].path
             ):
                 venvMessages.append(
                     self.tr("{0} - {1}").format(
-                        venvName, self.__virtualEnvironments[venvName]["path"]
+                        venvName, self.__virtualEnvironments[venvName].path
                     )
                 )
         if venvMessages:
@@ -492,13 +385,13 @@
                     if self.__isEnvironmentDeleteable(venvName):
                         if self.isCondaEnvironment(venvName):
                             conda = ericApp().getObject("Conda")
-                            path = self.__virtualEnvironments[venvName]["path"]
+                            path = self.__virtualEnvironments[venvName].path
                             res = conda.removeCondaEnvironment(prefix=path)
                             if res:
                                 del self.__virtualEnvironments[venvName]
                         else:
                             shutil.rmtree(
-                                self.__virtualEnvironments[venvName]["path"], True
+                                self.__virtualEnvironments[venvName].path, True
                             )
                             del self.__virtualEnvironments[venvName]
 
@@ -520,10 +413,10 @@
         ok = False
         if venvName in self.__virtualEnvironments:
             ok = True
-            ok &= bool(self.__virtualEnvironments[venvName]["path"])
-            ok &= not self.__virtualEnvironments[venvName]["is_global"]
-            ok &= not self.__virtualEnvironments[venvName]["is_remote"]
-            ok &= os.access(self.__virtualEnvironments[venvName]["path"], os.W_OK)
+            ok &= bool(self.__virtualEnvironments[venvName].path)
+            ok &= not self.__virtualEnvironments[venvName].is_global
+            ok &= not self.__virtualEnvironments[venvName].is_remote
+            ok &= os.access(self.__virtualEnvironments[venvName].path, os.W_OK)
 
         return ok
 
@@ -539,7 +432,7 @@
             if venvName in self.__virtualEnvironments:
                 venvMessages.append(
                     self.tr("{0} - {1}").format(
-                        venvName, self.__virtualEnvironments[venvName]["path"]
+                        venvName, self.__virtualEnvironments[venvName].path
                     )
                 )
         if venvMessages:
@@ -564,14 +457,12 @@
 
     def getEnvironmentEntries(self):
         """
-        Public method to get a dictionary containing the defined virtual
-        environment entries.
+        Public method to get a list of the defined virtual environment entries.
 
-        @return dictionary containing a copy of the defined virtual
-            environments
-        @rtype dict
+        @return list containing a copy of the defined virtual environments
+        @rtype list
         """
-        return copy.deepcopy(self.__virtualEnvironments)
+        return [copy.copy(env) for env in self.__virtualEnvironments.values()]
 
     @pyqtSlot()
     def showVirtualenvManagerDialog(self, modal=False):
@@ -611,7 +502,7 @@
         @rtype str
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["interpreter"].replace(
+            return self.__virtualEnvironments[venvName].interpreter.replace(
                 "w.exe", ".exe"
             )
         elif venvName == VirtualenvManager.SystemKey:
@@ -629,7 +520,7 @@
         @type str
         """
         if venvName in self.__virtualEnvironments:
-            self.__virtualEnvironments[venvName]["interpreter"] = venvInterpreter
+            self.__virtualEnvironments[venvName].interpreter = venvInterpreter
             self.__saveSettings()
 
             self.virtualEnvironmentChanged.emit(venvName)
@@ -645,7 +536,7 @@
         @rtype str
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["path"]
+            return self.__virtualEnvironments[venvName].path
         else:
             return ""
 
@@ -683,7 +574,7 @@
         @rtype bool
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["is_global"]
+            return self.__virtualEnvironments[venvName].is_global
         else:
             return False
 
@@ -698,7 +589,7 @@
         @rtype bool
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["is_conda"]
+            return self.__virtualEnvironments[venvName].is_conda
         else:
             return False
 
@@ -713,7 +604,7 @@
         @rtype bool
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["is_remote"]
+            return self.__virtualEnvironments[venvName].is_remote
         else:
             return False
 
@@ -727,7 +618,7 @@
         @rtype str
         """
         if venvName in self.__virtualEnvironments:
-            return self.__virtualEnvironments[venvName]["exec_path"]
+            return self.__virtualEnvironments[venvName].exec_path
         else:
             return ""
 

eric ide

mercurial