Search code examples
pythonsqlalchemypython-elixir

How to iterate through every class declaration, descended from a particular base class?


I was wandering how does elixir\sqlalchemy get to know all the entity classes I've declared in my model, when I call setup_all()? I need that kind of functionality in a little project of mine, but I have no clue. I've tried to steptrace through elixir's setup_all(), and I found that it keeps a collection of all entity classes in a "global" list (or was it dict?), but I can't catch the moment when the list is filled. Any ideas?


Solution

  • Answering the main question, without dealign with SQLALchemy or elixir at all - yes, it is possible in Python.

    The garbage colector (gc) module on the standard library, have a function call that allows one to retrieve all references to a given object, interpreter wide. A class is always referred to in the __mro__ attribute of any inherited classes.

    So, the following function could retrieve all classes that inherit from a given class:

    import gc
    def find_subclasses(cls):
        all_refs = gc.get_referrers(cls)
        results = []
        for obj in all_refs:
            # __mro__ attributes are tuples
            # and if a tuple is found here, the given class is one of its members
            if (isinstance(obj, tuple) and
                # check if the found tuple is the __mro__ attribute of a class
                getattr(obj[0], "__mro__", None) is obj):
                results.append(obj[0])
        return results