py.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import os
  2. import importlib
  3. import inspect
  4. from pike.discovery import filesystem
  5. def get_module_by_name(full_module_name):
  6. """Import module by full name
  7. :param str full_module_name: Full module name e.g. (pike.discovery.py)
  8. :return: Imported :class:`module`
  9. """
  10. return importlib.import_module(full_module_name)
  11. def is_child_of_module(obj, parent):
  12. package, _, name = obj.__name__.rpartition('.')
  13. return package.startswith(parent.__name__)
  14. def _import_from_path(path, package_name):
  15. module_name = filesystem.get_name(path)
  16. fullname = '{}.{}'.format(package_name, module_name)
  17. return get_module_by_name(fullname)
  18. def _child_modules(module):
  19. package_path = os.path.dirname(inspect.getabsfile(module))
  20. # Import all child modules
  21. for module_path in filesystem.find_modules(package_path):
  22. _import_from_path(module_path, module.__package__ or module.__name__)
  23. # Import all sub packages
  24. for package_path in filesystem.find_packages(package_path):
  25. _import_from_path(package_path, module.__package__ or module.__name__)
  26. for name, obj in inspect.getmembers(module):
  27. if inspect.ismodule(obj) and is_child_of_module(obj, module):
  28. yield obj
  29. def classes_in_module(module, filter_func=None):
  30. """Retrieve classes within a module
  31. :param module module: Module to search under
  32. :param Function filter_func: Custom filter function(cls_obj).
  33. :return: :class:`generator` containing classes within a module
  34. """
  35. finder_filter = filter_func or (lambda x: True)
  36. for name, obj in inspect.getmembers(module):
  37. if inspect.isclass(obj) and finder_filter(obj):
  38. yield obj
  39. def get_inherited_classes(module, base_class):
  40. """Retrieve inherited classes from a single module
  41. :param module module: Module to search under
  42. :param Class base_class: Base class to filter results by
  43. :return: :class:`List` of all found classes
  44. """
  45. def class_filter(cls):
  46. return cls != base_class and issubclass(cls, base_class)
  47. return list(classes_in_module(module, class_filter))
  48. def get_child_modules(module, recursive=True):
  49. """Retrieve child modules
  50. :param module module: Module to search under
  51. :param bool recursive: Toggles the retrieval of sub-children module.
  52. :return: :class:`generator` containing child modules
  53. """
  54. for child_module in _child_modules(module):
  55. yield child_module
  56. if recursive:
  57. for sub_child_module in _child_modules(child_module):
  58. yield sub_child_module
  59. def get_all_classes(module, filter_func=None):
  60. """Retrieve all classes from modules
  61. :param module module: Module to search under
  62. :param Function filter_func: Custom filter function(cls_obj).
  63. :returns: :class:`List` of all found classes
  64. """
  65. all_classes = []
  66. # Current module's classes
  67. all_classes.extend([cls for cls in classes_in_module(module, filter_func)])
  68. # All child module classes
  69. for child_module in get_child_modules(module):
  70. child_module_classes = classes_in_module(child_module, filter_func)
  71. all_classes.extend([cls for cls in child_module_classes])
  72. # TODO(jmvrbanac): Rework this so that we don't have to use a set
  73. return list(set(all_classes))
  74. def get_all_inherited_classes(module, base_class):
  75. """Retrieve all inherited classes from modules
  76. :param module module: Module to search under
  77. :param Class base_class: Base class to filter results by
  78. :return: :class:`List` of all found classes
  79. """
  80. def class_filter(cls):
  81. return cls != base_class and issubclass(cls, base_class)
  82. return get_all_classes(module, class_filter)