Last active
August 1, 2018 22:56
-
-
Save shawnohare/a146d8580020c5ad91cf37c94535d295 to your computer and use it in GitHub Desktop.
Get all modules from a package.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import inspect | |
import pkgutil | |
from importlib import import_module | |
def get_package_modules(package): | |
"""Recursively get all modules of a package, including modules of any | |
subpackages. | |
""" | |
modules = [] | |
for _, name, ispkg in pkgutil.iter_modules(package.__path__): | |
mod = import_module('.' + name, package=package.__name__) | |
# Include package modules in the list to inspect what might be defined there. | |
modules.append(mod) | |
if ispkg: | |
modules.extend(_get_package_modules(mod)) | |
return modules | |
def get_defined_subclasses(module, cls): | |
"""Get any subclasses that are defined in the specified module. | |
This can include the class itself. | |
Args: | |
module (module): Module instance to inspect. | |
cls (class): Class to find subclasses of. | |
Returns: | |
list(class): List of subclasses defined in the module. | |
""" | |
def ok(member): | |
return ( | |
inspect.isclass(member) and | |
member.__module__ == module.__name__ and | |
issubclass(member, cls) and | |
) | |
return [m for _, m in inspect.getmembers(module, ok)] | |
def subclasses(cls, module=None): | |
"""Finds subclasses of given class and returns as a :py:class:`dict` | |
of subclass name key to its class object value. Subclasses are | |
looked for within the same package where ``cls`` is defined, or within | |
a specific module when ``module`` is provided. | |
Args: | |
cls (class): Class to find subclasses of. | |
module (str or module): A module instance to inspect. Only classes defined | |
in the module are included. | |
""" | |
ispkg = lambda mod: hasattr(mod, '__path__') | |
# Look in either the specified module or the package containing cls. | |
module = import_module(module) if isinstance(module, basestring) else module | |
if module is not None: | |
modules = _get_package_modules(module) if ispkg(module) else [module] | |
else: | |
# Look at all modules in the top-most package containing cls. | |
package_name = cls.__module__.split('.', 1)[0] | |
modules = _get_package_modules(import_module(package_name)) | |
subclasses = [] | |
for module in modules: | |
subclasses.extend(get_defined_subclasses(module)) | |
return subclasses | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment