4545 :toctree: generated/
4646 :nosignatures:
4747
48+ IncompletePluginImplError
4849 PluginNotInstalledError
4950"""
5051from __future__ import absolute_import
6061 'pluggable' ,
6162 'plugin' ,
6263 'plugin_manager' ,
64+ 'IncompletePluginImplError' ,
6365 'PluginManager' ,
6466 'PluginNotInstalledError' ,
67+ 'PluginValidator' ,
6568]
6669
6770
@@ -81,6 +84,11 @@ def _get_extension_point_url_from_method(domain, category, plugin_method):
8184 return '{}/{}/{}' .format (domain , category , name ).replace ('//' , '/' )
8285
8386
87+ class IncompletePluginImplError (Exception ):
88+ """Exception raised when a plugin does not have implementations for all abstract methods of its base class."""
89+ pass
90+
91+
8492class PluginImpl (object ):
8593 """Internal data class to keep track of a loaded plugin implementation.
8694
@@ -392,7 +400,11 @@ def try_import(self, module_name):
392400 try :
393401 module = __import__ (module_name , fromlist = ['__name__' ], level = 0 )
394402 self ._cache [module_name ] = True
395- except ImportError :
403+
404+ # There are two types of possible failure modes:
405+ # 1) cannot be imported, or
406+ # 2) is a python 3 module and we're in IPY, which causes a SyntaxError
407+ except (ImportError , SyntaxError ):
396408 self ._cache [module_name ] = False
397409
398410 return module
@@ -416,46 +428,56 @@ def check_importable(self, module_name):
416428 return self ._cache [module_name ]
417429
418430
419- def verify_requirement (manager , requirement ):
420- if callable (requirement ):
421- return requirement ()
431+ class PluginValidator (object ):
432+ """Plugin Validator handles validation of plugins."""
422433
423- return manager .importer .check_importable (requirement )
434+ def __init__ (self , manager ):
435+ self .manager = manager
424436
437+ def verify_requirement (self , requirement ):
438+ if callable (requirement ):
439+ return requirement ()
425440
426- def is_plugin_selectable (plugin , manager ):
427- if plugin .opts ['requires' ]:
428- importable_requirements = (verify_requirement (manager , requirement ) for requirement in plugin .opts ['requires' ])
441+ return self .manager .importer .check_importable (requirement )
429442
430- if not all (importable_requirements ):
431- if manager .DEBUG :
432- print ('Requirements not satisfied. Plugin will not be used: {}' .format (plugin .id ))
433- return False
443+ def is_plugin_selectable (self , plugin ):
444+ if plugin .opts ['requires' ]:
445+ importable_requirements = (self .verify_requirement (requirement ) for requirement in plugin .opts ['requires' ])
434446
435- return True
447+ if not all (importable_requirements ):
448+ if self .manager .DEBUG :
449+ print ('Requirements not satisfied. Plugin will not be used: {}' .format (plugin .id ))
450+ return False
436451
452+ return True
437453
438- def select_plugin (extension_point_url , manager ):
439- if manager .DEBUG :
440- print ('Extension Point URL {} invoked. Will select a matching plugin' .format (extension_point_url ))
454+ def select_plugin (self , extension_point_url ):
455+ if self . manager .DEBUG :
456+ print ('Extension Point URL {} invoked. Will select a matching plugin' .format (extension_point_url ))
441457
442- plugins = manager .registry .get (extension_point_url ) or []
443- for plugin in plugins :
444- if is_plugin_selectable (plugin , manager ):
445- return plugin
458+ plugins = self . manager .registry .get (extension_point_url ) or []
459+ for plugin in plugins :
460+ if self . is_plugin_selectable (plugin ):
461+ return plugin
446462
447- # Nothing found, raise
448- raise PluginNotInstalledError ('Plugin not found for extension point URL: {}' .format (extension_point_url ))
463+ # Nothing found, raise
464+ raise PluginNotInstalledError ('Plugin not found for extension point URL: {}' .format (extension_point_url ))
449465
466+ def collect_plugins (self , extension_point_url ):
467+ if self .manager .DEBUG :
468+ print ('Extension Point URL {} invoked. Will select a matching plugin' .format (extension_point_url ))
450469
451- def collect_plugins (extension_point_url , manager ):
452- if manager .DEBUG :
453- print ('Extension Point URL {} invoked. Will select a matching plugin' .format (extension_point_url ))
470+ plugins = self .manager .registry .get (extension_point_url ) or []
471+ return [plugin for plugin in plugins if self .is_plugin_selectable (plugin )]
454472
455- plugins = manager .registry .get (extension_point_url ) or []
456- return [plugin for plugin in plugins if is_plugin_selectable (plugin , manager )]
473+ @staticmethod
474+ def ensure_implementations (cls ):
475+ for name , value in inspect .getmembers (cls ):
476+ if inspect .isfunction (value ) or inspect .ismethod (value ):
477+ if hasattr (value , '__isabstractmethod__' ):
478+ raise IncompletePluginImplError ('Abstract method not implemented: {}' .format (value ))
457479
458480
459481plugin_manager = PluginManager ()
460- _select_plugin = functools . partial ( select_plugin , manager = plugin_manager )
461- _collect_plugins = functools . partial ( collect_plugins , manager = plugin_manager )
482+ _select_plugin = PluginValidator ( plugin_manager ). select_plugin
483+ _collect_plugins = PluginValidator ( plugin_manager ). collect_plugins
0 commit comments