1

I try to get the list of class from python file using python. After a few search, I get the code which I think it's work as follow

def get_class_from_file(class_obj, file, path='app', exclude=[]):
    class_list = []
    module = importlib.import_module(path + '.' + file)
    for x in dir(module) :
        app_cls = getattr( importlib.import_module(path + '.' + file), x )
        try :
            if app_cls and issubclass(app_cls, class_obj) and app_cls != class_obj and app_cls not in exclude:
                class_list.append( (file, x) )
        except TypeError :
            pass
    return class_list

However, I found out that the code don't get only the list of the class, but It still keep showing me the superclass of the class inside the file, here is example

file_1.py

class A:
    pass

class B(A):
    pass

file_2.py

class C(B):
    pass

class D:
    pass

when I call the function as class_list = get_class_from_file(A, 'file_2')

I expect the result would be [C], but It return [C, B] as B is one of super class of C

Please help me fix this, I just want class inside the given file, not any superclass of them. By the way, I use exclude for fixing it at first, but It isn't give me a long run solution.

5
  • 1
    In file_2.py, you probably have from file_1 import A. And that means that from then on, A is in file_2 as well as in file_1. Commented Dec 8, 2016 at 12:15
  • @RemcoGerlich answer is correct, I just want to add that this task is not as trivial as you think. What if there is class A: pass and B = A. Are there two classes or one class in this file? Class list would contain a dupe, maybe that's what you want, maybe not. Commented Dec 8, 2016 at 12:25
  • @ŁukaszRogalski: yes, and even if you'd do something like keep a set of already found id()s around, you'd have no control over A or B being found first. But maybe his use case is such that he doesn't have those problems. Commented Dec 8, 2016 at 12:26
  • if you really only need the class name you can extract that with a regex: class ([\w]*) Commented Dec 8, 2016 at 12:51
  • Thank you for your concern, I understand that the order of the list is uncontrollable, that's ok for me. And the files was written by myself so B = A isn't appear (at least, not appear is module scope, it isn't make sense to have this kind of declaration.), By the way, Thank you very much for your help Commented Dec 8, 2016 at 14:41

1 Answer 1

2

The problem is that imported modules are also found. You can check a class' __module__ attribute to see if it originates from the current module or was imported into it.

You also have importlib.import_module(path + '.' + file) twice, I removed one of them. I renamed x to name.

def get_class_from_file(class_obj, file, path='app', exclude=[]):
    class_list = []
    module_path = path + '.' + file
    module = importlib.import_module(module_path)
    for name in dir(module) :
        app_cls = getattr(module, name)
        try:
            if (issubclass(app_cls, class_obj) and
                 app_cls != class_obj and
                 app_cls not in exclude and
                 app_cls.__module__ == module_path):
            class_list.append( (file, name) )
        except TypeError:
            # Not a class
            pass
    return class_list
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.