eric6/PluginManager/PluginManager.py

changeset 7255
d595f6f9cbf8
parent 7229
53054eb5b15a
child 7360
9190402e4505
equal deleted inserted replaced
7254:f00d825fbdb3 7255:d595f6f9cbf8
10 import os 10 import os
11 import sys 11 import sys
12 import imp 12 import imp
13 import zipfile 13 import zipfile
14 14
15 from PyQt5.QtCore import pyqtSignal, QObject, QDate, QFile, QFileInfo, QUrl, \ 15 from PyQt5.QtCore import (
16 QIODevice 16 pyqtSignal, QObject, QDate, QFile, QFileInfo, QUrl, QIODevice
17 )
17 from PyQt5.QtGui import QPixmap 18 from PyQt5.QtGui import QPixmap
18 from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, \ 19 from PyQt5.QtNetwork import (
19 QNetworkReply 20 QNetworkAccessManager, QNetworkRequest, QNetworkReply
21 )
20 22
21 from E5Gui import E5MessageBox 23 from E5Gui import E5MessageBox
22 from E5Gui.E5Application import e5App 24 from E5Gui.E5Application import e5App
23 25
24 from E5Network.E5NetworkProxyFactory import proxyAuthenticationRequired 26 from E5Network.E5NetworkProxyFactory import proxyAuthenticationRequired
26 from E5Network.E5SslErrorHandler import E5SslErrorHandler 28 from E5Network.E5SslErrorHandler import E5SslErrorHandler
27 SSL_AVAILABLE = True 29 SSL_AVAILABLE = True
28 except ImportError: 30 except ImportError:
29 SSL_AVAILABLE = False 31 SSL_AVAILABLE = False
30 32
31 from .PluginExceptions import PluginPathError, PluginModulesError, \ 33 from .PluginExceptions import (
32 PluginLoadError, PluginActivationError, PluginModuleFormatError, \ 34 PluginPathError, PluginModulesError, PluginLoadError,
33 PluginClassFormatError 35 PluginActivationError, PluginModuleFormatError, PluginClassFormatError
36 )
34 37
35 import UI.PixmapCache 38 import UI.PixmapCache
36 39
37 import Globals 40 import Globals
38 import Utilities 41 import Utilities
142 145
143 self.__loadPlugins() 146 self.__loadPlugins()
144 147
145 self.__checkPluginsDownloadDirectory() 148 self.__checkPluginsDownloadDirectory()
146 149
147 self.pluginRepositoryFile = \ 150 self.pluginRepositoryFile = os.path.join(Utilities.getConfigDir(),
148 os.path.join(Utilities.getConfigDir(), "PluginRepository") 151 "PluginRepository")
149 152
150 # attributes for the network objects 153 # attributes for the network objects
151 self.__networkManager = QNetworkAccessManager(self) 154 self.__networkManager = QNetworkAccessManager(self)
152 self.__networkManager.proxyAuthenticationRequired.connect( 155 self.__networkManager.proxyAuthenticationRequired.connect(
153 proxyAuthenticationRequired) 156 proxyAuthenticationRequired)
164 167
165 def finalizeSetup(self): 168 def finalizeSetup(self):
166 """ 169 """
167 Public method to finalize the setup of the plugin manager. 170 Public method to finalize the setup of the plugin manager.
168 """ 171 """
169 for module in list(self.__onDemandInactiveModules.values()) + \ 172 for module in (
170 list(self.__onDemandActiveModules.values()): 173 list(self.__onDemandInactiveModules.values()) +
174 list(self.__onDemandActiveModules.values())
175 ):
171 if hasattr(module, "moduleSetup"): 176 if hasattr(module, "moduleSetup"):
172 module.moduleSetup() 177 module.moduleSetup()
173 178
174 def getPluginDir(self, key): 179 def getPluginDir(self, key):
175 """ 180 """
216 f = open(fname, "w") 221 f = open(fname, "w")
217 f.close() 222 f.close()
218 except IOError: 223 except IOError:
219 del self.pluginDirs["user"] 224 del self.pluginDirs["user"]
220 225
221 if not os.path.exists(self.pluginDirs["global"]) and \ 226 if (
222 os.access(Utilities.getPythonModulesDirectory(), os.W_OK): 227 not os.path.exists(self.pluginDirs["global"]) and
228 os.access(Utilities.getPythonModulesDirectory(), os.W_OK)
229 ):
223 # create the global plugins directory 230 # create the global plugins directory
224 os.mkdir(self.pluginDirs["global"], 0o755) 231 os.mkdir(self.pluginDirs["global"], 0o755)
225 fname = os.path.join(self.pluginDirs["global"], "__init__.py") 232 fname = os.path.join(self.pluginDirs["global"], "__init__.py")
226 f = open(fname, "w", encoding="utf-8") 233 f = open(fname, "w", encoding="utf-8")
227 f.write('# -*- coding: utf-8 -*-' + "\n") 234 f.write('# -*- coding: utf-8 -*-' + "\n")
246 """ 253 """
247 Private method to check, if there are plugins available. 254 Private method to check, if there are plugins available.
248 255
249 @return flag indicating the availability of plugins (boolean) 256 @return flag indicating the availability of plugins (boolean)
250 """ 257 """
251 if self.__develPluginFile and \ 258 if (
252 not os.path.exists(self.__develPluginFile): 259 self.__develPluginFile and
260 not os.path.exists(self.__develPluginFile)
261 ):
253 return False 262 return False
254 263
255 self.__foundCoreModules = self.getPluginModules( 264 self.__foundCoreModules = self.getPluginModules(
256 self.pluginDirs["eric6"]) 265 self.pluginDirs["eric6"])
257 if Preferences.getPluginManager("ActivateExternal"): 266 if Preferences.getPluginManager("ActivateExternal"):
258 if "global" in self.pluginDirs: 267 if "global" in self.pluginDirs:
259 self.__foundGlobalModules = \ 268 self.__foundGlobalModules = self.getPluginModules(
260 self.getPluginModules(self.pluginDirs["global"]) 269 self.pluginDirs["global"])
261 if "user" in self.pluginDirs: 270 if "user" in self.pluginDirs:
262 self.__foundUserModules = \ 271 self.__foundUserModules = self.getPluginModules(
263 self.getPluginModules(self.pluginDirs["user"]) 272 self.pluginDirs["user"])
264 273
265 return len(self.__foundCoreModules + self.__foundGlobalModules + 274 return len(self.__foundCoreModules + self.__foundGlobalModules +
266 self.__foundUserModules) > 0 275 self.__foundUserModules) > 0
267 276
268 def getPluginModules(self, pluginPath): 277 def getPluginModules(self, pluginPath):
307 """ 316 """
308 Private method to load the plugins found. 317 Private method to load the plugins found.
309 """ 318 """
310 develPluginName = "" 319 develPluginName = ""
311 if self.__develPluginFile: 320 if self.__develPluginFile:
312 develPluginPath, develPluginName = \ 321 develPluginPath, develPluginName = Utilities.splitPath(
313 Utilities.splitPath(self.__develPluginFile) 322 self.__develPluginFile)
314 if self.isValidPluginName(develPluginName): 323 if self.isValidPluginName(develPluginName):
315 develPluginName = develPluginName[:-3] 324 develPluginName = develPluginName[:-3]
316 325
317 for pluginName in self.__foundGlobalModules: 326 for pluginName in self.__foundGlobalModules:
318 # user and core plug-ins have priority 327 # user and core plug-ins have priority
319 if pluginName not in self.__foundUserModules and \ 328 if (
320 pluginName not in self.__foundCoreModules and \ 329 pluginName not in self.__foundUserModules and
321 pluginName != develPluginName: 330 pluginName not in self.__foundCoreModules and
331 pluginName != develPluginName
332 ):
322 self.loadPlugin(pluginName, self.pluginDirs["global"]) 333 self.loadPlugin(pluginName, self.pluginDirs["global"])
323 334
324 for pluginName in self.__foundUserModules: 335 for pluginName in self.__foundUserModules:
325 # core plug-ins have priority 336 # core plug-ins have priority
326 if pluginName not in self.__foundCoreModules and \ 337 if (
327 pluginName != develPluginName: 338 pluginName not in self.__foundCoreModules and
339 pluginName != develPluginName
340 ):
328 self.loadPlugin(pluginName, self.pluginDirs["user"]) 341 self.loadPlugin(pluginName, self.pluginDirs["user"])
329 342
330 for pluginName in self.__foundCoreModules: 343 for pluginName in self.__foundCoreModules:
331 # plug-in under development has priority 344 # plug-in under development has priority
332 if pluginName != develPluginName: 345 if pluginName != develPluginName:
348 361
349 self.__insertPluginsPaths() 362 self.__insertPluginsPaths()
350 363
351 for pluginName in self.__foundGlobalModules: 364 for pluginName in self.__foundGlobalModules:
352 # user and core plug-ins have priority 365 # user and core plug-ins have priority
353 if pluginName not in self.__foundUserModules and \ 366 if (
354 pluginName not in self.__foundCoreModules and \ 367 pluginName not in self.__foundUserModules and
355 pluginName.startswith("PluginDocumentationSets"): 368 pluginName not in self.__foundCoreModules and
369 pluginName.startswith("PluginDocumentationSets")
370 ):
356 self.loadPlugin(pluginName, self.pluginDirs["global"]) 371 self.loadPlugin(pluginName, self.pluginDirs["global"])
357 372
358 for pluginName in self.__foundUserModules: 373 for pluginName in self.__foundUserModules:
359 # core plug-ins have priority 374 # core plug-ins have priority
360 if pluginName not in self.__foundCoreModules and \ 375 if (
361 pluginName.startswith("PluginDocumentationSets"): 376 pluginName not in self.__foundCoreModules and
377 pluginName.startswith("PluginDocumentationSets")
378 ):
362 self.loadPlugin(pluginName, self.pluginDirs["user"]) 379 self.loadPlugin(pluginName, self.pluginDirs["user"])
363 380
364 for pluginName in self.__foundCoreModules: 381 for pluginName in self.__foundCoreModules:
365 # plug-in under development has priority 382 # plug-in under development has priority
366 if pluginName.startswith("PluginDocumentationSets"): 383 if pluginName.startswith("PluginDocumentationSets"):
390 self.__failedModules[name] = module 407 self.__failedModules[name] = module
391 raise PluginLoadError(name) 408 raise PluginLoadError(name)
392 if getattr(module, "autoactivate", False): 409 if getattr(module, "autoactivate", False):
393 self.__inactiveModules[name] = module 410 self.__inactiveModules[name] = module
394 else: 411 else:
395 if not hasattr(module, "pluginType") or \ 412 if (
396 not hasattr(module, "pluginTypename"): 413 not hasattr(module, "pluginType") or
397 module.error = \ 414 not hasattr(module, "pluginTypename")
398 self.tr("Module is missing the 'pluginType' " 415 ):
399 "and/or 'pluginTypename' attributes.") 416 module.error = self.tr(
417 "Module is missing the 'pluginType' "
418 "and/or 'pluginTypename' attributes."
419 )
400 self.__failedModules[name] = module 420 self.__failedModules[name] = module
401 raise PluginLoadError(name) 421 raise PluginLoadError(name)
402 else: 422 else:
403 self.__onDemandInactiveModules[name] = module 423 self.__onDemandInactiveModules[name] = module
404 module.eric6PluginModuleName = name 424 module.eric6PluginModuleName = name
480 packages = [package] + internalPackages 500 packages = [package] + internalPackages
481 found = False 501 found = False
482 if not package: 502 if not package:
483 package = "__None__" 503 package = "__None__"
484 for moduleName in list(sys.modules.keys())[:]: 504 for moduleName in list(sys.modules.keys())[:]:
485 if moduleName == pluginName or \ 505 if (
486 moduleName.split(".")[0] in packages: 506 moduleName == pluginName or
507 moduleName.split(".")[0] in packages
508 ):
487 found = True 509 found = True
488 del sys.modules[moduleName] 510 del sys.modules[moduleName]
489 return found 511 return found
490 512
491 def initOnDemandPlugins(self): 513 def initOnDemandPlugins(self):
553 self.__inactivePluginsKey) 575 self.__inactivePluginsKey)
554 inactiveList = self.__disabledPlugins[:] 576 inactiveList = self.__disabledPlugins[:]
555 if savedInactiveList is not None: 577 if savedInactiveList is not None:
556 inactiveList += [p for p in savedInactiveList 578 inactiveList += [p for p in savedInactiveList
557 if p not in self.__disabledPlugins] 579 if p not in self.__disabledPlugins]
558 if self.__develPluginName is not None and \ 580 if (
559 self.__develPluginName in inactiveList: 581 self.__develPluginName is not None and
582 self.__develPluginName in inactiveList
583 ):
560 inactiveList.remove(self.__develPluginName) 584 inactiveList.remove(self.__develPluginName)
561 names = sorted(self.__inactiveModules.keys()) 585 names = sorted(self.__inactiveModules.keys())
562 for name in names: 586 for name in names:
563 if name not in inactiveList: 587 if name not in inactiveList:
564 self.activatePlugin(name) 588 self.activatePlugin(name)
741 @keyparam maybeActive flag indicating, that the plugin may be active 765 @keyparam maybeActive flag indicating, that the plugin may be active
742 already (boolean) 766 already (boolean)
743 @return reference to the initialized plugin object 767 @return reference to the initialized plugin object
744 """ 768 """
745 for name, module in list(self.__onDemandInactiveModules.items()): 769 for name, module in list(self.__onDemandInactiveModules.items()):
746 if getattr(module, "pluginType", "") == type_ and \ 770 if (
747 getattr(module, "pluginTypename", "") == typename: 771 getattr(module, "pluginType", "") == type_ and
772 getattr(module, "pluginTypename", "") == typename
773 ):
748 return self.activatePlugin(name, onDemand=True) 774 return self.activatePlugin(name, onDemand=True)
749 775
750 if maybeActive: 776 if maybeActive:
751 for name, module in list(self.__onDemandActiveModules.items()): 777 for name, module in list(self.__onDemandActiveModules.items()):
752 if getattr(module, "pluginType", "") == type_ and \ 778 if (
753 getattr(module, "pluginTypename", "") == typename: 779 getattr(module, "pluginType", "") == type_ and
780 getattr(module, "pluginTypename", "") == typename
781 ):
754 self.deactivatePlugin(name, onDemand=True) 782 self.deactivatePlugin(name, onDemand=True)
755 return self.activatePlugin(name, onDemand=True) 783 return self.activatePlugin(name, onDemand=True)
756 784
757 return None 785 return None
758 786
904 @return dictionary with name as key and display string as value 932 @return dictionary with name as key and display string as value
905 (dictionary of string) 933 (dictionary of string)
906 """ 934 """
907 pluginDict = {} 935 pluginDict = {}
908 936
909 for module in list(self.__onDemandActiveModules.values()) + \ 937 for module in (
910 list(self.__onDemandInactiveModules.values()): 938 list(self.__onDemandActiveModules.values()) +
911 if getattr(module, "pluginType", "") == type_ and \ 939 list(self.__onDemandInactiveModules.values())
912 getattr(module, "error", "") == "": 940 ):
941 if (
942 getattr(module, "pluginType", "") == type_ and
943 getattr(module, "error", "") == ""
944 ):
913 plugin_name = getattr(module, "pluginTypename", "") 945 plugin_name = getattr(module, "pluginTypename", "")
914 if plugin_name: 946 if plugin_name:
915 if hasattr(module, "displayString"): 947 if hasattr(module, "displayString"):
916 try: 948 try:
917 disp = module.displayString() 949 disp = module.displayString()
930 962
931 @param type_ type of the plugin (string) 963 @param type_ type of the plugin (string)
932 @param name name of the plugin type (string) 964 @param name name of the plugin type (string)
933 @return preview pixmap (QPixmap) 965 @return preview pixmap (QPixmap)
934 """ 966 """
935 for module in list(self.__onDemandActiveModules.values()) + \ 967 for module in (
936 list(self.__onDemandInactiveModules.values()): 968 list(self.__onDemandActiveModules.values()) +
937 if getattr(module, "pluginType", "") == type_ and \ 969 list(self.__onDemandInactiveModules.values())
938 getattr(module, "pluginTypename", "") == name: 970 ):
971 if (
972 getattr(module, "pluginType", "") == type_ and
973 getattr(module, "pluginTypename", "") == name
974 ):
939 if hasattr(module, "previewPix"): 975 if hasattr(module, "previewPix"):
940 return module.previewPix() 976 return module.previewPix()
941 else: 977 else:
942 return QPixmap() 978 return QPixmap()
943 979
950 @param language language of the requested API files (string) 986 @param language language of the requested API files (string)
951 @return list of API filenames (list of string) 987 @return list of API filenames (list of string)
952 """ 988 """
953 apis = [] 989 apis = []
954 990
955 for module in list(self.__activeModules.values()) + \ 991 for module in (
956 list(self.__onDemandActiveModules.values()): 992 list(self.__activeModules.values()) +
993 list(self.__onDemandActiveModules.values())
994 ):
957 if hasattr(module, "apiFiles"): 995 if hasattr(module, "apiFiles"):
958 apis.extend(module.apiFiles(language)) 996 apis.extend(module.apiFiles(language))
959 997
960 return apis 998 return apis
961 999
967 @return dictionary with documentation type as key and list of files 1005 @return dictionary with documentation type as key and list of files
968 as value 1006 as value
969 @rtype dict (key: str, value: list of str) 1007 @rtype dict (key: str, value: list of str)
970 """ 1008 """
971 helpFiles = {} 1009 helpFiles = {}
972 for module in list(self.__activeModules.values()) + \ 1010 for module in (
973 list(self.__onDemandActiveModules.values()): 1011 list(self.__activeModules.values()) +
1012 list(self.__onDemandActiveModules.values())
1013 ):
974 if hasattr(module, "helpFiles"): 1014 if hasattr(module, "helpFiles"):
975 helpFiles.update(module.helpFiles()) 1015 helpFiles.update(module.helpFiles())
976 1016
977 return helpFiles 1017 return helpFiles
978 1018
1010 <li>version - version text to be shown (string)</li> 1050 <li>version - version text to be shown (string)</li>
1011 </ul> 1051 </ul>
1012 """ 1052 """
1013 infos = [] 1053 infos = []
1014 1054
1015 for module in list(self.__activeModules.values()) + \ 1055 for module in (
1016 list(self.__inactiveModules.values()): 1056 list(self.__activeModules.values()) +
1057 list(self.__inactiveModules.values())
1058 ):
1017 if hasattr(module, "exeDisplayDataList"): 1059 if hasattr(module, "exeDisplayDataList"):
1018 infos.extend(module.exeDisplayDataList()) 1060 infos.extend(module.exeDisplayDataList())
1019 elif hasattr(module, "exeDisplayData"): 1061 elif hasattr(module, "exeDisplayData"):
1020 infos.append(module.exeDisplayData()) 1062 infos.append(module.exeDisplayData())
1021 for module in list(self.__onDemandActiveModules.values()) + \ 1063 for module in (
1022 list(self.__onDemandInactiveModules.values()): 1064 list(self.__onDemandActiveModules.values()) +
1065 list(self.__onDemandInactiveModules.values())
1066 ):
1023 if hasattr(module, "exeDisplayDataList"): 1067 if hasattr(module, "exeDisplayDataList"):
1024 infos.extend(module.exeDisplayDataList()) 1068 infos.extend(module.exeDisplayDataList())
1025 elif hasattr(module, "exeDisplayData"): 1069 elif hasattr(module, "exeDisplayData"):
1026 infos.append(module.exeDisplayData()) 1070 infos.append(module.exeDisplayData())
1027 1071
1058 </dl> 1102 </dl>
1059 1103
1060 @return plug-in configuration data 1104 @return plug-in configuration data
1061 """ 1105 """
1062 configData = {} 1106 configData = {}
1063 for module in list(self.__activeModules.values()) + \ 1107 for module in (
1064 list(self.__onDemandActiveModules.values()) + \ 1108 list(self.__activeModules.values()) +
1065 list(self.__onDemandInactiveModules.values()): 1109 list(self.__onDemandActiveModules.values()) +
1110 list(self.__onDemandInactiveModules.values())
1111 ):
1066 if hasattr(module, 'getConfigData'): 1112 if hasattr(module, 'getConfigData'):
1067 configData.update(module.getConfigData()) 1113 configData.update(module.getConfigData())
1068 return configData 1114 return configData
1069 1115
1070 def isPluginLoaded(self, pluginName): 1116 def isPluginLoaded(self, pluginName):
1072 Public method to check, if a certain plugin is loaded. 1118 Public method to check, if a certain plugin is loaded.
1073 1119
1074 @param pluginName name of the plugin to check for (string) 1120 @param pluginName name of the plugin to check for (string)
1075 @return flag indicating, if the plugin is loaded (boolean) 1121 @return flag indicating, if the plugin is loaded (boolean)
1076 """ 1122 """
1077 return pluginName in self.__activeModules or \ 1123 return (
1078 pluginName in self.__inactiveModules or \ 1124 pluginName in self.__activeModules or
1079 pluginName in self.__onDemandActiveModules or \ 1125 pluginName in self.__inactiveModules or
1126 pluginName in self.__onDemandActiveModules or
1080 pluginName in self.__onDemandInactiveModules 1127 pluginName in self.__onDemandInactiveModules
1128 )
1081 1129
1082 def isPluginActive(self, pluginName): 1130 def isPluginActive(self, pluginName):
1083 """ 1131 """
1084 Public method to check, if a certain plugin is active. 1132 Public method to check, if a certain plugin is active.
1085 1133
1086 @param pluginName name of the plugin to check for (string) 1134 @param pluginName name of the plugin to check for (string)
1087 @return flag indicating, if the plugin is active (boolean) 1135 @return flag indicating, if the plugin is active (boolean)
1088 """ 1136 """
1089 return pluginName in self.__activeModules or \ 1137 return (
1138 pluginName in self.__activeModules or
1090 pluginName in self.__onDemandActiveModules 1139 pluginName in self.__onDemandActiveModules
1140 )
1091 1141
1092 ########################################################################### 1142 ###########################################################################
1093 ## Specialized plug-in module handling methods below 1143 ## Specialized plug-in module handling methods below
1094 ########################################################################### 1144 ###########################################################################
1095 1145
1109 values. Each tuple contains the vcs name (string) and vcs display 1159 values. Each tuple contains the vcs name (string) and vcs display
1110 string (string). 1160 string (string).
1111 """ 1161 """
1112 vcsDict = {} 1162 vcsDict = {}
1113 1163
1114 for module in list(self.__onDemandActiveModules.values()) + \ 1164 for module in (
1115 list(self.__onDemandInactiveModules.values()): 1165 list(self.__onDemandActiveModules.values()) +
1166 list(self.__onDemandInactiveModules.values())
1167 ):
1116 if getattr(module, "pluginType", "") == "version_control": 1168 if getattr(module, "pluginType", "") == "version_control":
1117 if hasattr(module, "getVcsSystemIndicator"): 1169 if hasattr(module, "getVcsSystemIndicator"):
1118 res = module.getVcsSystemIndicator() 1170 res = module.getVcsSystemIndicator()
1119 for indicator, vcsData in list(res.items()): 1171 for indicator, vcsData in list(res.items()):
1120 if indicator in vcsDict: 1172 if indicator in vcsDict:
1204 # daily 1256 # daily
1205 return 1257 return
1206 elif period == 2 and lastModifiedDate.daysTo(now) < 7: 1258 elif period == 2 and lastModifiedDate.daysTo(now) < 7:
1207 # weekly 1259 # weekly
1208 return 1260 return
1209 elif period == 3 and \ 1261 elif (
1262 period == 3 and
1210 (lastModifiedDate.daysTo(now) < 1263 (lastModifiedDate.daysTo(now) <
1211 lastModifiedDate.daysInMonth()): 1264 lastModifiedDate.daysInMonth())
1265 ):
1212 # monthly 1266 # monthly
1213 return 1267 return
1214 1268
1215 self.__updateAvailable = False 1269 self.__updateAvailable = False
1216 1270
1369 Plugins supporting this functionality must support the module function 1423 Plugins supporting this functionality must support the module function
1370 clearPrivateData() and have the module level attribute pluginType. 1424 clearPrivateData() and have the module level attribute pluginType.
1371 1425
1372 @param type_ type of the plugin to clear private data for (string) 1426 @param type_ type of the plugin to clear private data for (string)
1373 """ 1427 """
1374 for module in \ 1428 for module in (
1375 list(self.__onDemandActiveModules.values()) + \ 1429 list(self.__onDemandActiveModules.values()) +
1376 list(self.__onDemandInactiveModules.values()) + \ 1430 list(self.__onDemandInactiveModules.values()) +
1377 list(self.__activeModules.values()) + \ 1431 list(self.__activeModules.values()) +
1378 list(self.__inactiveModules.values()): 1432 list(self.__inactiveModules.values())
1433 ):
1379 if getattr(module, "pluginType", "") == type_: 1434 if getattr(module, "pluginType", "") == type_:
1380 if hasattr(module, "clearPrivateData"): 1435 if hasattr(module, "clearPrivateData"):
1381 module.clearPrivateData() 1436 module.clearPrivateData()
1382 1437
1383 # 1438 #

eric ide

mercurial