extension.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. """Cement core extensions module."""
  2. import sys
  3. from ..core import exc, interface, handler
  4. from ..utils.misc import minimal_logger
  5. if sys.version_info[0] >= 3:
  6. from imp import reload # pragma: no cover
  7. LOG = minimal_logger(__name__)
  8. def extension_validator(klass, obj):
  9. """
  10. Validates an handler implementation against the IExtension interface.
  11. """
  12. members = [
  13. '_setup',
  14. 'load_extension',
  15. 'load_extensions',
  16. 'get_loaded_extensions',
  17. ]
  18. interface.validate(IExtension, obj, members)
  19. class IExtension(interface.Interface):
  20. """
  21. This class defines the Extension Handler Interface. Classes that
  22. implement this handler must provide the methods and attributes defined
  23. below.
  24. Implementations do *not* subclass from interfaces.
  25. Usage:
  26. .. code-block:: python
  27. from cement.core import extension
  28. class MyExtensionHandler(object):
  29. class Meta:
  30. interface = extension.IExtension
  31. label = 'my_extension_handler'
  32. ...
  33. """
  34. # pylint: disable=W0232, C0111, R0903
  35. class IMeta:
  36. """Interface meta-data."""
  37. label = 'extension'
  38. """The string identifier of the interface."""
  39. validator = extension_validator
  40. """The interface validator function."""
  41. # Must be provided by the implementation
  42. Meta = interface.Attribute('Handler Meta-data class')
  43. def _setup(app_obj):
  44. """
  45. The _setup function is called during application initialization and
  46. must 'setup' the handler object making it ready for the framework
  47. or the application to make further calls to it.
  48. :param app_obj: The application object.
  49. :returns: None
  50. """
  51. def load_extension(self, ext_module):
  52. """
  53. Load an extension whose module is 'ext_module'. For example,
  54. 'cement.ext.ext_configobj'.
  55. :param ext_module: The name of the extension to load.
  56. :type ext_module: ``str``
  57. """
  58. def load_extensions(self, ext_list):
  59. """
  60. Load all extensions from ext_list.
  61. :param ext_list: A list of extension modules to load. For example:
  62. ``['cement.ext.ext_configobj', 'cement.ext.ext_logging']``
  63. :type ext_list: ``list``
  64. """
  65. class CementExtensionHandler(handler.CementBaseHandler):
  66. class Meta:
  67. """
  68. Handler meta-data (can be passed as keyword arguments to the parent
  69. class).
  70. """
  71. interface = IExtension
  72. """The interface that this class implements."""
  73. label = 'cement'
  74. """The string identifier of the handler."""
  75. def __init__(self, **kw):
  76. """
  77. This is an implementation of the IExtentionHandler interface. It
  78. handles loading framework extensions.
  79. """
  80. super(CementExtensionHandler, self).__init__(**kw)
  81. self.app = None
  82. self._loaded_extensions = []
  83. def get_loaded_extensions(self):
  84. """Returns list of loaded extensions."""
  85. return self._loaded_extensions
  86. def load_extension(self, ext_module):
  87. """
  88. Given an extension module name, load or in other-words 'import' the
  89. extension.
  90. :param ext_module: The extension module name. For example:
  91. 'cement.ext.ext_logging'.
  92. :type ext_module: ``str``
  93. :raises: cement.core.exc.FrameworkError
  94. """
  95. # If its not a full module path then preppend our default path
  96. if ext_module.find('.') == -1:
  97. ext_module = 'cement.ext.ext_%s' % ext_module
  98. if ext_module in self._loaded_extensions:
  99. LOG.debug("framework extension '%s' already loaded" % ext_module)
  100. return
  101. LOG.debug("loading the '%s' framework extension" % ext_module)
  102. try:
  103. if ext_module not in sys.modules:
  104. __import__(ext_module, globals(), locals(), [], 0)
  105. if hasattr(sys.modules[ext_module], 'load'):
  106. sys.modules[ext_module].load(self.app)
  107. if ext_module not in self._loaded_extensions:
  108. self._loaded_extensions.append(ext_module)
  109. except ImportError as e:
  110. raise exc.FrameworkError(e.args[0])
  111. def load_extensions(self, ext_list):
  112. """
  113. Given a list of extension modules, iterate over the list and pass
  114. individually to self.load_extension().
  115. :param ext_list: A list of extension modules.
  116. :type ext_list: ``list``
  117. """
  118. for ext in ext_list:
  119. self.load_extension(ext)