Update linecache from CPython 3.10.6

This commit is contained in:
CPython Developers authored and Jeong YunWon committed 2022-08-15 04:24:58 +09:00
1 parent 3073947a8b
commit 5dbab96678
2 files changed
+82 -35

No files matched your search

+28 -23
View File
@@ -13,17 +13,8 @@ except ImportError:
import _dummy_os as os
import tokenize
__all__ = ["getline", "clearcache", "checkcache"]
__all__ = ["getline", "clearcache", "checkcache", "lazycache"]
def getline(filename, lineno, module_globals=None):
lines = getlines(filename, module_globals)
if 1 <= lineno <= len(lines):
return lines[lineno-1]
else:
return ''
# The cache
# The cache. Maps filenames to either a thunk which will provide source code,
# or a tuple (size, mtime, lines, fullname) once loaded.
@@ -32,9 +23,17 @@ cache = {}
def clearcache():
"""Clear the cache entirely."""
cache.clear()
global cache
cache = {}
def getline(filename, lineno, module_globals=None):
"""Get a line for a Python source file from the cache.
Update the cache if it doesn't contain an entry for this file already."""
lines = getlines(filename, module_globals)
if 1 <= lineno <= len(lines):
return lines[lineno - 1]
return ''
def getlines(filename, module_globals=None):
@@ -59,11 +58,10 @@ def checkcache(filename=None):
if filename is None:
filenames = list(cache.keys())
elif filename in cache:
filenames = [filename]
else:
if filename in cache:
filenames = [filename]
else:
return
return
for filename in filenames:
entry = cache[filename]
@@ -112,8 +110,10 @@ def updatecache(filename, module_globals=None):
# for this module.
return []
cache[filename] = (
len(data), None,
[line+'\n' for line in data.splitlines()], fullname
len(data),
None,
[line + '\n' for line in data.splitlines()],
fullname
)
return cache[filename][2]
@@ -138,7 +138,7 @@ def updatecache(filename, module_globals=None):
try:
with tokenize.open(fullname) as fp:
lines = fp.readlines()
except OSError:
except (OSError, UnicodeDecodeError, SyntaxError):
return []
if lines and not lines[-1].endswith('\n'):
lines[-1] += '\n'
@@ -157,7 +157,7 @@ def lazycache(filename, module_globals):
:return: True if a lazy load is registered in the cache,
otherwise False. To register such a load a module loader with a
get_source method must be found, the filename must be a cachable
get_source method must be found, the filename must be a cacheable
filename, and the filename must not be already cached.
"""
if filename in cache:
@@ -168,9 +168,14 @@ def lazycache(filename, module_globals):
if not filename or (filename.startswith('<') and filename.endswith('>')):
return False
# Try for a __loader__, if available
if module_globals and '__loader__' in module_globals:
name = module_globals.get('__name__')
loader = module_globals['__loader__']
if module_globals and '__name__' in module_globals:
name = module_globals['__name__']
if (loader := module_globals.get('__loader__')) is None:
if spec := module_globals.get('__spec__'):
try:
loader = spec.loader
except AttributeError:
pass
get_source = getattr(loader, 'get_source', None)
if name and get_source:
+54 -12
View File
@@ -73,12 +73,10 @@ class GetLineTestsBadData(TempFile):
# file_byte_string = b'Bad data goes here'
def test_getline(self):
self.assertRaises((SyntaxError, UnicodeDecodeError),
linecache.getline, self.file_name, 1)
self.assertEqual(linecache.getline(self.file_name, 1), '')
def test_getlines(self):
self.assertRaises((SyntaxError, UnicodeDecodeError),
linecache.getlines, self.file_name)
self.assertEqual(linecache.getlines(self.file_name), [])
class EmptyFile(GetLineTestsGoodData, unittest.TestCase):
@@ -92,9 +90,11 @@ class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase):
class GoodUnicode(GetLineTestsGoodData, unittest.TestCase):
file_list = ['á\n', 'b\n', 'abcdef\n', 'ááááá\n']
class BadUnicode_NoDeclaration(GetLineTestsBadData, unittest.TestCase):
file_byte_string = b'\n\x80abc'
class BadUnicode(GetLineTestsBadData, unittest.TestCase):
file_byte_string = b'\x80abc'
class BadUnicode_WithDeclaration(GetLineTestsBadData, unittest.TestCase):
file_byte_string = b'# coding=utf-8\n\x80abc'
class LineCacheTests(unittest.TestCase):
@@ -116,7 +116,7 @@ class LineCacheTests(unittest.TestCase):
# Check module loading
for entry in MODULES:
filename = os.path.join(MODULE_PATH, entry) + '.py'
with open(filename) as file:
with open(filename, encoding='utf-8') as file:
for index, line in enumerate(file):
self.assertEqual(line, getline(filename, index + 1))
@@ -126,7 +126,7 @@ class LineCacheTests(unittest.TestCase):
def test_no_ending_newline(self):
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
with open(os_helper.TESTFN, "w") as fp:
with open(os_helper.TESTFN, "w", encoding='utf-8') as fp:
fp.write(SOURCE_3)
lines = linecache.getlines(os_helper.TESTFN)
self.assertEqual(lines, ["\n", "def f():\n", " return 3\n"])
@@ -153,18 +153,18 @@ class LineCacheTests(unittest.TestCase):
# Create a source file and cache its contents
source_name = os_helper.TESTFN + '.py'
self.addCleanup(os_helper.unlink, source_name)
with open(source_name, 'w') as source:
with open(source_name, 'w', encoding='utf-8') as source:
source.write(SOURCE_1)
getline(source_name, 1)
# Keep a copy of the old contents
source_list = []
with open(source_name) as source:
with open(source_name, encoding='utf-8') as source:
for index, line in enumerate(source):
self.assertEqual(line, getline(source_name, index + 1))
source_list.append(line)
with open(source_name, 'w') as source:
with open(source_name, 'w', encoding='utf-8') as source:
source.write(SOURCE_2)
# Try to update a bogus cache entry
@@ -176,7 +176,7 @@ class LineCacheTests(unittest.TestCase):
# Update the cache and check whether it matches the new source file
linecache.checkcache(source_name)
with open(source_name) as source:
with open(source_name, encoding='utf-8') as source:
for index, line in enumerate(source):
self.assertEqual(line, getline(source_name, index + 1))
source_list.append(line)
@@ -245,5 +245,47 @@ class LineCacheTests(unittest.TestCase):
self.assertEqual(linecache.getlines(FILENAME), lines)
class LineCacheInvalidationTests(unittest.TestCase):
def setUp(self):
super().setUp()
linecache.clearcache()
self.deleted_file = os_helper.TESTFN + '.1'
self.modified_file = os_helper.TESTFN + '.2'
self.unchanged_file = os_helper.TESTFN + '.3'
for fname in (self.deleted_file,
self.modified_file,
self.unchanged_file):
self.addCleanup(os_helper.unlink, fname)
with open(fname, 'w', encoding='utf-8') as source:
source.write(f'print("I am {fname}")')
self.assertNotIn(fname, linecache.cache)
linecache.getlines(fname)
self.assertIn(fname, linecache.cache)
os.remove(self.deleted_file)
with open(self.modified_file, 'w', encoding='utf-8') as source:
source.write('print("was modified")')
def test_checkcache_for_deleted_file(self):
linecache.checkcache(self.deleted_file)
self.assertNotIn(self.deleted_file, linecache.cache)
self.assertIn(self.modified_file, linecache.cache)
self.assertIn(self.unchanged_file, linecache.cache)
def test_checkcache_for_modified_file(self):
linecache.checkcache(self.modified_file)
self.assertIn(self.deleted_file, linecache.cache)
self.assertNotIn(self.modified_file, linecache.cache)
self.assertIn(self.unchanged_file, linecache.cache)
def test_checkcache_with_no_parameter(self):
linecache.checkcache()
self.assertNotIn(self.deleted_file, linecache.cache)
self.assertNotIn(self.modified_file, linecache.cache)
self.assertIn(self.unchanged_file, linecache.cache)
if __name__ == "__main__":
unittest.main()