5

I am trying to get a list of functions from a module using inspect.getmembers in the order of source code.

Below is the code

def get_functions_from_module(app_module):
    list_of_functions = dict(inspect.getmembers(app_module, 
    inspect.isfunction))

    return list_of_functions.values

The current code will not return the list of function objects in order of the source code and I'm wondering if it would be possible to order it.

Thank you!

Bahrom
  • 4,752
  • 32
  • 41
Young
  • 419
  • 3
  • 19
  • Why do you need them sorted in that order? Is it possible that this is an [XY Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)? – Bahrom Nov 02 '17 at 18:50
  • @Bahrom I need to iterate over a list of functions from a module sequentially and apply each function to a file. It will only work if the functions are in the order of source code – Young Nov 02 '17 at 19:05

2 Answers2

7

I think I came up with a solution.

def get_line_number_of_function(func):
    return func.__code__.co_firstlineno

def get_functions_from_module(app_module):
        list_of_functions = dict(inspect.getmembers(app_module, 
        inspect.isfunction))

    return sorted(list_of_functions.values(), key=lambda x:
           get_line_number_of_function(x))
Young
  • 419
  • 3
  • 19
  • Since you're using `inspect` anyway, you can replace `func.__code__.co_firstlineno` with `inspect.getsourcelines(func)[1]`, which allows you to generalize it beyond functions (e.g. adding classes as well). – Jim Pivarski Sep 15 '20 at 20:34
6

You can sort by line numbers using inspect.findsource. Docstring from the source code of that function:

def findsource(object):
    """Return the entire source file and starting line number for an object.
    The argument may be a module, class, method, function, traceback, frame,
    or code object.  The source code is returned as a list of all the lines
    in the file and the line number indexes a line in that list.  An OSError
    is raised if the source code cannot be retrieved."""

Here's an example in Python 2.7:

import ab.bc.de.t1 as t1
import inspect


def get_functions_from_module(app_module):
    list_of_functions = inspect.getmembers(app_module, inspect.isfunction)
    return list_of_functions

fns = get_functions_from_module(t1)

def sort_by_line_no(fn):
    fn_name, fn_obj = fn
    source, line_no = inspect.findsource(fn_obj)
    return line_no

for name, fn in sorted(fns, key=sort_by_line_no):
    print name, fn

My ab.bc.de.t1 is defined as follows:

class B(object):
    def a():
        print 'test'

def c():
    print 'c'

def a():
    print 'a'

def b():
    print 'b'

And the output I get when I try retrieving sorted functions is below:

c <function c at 0x00000000362517B8>
a <function a at 0x0000000036251438>
b <function b at 0x0000000036251668>
>>> 
Bahrom
  • 4,752
  • 32
  • 41