manager.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import sys
  2. import six
  3. from pike.discovery import filesystem
  4. from pike.discovery import py
  5. from pike.finder import PikeFinder
  6. class PikeManager(object):
  7. def __init__(self, search_paths=None):
  8. """The Pike plugin manager
  9. The manager allows for the dynamic loading of Python packages for any
  10. location on a user's filesystem.
  11. :param list search_paths: List of path strings to include during module
  12. importing. These paths are only in addition to existing Python
  13. import search paths.
  14. Using PikeManager as a context manager:
  15. .. code-block:: python
  16. from pike.manager import PikeManager
  17. with PikeManager(['/path/containing/package']) as mgr:
  18. import module_in_the_package
  19. Using PikeManager instance:
  20. .. code-block:: python
  21. from pike.manager import PikeManager
  22. mgr = PikeManager(['/path/container/package'])
  23. import module_in_the_package
  24. mgr.cleanup()
  25. """
  26. self.search_paths = search_paths or []
  27. self.module_finder = PikeFinder(search_paths)
  28. self.add_to_meta_path()
  29. def cleanup(self):
  30. """Removes Pike's import hooks
  31. This should be called if an implementer is not using the manager as
  32. a context manager.
  33. """
  34. if sys.meta_path and self.module_finder in sys.meta_path:
  35. sys.meta_path.remove(self.module_finder)
  36. def add_to_meta_path(self):
  37. """Adds Pike's import hooks to Python
  38. This should be automatically handled by Pike; however, this is method
  39. is accessible for very rare use-cases.
  40. """
  41. if self.module_finder in sys.meta_path:
  42. return
  43. if six.PY3:
  44. sys.meta_path.insert(0, self.module_finder)
  45. else:
  46. sys.meta_path.append(self.module_finder)
  47. def get_classes(self, filter_func=None):
  48. """Get all classes within modules on the manager's search paths
  49. :param Function filter_func: Custom filter function(cls_obj).
  50. :returns: :class:`List` of all found classes
  51. """
  52. all_classes = []
  53. # Top-most Modules
  54. for module_name in self.get_module_names():
  55. module = py.get_module_by_name(module_name)
  56. all_classes.extend(py.classes_in_module(module, filter_func))
  57. # All packages
  58. for module_name in self.get_package_names():
  59. module = py.get_module_by_name(module_name)
  60. all_classes.extend(py.get_all_classes(module, filter_func))
  61. return all_classes
  62. def get_all_inherited_classes(self, base_class):
  63. """Retrieve all inherited classes from manager's search paths
  64. :param Class base_class: Base class to filter results by
  65. :return: :class:`List` of all found classes
  66. """
  67. all_classes = []
  68. # Top-most Modules
  69. for module_name in self.get_module_names():
  70. module = py.get_module_by_name(module_name)
  71. all_classes.extend(py.get_inherited_classes(module, base_class))
  72. # All packages
  73. for module_name in self.get_package_names():
  74. module = py.get_module_by_name(module_name)
  75. inherited = py.get_all_inherited_classes(module, base_class)
  76. all_classes.extend(inherited)
  77. return all_classes
  78. def get_module_names(self):
  79. """Get root module names available on the manager's search paths
  80. :returns: :class:`generator` providing available module names.
  81. """
  82. for path in self.search_paths:
  83. for package_path in filesystem.find_modules(path):
  84. yield filesystem.get_name(package_path)
  85. def get_package_names(self):
  86. """Get root package names available on the manager's search paths
  87. :returns: :class:`generator` providing available package names.
  88. """
  89. for path in self.search_paths:
  90. for package_path in filesystem.find_packages(path):
  91. yield filesystem.get_name(package_path)
  92. def __enter__(self):
  93. return self
  94. def __exit__(self, type, value, traceback):
  95. self.cleanup()
  96. def __del__(self):
  97. self.cleanup()