Skip to content

Commit f83c060

Browse files
committed
Change executable_linenos_cache to global variable and add check cache mechanism
1 parent eaf71ac commit f83c060

File tree

1 file changed

+58
-4
lines changed

1 file changed

+58
-4
lines changed

Lib/bdb.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,51 @@ def _get_executable_linenos(code):
189189
return linenos
190190

191191

192+
# filename: (size, mtime, executable_linenos, fullname)
193+
_executable_linenos_cache = {}
194+
195+
196+
def _check_executable_linenos_cache(filename=None):
197+
if filename is None:
198+
filenames = tuple(_executable_linenos_cache)
199+
else:
200+
filenames = tuple(filename)
201+
202+
for filename in filenames:
203+
if (entry := _executable_linenos_cache.get(filename)) is None:
204+
continue
205+
size, mtime, _, fullname = entry
206+
if mtime is None:
207+
continue
208+
try:
209+
stat = os.stat(fullname)
210+
except (OSError, ValueError):
211+
_executable_linenos_cache.pop(filename, None)
212+
continue
213+
if size != stat.st_size or mtime != stat.st_mtime:
214+
_executable_linenos_cache.pop(filename, None)
215+
216+
217+
def _set_executable_linenos_cache_entry(
218+
filename, executable_linenos, source, linecache_entry
219+
):
220+
if linecache_entry is not None and len(linecache_entry) != 1:
221+
size, mtime, _, fullname = linecache_entry
222+
else:
223+
fullname = filename
224+
try:
225+
stat = os.stat(filename)
226+
except (OSError, ValueError):
227+
size = len(source)
228+
mtime = None
229+
else:
230+
size = stat.st_size
231+
mtime = stat.st_mtime
232+
_executable_linenos_cache[filename] = (
233+
size, mtime, executable_linenos, fullname
234+
)
235+
236+
192237
class Bdb:
193238
"""Generic Python debugger base class.
194239
@@ -207,7 +252,6 @@ def __init__(self, skip=None, backend='settrace'):
207252
self.skip = set(skip) if skip else None
208253
self.breaks = {}
209254
self.fncache = {}
210-
self.executable_linenos_cache = {}
211255
self.frame_trace_lines_opcodes = {}
212256
self.frame_returning = None
213257
self.trace_opcodes = False
@@ -258,6 +302,7 @@ def reset(self):
258302
"""Set values of attributes as ready to start debugging."""
259303
import linecache
260304
linecache.checkcache()
305+
_check_executable_linenos_cache()
261306
self.botframe = None
262307
self._set_stopinfo(None, None)
263308

@@ -681,16 +726,25 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
681726
"""
682727
filename = self.canonic(filename)
683728
import linecache # Import as late as possible
729+
linecache.checkcache(filename)
730+
_check_executable_linenos_cache(filename)
684731
line = linecache.getline(filename, lineno)
685732
if not line:
686733
return 'Line %s:%d does not exist' % (filename, lineno)
687-
if filename not in self.executable_linenos_cache:
734+
if filename not in _executable_linenos_cache:
688735
source = ''.join(linecache.getlines(filename))
689736
if source:
690737
with suppress(SyntaxError):
691738
code = compile(source, filename, 'exec')
692-
self.executable_linenos_cache[filename] = _get_executable_linenos(code)
693-
executable_lines = self.executable_linenos_cache.get(filename)
739+
executable_lines = _get_executable_linenos(code)
740+
_set_executable_linenos_cache_entry(
741+
filename,
742+
executable_lines,
743+
source,
744+
linecache.cache.get(filename),
745+
)
746+
cache_entry = _executable_linenos_cache.get(filename)
747+
executable_lines = cache_entry[2] if cache_entry else None
694748
if executable_lines and lineno not in executable_lines:
695749
return 'Line %d has no code associated with it' % lineno
696750
self._add_to_breaks(filename, lineno)

0 commit comments

Comments
 (0)