PluginManager/PluginManager.py

changeset 945
8cd4d08fa9f6
parent 791
9ec2ac20e54e
child 1112
8a7d1b9d18db
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
22 22
23 import Utilities 23 import Utilities
24 import Preferences 24 import Preferences
25 25
26 from eric5config import getConfig 26 from eric5config import getConfig
27
27 28
28 class PluginManager(QObject): 29 class PluginManager(QObject):
29 """ 30 """
30 Class implementing the Plugin Manager. 31 Class implementing the Plugin Manager.
31 32
46 pluginActivated = pyqtSignal(str, object) 47 pluginActivated = pyqtSignal(str, object)
47 allPlugginsActivated = pyqtSignal() 48 allPlugginsActivated = pyqtSignal()
48 pluginAboutToBeDeactivated = pyqtSignal(str, object) 49 pluginAboutToBeDeactivated = pyqtSignal(str, object)
49 pluginDeactivated = pyqtSignal(str, object) 50 pluginDeactivated = pyqtSignal(str, object)
50 51
51 def __init__(self, parent = None, doLoadPlugins = True, develPlugin = None): 52 def __init__(self, parent=None, doLoadPlugins=True, develPlugin=None):
52 """ 53 """
53 Constructor 54 Constructor
54 55
55 The Plugin Manager deals with three different plugin directories. 56 The Plugin Manager deals with three different plugin directories.
56 The first is the one, that is part of eric5 (eric5/Plugins). The 57 The first is the one, that is part of eric5 (eric5/Plugins). The
57 second one is the global plugin directory called 'eric5plugins', 58 second one is the global plugin directory called 'eric5plugins',
58 which is located inside the site-packages directory. The last one 59 which is located inside the site-packages directory. The last one
59 is the user plugin directory located inside the .eric5 directory 60 is the user plugin directory located inside the .eric5 directory
60 of the users home directory. 61 of the users home directory.
61 62
62 @param parent reference to the parent object (QObject) 63 @param parent reference to the parent object (QObject)
63 @keyparam doLoadPlugins flag indicating, that plugins should 64 @keyparam doLoadPlugins flag indicating, that plugins should
64 be loaded (boolean) 65 be loaded (boolean)
65 @keyparam develPlugin filename of a plugin to be loaded for 66 @keyparam develPlugin filename of a plugin to be loaded for
66 development (string) 67 development (string)
67 """ 68 """
68 QObject.__init__(self, parent) 69 QObject.__init__(self, parent)
69 70
70 self.__ui = parent 71 self.__ui = parent
72 self.__develPluginName = None 73 self.__develPluginName = None
73 74
74 self.__inactivePluginsKey = "PluginManager/InactivePlugins" 75 self.__inactivePluginsKey = "PluginManager/InactivePlugins"
75 76
76 self.pluginDirs = { 77 self.pluginDirs = {
77 "eric5" : os.path.join(getConfig('ericDir'), "Plugins"), 78 "eric5": os.path.join(getConfig('ericDir'), "Plugins"),
78 "global" : os.path.join(Utilities.getPythonModulesDirectory(), 79 "global": os.path.join(Utilities.getPythonModulesDirectory(),
79 "eric5plugins"), 80 "eric5plugins"),
80 "user" : os.path.join(Utilities.getConfigDir(), "eric5plugins"), 81 "user": os.path.join(Utilities.getConfigDir(), "eric5plugins"),
81 } 82 }
82 self.__priorityOrder = ["eric5", "global", "user"] 83 self.__priorityOrder = ["eric5", "global", "user"]
83 84
84 self.__defaultDownloadDir = os.path.join(Utilities.getConfigDir(), "Downloads") 85 self.__defaultDownloadDir = os.path.join(Utilities.getConfigDir(), "Downloads")
85 86
140 """ 141 """
141 Private method to check, if the plugin folders exist. 142 Private method to check, if the plugin folders exist.
142 143
143 If the plugin folders don't exist, they are created (if possible). 144 If the plugin folders don't exist, they are created (if possible).
144 145
145 @return tuple of a flag indicating existence of any of the plugin 146 @return tuple of a flag indicating existence of any of the plugin
146 directories (boolean) and a message (string) 147 directories (boolean) and a message (string)
147 """ 148 """
148 if self.__develPluginFile: 149 if self.__develPluginFile:
149 path = Utilities.splitPath(self.__develPluginFile)[0] 150 path = Utilities.splitPath(self.__develPluginFile)[0]
150 fname = os.path.join(path, "__init__.py") 151 fname = os.path.join(path, "__init__.py")
151 if not os.path.exists(fname): 152 if not os.path.exists(fname):
152 try: 153 try:
153 f = open(fname, "w") 154 f = open(fname, "w")
154 f.close() 155 f.close()
155 except IOError: 156 except IOError:
156 return (False, 157 return (False,
157 self.trUtf8("Could not create a package for {0}.")\ 158 self.trUtf8("Could not create a package for {0}.")\
158 .format(self.__develPluginFile)) 159 .format(self.__develPluginFile))
159 160
160 if Preferences.getPluginManager("ActivateExternal"): 161 if Preferences.getPluginManager("ActivateExternal"):
161 fname = os.path.join(self.pluginDirs["user"], "__init__.py") 162 fname = os.path.join(self.pluginDirs["user"], "__init__.py")
171 if not os.path.exists(self.pluginDirs["global"]) and \ 172 if not os.path.exists(self.pluginDirs["global"]) and \
172 os.access(Utilities.getPythonModulesDirectory(), os.W_OK): 173 os.access(Utilities.getPythonModulesDirectory(), os.W_OK):
173 # create the global plugins directory 174 # create the global plugins directory
174 os.mkdir(self.pluginDirs["global"], 0o755) 175 os.mkdir(self.pluginDirs["global"], 0o755)
175 fname = os.path.join(self.pluginDirs["global"], "__init__.py") 176 fname = os.path.join(self.pluginDirs["global"], "__init__.py")
176 f = open(fname, "w", encoding = "utf-8") 177 f = open(fname, "w", encoding="utf-8")
177 f.write('# -*- coding: utf-8 -*-' + "\n") 178 f.write('# -*- coding: utf-8 -*-' + "\n")
178 f.write("\n") 179 f.write("\n")
179 f.write('"""' + "\n") 180 f.write('"""' + "\n")
180 f.write('Package containing the global plugins.' + "\n") 181 f.write('Package containing the global plugins.' + "\n")
181 f.write('"""' + "\n") 182 f.write('"""' + "\n")
185 else: 186 else:
186 del self.pluginDirs["user"] 187 del self.pluginDirs["user"]
187 del self.pluginDirs["global"] 188 del self.pluginDirs["global"]
188 189
189 if not os.path.exists(self.pluginDirs["eric5"]): 190 if not os.path.exists(self.pluginDirs["eric5"]):
190 return (False, 191 return (False,
191 self.trUtf8("The internal plugin directory <b>{0}</b> does not exits.")\ 192 self.trUtf8("The internal plugin directory <b>{0}</b> does not exits.")\
192 .format(self.pluginDirs["eric5"])) 193 .format(self.pluginDirs["eric5"]))
193 194
194 return (True, "") 195 return (True, "")
195 196
281 282
282 if develPluginName: 283 if develPluginName:
283 self.loadPlugin(develPluginName, develPluginPath) 284 self.loadPlugin(develPluginName, develPluginPath)
284 self.__develPluginName = develPluginName 285 self.__develPluginName = develPluginName
285 286
286 def loadPlugin(self, name, directory, reload_ = False): 287 def loadPlugin(self, name, directory, reload_=False):
287 """ 288 """
288 Public method to load a plugin module. 289 Public method to load a plugin module.
289 290
290 Initially all modules are inactive. Modules that are requested on 291 Initially all modules are inactive. Modules that are requested on
291 demand are sorted out and are added to the on demand list. Some 292 demand are sorted out and are added to the on demand list. Some
439 for name in names: 440 for name in names:
440 if savedInactiveList is None or name not in savedInactiveList: 441 if savedInactiveList is None or name not in savedInactiveList:
441 self.activatePlugin(name) 442 self.activatePlugin(name)
442 self.allPlugginsActivated.emit() 443 self.allPlugginsActivated.emit()
443 444
444 def activatePlugin(self, name, onDemand = False): 445 def activatePlugin(self, name, onDemand=False):
445 """ 446 """
446 Public method to activate a plugin. 447 Public method to activate a plugin.
447 448
448 @param name name of the module to be activated 449 @param name name of the module to be activated
449 @keyparam onDemand flag indicating activation of an 450 @keyparam onDemand flag indicating activation of an
450 on demand plugin (boolean) 451 on demand plugin (boolean)
451 @return reference to the initialized plugin object 452 @return reference to the initialized plugin object
452 """ 453 """
453 try: 454 try:
454 try: 455 try:
526 className = getattr(module, "className") 527 className = getattr(module, "className")
527 if not hasattr(module, className): 528 if not hasattr(module, className):
528 raise PluginModuleFormatError(module.eric5PluginModuleName, className) 529 raise PluginModuleFormatError(module.eric5PluginModuleName, className)
529 pluginClass = getattr(module, className) 530 pluginClass = getattr(module, className)
530 if not hasattr(pluginClass, "__init__"): 531 if not hasattr(pluginClass, "__init__"):
531 raise PluginClassFormatError(module.eric5PluginModuleName, 532 raise PluginClassFormatError(module.eric5PluginModuleName,
532 className, "__init__") 533 className, "__init__")
533 if not hasattr(pluginClass, "activate"): 534 if not hasattr(pluginClass, "activate"):
534 raise PluginClassFormatError(module.eric5PluginModuleName, 535 raise PluginClassFormatError(module.eric5PluginModuleName,
535 className, "activate") 536 className, "activate")
536 if not hasattr(pluginClass, "deactivate"): 537 if not hasattr(pluginClass, "deactivate"):
537 raise PluginClassFormatError(module.eric5PluginModuleName, 538 raise PluginClassFormatError(module.eric5PluginModuleName,
538 className, "deactivate") 539 className, "deactivate")
539 return True 540 return True
540 except PluginModuleFormatError as e: 541 except PluginModuleFormatError as e:
541 print(repr(e)) 542 print(repr(e))
542 return False 543 return False
543 except PluginClassFormatError as e: 544 except PluginClassFormatError as e:
544 print(repr(e)) 545 print(repr(e))
545 return False 546 return False
546 547
547 def deactivatePlugin(self, name, onDemand = False): 548 def deactivatePlugin(self, name, onDemand=False):
548 """ 549 """
549 Public method to deactivate a plugin. 550 Public method to deactivate a plugin.
550 551
551 @param name name of the module to be deactivated 552 @param name name of the module to be deactivated
552 @keyparam onDemand flag indicating deactivation of an 553 @keyparam onDemand flag indicating deactivation of an
553 on demand plugin (boolean) 554 on demand plugin (boolean)
554 """ 555 """
555 try: 556 try:
556 if onDemand: 557 if onDemand:
557 module = self.__onDemandActiveModules[name] 558 module = self.__onDemandActiveModules[name]
593 @return flag indicating, if the module satisfies all requirements 594 @return flag indicating, if the module satisfies all requirements
594 for being deactivated (boolean) 595 for being deactivated (boolean)
595 """ 596 """
596 return getattr(module, "deactivateable", True) 597 return getattr(module, "deactivateable", True)
597 598
598 def getPluginObject(self, type_, typename, maybeActive = False): 599 def getPluginObject(self, type_, typename, maybeActive=False):
599 """ 600 """
600 Public method to activate an ondemand plugin given by type and typename. 601 Public method to activate an ondemand plugin given by type and typename.
601 602
602 @param type_ type of the plugin to be activated (string) 603 @param type_ type of the plugin to be activated (string)
603 @param typename name of the plugin within the type category (string) 604 @param typename name of the plugin within the type category (string)
606 @return reference to the initialized plugin object 607 @return reference to the initialized plugin object
607 """ 608 """
608 for name, module in list(self.__onDemandInactiveModules.items()): 609 for name, module in list(self.__onDemandInactiveModules.items()):
609 if getattr(module, "pluginType") == type_ and \ 610 if getattr(module, "pluginType") == type_ and \
610 getattr(module, "pluginTypename") == typename: 611 getattr(module, "pluginTypename") == typename:
611 return self.activatePlugin(name, onDemand = True) 612 return self.activatePlugin(name, onDemand=True)
612 613
613 if maybeActive: 614 if maybeActive:
614 for name, module in list(self.__onDemandActiveModules.items()): 615 for name, module in list(self.__onDemandActiveModules.items()):
615 if getattr(module, "pluginType") == type_ and \ 616 if getattr(module, "pluginType") == type_ and \
616 getattr(module, "pluginTypename") == typename: 617 getattr(module, "pluginTypename") == typename:
617 self.deactivatePlugin(name, onDemand = True) 618 self.deactivatePlugin(name, onDemand=True)
618 return self.activatePlugin(name, onDemand = True) 619 return self.activatePlugin(name, onDemand=True)
619 620
620 return None 621 return None
621 622
622 def getPluginInfos(self): 623 def getPluginInfos(self):
623 """ 624 """
624 Public method to get infos about all loaded plugins. 625 Public method to get infos about all loaded plugins.
625 626
626 @return list of tuples giving module name (string), plugin name (string), 627 @return list of tuples giving module name (string), plugin name (string),
627 version (string), autoactivate (boolean), active (boolean), 628 version (string), autoactivate (boolean), active (boolean),
628 short description (string), error flag (boolean) 629 short description (string), error flag (boolean)
629 """ 630 """
630 infos = [] 631 infos = []
631 632
632 for name in list(self.__activeModules.keys()): 633 for name in list(self.__activeModules.keys()):
654 def __getShortInfo(self, module): 655 def __getShortInfo(self, module):
655 """ 656 """
656 Private method to extract the short info from a module. 657 Private method to extract the short info from a module.
657 658
658 @param module module to extract short info from 659 @param module module to extract short info from
659 @return short info as a tuple giving plugin name (string), 660 @return short info as a tuple giving plugin name (string),
660 short description (string), error flag (boolean) and 661 short description (string), error flag (boolean) and
661 version (string) 662 version (string)
662 """ 663 """
663 name = getattr(module, "name", "") 664 name = getattr(module, "name", "")
664 shortDesc = getattr(module, "shortDescription", "") 665 shortDesc = getattr(module, "shortDescription", "")
797 <li>header - string to be diplayed as a header (string)</li> 798 <li>header - string to be diplayed as a header (string)</li>
798 <li>exe - the executable (string)</li> 799 <li>exe - the executable (string)</li>
799 <li>versionCommand - commandline parameter for the exe (string)</li> 800 <li>versionCommand - commandline parameter for the exe (string)</li>
800 <li>versionStartsWith - indicator for the output line containing 801 <li>versionStartsWith - indicator for the output line containing
801 the version (string)</li> 802 the version (string)</li>
802 <li>versionPosition - number of element containing the 803 <li>versionPosition - number of element containing the
803 version (integer)</li> 804 version (integer)</li>
804 <li>version - version to be used as default (string)</li> 805 <li>version - version to be used as default (string)</li>
805 <li>versionCleanup - tuple of two integers giving string positions 806 <li>versionCleanup - tuple of two integers giving string positions
806 start and stop for the version string (tuple of integers)</li> 807 start and stop for the version string (tuple of integers)</li>
807 </ul> 808 </ul>
845 This should be a localized string</dd> 846 This should be a localized string</dd>
846 <dt>pixmap name</dt> 847 <dt>pixmap name</dt>
847 <dd>filename of the pixmap to be shown next to the display string</dd> 848 <dd>filename of the pixmap to be shown next to the display string</dd>
848 <dt>page creation function</dt> 849 <dt>page creation function</dt>
849 <dd>plugin module function to be called to create the configuration 850 <dd>plugin module function to be called to create the configuration
850 page. The page must be subclasses from 851 page. The page must be subclasses from
851 Preferences.ConfigurationPages.ConfigurationPageBase and must 852 Preferences.ConfigurationPages.ConfigurationPageBase and must
852 implement a method called 'save' to save the settings. A parent 853 implement a method called 'save' to save the settings. A parent
853 entry will be created in the selection list, if this value is None.</dd> 854 entry will be created in the selection list, if this value is None.</dd>
854 <dt>parent key</dt> 855 <dt>parent key</dt>
855 <dd>dictionary key of the parent entry or None, if this defines a 856 <dd>dictionary key of the parent entry or None, if this defines a
856 toplevel entry.</dd> 857 toplevel entry.</dd>
857 <dt>reference to configuration page</dt> 858 <dt>reference to configuration page</dt>
858 <dd>This will be used by the configuration dialog and must always be None</dd> 859 <dd>This will be used by the configuration dialog and must always be None</dd>
859 </dl> 860 </dl>
860 """ 861 """

eric ide

mercurial