5

When defining code dynamically in Python (e.g. through exec or loading it from some other medium other than import), I am unable to get to the source of the defined function.

inspect.getsource seems to look for a loaded module from where it was loaded.

import inspect

code = """
def my_function():
  print("Hello dears")
"""
exec(code)
my_function() #Works, as expected
print(inspect.getsource(my_function)) ## Fails with OSError('could not get source code')

Is there any other way to get at the source of a dynamically interpreted function (or other object, for that matter)?

2 Answers 2

1

Is there any other way to get at the source of a dynamically interpreted function (or other object, for that matter)?

One option would be to dump the source to a file and exec from there, though that litters your filesystem with garbage you need to cleanup.

A somewhat less reliable but less garbagey alternative would be to rebuild the source (-ish) from the bytecode, using astor.to_source() for instance. It will give you a "corresponding" source but may alter formatting or lose metadata compared to the original.

The simplest would be to simply attach your original source to the created function object:

code = """
def my_function():
  print("Hello dears")
"""
exec(code)
my_function.__source__ = code # has nothing to do with getsource

One more alternative (though probably not useful here as I assume you want the body to be created dynamically from a template for instance) would be to swap the codeobject for one you've updated with the correct / relevant firstlineno (and optionally filename though you can set that as part of the compile statement). That's only useful if for some weird reason you have your python code literally embedded in an other file but can't or don't want to extract it to its own module for a normal evaluation.

0

You can do it almost like below

import inspect

source = """
def foo():
  print("Hello World")
"""

file_name ='/tmp/foo.py' # you can use any hash_function
with open(file_name, 'w') as f:
    f.write(source)
code = compile(source, file_name, 'exec')
exec(code)


foo() # Works, as expected
print(inspect.getsource(foo))

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.