Reputation: 949
I have a module Class3.py, with the following code in it:
from common.Step import Step
from StageThree.Class2 import Class2
class Class3(Step):
pass
I have a logic inside of my project, which will dynamically access this module, and read it in:
module = importlib.import_module(module_name, package_path)
Now, the module variable will hold a dictionary of all information about this module, but I am interested only in grabbing a handle to Class3 from it, for later dynamic instantiation. I sort through that dict with the following code:
dict([(name, cls) for name, cls in module.__dict__.items() if isinstance(cls, type)])
Which yields this result:
{'Step': <class 'common.Step.Step'>, 'Class2': <class 'StageThree.Class2.Class2'>, 'Class3': <class 'StageThree.Class3.Class3'>}
While I know now what classes are present in that module, this still does not help me, because I just want to instantiate a class which was defined in this module (Class3), not imported like Step or Class2.
Any ideas on how I can make Python actually grab only a handle to Class3 in this situation?
UPDATE:
With some ingenuity, I have scrambled together a code which interrogates module for its path, and then reads in file, looks for a line which includes statement "class some_name(" and grabs the name from there. Dirty, but works for now.
available_classes = dict([(name, cls) for name, cls in module.__dict__.items() if isinstance(cls, type)])
with open(module.__file__) as f:
declared_classes_names = re.findall(r"class (\w+)\(", " ".join(f.read().splitlines()))
output = []
for class_name in declared_class_names:
output.append(available_classes[class_name])
Would still be interested to see, if there is any valid way of doing it without brute force approach like above.
Upvotes: 0
Views: 204
Reputation: 18106
You can check the __module__
's name as well:
import importlib
class ModuleInspector(object):
def __init__(self):
self.module = None
def getClassesInModule(self, localOnly=True):
"""
localOnly, returns only locally defined classes in that particular module.
"""
_classes = {}
for k, v in self.module.__dict__.items():
if isinstance(v, type):
if not localOnly or v.__module__ == self.module.__name__:
_classes[k] = v
return _classes
def importFromFile(self, fpath, name=None):
try:
self.module = importlib.import_module(name, fpath)
except:
traceback.print_exc()
if __name__ == '__main__':
i = ModuleInspector()
i.importFromFile('/tmp/class3.py', 'class3')
available_classes = i.getClassesInModule(localOnly=False)
declared_classes_names = i.getClassesInModule()
print(available_classes)
print(declared_classes_names)
Output:
{'Queue': <class 'queue.Queue'>, 'scheduler': <class 'sched.scheduler'>, 'Class3': <class 'class3.Class3'>}
{'Class3': <class 'class3.Class3'>}
Upvotes: 2