--- a/src/eric7/VirtualEnv/VirtualenvManager.py Tue May 13 16:46:34 2025 +0200 +++ b/src/eric7/VirtualEnv/VirtualenvManager.py Wed May 14 18:18:06 2025 +0200 @@ -137,6 +137,7 @@ ) self.__cleanEnvironments() + self.__checkEnvironmentInterpretersExist() self.__saveSettings() @@ -194,11 +195,51 @@ if not os.path.exists(venvPath): del self.__virtualEnvironments[venvName] removed = True + if removed: - self.__saveSettings() self.virtualEnvironmentRemoved.emit() self.virtualEnvironmentsListChanged.emit() + def __checkEnvironmentInterpretersExist(self): + """ + Private method to set all environments with non-existent interpreters to + the disabled state. + """ + changed = False + + for venvName in self.__virtualEnvironments: + venvItem = self.__virtualEnvironments[venvName] + if venvItem.environment_type != "remote": + venvInterpreter = venvItem.interpreter + if venvInterpreter: + if venvItem.environment_type == "eric_server": + with contextlib.suppress(KeyError): + # It is an eric-ide server environment; check it has + # an existing interpreter. + ericServer = ericApp().getObject("EricServer") + if ( + ericServer.isServerConnected() + and ericServer.getHost() == venvItem.eric_server + and not ericServer.getServiceInterface( + "FileSystem" + ).exists(venvInterpreter) + ): + venvItem.available = False + changed = True + else: + # It is a local environment; check it has an existing + # interpreter. + if not os.path.exists(venvInterpreter): + venvItem.available = False + changed = True + else: + # no interpreter defined + venvItem.available = False + changed = True + + if changed: + self.virtualEnvironmentsListChanged.emit() + def getDefaultEnvironment(self): """ Public method to get the default virtual environment. @@ -232,8 +273,12 @@ """ py = FileSystemUtilities.normcaseabspath(interpreter.replace("w.exe", ".exe")) for venvName in self.__virtualEnvironments: - if py == FileSystemUtilities.normcaseabspath( - self.__virtualEnvironments[venvName].interpreter + if ( + py + == FileSystemUtilities.normcaseabspath( + self.__virtualEnvironments[venvName].interpreter + ) + and self.__virtualEnvironments[venvName].available ): return (venvName, copy.copy(self.__virtualEnvironments[venvName])) @@ -606,7 +651,10 @@ @return interpreter path @rtype str """ - if venvName in self.__virtualEnvironments: + if ( + venvName in self.__virtualEnvironments + and self.__virtualEnvironments[venvName].available + ): return self.__virtualEnvironments[venvName].interpreter.replace( "w.exe", ".exe" ) @@ -626,6 +674,9 @@ """ if venvName in self.__virtualEnvironments: self.__virtualEnvironments[venvName].interpreter = venvInterpreter + self.__virtualEnvironments[venvName].available = os.path.exists( + venvInterpreter + ) self.__saveSettings() self.virtualEnvironmentChanged.emit(venvName) @@ -659,7 +710,11 @@ @return list of defined virtual environments @rtype list of str """ - environments = list(self.__virtualEnvironments) + environments = [ + name + for name in self.__virtualEnvironments + if self.isAvailableEnvironment(name) + ] if noGlobals: environments = [ name for name in environments if not self.isGlobalEnvironment(name) @@ -684,6 +739,20 @@ return environments + def isAvailableEnvironment(self, venvName): + """ + Public method to test, if a given environment is available. + + @param venvName logical name of the virtual environment + @type str + @return flag indicating an available environment + @rtype bool + """ + try: + return self.__virtualEnvironments[venvName].available + except KeyError: + return False + def isGlobalEnvironment(self, venvName): """ Public method to test, if a given environment is a global one.