(root)/
Python-3.11.7/
Lib/
bdb.py
       1  """Debugger basics"""
       2  
       3  import fnmatch
       4  import sys
       5  import os
       6  from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
       7  
       8  __all__ = ["BdbQuit", "Bdb", "Breakpoint"]
       9  
      10  GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR
      11  
      12  
      13  class ESC[4;38;5;81mBdbQuit(ESC[4;38;5;149mException):
      14      """Exception to give up completely."""
      15  
      16  
      17  class ESC[4;38;5;81mBdb:
      18      """Generic Python debugger base class.
      19  
      20      This class takes care of details of the trace facility;
      21      a derived class should implement user interaction.
      22      The standard debugger class (pdb.Pdb) is an example.
      23  
      24      The optional skip argument must be an iterable of glob-style
      25      module name patterns.  The debugger will not step into frames
      26      that originate in a module that matches one of these patterns.
      27      Whether a frame is considered to originate in a certain module
      28      is determined by the __name__ in the frame globals.
      29      """
      30  
      31      def __init__(self, skip=None):
      32          self.skip = set(skip) if skip else None
      33          self.breaks = {}
      34          self.fncache = {}
      35          self.frame_returning = None
      36  
      37          self._load_breaks()
      38  
      39      def canonic(self, filename):
      40          """Return canonical form of filename.
      41  
      42          For real filenames, the canonical form is a case-normalized (on
      43          case insensitive filesystems) absolute path.  'Filenames' with
      44          angle brackets, such as "<stdin>", generated in interactive
      45          mode, are returned unchanged.
      46          """
      47          if filename == "<" + filename[1:-1] + ">":
      48              return filename
      49          canonic = self.fncache.get(filename)
      50          if not canonic:
      51              canonic = os.path.abspath(filename)
      52              canonic = os.path.normcase(canonic)
      53              self.fncache[filename] = canonic
      54          return canonic
      55  
      56      def reset(self):
      57          """Set values of attributes as ready to start debugging."""
      58          import linecache
      59          linecache.checkcache()
      60          self.botframe = None
      61          self._set_stopinfo(None, None)
      62  
      63      def trace_dispatch(self, frame, event, arg):
      64          """Dispatch a trace function for debugged frames based on the event.
      65  
      66          This function is installed as the trace function for debugged
      67          frames. Its return value is the new trace function, which is
      68          usually itself. The default implementation decides how to
      69          dispatch a frame, depending on the type of event (passed in as a
      70          string) that is about to be executed.
      71  
      72          The event can be one of the following:
      73              line: A new line of code is going to be executed.
      74              call: A function is about to be called or another code block
      75                    is entered.
      76              return: A function or other code block is about to return.
      77              exception: An exception has occurred.
      78              c_call: A C function is about to be called.
      79              c_return: A C function has returned.
      80              c_exception: A C function has raised an exception.
      81  
      82          For the Python events, specialized functions (see the dispatch_*()
      83          methods) are called.  For the C events, no action is taken.
      84  
      85          The arg parameter depends on the previous event.
      86          """
      87          if self.quitting:
      88              return # None
      89          if event == 'line':
      90              return self.dispatch_line(frame)
      91          if event == 'call':
      92              return self.dispatch_call(frame, arg)
      93          if event == 'return':
      94              return self.dispatch_return(frame, arg)
      95          if event == 'exception':
      96              return self.dispatch_exception(frame, arg)
      97          if event == 'c_call':
      98              return self.trace_dispatch
      99          if event == 'c_exception':
     100              return self.trace_dispatch
     101          if event == 'c_return':
     102              return self.trace_dispatch
     103          print('bdb.Bdb.dispatch: unknown debugging event:', repr(event))
     104          return self.trace_dispatch
     105  
     106      def dispatch_line(self, frame):
     107          """Invoke user function and return trace function for line event.
     108  
     109          If the debugger stops on the current line, invoke
     110          self.user_line(). Raise BdbQuit if self.quitting is set.
     111          Return self.trace_dispatch to continue tracing in this scope.
     112          """
     113          if self.stop_here(frame) or self.break_here(frame):
     114              self.user_line(frame)
     115              if self.quitting: raise BdbQuit
     116          return self.trace_dispatch
     117  
     118      def dispatch_call(self, frame, arg):
     119          """Invoke user function and return trace function for call event.
     120  
     121          If the debugger stops on this function call, invoke
     122          self.user_call(). Raise BdbQuit if self.quitting is set.
     123          Return self.trace_dispatch to continue tracing in this scope.
     124          """
     125          # XXX 'arg' is no longer used
     126          if self.botframe is None:
     127              # First call of dispatch since reset()
     128              self.botframe = frame.f_back # (CT) Note that this may also be None!
     129              return self.trace_dispatch
     130          if not (self.stop_here(frame) or self.break_anywhere(frame)):
     131              # No need to trace this function
     132              return # None
     133          # Ignore call events in generator except when stepping.
     134          if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
     135              return self.trace_dispatch
     136          self.user_call(frame, arg)
     137          if self.quitting: raise BdbQuit
     138          return self.trace_dispatch
     139  
     140      def dispatch_return(self, frame, arg):
     141          """Invoke user function and return trace function for return event.
     142  
     143          If the debugger stops on this function return, invoke
     144          self.user_return(). Raise BdbQuit if self.quitting is set.
     145          Return self.trace_dispatch to continue tracing in this scope.
     146          """
     147          if self.stop_here(frame) or frame == self.returnframe:
     148              # Ignore return events in generator except when stepping.
     149              if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
     150                  return self.trace_dispatch
     151              try:
     152                  self.frame_returning = frame
     153                  self.user_return(frame, arg)
     154              finally:
     155                  self.frame_returning = None
     156              if self.quitting: raise BdbQuit
     157              # The user issued a 'next' or 'until' command.
     158              if self.stopframe is frame and self.stoplineno != -1:
     159                  self._set_stopinfo(None, None)
     160          return self.trace_dispatch
     161  
     162      def dispatch_exception(self, frame, arg):
     163          """Invoke user function and return trace function for exception event.
     164  
     165          If the debugger stops on this exception, invoke
     166          self.user_exception(). Raise BdbQuit if self.quitting is set.
     167          Return self.trace_dispatch to continue tracing in this scope.
     168          """
     169          if self.stop_here(frame):
     170              # When stepping with next/until/return in a generator frame, skip
     171              # the internal StopIteration exception (with no traceback)
     172              # triggered by a subiterator run with the 'yield from' statement.
     173              if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
     174                      and arg[0] is StopIteration and arg[2] is None):
     175                  self.user_exception(frame, arg)
     176                  if self.quitting: raise BdbQuit
     177          # Stop at the StopIteration or GeneratorExit exception when the user
     178          # has set stopframe in a generator by issuing a return command, or a
     179          # next/until command at the last statement in the generator before the
     180          # exception.
     181          elif (self.stopframe and frame is not self.stopframe
     182                  and self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
     183                  and arg[0] in (StopIteration, GeneratorExit)):
     184              self.user_exception(frame, arg)
     185              if self.quitting: raise BdbQuit
     186  
     187          return self.trace_dispatch
     188  
     189      # Normally derived classes don't override the following
     190      # methods, but they may if they want to redefine the
     191      # definition of stopping and breakpoints.
     192  
     193      def is_skipped_module(self, module_name):
     194          "Return True if module_name matches any skip pattern."
     195          if module_name is None:  # some modules do not have names
     196              return False
     197          for pattern in self.skip:
     198              if fnmatch.fnmatch(module_name, pattern):
     199                  return True
     200          return False
     201  
     202      def stop_here(self, frame):
     203          "Return True if frame is below the starting frame in the stack."
     204          # (CT) stopframe may now also be None, see dispatch_call.
     205          # (CT) the former test for None is therefore removed from here.
     206          if self.skip and \
     207                 self.is_skipped_module(frame.f_globals.get('__name__')):
     208              return False
     209          if frame is self.stopframe:
     210              if self.stoplineno == -1:
     211                  return False
     212              return frame.f_lineno >= self.stoplineno
     213          if not self.stopframe:
     214              return True
     215          return False
     216  
     217      def break_here(self, frame):
     218          """Return True if there is an effective breakpoint for this line.
     219  
     220          Check for line or function breakpoint and if in effect.
     221          Delete temporary breakpoints if effective() says to.
     222          """
     223          filename = self.canonic(frame.f_code.co_filename)
     224          if filename not in self.breaks:
     225              return False
     226          lineno = frame.f_lineno
     227          if lineno not in self.breaks[filename]:
     228              # The line itself has no breakpoint, but maybe the line is the
     229              # first line of a function with breakpoint set by function name.
     230              lineno = frame.f_code.co_firstlineno
     231              if lineno not in self.breaks[filename]:
     232                  return False
     233  
     234          # flag says ok to delete temp. bp
     235          (bp, flag) = effective(filename, lineno, frame)
     236          if bp:
     237              self.currentbp = bp.number
     238              if (flag and bp.temporary):
     239                  self.do_clear(str(bp.number))
     240              return True
     241          else:
     242              return False
     243  
     244      def do_clear(self, arg):
     245          """Remove temporary breakpoint.
     246  
     247          Must implement in derived classes or get NotImplementedError.
     248          """
     249          raise NotImplementedError("subclass of bdb must implement do_clear()")
     250  
     251      def break_anywhere(self, frame):
     252          """Return True if there is any breakpoint for frame's filename.
     253          """
     254          return self.canonic(frame.f_code.co_filename) in self.breaks
     255  
     256      # Derived classes should override the user_* methods
     257      # to gain control.
     258  
     259      def user_call(self, frame, argument_list):
     260          """Called if we might stop in a function."""
     261          pass
     262  
     263      def user_line(self, frame):
     264          """Called when we stop or break at a line."""
     265          pass
     266  
     267      def user_return(self, frame, return_value):
     268          """Called when a return trap is set here."""
     269          pass
     270  
     271      def user_exception(self, frame, exc_info):
     272          """Called when we stop on an exception."""
     273          pass
     274  
     275      def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
     276          """Set the attributes for stopping.
     277  
     278          If stoplineno is greater than or equal to 0, then stop at line
     279          greater than or equal to the stopline.  If stoplineno is -1, then
     280          don't stop at all.
     281          """
     282          self.stopframe = stopframe
     283          self.returnframe = returnframe
     284          self.quitting = False
     285          # stoplineno >= 0 means: stop at line >= the stoplineno
     286          # stoplineno -1 means: don't stop at all
     287          self.stoplineno = stoplineno
     288  
     289      # Derived classes and clients can call the following methods
     290      # to affect the stepping state.
     291  
     292      def set_until(self, frame, lineno=None):
     293          """Stop when the line with the lineno greater than the current one is
     294          reached or when returning from current frame."""
     295          # the name "until" is borrowed from gdb
     296          if lineno is None:
     297              lineno = frame.f_lineno + 1
     298          self._set_stopinfo(frame, frame, lineno)
     299  
     300      def set_step(self):
     301          """Stop after one line of code."""
     302          # Issue #13183: pdb skips frames after hitting a breakpoint and running
     303          # step commands.
     304          # Restore the trace function in the caller (that may not have been set
     305          # for performance reasons) when returning from the current frame.
     306          if self.frame_returning:
     307              caller_frame = self.frame_returning.f_back
     308              if caller_frame and not caller_frame.f_trace:
     309                  caller_frame.f_trace = self.trace_dispatch
     310          self._set_stopinfo(None, None)
     311  
     312      def set_next(self, frame):
     313          """Stop on the next line in or below the given frame."""
     314          self._set_stopinfo(frame, None)
     315  
     316      def set_return(self, frame):
     317          """Stop when returning from the given frame."""
     318          if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
     319              self._set_stopinfo(frame, None, -1)
     320          else:
     321              self._set_stopinfo(frame.f_back, frame)
     322  
     323      def set_trace(self, frame=None):
     324          """Start debugging from frame.
     325  
     326          If frame is not specified, debugging starts from caller's frame.
     327          """
     328          if frame is None:
     329              frame = sys._getframe().f_back
     330          self.reset()
     331          while frame:
     332              frame.f_trace = self.trace_dispatch
     333              self.botframe = frame
     334              frame = frame.f_back
     335          self.set_step()
     336          sys.settrace(self.trace_dispatch)
     337  
     338      def set_continue(self):
     339          """Stop only at breakpoints or when finished.
     340  
     341          If there are no breakpoints, set the system trace function to None.
     342          """
     343          # Don't stop except at breakpoints or when finished
     344          self._set_stopinfo(self.botframe, None, -1)
     345          if not self.breaks:
     346              # no breakpoints; run without debugger overhead
     347              sys.settrace(None)
     348              frame = sys._getframe().f_back
     349              while frame and frame is not self.botframe:
     350                  del frame.f_trace
     351                  frame = frame.f_back
     352  
     353      def set_quit(self):
     354          """Set quitting attribute to True.
     355  
     356          Raises BdbQuit exception in the next call to a dispatch_*() method.
     357          """
     358          self.stopframe = self.botframe
     359          self.returnframe = None
     360          self.quitting = True
     361          sys.settrace(None)
     362  
     363      # Derived classes and clients can call the following methods
     364      # to manipulate breakpoints.  These methods return an
     365      # error message if something went wrong, None if all is well.
     366      # Set_break prints out the breakpoint line and file:lineno.
     367      # Call self.get_*break*() to see the breakpoints or better
     368      # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
     369  
     370      def _add_to_breaks(self, filename, lineno):
     371          """Add breakpoint to breaks, if not already there."""
     372          bp_linenos = self.breaks.setdefault(filename, [])
     373          if lineno not in bp_linenos:
     374              bp_linenos.append(lineno)
     375  
     376      def set_break(self, filename, lineno, temporary=False, cond=None,
     377                    funcname=None):
     378          """Set a new breakpoint for filename:lineno.
     379  
     380          If lineno doesn't exist for the filename, return an error message.
     381          The filename should be in canonical form.
     382          """
     383          filename = self.canonic(filename)
     384          import linecache # Import as late as possible
     385          line = linecache.getline(filename, lineno)
     386          if not line:
     387              return 'Line %s:%d does not exist' % (filename, lineno)
     388          self._add_to_breaks(filename, lineno)
     389          bp = Breakpoint(filename, lineno, temporary, cond, funcname)
     390          return None
     391  
     392      def _load_breaks(self):
     393          """Apply all breakpoints (set in other instances) to this one.
     394  
     395          Populates this instance's breaks list from the Breakpoint class's
     396          list, which can have breakpoints set by another Bdb instance. This
     397          is necessary for interactive sessions to keep the breakpoints
     398          active across multiple calls to run().
     399          """
     400          for (filename, lineno) in Breakpoint.bplist.keys():
     401              self._add_to_breaks(filename, lineno)
     402  
     403      def _prune_breaks(self, filename, lineno):
     404          """Prune breakpoints for filename:lineno.
     405  
     406          A list of breakpoints is maintained in the Bdb instance and in
     407          the Breakpoint class.  If a breakpoint in the Bdb instance no
     408          longer exists in the Breakpoint class, then it's removed from the
     409          Bdb instance.
     410          """
     411          if (filename, lineno) not in Breakpoint.bplist:
     412              self.breaks[filename].remove(lineno)
     413          if not self.breaks[filename]:
     414              del self.breaks[filename]
     415  
     416      def clear_break(self, filename, lineno):
     417          """Delete breakpoints for filename:lineno.
     418  
     419          If no breakpoints were set, return an error message.
     420          """
     421          filename = self.canonic(filename)
     422          if filename not in self.breaks:
     423              return 'There are no breakpoints in %s' % filename
     424          if lineno not in self.breaks[filename]:
     425              return 'There is no breakpoint at %s:%d' % (filename, lineno)
     426          # If there's only one bp in the list for that file,line
     427          # pair, then remove the breaks entry
     428          for bp in Breakpoint.bplist[filename, lineno][:]:
     429              bp.deleteMe()
     430          self._prune_breaks(filename, lineno)
     431          return None
     432  
     433      def clear_bpbynumber(self, arg):
     434          """Delete a breakpoint by its index in Breakpoint.bpbynumber.
     435  
     436          If arg is invalid, return an error message.
     437          """
     438          try:
     439              bp = self.get_bpbynumber(arg)
     440          except ValueError as err:
     441              return str(err)
     442          bp.deleteMe()
     443          self._prune_breaks(bp.file, bp.line)
     444          return None
     445  
     446      def clear_all_file_breaks(self, filename):
     447          """Delete all breakpoints in filename.
     448  
     449          If none were set, return an error message.
     450          """
     451          filename = self.canonic(filename)
     452          if filename not in self.breaks:
     453              return 'There are no breakpoints in %s' % filename
     454          for line in self.breaks[filename]:
     455              blist = Breakpoint.bplist[filename, line]
     456              for bp in blist:
     457                  bp.deleteMe()
     458          del self.breaks[filename]
     459          return None
     460  
     461      def clear_all_breaks(self):
     462          """Delete all existing breakpoints.
     463  
     464          If none were set, return an error message.
     465          """
     466          if not self.breaks:
     467              return 'There are no breakpoints'
     468          for bp in Breakpoint.bpbynumber:
     469              if bp:
     470                  bp.deleteMe()
     471          self.breaks = {}
     472          return None
     473  
     474      def get_bpbynumber(self, arg):
     475          """Return a breakpoint by its index in Breakpoint.bybpnumber.
     476  
     477          For invalid arg values or if the breakpoint doesn't exist,
     478          raise a ValueError.
     479          """
     480          if not arg:
     481              raise ValueError('Breakpoint number expected')
     482          try:
     483              number = int(arg)
     484          except ValueError:
     485              raise ValueError('Non-numeric breakpoint number %s' % arg) from None
     486          try:
     487              bp = Breakpoint.bpbynumber[number]
     488          except IndexError:
     489              raise ValueError('Breakpoint number %d out of range' % number) from None
     490          if bp is None:
     491              raise ValueError('Breakpoint %d already deleted' % number)
     492          return bp
     493  
     494      def get_break(self, filename, lineno):
     495          """Return True if there is a breakpoint for filename:lineno."""
     496          filename = self.canonic(filename)
     497          return filename in self.breaks and \
     498              lineno in self.breaks[filename]
     499  
     500      def get_breaks(self, filename, lineno):
     501          """Return all breakpoints for filename:lineno.
     502  
     503          If no breakpoints are set, return an empty list.
     504          """
     505          filename = self.canonic(filename)
     506          return filename in self.breaks and \
     507              lineno in self.breaks[filename] and \
     508              Breakpoint.bplist[filename, lineno] or []
     509  
     510      def get_file_breaks(self, filename):
     511          """Return all lines with breakpoints for filename.
     512  
     513          If no breakpoints are set, return an empty list.
     514          """
     515          filename = self.canonic(filename)
     516          if filename in self.breaks:
     517              return self.breaks[filename]
     518          else:
     519              return []
     520  
     521      def get_all_breaks(self):
     522          """Return all breakpoints that are set."""
     523          return self.breaks
     524  
     525      # Derived classes and clients can call the following method
     526      # to get a data structure representing a stack trace.
     527  
     528      def get_stack(self, f, t):
     529          """Return a list of (frame, lineno) in a stack trace and a size.
     530  
     531          List starts with original calling frame, if there is one.
     532          Size may be number of frames above or below f.
     533          """
     534          stack = []
     535          if t and t.tb_frame is f:
     536              t = t.tb_next
     537          while f is not None:
     538              stack.append((f, f.f_lineno))
     539              if f is self.botframe:
     540                  break
     541              f = f.f_back
     542          stack.reverse()
     543          i = max(0, len(stack) - 1)
     544          while t is not None:
     545              stack.append((t.tb_frame, t.tb_lineno))
     546              t = t.tb_next
     547          if f is None:
     548              i = max(0, len(stack) - 1)
     549          return stack, i
     550  
     551      def format_stack_entry(self, frame_lineno, lprefix=': '):
     552          """Return a string with information about a stack entry.
     553  
     554          The stack entry frame_lineno is a (frame, lineno) tuple.  The
     555          return string contains the canonical filename, the function name
     556          or '<lambda>', the input arguments, the return value, and the
     557          line of code (if it exists).
     558  
     559          """
     560          import linecache, reprlib
     561          frame, lineno = frame_lineno
     562          filename = self.canonic(frame.f_code.co_filename)
     563          s = '%s(%r)' % (filename, lineno)
     564          if frame.f_code.co_name:
     565              s += frame.f_code.co_name
     566          else:
     567              s += "<lambda>"
     568          s += '()'
     569          if '__return__' in frame.f_locals:
     570              rv = frame.f_locals['__return__']
     571              s += '->'
     572              s += reprlib.repr(rv)
     573          if lineno is not None:
     574              line = linecache.getline(filename, lineno, frame.f_globals)
     575              if line:
     576                  s += lprefix + line.strip()
     577          else:
     578              s += f'{lprefix}Warning: lineno is None'
     579          return s
     580  
     581      # The following methods can be called by clients to use
     582      # a debugger to debug a statement or an expression.
     583      # Both can be given as a string, or a code object.
     584  
     585      def run(self, cmd, globals=None, locals=None):
     586          """Debug a statement executed via the exec() function.
     587  
     588          globals defaults to __main__.dict; locals defaults to globals.
     589          """
     590          if globals is None:
     591              import __main__
     592              globals = __main__.__dict__
     593          if locals is None:
     594              locals = globals
     595          self.reset()
     596          if isinstance(cmd, str):
     597              cmd = compile(cmd, "<string>", "exec")
     598          sys.settrace(self.trace_dispatch)
     599          try:
     600              exec(cmd, globals, locals)
     601          except BdbQuit:
     602              pass
     603          finally:
     604              self.quitting = True
     605              sys.settrace(None)
     606  
     607      def runeval(self, expr, globals=None, locals=None):
     608          """Debug an expression executed via the eval() function.
     609  
     610          globals defaults to __main__.dict; locals defaults to globals.
     611          """
     612          if globals is None:
     613              import __main__
     614              globals = __main__.__dict__
     615          if locals is None:
     616              locals = globals
     617          self.reset()
     618          sys.settrace(self.trace_dispatch)
     619          try:
     620              return eval(expr, globals, locals)
     621          except BdbQuit:
     622              pass
     623          finally:
     624              self.quitting = True
     625              sys.settrace(None)
     626  
     627      def runctx(self, cmd, globals, locals):
     628          """For backwards-compatibility.  Defers to run()."""
     629          # B/W compatibility
     630          self.run(cmd, globals, locals)
     631  
     632      # This method is more useful to debug a single function call.
     633  
     634      def runcall(self, func, /, *args, **kwds):
     635          """Debug a single function call.
     636  
     637          Return the result of the function call.
     638          """
     639          self.reset()
     640          sys.settrace(self.trace_dispatch)
     641          res = None
     642          try:
     643              res = func(*args, **kwds)
     644          except BdbQuit:
     645              pass
     646          finally:
     647              self.quitting = True
     648              sys.settrace(None)
     649          return res
     650  
     651  
     652  def set_trace():
     653      """Start debugging with a Bdb instance from the caller's frame."""
     654      Bdb().set_trace()
     655  
     656  
     657  class ESC[4;38;5;81mBreakpoint:
     658      """Breakpoint class.
     659  
     660      Implements temporary breakpoints, ignore counts, disabling and
     661      (re)-enabling, and conditionals.
     662  
     663      Breakpoints are indexed by number through bpbynumber and by
     664      the (file, line) tuple using bplist.  The former points to a
     665      single instance of class Breakpoint.  The latter points to a
     666      list of such instances since there may be more than one
     667      breakpoint per line.
     668  
     669      When creating a breakpoint, its associated filename should be
     670      in canonical form.  If funcname is defined, a breakpoint hit will be
     671      counted when the first line of that function is executed.  A
     672      conditional breakpoint always counts a hit.
     673      """
     674  
     675      # XXX Keeping state in the class is a mistake -- this means
     676      # you cannot have more than one active Bdb instance.
     677  
     678      next = 1        # Next bp to be assigned
     679      bplist = {}     # indexed by (file, lineno) tuple
     680      bpbynumber = [None] # Each entry is None or an instance of Bpt
     681                  # index 0 is unused, except for marking an
     682                  # effective break .... see effective()
     683  
     684      def __init__(self, file, line, temporary=False, cond=None, funcname=None):
     685          self.funcname = funcname
     686          # Needed if funcname is not None.
     687          self.func_first_executable_line = None
     688          self.file = file    # This better be in canonical form!
     689          self.line = line
     690          self.temporary = temporary
     691          self.cond = cond
     692          self.enabled = True
     693          self.ignore = 0
     694          self.hits = 0
     695          self.number = Breakpoint.next
     696          Breakpoint.next += 1
     697          # Build the two lists
     698          self.bpbynumber.append(self)
     699          if (file, line) in self.bplist:
     700              self.bplist[file, line].append(self)
     701          else:
     702              self.bplist[file, line] = [self]
     703  
     704      @staticmethod
     705      def clearBreakpoints():
     706          Breakpoint.next = 1
     707          Breakpoint.bplist = {}
     708          Breakpoint.bpbynumber = [None]
     709  
     710      def deleteMe(self):
     711          """Delete the breakpoint from the list associated to a file:line.
     712  
     713          If it is the last breakpoint in that position, it also deletes
     714          the entry for the file:line.
     715          """
     716  
     717          index = (self.file, self.line)
     718          self.bpbynumber[self.number] = None   # No longer in list
     719          self.bplist[index].remove(self)
     720          if not self.bplist[index]:
     721              # No more bp for this f:l combo
     722              del self.bplist[index]
     723  
     724      def enable(self):
     725          """Mark the breakpoint as enabled."""
     726          self.enabled = True
     727  
     728      def disable(self):
     729          """Mark the breakpoint as disabled."""
     730          self.enabled = False
     731  
     732      def bpprint(self, out=None):
     733          """Print the output of bpformat().
     734  
     735          The optional out argument directs where the output is sent
     736          and defaults to standard output.
     737          """
     738          if out is None:
     739              out = sys.stdout
     740          print(self.bpformat(), file=out)
     741  
     742      def bpformat(self):
     743          """Return a string with information about the breakpoint.
     744  
     745          The information includes the breakpoint number, temporary
     746          status, file:line position, break condition, number of times to
     747          ignore, and number of times hit.
     748  
     749          """
     750          if self.temporary:
     751              disp = 'del  '
     752          else:
     753              disp = 'keep '
     754          if self.enabled:
     755              disp = disp + 'yes  '
     756          else:
     757              disp = disp + 'no   '
     758          ret = '%-4dbreakpoint   %s at %s:%d' % (self.number, disp,
     759                                                  self.file, self.line)
     760          if self.cond:
     761              ret += '\n\tstop only if %s' % (self.cond,)
     762          if self.ignore:
     763              ret += '\n\tignore next %d hits' % (self.ignore,)
     764          if self.hits:
     765              if self.hits > 1:
     766                  ss = 's'
     767              else:
     768                  ss = ''
     769              ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)
     770          return ret
     771  
     772      def __str__(self):
     773          "Return a condensed description of the breakpoint."
     774          return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)
     775  
     776  # -----------end of Breakpoint class----------
     777  
     778  
     779  def checkfuncname(b, frame):
     780      """Return True if break should happen here.
     781  
     782      Whether a break should happen depends on the way that b (the breakpoint)
     783      was set.  If it was set via line number, check if b.line is the same as
     784      the one in the frame.  If it was set via function name, check if this is
     785      the right function and if it is on the first executable line.
     786      """
     787      if not b.funcname:
     788          # Breakpoint was set via line number.
     789          if b.line != frame.f_lineno:
     790              # Breakpoint was set at a line with a def statement and the function
     791              # defined is called: don't break.
     792              return False
     793          return True
     794  
     795      # Breakpoint set via function name.
     796      if frame.f_code.co_name != b.funcname:
     797          # It's not a function call, but rather execution of def statement.
     798          return False
     799  
     800      # We are in the right frame.
     801      if not b.func_first_executable_line:
     802          # The function is entered for the 1st time.
     803          b.func_first_executable_line = frame.f_lineno
     804  
     805      if b.func_first_executable_line != frame.f_lineno:
     806          # But we are not at the first line number: don't break.
     807          return False
     808      return True
     809  
     810  
     811  def effective(file, line, frame):
     812      """Return (active breakpoint, delete temporary flag) or (None, None) as
     813         breakpoint to act upon.
     814  
     815         The "active breakpoint" is the first entry in bplist[line, file] (which
     816         must exist) that is enabled, for which checkfuncname is True, and that
     817         has neither a False condition nor a positive ignore count.  The flag,
     818         meaning that a temporary breakpoint should be deleted, is False only
     819         when the condiion cannot be evaluated (in which case, ignore count is
     820         ignored).
     821  
     822         If no such entry exists, then (None, None) is returned.
     823      """
     824      possibles = Breakpoint.bplist[file, line]
     825      for b in possibles:
     826          if not b.enabled:
     827              continue
     828          if not checkfuncname(b, frame):
     829              continue
     830          # Count every hit when bp is enabled
     831          b.hits += 1
     832          if not b.cond:
     833              # If unconditional, and ignoring go on to next, else break
     834              if b.ignore > 0:
     835                  b.ignore -= 1
     836                  continue
     837              else:
     838                  # breakpoint and marker that it's ok to delete if temporary
     839                  return (b, True)
     840          else:
     841              # Conditional bp.
     842              # Ignore count applies only to those bpt hits where the
     843              # condition evaluates to true.
     844              try:
     845                  val = eval(b.cond, frame.f_globals, frame.f_locals)
     846                  if val:
     847                      if b.ignore > 0:
     848                          b.ignore -= 1
     849                          # continue
     850                      else:
     851                          return (b, True)
     852                  # else:
     853                  #   continue
     854              except:
     855                  # if eval fails, most conservative thing is to stop on
     856                  # breakpoint regardless of ignore count.  Don't delete
     857                  # temporary, as another hint to user.
     858                  return (b, False)
     859      return (None, None)
     860  
     861  
     862  # -------------------- testing --------------------
     863  
     864  class ESC[4;38;5;81mTdb(ESC[4;38;5;149mBdb):
     865      def user_call(self, frame, args):
     866          name = frame.f_code.co_name
     867          if not name: name = '???'
     868          print('+++ call', name, args)
     869      def user_line(self, frame):
     870          import linecache
     871          name = frame.f_code.co_name
     872          if not name: name = '???'
     873          fn = self.canonic(frame.f_code.co_filename)
     874          line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
     875          print('+++', fn, frame.f_lineno, name, ':', line.strip())
     876      def user_return(self, frame, retval):
     877          print('+++ return', retval)
     878      def user_exception(self, frame, exc_stuff):
     879          print('+++ exception', exc_stuff)
     880          self.set_continue()
     881  
     882  def foo(n):
     883      print('foo(', n, ')')
     884      x = bar(n*10)
     885      print('bar returned', x)
     886  
     887  def bar(a):
     888      print('bar(', a, ')')
     889      return a/2
     890  
     891  def test():
     892      t = Tdb()
     893      t.run('import bdb; bdb.foo(10)')