/pyblosxom/Pyblosxom/plugin_utils.py

https://bitbucket.org/spaetz/pyblosxom_blog
Python | 166 lines | 116 code | 8 blank | 42 comment | 7 complexity | db108a5ba99e447317ed93b048a1b2df MD5 | raw file
  1. #######################################################################
  2. # This file is part of PyBlosxom.
  3. #
  4. # Copyright (c) 2003-2006 Wari Wahab
  5. # Copyright (c) 2003-2010 Will Kahn-Greene
  6. #
  7. # PyBlosxom is distributed under the MIT license. See the file LICENSE
  8. # for distribution details.
  9. #######################################################################
  10. """
  11. Holds a series of utility functions for cataloguing, retrieving, and
  12. manipulating callback functions and chains. Refer to the documentation
  13. for which callbacks are available and their behavior.
  14. """
  15. import os
  16. import glob
  17. import sys
  18. import os.path
  19. # this holds the list of plugins that have been loaded. if you're running
  20. # PyBlosxom as a long-running process, this only gets cleared when the
  21. # process is restarted.
  22. plugins = []
  23. # this holds a list of callbacks (any function that begins with cp_) and the
  24. # list of function instances that support that callback.
  25. # if you're running PyBlosxom as a long-running process, this only
  26. # gets cleared when the process is restarted.
  27. callbacks = {}
  28. def catalogue_plugin(plugin_module):
  29. """
  30. Goes through the plugin's contents and catalogues all the functions
  31. that start with cb_. Functions that start with cb_ are callbacks.
  32. @param plugin_module: the module to catalogue
  33. @type plugin_module: module
  34. """
  35. listing = dir(plugin_module)
  36. listing = [item for item in listing if item.startswith("cb_")]
  37. for mem in listing:
  38. func = getattr(plugin_module, mem)
  39. memadj = mem[3:]
  40. if callable(func):
  41. callbacks.setdefault(memadj, []).append(func)
  42. def get_callback_chain(chain):
  43. """
  44. Returns a list of functions registered with the callback.
  45. @returns: list of functions registered with the callback (or an
  46. empty list)
  47. @rtype: list of functions
  48. """
  49. return callbacks.get(chain, [])
  50. def initialize_plugins(plugin_dirs, plugin_list):
  51. """
  52. Imports and initializes plugins from the directories in the list
  53. specified by "plugins_dir". If no such list exists, then we don't
  54. load any plugins.
  55. If the user specifies a "load_plugins" list of plugins to load, then
  56. we explicitly load those plugins in the order they're listed. If the
  57. load_plugins key does not exist, then we load all the plugins in the
  58. plugins directory using an alphanumeric sorting order.
  59. NOTE: If PyBlosxom is part of a long-running process, you must
  60. restart PyBlosxom in order to pick up any changes to your plugins.
  61. @param plugin_dirs: the list of directories to add to the sys.path
  62. because that's where our plugins are located.
  63. @type plugin_dirs: list of strings
  64. @param plugin_list: the list of plugins to load, or if None, we'll
  65. load all the plugins we find in those dirs.
  66. @type plugin_list: list of strings or None
  67. """
  68. if plugins:
  69. return
  70. # we clear out the callbacks dict so we can rebuild them
  71. callbacks.clear()
  72. # handle plugin_dirs here
  73. for mem in plugin_dirs:
  74. if os.path.isdir(mem):
  75. sys.path.append(mem)
  76. else:
  77. raise Exception("Plugin directory '%s' does not exist. " \
  78. "Please check your config file." % mem)
  79. plugin_list = get_plugin_list(plugin_list, plugin_dirs)
  80. for mem in plugin_list:
  81. _module = __import__(mem)
  82. for comp in mem.split(".")[1:]:
  83. _module = getattr(_module, comp)
  84. catalogue_plugin(_module)
  85. plugins.append(_module)
  86. def get_plugin_by_name(name):
  87. """
  88. This retrieves a plugin instance (it's a Python module instance)
  89. by name.
  90. @param name: the name of the plugin to retrieve (ex: "xmlrpc")
  91. @type name: string
  92. @returns: the Python module instance for the plugin or None
  93. @rtype: Python module
  94. """
  95. if plugins:
  96. for mem in plugins:
  97. if mem.__name__ == name:
  98. return mem
  99. return None
  100. def get_module_name(filename):
  101. """
  102. Takes a filename and returns the module name from the filename.
  103. Example: passing in "/blah/blah/blah/module.ext" returns "module"
  104. @param filename: the filename in question (with a full path)
  105. @type filename: string
  106. @returns: the filename without path or extension
  107. @rtype: string
  108. """
  109. return os.path.splitext(os.path.split(filename)[1])[0]
  110. def get_plugin_list(plugin_list, plugin_dirs):
  111. """
  112. This handles the situation where the user has provided a series of
  113. plugin dirs, but has not specified which plugins they want to load
  114. from those dirs. In this case, we load all possible plugins except
  115. the ones whose names being with _ .
  116. @param plugin_list: List of plugins to load
  117. @type plugin_list: list or None
  118. @param plugin_dirs: A list of directories where plugins can be loaded from
  119. @type plugin_dirs: list
  120. @return: list of python module names of the plugins to load
  121. @rtype: list of strings
  122. """
  123. if plugin_list == None:
  124. plugin_list = []
  125. for mem in plugin_dirs:
  126. file_list = glob.glob(os.path.join(mem, "*.py"))
  127. file_list = [get_module_name(filename) for filename in file_list]
  128. # remove plugins that start with a _
  129. file_list = [plugin for plugin in file_list \
  130. if not plugin.startswith('_')]
  131. plugin_list += file_list
  132. plugin_list.sort()
  133. return plugin_list