Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(849)

Side by Side Diff: Lib/bdb.py

Issue 14913: tokenize the source to manage Pdb breakpoints
Patch Set: Created 11 months, 1 week ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | Lib/pdb.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """Debugger basics""" 1 """Debugger basics"""
2 2
3 import fnmatch 3 import fnmatch
4 import sys 4 import sys
5 import os 5 import os
6 import inspect
7 import linecache
8 import token
9 import tokenize
10 import imp
11 import importlib
12 import pprint
13 from operator import itemgetter, attrgetter
6 14
7 __all__ = ["BdbQuit", "Bdb", "Breakpoint"] 15 __all__ = ["BdbQuit", "Bdb", "Breakpoint"]
16
17 # A dictionary mapping a filename to a ModuleSource instance.
18 _modules = {}
19 _fncache = {}
20
21 def canonic(filename):
22 if filename == "<" + filename[1:-1] + ">":
23 return filename
24 canonic = _fncache.get(filename)
25 if not canonic:
26 canonic = os.path.abspath(filename)
27 canonic = os.path.normcase(canonic)
28 _fncache[filename] = canonic
29 return canonic
30
31 def getfilename(module_name, path=None, inpackage=None):
32 """Return the file name of module_name."""
33 if module_name in sys.modules:
34 return getattr(sys.modules[module_name], '__file__', None)
35
36 if inpackage is not None:
37 fullmodule = '{}.{}'.format(inpackage, module_name)
38 else:
39 fullmodule = module_name
40
41 i = module_name.rfind('.')
42 if i >= 0:
43 package = module_name[:i]
44 submodule = module_name[i+1:]
45 parent = getfilename(package, path, inpackage)
46 if parent is None:
47 return None
48 if inpackage is not None:
49 package = '{}.{}'.format(inpackage, package)
50 return getfilename(submodule, [os.path.dirname(parent)], package)
51
52 if inpackage is not None:
53 search_path = path
54 else:
55 search_path = sys.path
56 try:
57 loader = importlib.find_loader(fullmodule, search_path)
58 return loader.get_filename(fullmodule)
59 except (AttributeError, ImportError):
60 return None
61
62 def funcname_breakpoint(funcname, filename=None, frame=None):
63 """Return the filename and the line of the first statement of funcname.
64
65 Fail with BdbError when filename and line cannot be found.
66 """
67 if not filename and not frame:
68 raise BdbError('Error at funcname_breakpoint: invalid arguments.')
69
70 if filename:
71 filename = canonic(filename)
72 if filename not in _modules:
73 _modules[filename] = ModuleSource(filename)
74 module_src = _modules[filename]
75 func_lno = module_src.get_func_lno(funcname)
76 lineno = module_src.get_actual_bp(func_lno)[1]
77 if not lineno:
78 raise BdbError('Bad function name: "{}".'.format(funcname))
79 return filename, lineno
80
81 # frame is not None
82 try:
83 func = eval(funcname, frame.f_globals)
84 except:
85 # funcname is defined in a module not yet (fully) imported
86 module = inspect.getmodule(frame)
87 filename, lineno = FunctionQualifiedName(funcname,
88 module).get_fileline()
89 if not filename:
90 raise BdbError('Bad name: "{}".'.format(funcname))
91 return filename, lineno
92 else:
93 try:
94 filename = inspect.getfile(func)
95 except TypeError:
96 raise BdbError('Cannot set a breakpoint at "{}"'.format(funcname))
97 return funcname_breakpoint(funcname, filename)
98
99
100 class BdbError(Exception):
101 """Generic bdb exception."""
8 102
9 class BdbQuit(Exception): 103 class BdbQuit(Exception):
10 """Exception to give up completely.""" 104 """Exception to give up completely."""
11 105
106 class LineSet:
107 """A group of consecutive lines.
108
109 LineSet is defined by (start, last, ltype, func_lno) where start is the
110 first line number of the lineset, last the last line number, ltype its type
111 and func_lno is the first line number of the function definition that the
112 LineSet belongs to or zero when the group of lines is defined outside a
113 function.
114
115 """
116
117 # A LineSet type: a function definition possibly spanning multiple physical
118 # lines, or a group of consecutive lines, or a logical line that spans
119 # multiple physical lines.
120 LINE_DEF, LINE_GROUP, LINE_MULTI = tuple(range(3))
121
122 def __init__(self):
123 self.reset()
124
125 def reset(self, start=0, ltype=LINE_GROUP, func_lno=0, last=0):
126 self.start = start
127 self.last = last
128 self.ltype = ltype
129 self.func_lno = func_lno
130
131 def add(self, module):
132 """Add the lineset to the ModuleSource instance."""
133 if self.start and self.last:
134 lines = (module.functions_lines
135 if self.func_lno else module.module_lines)
136 lines.append((self.start, self.last, self.ltype, self.func_lno))
137 self.reset(func_lno=self.func_lno)
138
139 class ModuleSource:
140 """A parsed module source.
141
142 Instance attributes:
143 function_lineno: a dictionary mapping function and method names to the
144 first line number of their definition
145 firstlineno: a dictionary mapping the first line number of a callable to :
146 - the first line number of the enclosing function, when the
147 callable is nested in a function definition
148 - zero (by convention, zero is the module first line number for
149 breakpoints set at module level), when a class not nested in a
150 function definition
151 - the first line number of the callable otherwise
152 last_line: the last line number of the module
153 module_lines: a list of the module LineSet tuples
154 functions_lines: a list of the functions LineSet tuples
155 """
156
157 def __init__(self, filename):
158 self.filename = filename
159 self.stat = self.get_stat()
160 self.parse()
161
162 def reset(self):
163 """Update ModuleSource after the file has been modified."""
164 stat = self.get_stat()
165 if not self.stat or not stat:
166 return
167 if (self.stat.st_size == stat.st_size and
168 self.stat.st_mtime == stat.st_mtime):
169 return
170 self.stat = stat
171
172 # The file has been modified, attempt to reload its module.
173 for module in sys.modules.values():
174 fname = getattr(module, '__file__', None)
175 if fname and canonic(fname) == self.filename:
176 try:
177 imp.reload(module)
178 except:
179 pass
180 break
181
182 self.parse()
183
184 def get_stat(self):
185 try:
186 return os.stat(self.filename)
187 except os.error:
188 return None
189
190 def get_func_lno(self, funcname):
191 """Return the first line number of function funcname."""
192 return self.function_lineno.get(funcname)
193
194 def get_actual_bp(self, lineno, lines=None):
195 """Return the actual breakpoint as (func_lno, actual_lno).
196
197 func_lno: first line of the corresponding function definition or zero
198 when the breakpoint would be set outside a function.
199 actual_lno: line where the debugger would stop.
200 """
201 if (not lineno or lineno < 0 or
202 not self.last_line or lineno > self.last_line):
203 return None, None
204
205 if lines is None:
206 lines = self.functions_lines
207 i = 0
208 length = j = len(lines)
209 # Find the index of the first lineset whose start is the first to be
210 # strictly greater than lineno.
211 while i < j:
212 m = (i + j) // 2
213 if lineno < lines[m][0]:
214 j = m
215 else:
216 i = m + 1
217
218 if i != 0:
219 ltype = lines[i-1][2]
220 # lineno inside previous LINE_GROUP or LINE_MULTI
221 if lineno <= lines[i-1][1]:
222 if ltype == LineSet.LINE_GROUP:
223 return lines[i-1][3], lineno
224 elif ltype == LineSet.LINE_MULTI:
225 return lines[i-1][3], lines[i-1][0]
226 if lines is self.functions_lines:
227 if i != length:
228 ltype = lines[i][2]
229 # First statement of next group if not LINE_DEF
230 if ltype != LineSet.LINE_DEF:
231 return lines[i][3], lines[i][0]
232 # Outside a function definition
233 return self.get_actual_bp(lineno, self.module_lines)
234
235 # A comment line, string statement line or empty line outside a
236 # function definition.
237 return None, lineno
238
239 def _parse(self, tok_generator, lineset=LineSet(), cindent=0, clss=None):
240 func_lno = 0
241 prev_tokentype = token.ENDMARKER
242 try:
243 for tokentype, tok, srowcol, _end, _line in tok_generator:
244 if tokentype == token.DEDENT:
245 # End of function definition
246 if func_lno and srowcol[1] <= indent:
247 lineset.add(self)
248 func_lno = 0
249 # End of class definition
250 if clss and srowcol[1] <= cindent:
251 return
252 elif tokentype == tokenize.NL:
253 if lineset.start and lineset.ltype != lineset.LINE_DEF:
254 lineset.add(self)
255 # Start of a logical line with multiple physical lines
256 if (lineset.ltype != lineset.LINE_MULTI and
257 prev_tokentype != tokenize.NEWLINE and
258 prev_tokentype != tokenize.COMMENT):
259 lineset.reset(srowcol[0], lineset.LINE_MULTI,
260 func_lno)
261 elif tokentype == tokenize.NEWLINE:
262 lineset.last = srowcol[0]
263 if lineset.start:
264 if (lineset.ltype == lineset.LINE_DEF or
265 lineset.ltype == lineset.LINE_MULTI):
266 lineset.add(self)
267 elif tokentype == token.ENDMARKER:
268 lineset.add(self)
269 self.last_line = srowcol[0] - 1
270 elif tok == 'def' or tok == 'class':
271 tokentype, name = next(tok_generator)[0:2]
272 if tokentype != token.NAME:
273 continue # syntax error
274 # Nested def or class in a function
275 if func_lno:
276 self.firstlineno[srowcol[0]] = func_lno
277 prev_tokentype = tokentype
278 continue
279 if clss:
280 name = '{}.{}'.format(clss, name)
281 lineno, indent = srowcol
282 if tok == 'def':
283 lineset.add(self)
284 func_lno = lineno
285 # Start of a function definition
286 lineset.reset(lineno, lineset.LINE_DEF, func_lno)
287 self.function_lineno[name] = lineno
288 self.firstlineno[lineno] = lineno
289 else:
290 self.firstlineno[lineno] = 0
291 self._parse(tok_generator, lineset, indent, name)
292 elif (not lineset.start and tokentype != tokenize.COMMENT and
293 tokentype != token.INDENT and
294 tokentype != token.STRING):
295 # Start of a group of lines (possibly LINE_MULTI)
296 lineset.reset(srowcol[0], lineset.LINE_GROUP, func_lno)
297
298 prev_tokentype = tokentype
299 except StopIteration:
300 pass
301
302 def parse(self):
303 self.function_lineno = {}
304 self.firstlineno = {}
305 self.last_line = 0
306 self.module_lines = []
307 self.functions_lines = []
308
309 source_lines = linecache.getlines(self.filename)
310 if source_lines:
311 self._parse(tokenize.generate_tokens(iter(source_lines).__next__))
312
313 def __str__(self):
314 def lines_per_func(lines):
315 # Group lines per function
316 func_lno = 0
317 group = []
318 for lineset in lines:
319 if lineset[3] != func_lno:
320 if group:
321 yield pprint.pformat(group)
322 func_lno = lineset[3]
323 group = [lineset]
324 else:
325 group.append(lineset)
326 if group:
327 yield pprint.pformat(group)
328
329 return (
330 'Functions:\n{}\n'
331 'Functions and classes firstlineno:\n{}\n'
332 'Last line: {}\n'
333 'Module lines:\n{}\n'
334 'Functions lines:\n{}\n'.format(
335 pprint.pformat(
336 sorted(self.function_lineno.items(), key=itemgetter(1))),
337 pprint.pformat(
338 sorted(self.firstlineno.items(), key=itemgetter(0))),
339 self.last_line,
340 pprint.pformat(sorted(self.module_lines, key=itemgetter(0))),
341 '\n'.join(lines_per_func(self.functions_lines))))
342
343 class ModuleBreakpoints:
344 """The breakpoints of a module.
345
346 The breakpts attribute is a dictionary that maps the first line of a
347 function definition (or zero for all the lines outside a function
348 definition) to a line_bps dictionary that maps each line of the function,
349 where one or more breakpoints are set, to the list of corresponding
350 Breakpoint instances.
351
352 Note:
353 A line in line_bps is the actual line of the breakpoint (the line where the
354 debugger stops), this line may differ from the line attribute of the
355 Breakpoint instance as set by the user.
356 """
357
358 def __init__(self, filename):
359 assert filename, ('Attempt to instantiate ModuleBreakpoints'
360 ' with {}'.format(filename))
361 if filename not in _modules:
362 _modules[filename] = ModuleSource(filename)
363 self.module_src = _modules[filename]
364 self.stat = self.module_src.stat
365 self.breakpts = {}
366
367 def reset(self):
368 self.module_src.reset()
369 stat = self.module_src.stat
370 if not self.stat or not stat:
371 return
372 if (self.stat.st_size == stat.st_size and
373 self.stat.st_mtime == stat.st_mtime):
374 return
375
376 # The file has been modified
377 self.stat = stat
378 bplist = self.all_breakpoints()
379 self.breakpts = {}
380 for bp in bplist:
381 self.add_breakpoint(bp)
382
383 def add_breakpoint(self, bp):
384 func_lno, actual_lno = self.module_src.get_actual_bp(bp.line)
385 # May happen after the file has been modified and a reset.
386 if func_lno is None or not actual_lno:
387 return
388 if func_lno not in self.breakpts:
389 self.breakpts[func_lno] = {}
390 line_bps = self.breakpts[func_lno]
391 if actual_lno not in line_bps:
392 line_bps[actual_lno] = []
393 line_bps[actual_lno].append(bp)
394
395 def delete_breakpoint(self, bp):
396 func_lno, actual_lno = self.module_src.get_actual_bp(bp.line)
397 # May happen after the file has been modified and a reset.
398 if func_lno is None or not actual_lno:
399 return
400 try:
401 line_bps = self.breakpts[func_lno]
402 bplist = line_bps[actual_lno]
403 bplist.remove(bp)
404 except (KeyError, ValueError):
405 assert False, ('Internal error: bpbynumber and breakpts'
406 ' are inconsistent')
407 if not bplist:
408 del line_bps[actual_lno]
409 if not line_bps:
410 del self.breakpts[func_lno]
411
412 def get_breakpoints(self, lineno):
413 """Return the list of breakpoints set at lineno."""
414 func_lno, actual_lno = self.module_src.get_actual_bp(lineno)
415 if func_lno not in self.breakpts:
416 return []
417 line_bps = self.breakpts[func_lno]
418 if actual_lno not in line_bps:
419 return []
420 return [bp for bp in sorted(line_bps[actual_lno],
421 key=attrgetter('number')) if bp.line == lineno]
422
423 def all_breakpoints(self):
424 bpts = []
425 for line_bps in self.breakpts.values():
426 for bplist in line_bps.values():
427 bpts.extend(bplist)
428 return [bp for bp in sorted(bpts, key=attrgetter('number'))]
429
430 class FunctionQualifiedName:
431 """Utility to find where is defined a function from its qualified name."""
432
433 def __init__(self, name, module=None):
434 self.name = name
435 self.cur_fname = None
436 if module:
437 self.cur_fname = getfilename(module.__name__)
438 self.fileline = None, None
439
440 def get_fileline(self):
441 i = self.name.rfind('.')
442 if i >= 0:
443 funcname = self.name[i+1:]
444 prefix = self.name[:i]
445 j = prefix.rfind('.')
446 # Try first the current module for a class method, then a function
447 # in prefix and last a method in prefix[:j].
448 if (not (prefix and j < 0 and
449 self.lookup(self.cur_fname, self.name)) and
450 not self.lookup(getfilename(prefix), funcname) and
451 j > 0):
452 method = '{}.{}'.format(prefix[j+1:], funcname)
453 prefix = prefix[:j]
454 self.lookup(getfilename(prefix), method)
455 else:
456 # a function in the current module
457 self.lookup(self.cur_fname, self.name)
458
459 return self.fileline
460
461 def lookup(self, filename, funcname):
462 if filename:
463 try:
464 self.fileline = funcname_breakpoint(funcname, filename)
465 return True
466 except BdbError:
467 pass
468 return False
12 469
13 class Bdb: 470 class Bdb:
14 """Generic Python debugger base class. 471 """Generic Python debugger base class.
15 472
16 This class takes care of details of the trace facility; 473 This class takes care of details of the trace facility;
17 a derived class should implement user interaction. 474 a derived class should implement user interaction.
18 The standard debugger class (pdb.Pdb) is an example. 475 The standard debugger class (pdb.Pdb) is an example.
19 """ 476 """
20 477
21 def __init__(self, skip=None): 478 def __init__(self, skip=None):
22 self.skip = set(skip) if skip else None 479 self.skip = set(skip) if skip else None
23 self.breaks = {}
24 self.fncache = {}
25 self.frame_returning = None 480 self.frame_returning = None
481 # A dictionary mapping a filename to a ModuleBreakpoints instance.
482 self.breakpoints = {}
26 483
484 # Backward compatibility
27 def canonic(self, filename): 485 def canonic(self, filename):
28 if filename == "<" + filename[1:-1] + ">": 486 return canonic(filename)
29 return filename
30 canonic = self.fncache.get(filename)
31 if not canonic:
32 canonic = os.path.abspath(filename)
33 canonic = os.path.normcase(canonic)
34 self.fncache[filename] = canonic
35 return canonic
36 487
37 def reset(self): 488 def reset(self):
38 import linecache 489 # A dictionary mapping a code object to the first line of the enclosing
490 # non-nested function.
491 self.code_firstlineno = {}
39 linecache.checkcache() 492 linecache.checkcache()
40 self.botframe = None 493 self.botframe = None
41 self._set_stopinfo(None, None) 494 self._set_stopinfo(None, None)
495 for module_src in _modules.values():
496 module_src.reset()
497 for module_bpts in self.breakpoints.values():
498 module_bpts.reset()
499
500 def firstlineno(self, frame):
501 """Return the first line of the enclosing non-nested function."""
502 lineno = frame.f_code.co_firstlineno
503 if lineno == 1 and frame.f_code.co_name == '<module>':
504 return 0
505 filename = canonic(frame.f_code.co_filename)
506 if filename not in _modules:
507 _modules[filename] = ModuleSource(filename)
508 module_src = _modules[filename]
509 return module_src.firstlineno.get(lineno, lineno)
510
511 def _set_local_trace(self, frame):
512 frame.f_trace = self.trace_dispatch
513 if frame.f_code not in self.code_firstlineno:
514 self.code_firstlineno[frame.f_code] = self.firstlineno(frame)
42 515
43 def trace_dispatch(self, frame, event, arg): 516 def trace_dispatch(self, frame, event, arg):
44 if self.quitting: 517 if self.quitting:
45 return # None 518 return # None
46 if event == 'line': 519 if event == 'line':
47 return self.dispatch_line(frame) 520 return self.dispatch_line(frame)
48 if event == 'call': 521 if event == 'call':
49 return self.dispatch_call(frame, arg) 522 return self.dispatch_call(frame, arg)
50 if event == 'return': 523 if event == 'return':
51 return self.dispatch_return(frame, arg) 524 return self.dispatch_return(frame, arg)
52 if event == 'exception': 525 if event == 'exception':
53 return self.dispatch_exception(frame, arg) 526 return self.dispatch_exception(frame, arg)
54 if event == 'c_call': 527 if event == 'c_call':
55 return self.trace_dispatch 528 return self.trace_dispatch
56 if event == 'c_exception': 529 if event == 'c_exception':
57 return self.trace_dispatch 530 return self.trace_dispatch
58 if event == 'c_return': 531 if event == 'c_return':
59 return self.trace_dispatch 532 return self.trace_dispatch
60 print('bdb.Bdb.dispatch: unknown debugging event:', repr(event)) 533 print('bdb.Bdb.dispatch: unknown debugging event:', repr(event))
61 return self.trace_dispatch 534 return self.trace_dispatch
62 535
63 def dispatch_line(self, frame): 536 def dispatch_line(self, frame):
64 if self.stop_here(frame) or self.break_here(frame): 537 if self.stop_here(frame) or self.break_here(frame):
65 self.user_line(frame) 538 self.user_line(frame)
66 if self.quitting: raise BdbQuit 539 if self.quitting: raise BdbQuit
67 return self.trace_dispatch 540 return self.trace_dispatch
68 541
69 def dispatch_call(self, frame, arg): 542 def dispatch_call(self, frame, arg):
70 # XXX 'arg' is no longer used 543 # XXX 'arg' is no longer used
544 if frame.f_code not in self.code_firstlineno:
545 self.code_firstlineno[frame.f_code] = self.firstlineno(frame)
71 if self.botframe is None: 546 if self.botframe is None:
72 # First call of dispatch since reset() 547 # First call of dispatch since reset()
73 self.botframe = frame.f_back # (CT) Note that this may also be None! 548 self.botframe = frame.f_back # (CT) Note that this may also be None!
74 return self.trace_dispatch 549 return self.trace_dispatch
75 if not (self.stop_here(frame) or self.break_anywhere(frame)): 550 if not (self.stop_here(frame) or self.break_at_function(frame)):
76 # No need to trace this function 551 # No need to trace this function
77 return # None 552 return # None
78 self.user_call(frame, arg) 553 self.user_call(frame, arg)
79 if self.quitting: raise BdbQuit 554 if self.quitting: raise BdbQuit
80 return self.trace_dispatch 555 return self.trace_dispatch
81 556
82 def dispatch_return(self, frame, arg): 557 def dispatch_return(self, frame, arg):
83 if self.stop_here(frame) or frame == self.returnframe: 558 if self.stop_here(frame) or frame == self.returnframe:
84 try: 559 try:
85 self.frame_returning = frame 560 self.frame_returning = frame
(...skipping 29 matching lines...) Expand all
115 if self.stoplineno == -1: 590 if self.stoplineno == -1:
116 return False 591 return False
117 return frame.f_lineno >= self.stoplineno 592 return frame.f_lineno >= self.stoplineno
118 while frame is not None and frame is not self.stopframe: 593 while frame is not None and frame is not self.stopframe:
119 if frame is self.botframe: 594 if frame is self.botframe:
120 return True 595 return True
121 frame = frame.f_back 596 frame = frame.f_back
122 return False 597 return False
123 598
124 def break_here(self, frame): 599 def break_here(self, frame):
125 filename = self.canonic(frame.f_code.co_filename) 600 filename = canonic(frame.f_code.co_filename)
126 if filename not in self.breaks: 601 if filename not in self.breakpoints:
127 return False 602 return False
128 lineno = frame.f_lineno 603 func_lno = self.code_firstlineno[frame.f_code]
129 if lineno not in self.breaks[filename]: 604 module_bpts = self.breakpoints[filename]
130 # The line itself has no breakpoint, but maybe the line is the 605 if (func_lno not in module_bpts.breakpts or
131 # first line of a function with breakpoint set by function name. 606 frame.f_lineno not in module_bpts.breakpts[func_lno]):
132 lineno = frame.f_code.co_firstlineno 607 return False
133 if lineno not in self.breaks[filename]:
134 return False
135 608
136 # flag says ok to delete temp. bp 609 # Handle multiple breakpoints on the same line (issue 14789)
137 (bp, flag) = effective(filename, lineno, frame) 610 self.effective_bp_list = []
138 if bp: 611 for bp in module_bpts.breakpts[func_lno][frame.f_lineno]:
139 self.currentbp = bp.number 612 stop, delete = bp.process_hit_event(frame)
140 if (flag and bp.temporary): 613 if stop:
141 self.do_clear(str(bp.number)) 614 self.effective_bp_list.append(bp.number)
142 return True 615 if bp.temporary and delete:
143 else: 616 self.do_clear(str(bp.number))
144 return False 617 return len(self.effective_bp_list) != 0
145 618
146 def do_clear(self, arg): 619 def do_clear(self, arg):
147 raise NotImplementedError("subclass of bdb must implement do_clear()") 620 raise NotImplementedError("subclass of bdb must implement do_clear()")
148 621
149 def break_anywhere(self, frame): 622 def break_at_function(self, frame):
150 return self.canonic(frame.f_code.co_filename) in self.breaks 623 filename = canonic(frame.f_code.co_filename)
624 return (filename in self.breakpoints and
625 self.code_firstlineno[frame.f_code] in
626 self.breakpoints[filename].breakpts)
151 627
152 # Derived classes should override the user_* methods 628 # Derived classes should override the user_* methods
153 # to gain control. 629 # to gain control.
154 630
155 def user_call(self, frame, argument_list): 631 def user_call(self, frame, argument_list):
156 """This method is called when there is the remote possibility 632 """This method is called when there is the remote possibility
157 that we ever need to stop in this function.""" 633 that we ever need to stop in this function."""
158 pass 634 pass
159 635
160 def user_line(self, frame): 636 def user_line(self, frame):
(...skipping 30 matching lines...) Expand all
191 667
192 def set_step(self): 668 def set_step(self):
193 """Stop after one line of code.""" 669 """Stop after one line of code."""
194 # Issue #13183: pdb skips frames after hitting a breakpoint and running 670 # Issue #13183: pdb skips frames after hitting a breakpoint and running
195 # step commands. 671 # step commands.
196 # Restore the trace function in the caller (that may not have been set 672 # Restore the trace function in the caller (that may not have been set
197 # for performance reasons) when returning from the current frame. 673 # for performance reasons) when returning from the current frame.
198 if self.frame_returning: 674 if self.frame_returning:
199 caller_frame = self.frame_returning.f_back 675 caller_frame = self.frame_returning.f_back
200 if caller_frame and not caller_frame.f_trace: 676 if caller_frame and not caller_frame.f_trace:
201 caller_frame.f_trace = self.trace_dispatch 677 self._set_local_trace(caller_frame)
202 self._set_stopinfo(None, None) 678 self._set_stopinfo(None, None)
203 679
204 def set_next(self, frame): 680 def set_next(self, frame):
205 """Stop on the next line in or below the given frame.""" 681 """Stop on the next line in or below the given frame."""
206 self._set_stopinfo(frame, None) 682 self._set_stopinfo(frame, None)
207 683
208 def set_return(self, frame): 684 def set_return(self, frame):
209 """Stop when returning from the given frame.""" 685 """Stop when returning from the given frame."""
210 self._set_stopinfo(frame.f_back, frame) 686 self._set_stopinfo(frame.f_back, frame)
211 687
212 def set_trace(self, frame=None): 688 def set_trace(self, frame=None):
213 """Start debugging from `frame`. 689 """Start debugging from `frame`.
214 690
215 If frame is not specified, debugging starts from caller's frame. 691 If frame is not specified, debugging starts from caller's frame.
216 """ 692 """
217 if frame is None: 693 if frame is None:
218 frame = sys._getframe().f_back 694 frame = sys._getframe().f_back
219 self.reset() 695 self.reset()
220 while frame: 696 while frame:
221 frame.f_trace = self.trace_dispatch 697 self._set_local_trace(frame)
222 self.botframe = frame 698 self.botframe = frame
223 frame = frame.f_back 699 frame = frame.f_back
224 self.set_step() 700 self.set_step()
225 sys.settrace(self.trace_dispatch) 701 sys.settrace(self.trace_dispatch)
226 702
227 def set_continue(self): 703 def set_continue(self):
228 # Don't stop except at breakpoints or when finished 704 # Don't stop except at breakpoints or when finished
229 self._set_stopinfo(self.botframe, None, -1) 705 self._set_stopinfo(self.botframe, None, -1)
230 if not self.breaks: 706 if not self.has_breaks():
231 # no breakpoints; run without debugger overhead 707 # no breakpoints; run without debugger overhead
232 sys.settrace(None) 708 sys.settrace(None)
233 frame = sys._getframe().f_back 709 frame = sys._getframe().f_back
234 while frame and frame is not self.botframe: 710 while frame and frame is not self.botframe:
235 del frame.f_trace 711 del frame.f_trace
236 frame = frame.f_back 712 frame = frame.f_back
237 713
238 def set_quit(self): 714 def set_quit(self):
239 self.stopframe = self.botframe 715 self.stopframe = self.botframe
240 self.returnframe = None 716 self.returnframe = None
241 self.quitting = True 717 self.quitting = True
242 sys.settrace(None) 718 sys.settrace(None)
243 719
244 # Derived classes and clients can call the following methods 720 # Derived classes and clients can call the following methods
245 # to manipulate breakpoints. These methods return an 721 # to manipulate breakpoints. These methods return an
246 # error message is something went wrong, None if all is well. 722 # error message is something went wrong, None if all is well.
247 # Set_break prints out the breakpoint line and file:lineno.
248 # Call self.get_*break*() to see the breakpoints or better 723 # Call self.get_*break*() to see the breakpoints or better
249 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint(). 724 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
250 725
251 def set_break(self, filename, lineno, temporary=False, cond=None, 726 def set_break(self, fname, lineno, temporary=False, cond=None,
252 funcname=None): 727 funcname=None):
253 filename = self.canonic(filename) 728 # funcname is not used anymore and kept for backward compatibility
254 import linecache # Import as late as possible 729 filename = canonic(fname)
255 line = linecache.getline(filename, lineno) 730 if filename not in self.breakpoints:
256 if not line: 731 module_bps = ModuleBreakpoints(filename)
257 return 'Line %s:%d does not exist' % (filename, lineno) 732 module_src = module_bps.module_src
258 list = self.breaks.setdefault(filename, []) 733 if not module_src.functions_lines and not module_src.module_lines:
259 if lineno not in list: 734 return 'No lines in {}'.format(fname)
260 list.append(lineno) 735 self.breakpoints[filename] = module_bps
261 bp = Breakpoint(filename, lineno, temporary, cond, funcname) 736 else:
262 737 module_bps = self.breakpoints[filename]
263 def _prune_breaks(self, filename, lineno): 738 func_lno, actual_lno = module_bps.module_src.get_actual_bp(lineno)
264 if (filename, lineno) not in Breakpoint.bplist: 739 if func_lno is None:
265 self.breaks[filename].remove(lineno) 740 if not actual_lno:
266 if not self.breaks[filename]: 741 return 'Line {}:{} does not exist'.format(fname, lineno)
267 del self.breaks[filename] 742 return ('A comment line, string statement line or empty line'
743 ' outside a function definition {}:{}'
744 .format(fname, lineno))
745 bp = Breakpoint(filename, lineno, module_bps, temporary, cond)
268 746
269 def clear_break(self, filename, lineno): 747 def clear_break(self, filename, lineno):
270 filename = self.canonic(filename) 748 bplist = self.get_breaks(filename, lineno)
271 if filename not in self.breaks: 749 if not bplist:
272 return 'There are no breakpoints in %s' % filename
273 if lineno not in self.breaks[filename]:
274 return 'There is no breakpoint at %s:%d' % (filename, lineno) 750 return 'There is no breakpoint at %s:%d' % (filename, lineno)
275 # If there's only one bp in the list for that file,line 751 for bp in bplist:
276 # pair, then remove the breaks entry
277 for bp in Breakpoint.bplist[filename, lineno][:]:
278 bp.deleteMe() 752 bp.deleteMe()
279 self._prune_breaks(filename, lineno)
280 753
281 def clear_bpbynumber(self, arg): 754 def clear_bpbynumber(self, arg):
282 try: 755 try:
283 bp = self.get_bpbynumber(arg) 756 bp = self.get_bpbynumber(arg)
284 except ValueError as err: 757 except ValueError as err:
285 return str(err) 758 return str(err)
286 bp.deleteMe() 759 bp.deleteMe()
287 self._prune_breaks(bp.file, bp.line)
288 760
289 def clear_all_file_breaks(self, filename): 761 def clear_all_file_breaks(self, fname):
290 filename = self.canonic(filename) 762 filename = canonic(fname)
291 if filename not in self.breaks: 763 if (filename not in self.breakpoints or not
292 return 'There are no breakpoints in %s' % filename 764 self.breakpoints[filename].breakpts.keys()):
293 for line in self.breaks[filename]: 765 return 'There are no breakpoints in %s' % fname
294 blist = Breakpoint.bplist[filename, line] 766 for bp in self.breakpoints[filename].all_breakpoints():
295 for bp in blist: 767 bp.deleteMe()
296 bp.deleteMe()
297 del self.breaks[filename]
298 768
299 def clear_all_breaks(self): 769 def clear_all_breaks(self):
300 if not self.breaks: 770 if not self.has_breaks():
301 return 'There are no breakpoints' 771 return 'There are no breakpoints'
302 for bp in Breakpoint.bpbynumber: 772 for bp in Breakpoint.bpbynumber:
303 if bp: 773 if bp:
304 bp.deleteMe() 774 bp.deleteMe()
305 self.breaks = {}
306 775
307 def get_bpbynumber(self, arg): 776 def get_bpbynumber(self, arg):
308 if not arg: 777 if not arg:
309 raise ValueError('Breakpoint number expected') 778 raise ValueError('Breakpoint number expected')
310 try: 779 try:
311 number = int(arg) 780 number = int(arg)
312 except ValueError: 781 except ValueError:
313 raise ValueError('Non-numeric breakpoint number %s' % arg) 782 raise ValueError('Non-numeric breakpoint number %s' % arg)
314 try: 783 try:
315 bp = Breakpoint.bpbynumber[number] 784 bp = Breakpoint.bpbynumber[number]
316 except IndexError: 785 except IndexError:
317 raise ValueError('Breakpoint number %d out of range' % number) 786 raise ValueError('Breakpoint number %d out of range' % number)
318 if bp is None: 787 if bp is None:
319 raise ValueError('Breakpoint %d already deleted' % number) 788 raise ValueError('Breakpoint %d already deleted' % number)
320 return bp 789 return bp
321 790
322 def get_break(self, filename, lineno): 791 def get_break(self, filename, lineno):
323 filename = self.canonic(filename) 792 return len(self.get_breaks(filename, lineno)) != 0
324 return filename in self.breaks and \
325 lineno in self.breaks[filename]
326 793
327 def get_breaks(self, filename, lineno): 794 def get_breaks(self, filename, lineno):
328 filename = self.canonic(filename) 795 filename = canonic(filename)
329 return filename in self.breaks and \ 796 if filename in self.breakpoints:
330 lineno in self.breaks[filename] and \ 797 return self.breakpoints[filename].get_breakpoints(lineno)
331 Breakpoint.bplist[filename, lineno] or [] 798 return []
332 799
333 def get_file_breaks(self, filename): 800 def get_file_breaks(self, filename):
334 filename = self.canonic(filename) 801 filename = canonic(filename)
335 if filename in self.breaks: 802 if filename not in self.breakpoints:
336 return self.breaks[filename]
337 else:
338 return [] 803 return []
804 return [bp.line for bp in self.breakpoints[filename].all_breakpoints()]
339 805
340 def get_all_breaks(self): 806 def get_all_breaks(self):
341 return self.breaks 807 breaks = {}
808 for filename in self.breakpoints:
809 linebp_list = self.get_file_breaks(filename)
810 if linebp_list:
811 breaks[filename] = self.get_file_breaks(filename)
812 return breaks
813
814 def has_breaks(self):
815 return any(self.breakpoints[f].breakpts.keys()
816 for f in self.breakpoints)
342 817
343 # Derived classes and clients can call the following method 818 # Derived classes and clients can call the following method
344 # to get a data structure representing a stack trace. 819 # to get a data structure representing a stack trace.
345 820
346 def get_stack(self, f, t): 821 def get_stack(self, f, t):
347 stack = [] 822 stack = []
348 if t and t.tb_frame is f: 823 if t and t.tb_frame is f:
349 t = t.tb_next 824 t = t.tb_next
350 while f is not None: 825 while f is not None:
351 stack.append((f, f.f_lineno)) 826 stack.append((f, f.f_lineno))
352 if f is self.botframe: 827 if f is self.botframe:
353 break 828 break
354 f = f.f_back 829 f = f.f_back
355 stack.reverse() 830 stack.reverse()
356 i = max(0, len(stack) - 1) 831 i = max(0, len(stack) - 1)
357 while t is not None: 832 while t is not None:
358 stack.append((t.tb_frame, t.tb_lineno)) 833 stack.append((t.tb_frame, t.tb_lineno))
359 t = t.tb_next 834 t = t.tb_next
360 if f is None: 835 if f is None:
361 i = max(0, len(stack) - 1) 836 i = max(0, len(stack) - 1)
362 return stack, i 837 return stack, i
363 838
364 def format_stack_entry(self, frame_lineno, lprefix=': '): 839 def format_stack_entry(self, frame_lineno, lprefix=': '):
365 import linecache, reprlib 840 import reprlib
366 frame, lineno = frame_lineno 841 frame, lineno = frame_lineno
367 filename = self.canonic(frame.f_code.co_filename) 842 filename = canonic(frame.f_code.co_filename)
368 s = '%s(%r)' % (filename, lineno) 843 s = '%s(%r)' % (filename, lineno)
369 if frame.f_code.co_name: 844 if frame.f_code.co_name:
370 s += frame.f_code.co_name 845 s += frame.f_code.co_name
371 else: 846 else:
372 s += "<lambda>" 847 s += "<lambda>"
373 if '__args__' in frame.f_locals: 848 if '__args__' in frame.f_locals:
374 args = frame.f_locals['__args__'] 849 args = frame.f_locals['__args__']
375 else: 850 else:
376 args = None 851 args = None
377 if args: 852 if args:
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 def set_trace(): 923 def set_trace():
449 Bdb().set_trace() 924 Bdb().set_trace()
450 925
451 926
452 class Breakpoint: 927 class Breakpoint:
453 """Breakpoint class. 928 """Breakpoint class.
454 929
455 Implements temporary breakpoints, ignore counts, disabling and 930 Implements temporary breakpoints, ignore counts, disabling and
456 (re)-enabling, and conditionals. 931 (re)-enabling, and conditionals.
457 932
458 Breakpoints are indexed by number through bpbynumber and by 933 Breakpoints are indexed by number through bpbynumber.
459 the file,line tuple using bplist. The former points to a
460 single instance of class Breakpoint. The latter points to a
461 list of such instances since there may be more than one
462 breakpoint per line.
463 934
464 """ 935 """
465 936
466 # XXX Keeping state in the class is a mistake -- this means 937 next = 1 # Next bp to be assigned
467 # you cannot have more than one active Bdb instance. 938 bpbynumber = [None] # Each entry is None or an instance of Bpt
468 939
469 next = 1 # Next bp to be assigned 940 def __init__(self, file, line, module, temporary=False,
470 bplist = {} # indexed by (file, lineno) tuple 941 cond=None):
471 bpbynumber = [None] # Each entry is None or an instance of Bpt
472 # index 0 is unused, except for marking an
473 # effective break .... see effective()
474
475 def __init__(self, file, line, temporary=False, cond=None, funcname=None):
476 self.funcname = funcname
477 # Needed if funcname is not None.
478 self.func_first_executable_line = None
479 self.file = file # This better be in canonical form! 942 self.file = file # This better be in canonical form!
480 self.line = line 943 self.line = line
944 self.module = module
481 self.temporary = temporary 945 self.temporary = temporary
482 self.cond = cond 946 self.cond = cond
483 self.enabled = True 947 self.enabled = True
484 self.ignore = 0 948 self.ignore = 0
485 self.hits = 0 949 self.hits = 0
486 self.number = Breakpoint.next 950 self.number = Breakpoint.next
487 Breakpoint.next += 1 951 Breakpoint.next += 1
488 # Build the two lists
489 self.bpbynumber.append(self) 952 self.bpbynumber.append(self)
490 if (file, line) in self.bplist: 953 self.module.add_breakpoint(self)
491 self.bplist[file, line].append(self)
492 else:
493 self.bplist[file, line] = [self]
494 954
495 def deleteMe(self): 955 def deleteMe(self):
496 index = (self.file, self.line) 956 if self.bpbynumber[self.number]:
497 self.bpbynumber[self.number] = None # No longer in list 957 self.bpbynumber[self.number] = None # No longer in list
498 self.bplist[index].remove(self) 958 self.module.delete_breakpoint(self)
499 if not self.bplist[index]:
500 # No more bp for this f:l combo
501 del self.bplist[index]
502 959
503 def enable(self): 960 def enable(self):
504 self.enabled = True 961 self.enabled = True
505 962
506 def disable(self): 963 def disable(self):
507 self.enabled = False 964 self.enabled = False
965
966 def process_hit_event(self, frame):
967 """Return (stop_state, delete_temporary) at a breakpoint hit event."""
968 if not self.enabled:
969 return False, False
970 # Count every hit when breakpoint is enabled.
971 self.hits += 1
972 # A conditional breakpoint.
973 if self.cond:
974 try:
975 if not eval(self.cond, frame.f_globals, frame.f_locals):
976 return False, False
977 except:
978 # If the breakpoint condition evaluation fails, the most
979 # conservative thing is to stop on the breakpoint. Don't
980 # delete temporary, as another hint to the user.
981 return True, False
982 if self.ignore > 0:
983 self.ignore -= 1
984 return False, False
985 return True, True
508 986
509 def bpprint(self, out=None): 987 def bpprint(self, out=None):
510 if out is None: 988 if out is None:
511 out = sys.stdout 989 out = sys.stdout
512 print(self.bpformat(), file=out) 990 print(self.bpformat(), file=out)
513 991
514 def bpformat(self): 992 def bpformat(self):
515 if self.temporary: 993 if self.temporary:
516 disp = 'del ' 994 disp = 'del '
517 else: 995 else:
(...skipping 11 matching lines...) Expand all
529 if self.hits: 1007 if self.hits:
530 if self.hits > 1: 1008 if self.hits > 1:
531 ss = 's' 1009 ss = 's'
532 else: 1010 else:
533 ss = '' 1011 ss = ''
534 ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss) 1012 ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)
535 return ret 1013 return ret
536 1014
537 def __str__(self): 1015 def __str__(self):
538 return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line) 1016 return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)
539
540 # -----------end of Breakpoint class----------
541
542 def checkfuncname(b, frame):
543 """Check whether we should break here because of `b.funcname`."""
544 if not b.funcname:
545 # Breakpoint was set via line number.
546 if b.line != frame.f_lineno:
547 # Breakpoint was set at a line with a def statement and the function
548 # defined is called: don't break.
549 return False
550 return True
551
552 # Breakpoint set via function name.
553
554 if frame.f_code.co_name != b.funcname:
555 # It's not a function call, but rather execution of def statement.
556 return False
557
558 # We are in the right frame.
559 if not b.func_first_executable_line:
560 # The function is entered for the 1st time.
561 b.func_first_executable_line = frame.f_lineno
562
563 if b.func_first_executable_line != frame.f_lineno:
564 # But we are not at the first line number: don't break.
565 return False
566 return True
567
568 # Determines if there is an effective (active) breakpoint at this
569 # line of code. Returns breakpoint number or 0 if none
570 def effective(file, line, frame):
571 """Determine which breakpoint for this file:line is to be acted upon.
572
573 Called only if we know there is a bpt at this
574 location. Returns breakpoint that was triggered and a flag
575 that indicates if it is ok to delete a temporary bp.
576
577 """
578 possibles = Breakpoint.bplist[file, line]
579 for b in possibles:
580 if not b.enabled:
581 continue
582 if not checkfuncname(b, frame):
583 continue
584 # Count every hit when bp is enabled
585 b.hits += 1
586 if not b.cond:
587 # If unconditional, and ignoring go on to next, else break
588 if b.ignore > 0:
589 b.ignore -= 1
590 continue
591 else:
592 # breakpoint and marker that it's ok to delete if temporary
593 return (b, True)
594 else:
595 # Conditional bp.
596 # Ignore count applies only to those bpt hits where the
597 # condition evaluates to true.
598 try:
599 val = eval(b.cond, frame.f_globals, frame.f_locals)
600 if val:
601 if b.ignore > 0:
602 b.ignore -= 1
603 # continue
604 else:
605 return (b, True)
606 # else:
607 # continue
608 except:
609 # if eval fails, most conservative thing is to stop on
610 # breakpoint regardless of ignore count. Don't delete
611 # temporary, as another hint to user.
612 return (b, False)
613 return (None, None)
614 1017
615 1018
616 # -------------------- testing -------------------- 1019 # -------------------- testing --------------------
617 1020
618 class Tdb(Bdb): 1021 class Tdb(Bdb):
619 def user_call(self, frame, args): 1022 def user_call(self, frame, args):
620 name = frame.f_code.co_name 1023 name = frame.f_code.co_name
621 if not name: name = '???' 1024 if not name: name = '???'
622 print('+++ call', name, args) 1025 print('+++ call', name, args)
623 def user_line(self, frame): 1026 def user_line(self, frame):
624 import linecache
625 name = frame.f_code.co_name 1027 name = frame.f_code.co_name
626 if not name: name = '???' 1028 if not name: name = '???'
627 fn = self.canonic(frame.f_code.co_filename) 1029 fn = canonic(frame.f_code.co_filename)
628 line = linecache.getline(fn, frame.f_lineno, frame.f_globals) 1030 line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
629 print('+++', fn, frame.f_lineno, name, ':', line.strip()) 1031 print('+++', fn, frame.f_lineno, name, ':', line.strip())
630 def user_return(self, frame, retval): 1032 def user_return(self, frame, retval):
631 print('+++ return', retval) 1033 print('+++ return', retval)
632 def user_exception(self, frame, exc_stuff): 1034 def user_exception(self, frame, exc_stuff):
633 print('+++ exception', exc_stuff) 1035 print('+++ exception', exc_stuff)
634 self.set_continue() 1036 self.set_continue()
635 1037
636 def foo(n): 1038 def foo(n):
637 print('foo(', n, ')') 1039 print('foo(', n, ')')
638 x = bar(n*10) 1040 x = bar(n*10)
639 print('bar returned', x) 1041 print('bar returned', x)
640 1042
641 def bar(a): 1043 def bar(a):
642 print('bar(', a, ')') 1044 print('bar(', a, ')')
643 return a/2 1045 return a/2
644 1046
645 def test(): 1047 def test():
646 t = Tdb() 1048 t = Tdb()
647 t.run('import bdb; bdb.foo(10)') 1049 t.run('import bdb; bdb.foo(10)')
OLDNEW
« no previous file with comments | « no previous file | Lib/pdb.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7