-
-
Save Dbof/c7df34806cbbda2f94ca119db97b2e70 to your computer and use it in GitHub Desktop.
Script to find and load classes from a specific directory
This file contains 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 os | |
import inspect | |
import logging | |
from importlib.machinery import SourceFileLoader | |
import pkg_resources | |
logger = logging.getLogger(__name__) | |
# Search in "project/modules/" | |
SEARCH_PATHS = [pkg_resources.resource_filename("project", "modules")] | |
def search(base): | |
""" | |
Search subclasses of class 'base' and return a list. | |
""" | |
class_list = set() | |
class_list_modules = set() # for preventing module reload | |
for path in SEARCH_PATHS: | |
logger.debug('Entering path \'{}\''.format(path)) | |
for root, d, files in os.walk(path): | |
# search for files with .py extension | |
candidates = [fname for fname in files if fname.endswith('.py') and | |
not fname.startswith('__')] | |
classes = [] | |
for c in candidates: | |
# get filename | |
modname = os.path.splitext(c)[0] | |
try: | |
if modname in class_list_modules: | |
# module already loaded | |
continue | |
# load class into current Python env | |
module = SourceFileLoader( | |
modname, | |
os.path.join(root, c)).load_module() | |
# add loaded module to set | |
class_list_modules.add(modname) | |
logger.debug('Loaded module \'{}\''.format(modname)) | |
except (SystemError, ImportError, | |
NotImplementedError, SyntaxError) as e: | |
logger.debug(e) | |
logger.warn(f'Module could not be loaded: {modname}') | |
continue | |
# enumerate classes found in module | |
for cls in dir(module): | |
# for every class, get the actual "class" object" for checks | |
cls = getattr(module, cls) | |
# if class is a class and is part of the module | |
# and is a subclass of argument base (but not the base itself) | |
if (inspect.isclass(cls) and | |
inspect.getmodule(cls) == module and | |
issubclass(cls, base) and | |
cls != base): | |
logger.info('Class found in {f}'.format(f=module)) | |
# found | |
classes.append(cls) | |
class_list.update(classes) | |
logger.debug('Imported modules: {}'.format(str(class_list_modules))) | |
logger.debug('Returned class list: {}'.format(str(class_list))) | |
return list(class_list) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment