]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-71765: Fix inspect.getsource() on empty file (GH-20809)
authorkernc <kerncece@gmail.com>
Mon, 18 Mar 2024 15:13:02 +0000 (16:13 +0100)
committerGitHub <noreply@github.com>
Mon, 18 Mar 2024 15:13:02 +0000 (16:13 +0100)
* 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 <oleg@arhadthedev.net>
Lib/linecache.py
Lib/test/test_inspect/test_inspect.py
Lib/test/test_linecache.py
Misc/NEWS.d/next/Library/2020-06-11-16-20-33.bpo-27578.CIA-fu.rst [new file with mode: 0644]

index 04c8f45a6c60ca27cf8eb6be1c0ffb25e25a575e..b97999fc1dc909ceb203d687ab054cc9fe833f7c 100644 (file)
@@ -137,7 +137,9 @@ def updatecache(filename, module_globals=None):
             lines = fp.readlines()
     except (OSError, UnicodeDecodeError, SyntaxError):
         return []
-    if lines and not lines[-1].endswith('\n'):
+    if not lines:
+        lines = ['\n']
+    elif not lines[-1].endswith('\n'):
         lines[-1] += '\n'
     size, mtime = stat.st_size, stat.st_mtime
     cache[filename] = size, mtime, lines, fullname
index c3a9dc998e38d04c7056a056c94e079d08f3812b..21d9f96c8c460e8c9b4f72044bccc04704d7bd33 100644 (file)
@@ -35,7 +35,7 @@ except ImportError:
 from test.support import cpython_only
 from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ
 from test.support.import_helper import DirsOnSysPath, ready_to_import
-from test.support.os_helper import TESTFN
+from test.support.os_helper import TESTFN, temp_cwd
 from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
 from test.support import has_subprocess_support, SuppressCrashReport
 from test import support
@@ -730,6 +730,18 @@ class TestRetrievingSourceCode(GetSourceBase):
         finally:
             del linecache.cache[co.co_filename]
 
+    def test_getsource_empty_file(self):
+        with temp_cwd() as cwd:
+            with open('empty_file.py', 'w'):
+                pass
+            sys.path.insert(0, cwd)
+            try:
+                import empty_file
+                self.assertEqual(inspect.getsource(empty_file), '\n')
+                self.assertEqual(inspect.getsourcelines(empty_file), (['\n'], 0))
+            finally:
+                sys.path.remove(cwd)
+
     def test_getfile(self):
         self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
 
index e42df3d9496bc82e482eba0e101168e528cbb3c2..8ac521d72ef13edb183b5250bd3208736b28fdeb 100644 (file)
@@ -83,6 +83,10 @@ class GetLineTestsBadData(TempFile):
 class EmptyFile(GetLineTestsGoodData, unittest.TestCase):
     file_list = []
 
+    def test_getlines(self):
+        lines = linecache.getlines(self.file_name)
+        self.assertEqual(lines, ['\n'])
+
 
 class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase):
     file_list = ['\n']
diff --git a/Misc/NEWS.d/next/Library/2020-06-11-16-20-33.bpo-27578.CIA-fu.rst b/Misc/NEWS.d/next/Library/2020-06-11-16-20-33.bpo-27578.CIA-fu.rst
new file mode 100644 (file)
index 0000000..df58a7e
--- /dev/null
@@ -0,0 +1,3 @@
+:func:`inspect.getsource` (and related functions) work with
+empty module files, returning ``'\n'`` (or reasonable equivalent)
+instead of raising ``OSError``. Patch by Kernc.