This PR provides one additional fallback if the source file cannot be found - it tries to read the input from the IPython input history. This seems to work quite well for cell blocks, and allows profiling of functions defined in a notebook for example without requiring one to save the cells to a file.
Cool! We shouldn't need to pass around the IPython shell object. IPython helpfully stuffs linecache with the appropriate code. We just need to handle the actual-file case specially to use linecache.updatecache(filename) to make sure we have a fresh copy. Other than that, the rest of the code should work.