11 import sys |
11 import sys |
12 import zipfile |
12 import zipfile |
13 import types |
13 import types |
14 import importlib |
14 import importlib |
15 import contextlib |
15 import contextlib |
|
16 import logging |
16 |
17 |
17 from PyQt5.QtCore import ( |
18 from PyQt5.QtCore import ( |
18 pyqtSignal, QObject, QDate, QFile, QFileInfo, QUrl, QIODevice |
19 pyqtSignal, QObject, QDate, QFile, QFileInfo, QUrl, QIODevice |
19 ) |
20 ) |
20 from PyQt5.QtGui import QPixmap |
21 from PyQt5.QtGui import QPixmap |
108 |
109 |
109 self.__inactivePluginsKey = "PluginManager/InactivePlugins" |
110 self.__inactivePluginsKey = "PluginManager/InactivePlugins" |
110 |
111 |
111 self.pluginDirs = { |
112 self.pluginDirs = { |
112 "eric6": os.path.join(getConfig('ericDir'), "Plugins"), |
113 "eric6": os.path.join(getConfig('ericDir'), "Plugins"), |
113 "global": os.path.join(Utilities.getPythonModulesDirectory(), |
114 "global": os.path.join(Utilities.getPythonLibraryDirectory(), |
114 "eric6plugins"), |
115 "eric6plugins"), |
115 "user": os.path.join(Utilities.getConfigDir(), "eric6plugins"), |
116 "user": os.path.join(Utilities.getConfigDir(), "eric6plugins"), |
116 } |
117 } |
117 self.__priorityOrder = ["eric6", "global", "user"] |
118 self.__priorityOrder = ["eric6", "global", "user"] |
118 |
119 |
377 for pluginName in self.__foundCoreModules: |
378 for pluginName in self.__foundCoreModules: |
378 # plug-in under development has priority |
379 # plug-in under development has priority |
379 if pluginName.startswith("PluginDocumentationSets"): |
380 if pluginName.startswith("PluginDocumentationSets"): |
380 self.loadPlugin(pluginName, self.pluginDirs["eric6"]) |
381 self.loadPlugin(pluginName, self.pluginDirs["eric6"]) |
381 |
382 |
382 def loadPlugin(self, name, directory, reload_=False): |
383 def loadPlugin(self, name, directory, reload_=False, install=False): |
383 """ |
384 """ |
384 Public method to load a plugin module. |
385 Public method to load a plugin module. |
385 |
386 |
386 Initially all modules are inactive. Modules that are requested on |
387 Initially all modules are inactive. Modules that are requested on |
387 demand are sorted out and are added to the on demand list. Some |
388 demand are sorted out and are added to the on demand list. Some |
388 basic validity checks are performed as well. Modules failing these |
389 basic validity checks are performed as well. Modules failing these |
389 checks are added to the failed modules list. |
390 checks are added to the failed modules list. |
390 |
391 |
391 @param name name of the module to be loaded (string) |
392 @param name name of the module to be loaded |
392 @param directory name of the plugin directory (string) |
393 @type str |
393 @param reload_ flag indicating to reload the module (boolean) |
394 @param directory name of the plugin directory |
|
395 @type str |
|
396 @param reload_ flag indicating to reload the module |
|
397 @type bool |
|
398 @param install flag indicating a load operation as part of an |
|
399 installation process |
|
400 @type bool |
394 @exception PluginLoadError raised to indicate an issue loading |
401 @exception PluginLoadError raised to indicate an issue loading |
395 the plug-in |
402 the plug-in |
396 """ |
403 """ |
397 try: |
404 try: |
398 fname = "{0}.py".format(os.path.join(directory, name)) |
405 fname = "{0}.py".format(os.path.join(directory, name)) |
401 sys.modules[module.__name__] = module |
408 sys.modules[module.__name__] = module |
402 spec.loader.exec_module(module) |
409 spec.loader.exec_module(module) |
403 if not hasattr(module, "autoactivate"): |
410 if not hasattr(module, "autoactivate"): |
404 module.error = self.tr( |
411 module.error = self.tr( |
405 "Module is missing the 'autoactivate' attribute.") |
412 "Module is missing the 'autoactivate' attribute.") |
|
413 logging.debug( |
|
414 "{0}: Module is missing the 'autoactivate' attribute." |
|
415 .format(name) |
|
416 ) |
406 self.__failedModules[name] = module |
417 self.__failedModules[name] = module |
407 raise PluginLoadError(name) |
418 raise PluginLoadError(name) |
408 if getattr(module, "autoactivate", False): |
419 if getattr(module, "autoactivate", False): |
409 self.__inactiveModules[name] = module |
420 self.__inactiveModules[name] = module |
410 else: |
421 else: |
414 ): |
425 ): |
415 module.error = self.tr( |
426 module.error = self.tr( |
416 "Module is missing the 'pluginType' " |
427 "Module is missing the 'pluginType' " |
417 "and/or 'pluginTypename' attributes." |
428 "and/or 'pluginTypename' attributes." |
418 ) |
429 ) |
|
430 logging.debug( |
|
431 "{0}: Module is missing the 'pluginType' " |
|
432 "and/or 'pluginTypename' attributes." |
|
433 .format(name) |
|
434 ) |
419 self.__failedModules[name] = module |
435 self.__failedModules[name] = module |
420 raise PluginLoadError(name) |
436 raise PluginLoadError(name) |
421 else: |
437 else: |
422 self.__onDemandInactiveModules[name] = module |
438 self.__onDemandInactiveModules[name] = module |
423 module.eric6PluginModuleName = name |
439 module.eric6PluginModuleName = name |
424 module.eric6PluginModuleFilename = fname |
440 module.eric6PluginModuleFilename = fname |
|
441 if install and hasattr(module, "installDependencies"): |
|
442 # ask the module to install its dependencies |
|
443 module.installDependencies(self.pipInstall) |
425 self.__modulesCount += 1 |
444 self.__modulesCount += 1 |
426 if reload_: |
445 if reload_: |
427 importlib.reload(module) |
446 importlib.reload(module) |
428 self.initOnDemandPlugin(name) |
447 self.initOnDemandPlugin(name) |
429 with contextlib.suppress(KeyError, AttributeError): |
448 with contextlib.suppress(KeyError, AttributeError): |
434 print("Error loading plug-in module:", name) |
453 print("Error loading plug-in module:", name) |
435 except Exception as err: |
454 except Exception as err: |
436 module = types.ModuleType(name) |
455 module = types.ModuleType(name) |
437 module.error = self.tr( |
456 module.error = self.tr( |
438 "Module failed to load. Error: {0}").format(str(err)) |
457 "Module failed to load. Error: {0}").format(str(err)) |
|
458 logging.debug( |
|
459 "{0}: Module failed to load. Error: {1}" |
|
460 .format(name, str(err)) |
|
461 ) |
439 self.__failedModules[name] = module |
462 self.__failedModules[name] = module |
440 print("Error loading plug-in module:", name) |
463 print("Error loading plug-in module:", name) |
441 print(str(err)) |
464 print(str(err)) |
442 |
465 |
443 def unloadPlugin(self, name): |
466 def unloadPlugin(self, name): |
611 try: |
634 try: |
612 obj, ok = pluginObject.activate() |
635 obj, ok = pluginObject.activate() |
613 except TypeError: |
636 except TypeError: |
614 module.error = self.tr( |
637 module.error = self.tr( |
615 "Incompatible plugin activation method.") |
638 "Incompatible plugin activation method.") |
|
639 logging.debug( |
|
640 "{0}: Incompatible plugin activation method." |
|
641 .format(name) |
|
642 ) |
616 obj = None |
643 obj = None |
617 ok = True |
644 ok = True |
618 except Exception as err: |
645 except Exception as err: |
619 module.error = str(err) |
646 module.error = str(err) |
|
647 logging.debug("{0}: {1}".format(name, str(err))) |
620 obj = None |
648 obj = None |
621 ok = False |
649 ok = False |
622 if not ok: |
650 if not ok: |
623 return None |
651 return None |
624 |
652 |
1414 if ( |
1442 if ( |
1415 getattr(module, "pluginType", "") == type_ and |
1443 getattr(module, "pluginType", "") == type_ and |
1416 hasattr(module, "clearPrivateData") |
1444 hasattr(module, "clearPrivateData") |
1417 ): |
1445 ): |
1418 module.clearPrivateData() |
1446 module.clearPrivateData() |
|
1447 |
|
1448 ######################################################################## |
|
1449 ## Methods to install a plug-in module dependency via pip |
|
1450 ######################################################################## |
|
1451 |
|
1452 def pipInstall(self, packages): |
|
1453 """ |
|
1454 Public method to install the given package via pip. |
|
1455 |
|
1456 @param packages list of packages to install |
|
1457 @type list of str |
|
1458 """ |
|
1459 try: |
|
1460 pip = e5App().getObject("Pip") |
|
1461 except KeyError: |
|
1462 # Installation is performed via the plug-in installation script. |
|
1463 from PipInterface.Pip import Pip |
|
1464 pip = Pip(self) |
|
1465 pip.installPackages(packages, interpreter=sys.executable) |
1419 |
1466 |
1420 # |
1467 # |
1421 # eflag: noqa = M801 |
1468 # eflag: noqa = M801 |