pythonpython-3.xinspect

inspect.getsourcelines(object) shows OSError if run from python shell but gives no error if run from a file


I tried this code-snippet inside a script named test.py :

from inspect import *

def f1(p,r):
    """Return f1 score from p,r"""
    return 2*p*r/(p+r)

print(getsourcelines(f1))

If I run this from terminal with python3 test.py, it outputs the following :

(['def f1(p,r):\n', '\t"""Return f1 score from p,r"""\n', '\treturn 2*p*r/(p+r)\n'], 3)

But, if I run the same whole script line by line inside python shell, it throws a OSError. This is what I tried in python shell along with the error :

>>> from inspect import *
>>> 
>>> def f1(p,r):
...     """Return f1 score from p,r"""
...     return 2*p*r/(p+r)
... 
>>> print(getsourcelines(f1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/inspect.py", line 955, in getsourcelines
    lines, lnum = findsource(object)
  File "/usr/lib/python3.6/inspect.py", line 786, in findsource
    raise OSError('could not get source code')
OSError: could not get source code
>>> 

Why does inspect.getsourcelines(f1) throws error inside python shell, but not when it is run form the file? Is there any other way to get the source lines of a function declared inside a python shell?


Solution

  • This is the expected behaviour. inspect has only a limited support for builtin objects (not loaded from files).

    It is explicit in other functions like getsourcefile where the doc says:

    This will fail with a TypeError if the object is a built-in module, class, or function.

    Either if less explicit, the doc for getsourcelines says (emphasize mine):

    The source code is returned as a list of the lines corresponding to the object and the line number indicates where in the original source file the first line of code was found. An OSError is raised if the source code cannot be retrieved.

    In the current versions, getsourcelines try to locate the function in the current source file. As it cannot get the current source file for the functions declared outside of a file, it raises an exception.

    The underlying cause, is that when python is started in interactive mode, the main module is a builtin module and has no __file__ attribute.