MASBHA NOMAN
MASBHA NOMAN

Reputation: 198

python3: getting module source code using user input (inspect .getsource)

what I want to do...
I have a module called 'my_library.py' which contains some functions or methods.
I have another module called 'test_library.py' and from test_library I want to print source code of some specific functions which is inside "my_library" module
I know we can do it using....
print(inspect.getsource(my_library.add))
or
print(open(my_library.__file__).read())
here, i want to take the function or module name from the user as an input
example :

    **my_library.py**
    def add(x,y):
        return x+y

    def substract(x,y):
        return x-y

    **test_library.py**
    import inspect
    import my_library
    name = "my_library.substract"
    print(inspect.getsource(name))


TypeError: module, class, method, function, traceback, frame, or code object was expected, got str
I have tried to convert that string input into object, file, class ...nothing seems to work
is there any way to take the input from a user and show that specific function or module?
any suggestions or advice to solve the problem?

thanks in advance

Upvotes: 2

Views: 832

Answers (2)

csunday95
csunday95

Reputation: 1319

Say we had a file module.py:

def test_func(arg1, arg2):
    return arg1 + arg2

We can resolve this member for use by getsource() from another region of code by getting a reference to the function object:

import inspect
import sys
import module

def main():
    # what the user would input
    input_str = 'module.test_func'  
    # split user input up into individual members
    name_list = input_str.split('.')
    # extract the starting point name
    base_name = name_list[0]
    # check to make sure that name exists in the current scope and extract a reference to it
    if base_name in locals():
        base_obj = locals()[base_name]
    elif base_name in globals():
        base_obj = globals()[base_name]
    else:
        print('base name {} is unknown'.format(base_name))
        return 1
    # iteratively step through the attribute chain
    containing_object = base_obj
    for name in name_list[1:]:
        try:
            containing_object = getattr(containing_object, name)
        except AttributeError:
            print('unable to resolve name {} from object {}'.format(name, containing_object))
            return 1
    # print out source of final reference
    print(inspect.getsource(containing_object))
    return 0


if __name__ == '__main__':
    sys.exit(main())

You could also extend this to retrieve members of modules that haven't yet been imported using importlib

Upvotes: 1

Steve Barnes
Steve Barnes

Reputation: 28370

You need to create an actual object to pass to get_source, e.g.:

In [1]: def add(x,y):
   ...:         return x+y
   ...:

In [2]: def substract(x,y):   return x-y

In [3]: %save my_library.py 1-2
The following commands were written to file `my_library.py`:
def add(x,y):
        return x+y
def substract(x,y):   return x-y

In [4]: import inspect

In [5]: import my_library

In [6]: obj = my_library.substract

In [7]: inspect.getsource(obj)
Out[7]: 'def substract(x,y):   return x-y\n'

In [8]: obj = my_library.add

In [9]: inspect.getsource(obj)
Out[9]: 'def add(x,y):\n        return x+y\n'

In [10]:

You can generate them from strings by using eval on the strings, e.g.:

for item in dir(my_library):
     if not item.startswith('_'):
         print(item)
         nam = '.'.join(['my_library', item])
         print(inspect.getsource(eval(nam)))

Gives:

add
def add(x,y):
        return x+y

substract
def substract(x,y):   return x-y

Upvotes: 1

Related Questions