Index: Lib/inspect.py =================================================================== --- Lib/inspect.py (revision 80573) +++ Lib/inspect.py (working copy) @@ -434,8 +434,10 @@ info = getmoduleinfo(path) if info: return info[0] -def getsourcefile(object): - """Return the Python source file an object was defined in, if it exists.""" +def getsourcefile(object, check=True): + """Return the Python source filename an object was defined in or None + if ``check`` is true (the default) and the filename does not exist + and was not created by a PEP 302 loader.""" filename = getfile(object) if filename[-4:].lower() in ('.pyc', '.pyo'): filename = filename[:-4] + '.py' @@ -443,6 +445,8 @@ if 'b' in mode and filename[-len(suffix):].lower() == suffix: # Looks like a binary file. We want to only return a text file. return None + if not check: + return filename if os.path.exists(filename): return filename # only return a non-existent filename if the module has a PEP 302 loader @@ -514,9 +518,7 @@ 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 IOError is raised if the source code cannot be retrieved.""" - file = getsourcefile(object) - if not file: - raise IOError('source code not available') + file = getsourcefile(object, check=False) module = getmodule(object, file) if module: lines = linecache.getlines(file, module.__dict__) Index: Lib/test/test_inspect.py =================================================================== --- Lib/test/test_inspect.py (revision 80573) +++ Lib/test/test_inspect.py (working copy) @@ -2,6 +2,7 @@ import types import unittest import inspect +import linecache import datetime import collections from os.path import normcase @@ -250,6 +251,10 @@ def test_getsourcefile(self): self.assertEqual(normcase(inspect.getsourcefile(mod.spam)), modfile) self.assertEqual(normcase(inspect.getsourcefile(git.abuse)), modfile) + fn = "_non_existing_filename_used_for_sourcefile_test.py" + co = compile("None", fn, "exec") + self.assertEqual(normcase(inspect.getsourcefile(co, check=False)), fn) + self.assertEqual(normcase(inspect.getsourcefile(co, check=True)), None) def test_getfile(self): self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) @@ -348,6 +353,15 @@ self.assertRaises(IOError, inspect.getsource, unicodedata) self.assertRaises(IOError, inspect.findsource, unicodedata) + def test_findsource_code_in_linecache(self): + lines = ["x=1"] + co = compile(lines[0], "_dynamically_created_file", "exec") + self.assertRaises(IOError, inspect.findsource, co) + self.assertRaises(IOError, inspect.getsource, co) + linecache.cache[co.co_filename] = (1, None, lines, co.co_filename) + self.assertEquals(inspect.findsource(co), (lines,0)) + self.assertEquals(inspect.getsource(co), lines[0]) + # Helper for testing classify_class_attrs. def attrs_wo_objs(cls): return [t[:3] for t in inspect.classify_class_attrs(cls)]