PluginManager/PluginManager.py

changeset 2992
dbdf27746da5
parent 2960
9453efa25fd5
child 3020
542e97d4ecb3
child 3057
10516539f238
equal deleted inserted replaced
2991:226481ff40d1 2992:dbdf27746da5
14 from PyQt4.QtCore import pyqtSignal, QObject 14 from PyQt4.QtCore import pyqtSignal, QObject
15 from PyQt4.QtGui import QPixmap 15 from PyQt4.QtGui import QPixmap
16 16
17 from E5Gui import E5MessageBox 17 from E5Gui import E5MessageBox
18 18
19 from .PluginExceptions import PluginPathError, PluginModulesError, PluginLoadError, \ 19 from .PluginExceptions import PluginPathError, PluginModulesError, \
20 PluginActivationError, PluginModuleFormatError, PluginClassFormatError 20 PluginLoadError, PluginActivationError, PluginModuleFormatError, \
21 PluginClassFormatError
21 22
22 import UI.PixmapCache 23 import UI.PixmapCache
23 24
24 import Utilities 25 import Utilities
25 import Preferences 26 import Preferences
30 class PluginManager(QObject): 31 class PluginManager(QObject):
31 """ 32 """
32 Class implementing the Plugin Manager. 33 Class implementing the Plugin Manager.
33 34
34 @signal shutdown() emitted at shutdown of the IDE 35 @signal shutdown() emitted at shutdown of the IDE
35 @signal pluginAboutToBeActivated(modulName, pluginObject) emitted just before a 36 @signal pluginAboutToBeActivated(modulName, pluginObject) emitted just
36 plugin is activated 37 before a plugin is activated
37 @signal pluginActivated(modulName, pluginObject) emitted just after a plugin 38 @signal pluginActivated(modulName, pluginObject) emitted just after
38 was activated 39 a plugin was activated
39 @signal allPlugginsActivated() emitted at startup after all plugins have 40 @signal allPlugginsActivated() emitted at startup after all plugins have
40 been activated 41 been activated
41 @signal pluginAboutToBeDeactivated(modulName, pluginObject) emitted just before a 42 @signal pluginAboutToBeDeactivated(modulName, pluginObject) emitted just
42 plugin is deactivated 43 before a plugin is deactivated
43 @signal pluginDeactivated(modulName, pluginObject) emitted just after a plugin 44 @signal pluginDeactivated(modulName, pluginObject) emitted just after
44 was deactivated 45 a plugin was deactivated
45 """ 46 """
46 shutdown = pyqtSignal() 47 shutdown = pyqtSignal()
47 pluginAboutToBeActivated = pyqtSignal(str, object) 48 pluginAboutToBeActivated = pyqtSignal(str, object)
48 pluginActivated = pyqtSignal(str, object) 49 pluginActivated = pyqtSignal(str, object)
49 allPlugginsActivated = pyqtSignal() 50 allPlugginsActivated = pyqtSignal()
82 "eric5plugins"), 83 "eric5plugins"),
83 "user": os.path.join(Utilities.getConfigDir(), "eric5plugins"), 84 "user": os.path.join(Utilities.getConfigDir(), "eric5plugins"),
84 } 85 }
85 self.__priorityOrder = ["eric5", "global", "user"] 86 self.__priorityOrder = ["eric5", "global", "user"]
86 87
87 self.__defaultDownloadDir = os.path.join(Utilities.getConfigDir(), "Downloads") 88 self.__defaultDownloadDir = os.path.join(
89 Utilities.getConfigDir(), "Downloads")
88 90
89 self.__activePlugins = {} 91 self.__activePlugins = {}
90 self.__inactivePlugins = {} 92 self.__inactivePlugins = {}
91 self.__onDemandActivePlugins = {} 93 self.__onDemandActivePlugins = {}
92 self.__onDemandInactivePlugins = {} 94 self.__onDemandInactivePlugins = {}
190 del self.pluginDirs["user"] 192 del self.pluginDirs["user"]
191 del self.pluginDirs["global"] 193 del self.pluginDirs["global"]
192 194
193 if not os.path.exists(self.pluginDirs["eric5"]): 195 if not os.path.exists(self.pluginDirs["eric5"]):
194 return (False, 196 return (False,
195 self.trUtf8("The internal plugin directory <b>{0}</b> does not exits.")\ 197 self.trUtf8(
196 .format(self.pluginDirs["eric5"])) 198 "The internal plugin directory <b>{0}</b>"
199 " does not exits.").format(self.pluginDirs["eric5"]))
197 200
198 return (True, "") 201 return (True, "")
199 202
200 def __pluginModulesExist(self): 203 def __pluginModulesExist(self):
201 """ 204 """
202 Private method to check, if there are plugins available. 205 Private method to check, if there are plugins available.
203 206
204 @return flag indicating the availability of plugins (boolean) 207 @return flag indicating the availability of plugins (boolean)
205 """ 208 """
206 if self.__develPluginFile and not os.path.exists(self.__develPluginFile): 209 if self.__develPluginFile and \
210 not os.path.exists(self.__develPluginFile):
207 return False 211 return False
208 212
209 self.__foundCoreModules = self.getPluginModules(self.pluginDirs["eric5"]) 213 self.__foundCoreModules = self.getPluginModules(
214 self.pluginDirs["eric5"])
210 if "global" in self.pluginDirs: 215 if "global" in self.pluginDirs:
211 self.__foundGlobalModules = \ 216 self.__foundGlobalModules = \
212 self.getPluginModules(self.pluginDirs["global"]) 217 self.getPluginModules(self.pluginDirs["global"])
213 if "user" in self.pluginDirs: 218 if "user" in self.pluginDirs:
214 self.__foundUserModules = \ 219 self.__foundUserModules = \
304 """ 309 """
305 try: 310 try:
306 fname = "{0}.py".format(os.path.join(directory, name)) 311 fname = "{0}.py".format(os.path.join(directory, name))
307 module = imp.load_source(name, fname) 312 module = imp.load_source(name, fname)
308 if not hasattr(module, "autoactivate"): 313 if not hasattr(module, "autoactivate"):
309 module.error = \ 314 module.error = self.trUtf8(
310 self.trUtf8("Module is missing the 'autoactivate' attribute.") 315 "Module is missing the 'autoactivate' attribute.")
311 self.__failedModules[name] = module 316 self.__failedModules[name] = module
312 raise PluginLoadError(name) 317 raise PluginLoadError(name)
313 if getattr(module, "autoactivate"): 318 if getattr(module, "autoactivate"):
314 self.__inactiveModules[name] = module 319 self.__inactiveModules[name] = module
315 else: 320 else:
329 imp.reload(module) 334 imp.reload(module)
330 except PluginLoadError: 335 except PluginLoadError:
331 print("Error loading plugin module:", name) 336 print("Error loading plugin module:", name)
332 except Exception as err: 337 except Exception as err:
333 module = imp.new_module(name) 338 module = imp.new_module(name)
334 module.error = \ 339 module.error = self.trUtf8(
335 self.trUtf8("Module failed to load. Error: {0}").format(str(err)) 340 "Module failed to load. Error: {0}").format(str(err))
336 self.__failedModules[name] = module 341 self.__failedModules[name] = module
337 print("Error loading plugin module:", name) 342 print("Error loading plugin module:", name)
338 print(str(err)) 343 print(str(err))
339 344
340 def unloadPlugin(self, name): 345 def unloadPlugin(self, name):
367 del self.__failedModules[name] 372 del self.__failedModules[name]
368 373
369 self.__modulesCount -= 1 374 self.__modulesCount -= 1
370 return True 375 return True
371 376
372 def removePluginFromSysModules(self, pluginName, package, internalPackages): 377 def removePluginFromSysModules(self, pluginName, package,
373 """ 378 internalPackages):
374 Public method to remove a plugin and all related modules from sys.modules. 379 """
380 Public method to remove a plugin and all related modules from
381 sys.modules.
375 382
376 @param pluginName name of the plugin module (string) 383 @param pluginName name of the plugin module (string)
377 @param package name of the plugin package (string) 384 @param package name of the plugin package (string)
378 @param internalPackages list of intenal packages (list of string) 385 @param internalPackages list of intenal packages (list of string)
379 @return flag indicating the plugin module was found in sys.modules (boolean) 386 @return flag indicating the plugin module was found in sys.modules
387 (boolean)
380 """ 388 """
381 packages = [package] + internalPackages 389 packages = [package] + internalPackages
382 found = False 390 found = False
383 if not package: 391 if not package:
384 package = "__None__" 392 package = "__None__"
385 for moduleName in list(sys.modules.keys())[:]: 393 for moduleName in list(sys.modules.keys())[:]:
386 if moduleName == pluginName or moduleName.split(".")[0] in packages: 394 if moduleName == pluginName or \
395 moduleName.split(".")[0] in packages:
387 found = True 396 found = True
388 del sys.modules[moduleName] 397 del sys.modules[moduleName]
389 return found 398 return found
390 399
391 def initOnDemandPlugins(self): 400 def initOnDemandPlugins(self):
429 except PluginActivationError: 438 except PluginActivationError:
430 return 439 return
431 440
432 def activatePlugins(self): 441 def activatePlugins(self):
433 """ 442 """
434 Public method to activate all plugins having the "autoactivate" attribute 443 Public method to activate all plugins having the "autoactivate"
435 set to True. 444 attribute set to True.
436 """ 445 """
437 savedInactiveList = Preferences.Prefs.settings.value(self.__inactivePluginsKey) 446 savedInactiveList = Preferences.Prefs.settings.value(
447 self.__inactivePluginsKey)
438 if self.__develPluginName is not None and \ 448 if self.__develPluginName is not None and \
439 savedInactiveList is not None and \ 449 savedInactiveList is not None and \
440 self.__develPluginName in savedInactiveList: 450 self.__develPluginName in savedInactiveList:
441 savedInactiveList.remove(self.__develPluginName) 451 savedInactiveList.remove(self.__develPluginName)
442 names = sorted(self.__inactiveModules.keys()) 452 names = sorted(self.__inactiveModules.keys())
479 pluginObject = pluginClass(self.__ui) 489 pluginObject = pluginClass(self.__ui)
480 self.pluginAboutToBeActivated.emit(name, pluginObject) 490 self.pluginAboutToBeActivated.emit(name, pluginObject)
481 try: 491 try:
482 obj, ok = pluginObject.activate() 492 obj, ok = pluginObject.activate()
483 except TypeError: 493 except TypeError:
484 module.error = self.trUtf8("Incompatible plugin activation method.") 494 module.error = self.trUtf8(
495 "Incompatible plugin activation method.")
485 obj = None 496 obj = None
486 ok = True 497 ok = True
487 except Exception as err: 498 except Exception as err:
488 module.error = str(err) 499 module.error = str(err)
489 obj = None 500 obj = None
528 @exception PluginClassFormatError raised to indicate an invalid 539 @exception PluginClassFormatError raised to indicate an invalid
529 plug-in class format 540 plug-in class format
530 """ 541 """
531 try: 542 try:
532 if not hasattr(module, "version"): 543 if not hasattr(module, "version"):
533 raise PluginModuleFormatError(module.eric5PluginModuleName, "version") 544 raise PluginModuleFormatError(
545 module.eric5PluginModuleName, "version")
534 if not hasattr(module, "className"): 546 if not hasattr(module, "className"):
535 raise PluginModuleFormatError(module.eric5PluginModuleName, "className") 547 raise PluginModuleFormatError(
548 module.eric5PluginModuleName, "className")
536 className = getattr(module, "className") 549 className = getattr(module, "className")
537 if not hasattr(module, className): 550 if not hasattr(module, className):
538 raise PluginModuleFormatError(module.eric5PluginModuleName, className) 551 raise PluginModuleFormatError(
552 module.eric5PluginModuleName, className)
539 pluginClass = getattr(module, className) 553 pluginClass = getattr(module, className)
540 if not hasattr(pluginClass, "__init__"): 554 if not hasattr(pluginClass, "__init__"):
541 raise PluginClassFormatError(module.eric5PluginModuleName, 555 raise PluginClassFormatError(module.eric5PluginModuleName,
542 className, "__init__") 556 className, "__init__")
543 if not hasattr(pluginClass, "activate"): 557 if not hasattr(pluginClass, "activate"):
605 """ 619 """
606 return getattr(module, "deactivateable", True) 620 return getattr(module, "deactivateable", True)
607 621
608 def getPluginObject(self, type_, typename, maybeActive=False): 622 def getPluginObject(self, type_, typename, maybeActive=False):
609 """ 623 """
610 Public method to activate an ondemand plugin given by type and typename. 624 Public method to activate an ondemand plugin given by type and
625 typename.
611 626
612 @param type_ type of the plugin to be activated (string) 627 @param type_ type of the plugin to be activated (string)
613 @param typename name of the plugin within the type category (string) 628 @param typename name of the plugin within the type category (string)
614 @keyparam maybeActive flag indicating, that the plugin may be active 629 @keyparam maybeActive flag indicating, that the plugin may be active
615 already (boolean) 630 already (boolean)
631 646
632 def getPluginInfos(self): 647 def getPluginInfos(self):
633 """ 648 """
634 Public method to get infos about all loaded plugins. 649 Public method to get infos about all loaded plugins.
635 650
636 @return list of tuples giving module name (string), plugin name (string), 651 @return list of tuples giving module name (string), plugin name
637 version (string), autoactivate (boolean), active (boolean), 652 (string), version (string), autoactivate (boolean), active
638 short description (string), error flag (boolean) 653 (boolean), short description (string), error flag (boolean)
639 """ 654 """
640 infos = [] 655 infos = []
641 656
642 for name in list(self.__activeModules.keys()): 657 for name in list(self.__activeModules.keys()):
643 pname, shortDesc, error, version = \ 658 pname, shortDesc, error, version = \
644 self.__getShortInfo(self.__activeModules[name]) 659 self.__getShortInfo(self.__activeModules[name])
645 infos.append((name, pname, version, True, True, shortDesc, error)) 660 infos.append((name, pname, version, True, True, shortDesc, error))
646 for name in list(self.__inactiveModules.keys()): 661 for name in list(self.__inactiveModules.keys()):
647 pname, shortDesc, error, version = \ 662 pname, shortDesc, error, version = \
648 self.__getShortInfo(self.__inactiveModules[name]) 663 self.__getShortInfo(self.__inactiveModules[name])
649 infos.append((name, pname, version, True, False, shortDesc, error)) 664 infos.append(
665 (name, pname, version, True, False, shortDesc, error))
650 for name in list(self.__onDemandActiveModules.keys()): 666 for name in list(self.__onDemandActiveModules.keys()):
651 pname, shortDesc, error, version = \ 667 pname, shortDesc, error, version = \
652 self.__getShortInfo(self.__onDemandActiveModules[name]) 668 self.__getShortInfo(self.__onDemandActiveModules[name])
653 infos.append((name, pname, version, False, True, shortDesc, error)) 669 infos.append(
670 (name, pname, version, False, True, shortDesc, error))
654 for name in list(self.__onDemandInactiveModules.keys()): 671 for name in list(self.__onDemandInactiveModules.keys()):
655 pname, shortDesc, error, version = \ 672 pname, shortDesc, error, version = \
656 self.__getShortInfo(self.__onDemandInactiveModules[name]) 673 self.__getShortInfo(self.__onDemandInactiveModules[name])
657 infos.append((name, pname, version, False, False, shortDesc, error)) 674 infos.append(
675 (name, pname, version, False, False, shortDesc, error))
658 for name in list(self.__failedModules.keys()): 676 for name in list(self.__failedModules.keys()):
659 pname, shortDesc, error, version = \ 677 pname, shortDesc, error, version = \
660 self.__getShortInfo(self.__failedModules[name]) 678 self.__getShortInfo(self.__failedModules[name])
661 infos.append((name, pname, version, False, False, shortDesc, error)) 679 infos.append(
680 (name, pname, version, False, False, shortDesc, error))
662 return infos 681 return infos
663 682
664 def __getShortInfo(self, module): 683 def __getShortInfo(self, module):
665 """ 684 """
666 Private method to extract the short info from a module. 685 Private method to extract the short info from a module.
707 else: 726 else:
708 # should not happen 727 # should not happen
709 return None 728 return None
710 729
711 details["moduleName"] = name 730 details["moduleName"] = name
712 details["moduleFileName"] = getattr(module, "eric5PluginModuleFilename", "") 731 details["moduleFileName"] = getattr(
732 module, "eric5PluginModuleFilename", "")
713 details["pluginName"] = getattr(module, "name", "") 733 details["pluginName"] = getattr(module, "name", "")
714 details["version"] = getattr(module, "version", "") 734 details["version"] = getattr(module, "version", "")
715 details["author"] = getattr(module, "author", "") 735 details["author"] = getattr(module, "author", "")
716 details["description"] = getattr(module, "longDescription", "") 736 details["description"] = getattr(module, "longDescription", "")
717 details["autoactivate"] = autoactivate 737 details["autoactivate"] = autoactivate
731 751
732 self.shutdown.emit() 752 self.shutdown.emit()
733 753
734 def getPluginDisplayStrings(self, type_): 754 def getPluginDisplayStrings(self, type_):
735 """ 755 """
736 Public method to get the display strings of all plugins of a specific type. 756 Public method to get the display strings of all plugins of a specific
757 type.
737 758
738 @param type_ type of the plugins (string) 759 @param type_ type of the plugins (string)
739 @return dictionary with name as key and display string as value 760 @return dictionary with name as key and display string as value
740 (dictionary of string) 761 (dictionary of string)
741 """ 762 """
799 """ 820 """
800 Public method to get data to display information about a plugins 821 Public method to get data to display information about a plugins
801 external tool. 822 external tool.
802 823
803 @return list of dictionaries containing the data. Each dictionary must 824 @return list of dictionaries containing the data. Each dictionary must
804 either contain data for the determination or the data to be displayed.<br /> 825 either contain data for the determination or the data to be
826 displayed.<br />
805 A dictionary of the first form must have the following entries: 827 A dictionary of the first form must have the following entries:
806 <ul> 828 <ul>
807 <li>programEntry - indicator for this dictionary form (boolean), 829 <li>programEntry - indicator for this dictionary form
808 always True</li> 830 (boolean), always True</li>
809 <li>header - string to be diplayed as a header (string)</li> 831 <li>header - string to be diplayed as a header (string)</li>
810 <li>exe - the executable (string)</li> 832 <li>exe - the executable (string)</li>
811 <li>versionCommand - commandline parameter for the exe (string)</li> 833 <li>versionCommand - commandline parameter for the exe
812 <li>versionStartsWith - indicator for the output line containing 834 (string)</li>
813 the version (string)</li> 835 <li>versionStartsWith - indicator for the output line
836 containing the version (string)</li>
814 <li>versionPosition - number of element containing the 837 <li>versionPosition - number of element containing the
815 version (integer)</li> 838 version (integer)</li>
816 <li>version - version to be used as default (string)</li> 839 <li>version - version to be used as default (string)</li>
817 <li>versionCleanup - tuple of two integers giving string positions 840 <li>versionCleanup - tuple of two integers giving string
818 start and stop for the version string (tuple of integers)</li> 841 positions start and stop for the version string
842 (tuple of integers)</li>
819 </ul> 843 </ul>
820 A dictionary of the second form must have the following entries: 844 A dictionary of the second form must have the following entries:
821 <ul> 845 <ul>
822 <li>programEntry - indicator for this dictionary form (boolean), 846 <li>programEntry - indicator for this dictionary form
823 always False</li> 847 (boolean), always False</li>
824 <li>header - string to be diplayed as a header (string)</li> 848 <li>header - string to be diplayed as a header (string)</li>
825 <li>text - entry text to be shown (string)</li> 849 <li>text - entry text to be shown (string)</li>
826 <li>version - version text to be shown (string)</li> 850 <li>version - version text to be shown (string)</li>
827 </ul> 851 </ul>
828 """ 852 """
843 867
844 return infos 868 return infos
845 869
846 def getPluginConfigData(self): 870 def getPluginConfigData(self):
847 """ 871 """
848 Public method to get the config data of all active, non on-demand plugins 872 Public method to get the config data of all active, non on-demand
849 used by the configuration dialog. 873 plugins used by the configuration dialog.
850 874
851 Plugins supporting this functionality must provide the plugin module 875 Plugins supporting this functionality must provide the plugin module
852 function 'getConfigData' returning a dictionary with unique keys 876 function 'getConfigData' returning a dictionary with unique keys
853 of lists with the following list contents: 877 of lists with the following list contents:
854 <dl> 878 <dl>
855 <dt>display string</dt> 879 <dt>display string</dt>
856 <dd>string shown in the selection area of the configuration page. 880 <dd>string shown in the selection area of the configuration page.
857 This should be a localized string</dd> 881 This should be a localized string</dd>
858 <dt>pixmap name</dt> 882 <dt>pixmap name</dt>
859 <dd>filename of the pixmap to be shown next to the display string</dd> 883 <dd>filename of the pixmap to be shown next to the display
884 string</dd>
860 <dt>page creation function</dt> 885 <dt>page creation function</dt>
861 <dd>plugin module function to be called to create the configuration 886 <dd>plugin module function to be called to create the configuration
862 page. The page must be subclasses from 887 page. The page must be subclasses from
863 Preferences.ConfigurationPages.ConfigurationPageBase and must 888 Preferences.ConfigurationPages.ConfigurationPageBase and must
864 implement a method called 'save' to save the settings. A parent 889 implement a method called 'save' to save the settings. A parent
865 entry will be created in the selection list, if this value is None.</dd> 890 entry will be created in the selection list, if this value is
891 None.</dd>
866 <dt>parent key</dt> 892 <dt>parent key</dt>
867 <dd>dictionary key of the parent entry or None, if this defines a 893 <dd>dictionary key of the parent entry or None, if this defines a
868 toplevel entry.</dd> 894 toplevel entry.</dd>
869 <dt>reference to configuration page</dt> 895 <dt>reference to configuration page</dt>
870 <dd>This will be used by the configuration dialog and must always be None</dd> 896 <dd>This will be used by the configuration dialog and must always
897 be None</dd>
871 </dl> 898 </dl>
872 899
873 @return plug-in configuration data 900 @return plug-in configuration data
874 """ 901 """
875 configData = {} 902 configData = {}
900 @return flag indicating, if the plugin is active (boolean) 927 @return flag indicating, if the plugin is active (boolean)
901 """ 928 """
902 return pluginName in self.__activeModules or \ 929 return pluginName in self.__activeModules or \
903 pluginName in self.__onDemandActiveModules 930 pluginName in self.__onDemandActiveModules
904 931
905 ############################################################################ 932 ###########################################################################
906 ## Specialized plugin module handling methods below 933 ## Specialized plugin module handling methods below
907 ############################################################################ 934 ###########################################################################
908 935
909 ############################################################################ 936 ###########################################################################
910 ## VCS related methods below 937 ## VCS related methods below
911 ############################################################################ 938 ###########################################################################
912 939
913 def getVcsSystemIndicators(self): 940 def getVcsSystemIndicators(self):
914 """ 941 """
915 Public method to get the Vcs System indicators. 942 Public method to get the Vcs System indicators.
916 943
917 Plugins supporting this functionality must support the module function 944 Plugins supporting this functionality must support the module function
918 getVcsSystemIndicator returning a dictionary with indicator as key and 945 getVcsSystemIndicator returning a dictionary with indicator as key and
919 a tuple with the vcs name (string) and vcs display string (string). 946 a tuple with the vcs name (string) and vcs display string (string).
920 947
921 @return dictionary with indicator as key and a list of tuples as values. 948 @return dictionary with indicator as key and a list of tuples as
922 Each tuple contains the vcs name (string) and vcs display string (string). 949 values. Each tuple contains the vcs name (string) and vcs display
950 string (string).
923 """ 951 """
924 vcsDict = {} 952 vcsDict = {}
925 953
926 for name, module in \ 954 for name, module in \
927 list(self.__onDemandActiveModules.items()) + \ 955 list(self.__onDemandActiveModules.items()) + \
945 if getattr(module, "pluginType") == "version_control": 973 if getattr(module, "pluginType") == "version_control":
946 self.deactivatePlugin(name, True) 974 self.deactivatePlugin(name, True)
947 975
948 def __checkPluginsDownloadDirectory(self): 976 def __checkPluginsDownloadDirectory(self):
949 """ 977 """
950 Private slot to check for the existence of the plugins download directory. 978 Private slot to check for the existence of the plugins download
979 directory.
951 """ 980 """
952 downloadDir = Preferences.getPluginManager("DownloadPath") 981 downloadDir = Preferences.getPluginManager("DownloadPath")
953 if not downloadDir: 982 if not downloadDir:
954 downloadDir = self.__defaultDownloadDir 983 downloadDir = self.__defaultDownloadDir
955 984
963 try: 992 try:
964 os.mkdir(downloadDir, 0o755) 993 os.mkdir(downloadDir, 0o755)
965 except (OSError, IOError) as err: 994 except (OSError, IOError) as err:
966 E5MessageBox.critical(self.__ui, 995 E5MessageBox.critical(self.__ui,
967 self.trUtf8("Plugin Manager Error"), 996 self.trUtf8("Plugin Manager Error"),
968 self.trUtf8("""<p>The plugin download directory <b>{0}</b> """ 997 self.trUtf8(
969 """could not be created. Please configure it """ 998 """<p>The plugin download directory"""
970 """via the configuration dialog.</p>""" 999 """ <b>{0}</b> could not be created. Please"""
971 """<p>Reason: {1}</p>""")\ 1000 """ configure it via the configuration"""
1001 """ dialog.</p><p>Reason: {1}</p>""")
972 .format(downloadDir, str(err))) 1002 .format(downloadDir, str(err)))
973 downloadDir = "" 1003 downloadDir = ""
974 1004
975 Preferences.setPluginManager("DownloadPath", downloadDir) 1005 Preferences.setPluginManager("DownloadPath", downloadDir)
976 1006

eric ide

mercurial