Source code for ccpn.util.SubclassLoader

#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (http://www.ccpn.ac.uk) 2014 - 2019"
__credits__ = ("Ed Brooksbank, Luca Mureddu, Timothy J Ragan & Geerten W Vuister")
__licence__ = ("CCPN licence. See http://www.ccpn.ac.uk/v3-software/downloads/license")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: CCPN $"
__dateModified__ = "$dateModified: 2017-07-07 16:32:59 +0100 (Fri, July 07, 2017) $"
__version__ = "$Revision: 3.0.0 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: TJ Ragan $"
__date__ = "$Date: 2017-04-07 10:28:41 +0000 (Fri, April 07, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================

import os
import sys
import importlib
import inspect


[docs]def loadSubclasses(path: str, baseclass, levels=2) -> set: ''' Gather subclasses of baseclass from path This attempts to import any file in the directory that doesn't start with a period or underscore, Then checks each class definition in that imported module for subclasses of the specified baseclass and finally returns the set of all classes it found. ''' extensions = [] savedPythonPath = sys.path try: path = os.path.expanduser(path) for root, dirs, files in os.walk(path): levels -= 1 if levels == 0: break dirs = [dir for dir in dirs if not dir.startswith('_')] dirs = [dir for dir in dirs if not dir.startswith('.')] dirs.insert(0, '.') for dir in dirs: pth = os.path.join(root, dir) sys.path = [pth] moduleFiles = os.listdir(pth) moduleFiles = [f for f in moduleFiles if not f.startswith('_')] moduleFiles = [f for f in moduleFiles if not f.startswith('.')] moduleFiles = [os.path.splitext(f)[0] for f in moduleFiles] for f in moduleFiles: try: # Fails on non-python files, directories, etc,... if f not in sys.modules: module = importlib.import_module(f) else: module = importlib.reload(sys.modules.get(f)) potentials = inspect.getmembers(module, inspect.isclass) for name, p in potentials: if issubclass(p, baseclass): if p.__module__ == f: # Make sure we only import classes declared in that module. extensions.append(p) except ImportError: pass finally: sys.path = savedPythonPath return set(extensions)