Skip to content

Commit 52ef443

Browse files
kerncarhadthedev
andauthored
gh-71765: Fix inspect.getsource() on empty file (GH-20809)
* bpo-27578: Fix inspect.getsource() on empty file For modules from empty files, `inspect.getsource()` now returns an empty string, and `inspect.getsourcelines()` returns a list of one empty string, fixing the expected invariant. As indicated by `exec('')`, empty strings are valid Python source code. Co-authored-by: Oleg Iarygin <[email protected]>
1 parent f6cdc6b commit 52ef443

File tree

4 files changed

+23
-2
lines changed

4 files changed

+23
-2
lines changed

Lib/linecache.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ def updatecache(filename, module_globals=None):
137137
lines = fp.readlines()
138138
except (OSError, UnicodeDecodeError, SyntaxError):
139139
return []
140-
if lines and not lines[-1].endswith('\n'):
140+
if not lines:
141+
lines = ['\n']
142+
elif not lines[-1].endswith('\n'):
141143
lines[-1] += '\n'
142144
size, mtime = stat.st_size, stat.st_mtime
143145
cache[filename] = size, mtime, lines, fullname

Lib/test/test_inspect/test_inspect.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from test.support import cpython_only
3636
from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ
3737
from test.support.import_helper import DirsOnSysPath, ready_to_import
38-
from test.support.os_helper import TESTFN
38+
from test.support.os_helper import TESTFN, temp_cwd
3939
from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
4040
from test.support import has_subprocess_support, SuppressCrashReport
4141
from test import support
@@ -730,6 +730,18 @@ def test_getsourcefile(self):
730730
finally:
731731
del linecache.cache[co.co_filename]
732732

733+
def test_getsource_empty_file(self):
734+
with temp_cwd() as cwd:
735+
with open('empty_file.py', 'w'):
736+
pass
737+
sys.path.insert(0, cwd)
738+
try:
739+
import empty_file
740+
self.assertEqual(inspect.getsource(empty_file), '\n')
741+
self.assertEqual(inspect.getsourcelines(empty_file), (['\n'], 0))
742+
finally:
743+
sys.path.remove(cwd)
744+
733745
def test_getfile(self):
734746
self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
735747

Lib/test/test_linecache.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def test_getlines(self):
8383
class EmptyFile(GetLineTestsGoodData, unittest.TestCase):
8484
file_list = []
8585

86+
def test_getlines(self):
87+
lines = linecache.getlines(self.file_name)
88+
self.assertEqual(lines, ['\n'])
89+
8690

8791
class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase):
8892
file_list = ['\n']
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`inspect.getsource` (and related functions) work with
2+
empty module files, returning ``'\n'`` (or reasonable equivalent)
3+
instead of raising ``OSError``. Patch by Kernc.

0 commit comments

Comments
 (0)