Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d93643f

Browse files
committed
Richard Wolff's changes:
bdb.py now has a class definition called Breakpoint along with associated methods. There's no reason why this class has to be there; if you prefer it elsewhere, 'tis easily done. (Minor reformatting by GvR; e.g. moved Breakpoint's doc string to proper point.)
1 parent 5fca6fd commit d93643f

1 file changed

Lines changed: 172 additions & 23 deletions

File tree

Lib/bdb.py

Lines changed: 172 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class Bdb: # Basic Debugger
1616

1717
def __init__(self):
1818
self.breaks = {}
19-
self.cbreaks = {}
2019

2120
def reset(self):
2221
import linecache
@@ -84,19 +83,23 @@ def stop_here(self, frame):
8483
return 1
8584
frame = frame.f_back
8685
return 0
87-
86+
8887
def break_here(self, frame):
8988
filename=frame.f_code.co_filename
9089
if not self.breaks.has_key(filename):
9190
return 0
9291
lineno=frame.f_lineno
9392
if not lineno in self.breaks[filename]:
9493
return 0
95-
if self.cbreaks.has_key((filename, lineno)):
96-
cond=self.cbreaks[filename, lineno]
97-
return eval(cond, frame.f_globals,
98-
frame.f_locals)
99-
return 1
94+
# flag says ok to delete temp. bp
95+
(bp, flag) = effective(filename, lineno, frame)
96+
if bp:
97+
self.currentbp = bp.number
98+
if (flag and bp.temporary):
99+
self.do_delete(str(bp.number))
100+
return 1
101+
else:
102+
return 0
100103

101104
def break_anywhere(self, frame):
102105
return self.breaks.has_key(frame.f_code.co_filename)
@@ -182,44 +185,61 @@ def set_quit(self):
182185
# Derived classes and clients can call the following methods
183186
# to manipulate breakpoints. These methods return an
184187
# error message is something went wrong, None if all is well.
185-
# Call self.get_*break*() to see the breakpoints.
188+
# Set_break prints out the breakpoint line and file:lineno.
189+
# Call self.get_*break*() to see the breakpoints or better
190+
# for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
186191

187-
def set_break(self, filename, lineno, cond=None):
192+
def set_break(self, filename, lineno, temporary=0, cond = None):
188193
import linecache # Import as late as possible
189194
line = linecache.getline(filename, lineno)
190195
if not line:
191196
return 'That line does not exist!'
192197
if not self.breaks.has_key(filename):
193198
self.breaks[filename] = []
194199
list = self.breaks[filename]
195-
if lineno in list:
196-
return 'There is already a breakpoint there!'
197-
list.append(lineno)
198-
if cond is not None: self.cbreaks[filename, lineno]=cond
199-
200-
def clear_break(self, filename, lineno):
200+
if not lineno in list:
201+
list.append(lineno)
202+
bp = Breakpoint(filename, lineno, temporary, cond)
203+
print 'Breakpoint %d, at %s:%d.' %(bp.number, filename, lineno)
204+
205+
def clear_break(self, arg):
206+
try:
207+
number = int(arg)
208+
bp = Breakpoint.bpbynumber[int(arg)]
209+
except:
210+
return 'Invalid argument'
211+
if not bp:
212+
return 'Breakpoint already deleted'
213+
filename = bp.file
214+
lineno = bp.line
201215
if not self.breaks.has_key(filename):
202216
return 'There are no breakpoints in that file!'
203217
if lineno not in self.breaks[filename]:
204218
return 'There is no breakpoint there!'
205-
self.breaks[filename].remove(lineno)
219+
# If there's only one bp in the list for that file,line
220+
# pair, then remove the breaks entry
221+
if len(Breakpoint.bplist[filename, lineno]) == 1:
222+
self.breaks[filename].remove(lineno)
206223
if not self.breaks[filename]:
207224
del self.breaks[filename]
208-
try: del self.cbreaks[filename, lineno]
209-
except: pass
225+
bp.deleteMe()
210226

211227
def clear_all_file_breaks(self, filename):
212228
if not self.breaks.has_key(filename):
213229
return 'There are no breakpoints in that file!'
230+
for line in self.breaks[filename]:
231+
blist = Breakpoint.bplist[filename, line]
232+
for bp in blist:
233+
bp.deleteMe()
214234
del self.breaks[filename]
215-
for f,l in self.cbreaks.keys():
216-
if f==filename: del self.cbreaks[f,l]
217235

218236
def clear_all_breaks(self):
219237
if not self.breaks:
220238
return 'There are no breakpoints!'
239+
for bp in Breakpoint.bpbynumber:
240+
if bp:
241+
bp.deleteMe()
221242
self.breaks = {}
222-
self.cbreaks = {}
223243

224244
def get_break(self, filename, lineno):
225245
return self.breaks.has_key(filename) and \
@@ -261,9 +281,9 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
261281
filename = frame.f_code.co_filename
262282
s = filename + '(' + `lineno` + ')'
263283
if frame.f_code.co_name:
264-
s = s + frame.f_code.co_name
284+
s = s + frame.f_code.co_name
265285
else:
266-
s = s + "<lambda>"
286+
s = s + "<lambda>"
267287
if frame.f_locals.has_key('__args__'):
268288
args = frame.f_locals['__args__']
269289
else:
@@ -345,6 +365,135 @@ def runcall(self, func, *args):
345365
def set_trace():
346366
Bdb().set_trace()
347367

368+
369+
class Breakpoint:
370+
371+
"""Breakpoint class
372+
373+
Implements temporary breakpoints, ignore counts, disabling and
374+
(re)-enabling, and conditionals.
375+
376+
Breakpoints are indexed by number through bpbynumber and by
377+
the file,line tuple using bplist. The former points to a
378+
single instance of class Breakpoint. The latter points to a
379+
list of such instances since there may be more than one
380+
breakpoint per line.
381+
382+
"""
383+
384+
385+
next = 1 # Next bp to be assigned
386+
bplist = {} # indexed by (file, lineno) tuple
387+
bpbynumber = [None] # Each entry is None or an instance of Bpt
388+
# index 0 is unused, except for marking an
389+
# effective break .... see effective()
390+
391+
def __init__(self, file, line, temporary=0, cond = None):
392+
self.file = file
393+
self.line = line
394+
self.temporary = temporary
395+
self.cond = cond
396+
self.enabled = 1
397+
self.ignore = 0
398+
self.hits = 0
399+
self.number = Breakpoint.next
400+
Breakpoint.next = Breakpoint.next + 1
401+
# Build the two lists
402+
self.bpbynumber.append(self)
403+
if self.bplist.has_key((file, line)):
404+
self.bplist[file, line].append(self)
405+
else:
406+
self.bplist[file, line] = [self]
407+
408+
409+
def deleteMe(self):
410+
index = (self.file, self.line)
411+
self.bpbynumber[self.number] = None # No longer in list
412+
self.bplist[index].remove(self)
413+
if not self.bplist[index]:
414+
# No more bp for this f:l combo
415+
del self.bplist[index]
416+
417+
def enable(self):
418+
self.enabled = 1
419+
420+
def disable(self):
421+
self.enabled = 0
422+
423+
def bpprint(self):
424+
if self.temporary:
425+
disp = 'del '
426+
else:
427+
disp = 'keep '
428+
if self.enabled:
429+
disp = disp + 'yes'
430+
else:
431+
disp = disp + 'no '
432+
print '%-4dbreakpoint %s at %s:%d' % (self.number, disp,
433+
self.file, self.line)
434+
if self.cond:
435+
print '\tstop only if %s' % (self.cond,)
436+
if self.ignore:
437+
print '\tignore next %d hits' % (self.ignore)
438+
if (self.hits):
439+
if (self.hits > 1): ss = 's'
440+
else: ss = ''
441+
print ('\tbreakpoint already hit %d time%s' %
442+
(self.hits, ss))
443+
444+
# -----------end of Breakpoint class----------
445+
446+
# Determines if there is an effective (active) breakpoint at this
447+
# line of code. Returns breakpoint number or 0 if none
448+
def effective(file, line, frame):
449+
"""Determine which breakpoint for this file:line is to be acted upon.
450+
451+
Called only if we know there is a bpt at this
452+
location. Returns breakpoint that was triggered and a flag
453+
that indicates if it is ok to delete a temporary bp.
454+
455+
"""
456+
possibles = Breakpoint.bplist[file,line]
457+
for i in range(0, len(possibles)):
458+
b = possibles[i]
459+
if b.enabled == 0:
460+
continue
461+
# Count every hit when bp is enabled
462+
b.hits = b.hits + 1
463+
if not b.cond:
464+
# If unconditional, and ignoring,
465+
# go on to next, else break
466+
if b.ignore > 0:
467+
b.ignore = b.ignore -1
468+
continue
469+
else:
470+
# breakpoint and marker that's ok
471+
# to delete if temporary
472+
return (b,1)
473+
else:
474+
# Conditional bp.
475+
# Ignore count applies only to those bpt hits where the
476+
# condition evaluates to true.
477+
try:
478+
val = eval(b.cond, frame.f_globals,
479+
frame.f_locals)
480+
if val:
481+
if b.ignore > 0:
482+
b.ignore = b.ignore -1
483+
# continue
484+
else:
485+
return (b,1)
486+
# else:
487+
# continue
488+
except:
489+
# if eval fails, most conservative
490+
# thing is to stop on breakpoint
491+
# regardless of ignore count.
492+
# Don't delete temporary,
493+
# as another hint to user.
494+
return (b,0)
495+
return (None, None)
496+
348497
# -------------------- testing --------------------
349498

350499
class Tdb(Bdb):

0 commit comments

Comments
 (0)