python (3.12.0)

(root)/
lib/
python3.12/
test/
test_bdb.py
       1  """ Test the bdb module.
       2  
       3      A test defines a list of tuples that may be seen as paired tuples, each
       4      pair being defined by 'expect_tuple, set_tuple' as follows:
       5  
       6          ([event, [lineno[, co_name[, eargs]]]]), (set_type, [sargs])
       7  
       8      * 'expect_tuple' describes the expected current state of the Bdb instance.
       9        It may be the empty tuple and no check is done in that case.
      10      * 'set_tuple' defines the set_*() method to be invoked when the Bdb
      11        instance reaches this state.
      12  
      13      Example of an 'expect_tuple, set_tuple' pair:
      14  
      15          ('line', 2, 'tfunc_main'), ('step', )
      16  
      17      Definitions of the members of the 'expect_tuple':
      18          event:
      19              Name of the trace event. The set methods that do not give back
      20              control to the tracer [1] do not trigger a tracer event and in
      21              that case the next 'event' may be 'None' by convention, its value
      22              is not checked.
      23              [1] Methods that trigger a trace event are set_step(), set_next(),
      24              set_return(), set_until() and set_continue().
      25          lineno:
      26              Line number. Line numbers are relative to the start of the
      27              function when tracing a function in the test_bdb module (i.e. this
      28              module).
      29          co_name:
      30              Name of the function being currently traced.
      31          eargs:
      32              A tuple:
      33              * On an 'exception' event the tuple holds a class object, the
      34                current exception must be an instance of this class.
      35              * On a 'line' event, the tuple holds a dictionary and a list. The
      36                dictionary maps each breakpoint number that has been hit on this
      37                line to its hits count. The list holds the list of breakpoint
      38                number temporaries that are being deleted.
      39  
      40      Definitions of the members of the 'set_tuple':
      41          set_type:
      42              The type of the set method to be invoked. This may
      43              be the type of one of the Bdb set methods: 'step', 'next',
      44              'until', 'return', 'continue', 'break', 'quit', or the type of one
      45              of the set methods added by test_bdb.Bdb: 'ignore', 'enable',
      46              'disable', 'clear', 'up', 'down'.
      47          sargs:
      48              The arguments of the set method if any, packed in a tuple.
      49  """
      50  
      51  import bdb as _bdb
      52  import sys
      53  import os
      54  import unittest
      55  import textwrap
      56  import importlib
      57  import linecache
      58  from contextlib import contextmanager
      59  from itertools import islice, repeat
      60  from test.support import import_helper
      61  from test.support import os_helper
      62  from test.support import patch_list
      63  
      64  
      65  class ESC[4;38;5;81mBdbException(ESC[4;38;5;149mException): pass
      66  class ESC[4;38;5;81mBdbError(ESC[4;38;5;149mBdbException): """Error raised by the Bdb instance."""
      67  class ESC[4;38;5;81mBdbSyntaxError(ESC[4;38;5;149mBdbException): """Syntax error in the test case."""
      68  class ESC[4;38;5;81mBdbNotExpectedError(ESC[4;38;5;149mBdbException): """Unexpected result."""
      69  
      70  # When 'dry_run' is set to true, expect tuples are ignored and the actual
      71  # state of the tracer is printed after running each set_*() method of the test
      72  # case. The full list of breakpoints and their attributes is also printed
      73  # after each 'line' event where a breakpoint has been hit.
      74  dry_run = 0
      75  
      76  def reset_Breakpoint():
      77      _bdb.Breakpoint.clearBreakpoints()
      78  
      79  def info_breakpoints():
      80      bp_list = [bp for  bp in _bdb.Breakpoint.bpbynumber if bp]
      81      if not bp_list:
      82          return ''
      83  
      84      header_added = False
      85      for bp in bp_list:
      86          if not header_added:
      87              info = 'BpNum Temp Enb Hits Ignore Where\n'
      88              header_added = True
      89  
      90          disp = 'yes ' if bp.temporary else 'no  '
      91          enab = 'yes' if bp.enabled else 'no '
      92          info += ('%-5d %s %s %-4d %-6d at %s:%d' %
      93                      (bp.number, disp, enab, bp.hits, bp.ignore,
      94                       os.path.basename(bp.file), bp.line))
      95          if bp.cond:
      96              info += '\n\tstop only if %s' % (bp.cond,)
      97          info += '\n'
      98      return info
      99  
     100  class ESC[4;38;5;81mBdb(ESC[4;38;5;149m_bdbESC[4;38;5;149m.ESC[4;38;5;149mBdb):
     101      """Extend Bdb to enhance test coverage."""
     102  
     103      def trace_dispatch(self, frame, event, arg):
     104          self.currentbp = None
     105          return super().trace_dispatch(frame, event, arg)
     106  
     107      def set_break(self, filename, lineno, temporary=False, cond=None,
     108                    funcname=None):
     109          if isinstance(funcname, str):
     110              if filename == __file__:
     111                  globals_ = globals()
     112              else:
     113                  module = importlib.import_module(filename[:-3])
     114                  globals_ = module.__dict__
     115              func = eval(funcname, globals_)
     116              code = func.__code__
     117              filename = code.co_filename
     118              lineno = code.co_firstlineno
     119              funcname = code.co_name
     120  
     121          res = super().set_break(filename, lineno, temporary=temporary,
     122                                   cond=cond, funcname=funcname)
     123          if isinstance(res, str):
     124              raise BdbError(res)
     125          return res
     126  
     127      def get_stack(self, f, t):
     128          self.stack, self.index = super().get_stack(f, t)
     129          self.frame = self.stack[self.index][0]
     130          return self.stack, self.index
     131  
     132      def set_ignore(self, bpnum):
     133          """Increment the ignore count of Breakpoint number 'bpnum'."""
     134          bp = self.get_bpbynumber(bpnum)
     135          bp.ignore += 1
     136  
     137      def set_enable(self, bpnum):
     138          bp = self.get_bpbynumber(bpnum)
     139          bp.enabled = True
     140  
     141      def set_disable(self, bpnum):
     142          bp = self.get_bpbynumber(bpnum)
     143          bp.enabled = False
     144  
     145      def set_clear(self, fname, lineno):
     146          err = self.clear_break(fname, lineno)
     147          if err:
     148              raise BdbError(err)
     149  
     150      def set_up(self):
     151          """Move up in the frame stack."""
     152          if not self.index:
     153              raise BdbError('Oldest frame')
     154          self.index -= 1
     155          self.frame = self.stack[self.index][0]
     156  
     157      def set_down(self):
     158          """Move down in the frame stack."""
     159          if self.index + 1 == len(self.stack):
     160              raise BdbError('Newest frame')
     161          self.index += 1
     162          self.frame = self.stack[self.index][0]
     163  
     164  class ESC[4;38;5;81mTracer(ESC[4;38;5;149mBdb):
     165      """A tracer for testing the bdb module."""
     166  
     167      def __init__(self, expect_set, skip=None, dry_run=False, test_case=None):
     168          super().__init__(skip=skip)
     169          self.expect_set = expect_set
     170          self.dry_run = dry_run
     171          self.header = ('Dry-run results for %s:' % test_case if
     172                         test_case is not None else None)
     173          self.init_test()
     174  
     175      def init_test(self):
     176          self.cur_except = None
     177          self.expect_set_no = 0
     178          self.breakpoint_hits = None
     179          self.expected_list = list(islice(self.expect_set, 0, None, 2))
     180          self.set_list = list(islice(self.expect_set, 1, None, 2))
     181  
     182      def trace_dispatch(self, frame, event, arg):
     183          # On an 'exception' event, call_exc_trace() in Python/ceval.c discards
     184          # a BdbException raised by the Tracer instance, so we raise it on the
     185          # next trace_dispatch() call that occurs unless the set_quit() or
     186          # set_continue() method has been invoked on the 'exception' event.
     187          if self.cur_except is not None:
     188              raise self.cur_except
     189  
     190          if event == 'exception':
     191              try:
     192                  res = super().trace_dispatch(frame, event, arg)
     193                  return res
     194              except BdbException as e:
     195                  self.cur_except = e
     196                  return self.trace_dispatch
     197          else:
     198              return super().trace_dispatch(frame, event, arg)
     199  
     200      def user_call(self, frame, argument_list):
     201          # Adopt the same behavior as pdb and, as a side effect, skip also the
     202          # first 'call' event when the Tracer is started with Tracer.runcall()
     203          # which may be possibly considered as a bug.
     204          if not self.stop_here(frame):
     205              return
     206          self.process_event('call', frame, argument_list)
     207          self.next_set_method()
     208  
     209      def user_line(self, frame):
     210          self.process_event('line', frame)
     211  
     212          if self.dry_run and self.breakpoint_hits:
     213              info = info_breakpoints().strip('\n')
     214              # Indent each line.
     215              for line in info.split('\n'):
     216                  print('  ' + line)
     217          self.delete_temporaries()
     218          self.breakpoint_hits = None
     219  
     220          self.next_set_method()
     221  
     222      def user_return(self, frame, return_value):
     223          self.process_event('return', frame, return_value)
     224          self.next_set_method()
     225  
     226      def user_exception(self, frame, exc_info):
     227          self.exc_info = exc_info
     228          self.process_event('exception', frame)
     229          self.next_set_method()
     230  
     231      def do_clear(self, arg):
     232          # The temporary breakpoints are deleted in user_line().
     233          bp_list = [self.currentbp]
     234          self.breakpoint_hits = (bp_list, bp_list)
     235  
     236      def delete_temporaries(self):
     237          if self.breakpoint_hits:
     238              for n in self.breakpoint_hits[1]:
     239                  self.clear_bpbynumber(n)
     240  
     241      def pop_next(self):
     242          self.expect_set_no += 1
     243          try:
     244              self.expect = self.expected_list.pop(0)
     245          except IndexError:
     246              raise BdbNotExpectedError(
     247                  'expect_set list exhausted, cannot pop item %d' %
     248                  self.expect_set_no)
     249          self.set_tuple = self.set_list.pop(0)
     250  
     251      def process_event(self, event, frame, *args):
     252          # Call get_stack() to enable walking the stack with set_up() and
     253          # set_down().
     254          tb = None
     255          if event == 'exception':
     256              tb = self.exc_info[2]
     257          self.get_stack(frame, tb)
     258  
     259          # A breakpoint has been hit and it is not a temporary.
     260          if self.currentbp is not None and not self.breakpoint_hits:
     261              bp_list = [self.currentbp]
     262              self.breakpoint_hits = (bp_list, [])
     263  
     264          # Pop next event.
     265          self.event= event
     266          self.pop_next()
     267          if self.dry_run:
     268              self.print_state(self.header)
     269              return
     270  
     271          # Validate the expected results.
     272          if self.expect:
     273              self.check_equal(self.expect[0], event, 'Wrong event type')
     274              self.check_lno_name()
     275  
     276          if event in ('call', 'return'):
     277              self.check_expect_max_size(3)
     278          elif len(self.expect) > 3:
     279              if event == 'line':
     280                  bps, temporaries = self.expect[3]
     281                  bpnums = sorted(bps.keys())
     282                  if not self.breakpoint_hits:
     283                      self.raise_not_expected(
     284                          'No breakpoints hit at expect_set item %d' %
     285                          self.expect_set_no)
     286                  self.check_equal(bpnums, self.breakpoint_hits[0],
     287                      'Breakpoint numbers do not match')
     288                  self.check_equal([bps[n] for n in bpnums],
     289                      [self.get_bpbynumber(n).hits for
     290                          n in self.breakpoint_hits[0]],
     291                      'Wrong breakpoint hit count')
     292                  self.check_equal(sorted(temporaries), self.breakpoint_hits[1],
     293                      'Wrong temporary breakpoints')
     294  
     295              elif event == 'exception':
     296                  if not isinstance(self.exc_info[1], self.expect[3]):
     297                      self.raise_not_expected(
     298                          "Wrong exception at expect_set item %d, got '%s'" %
     299                          (self.expect_set_no, self.exc_info))
     300  
     301      def check_equal(self, expected, result, msg):
     302          if expected == result:
     303              return
     304          self.raise_not_expected("%s at expect_set item %d, got '%s'" %
     305                                  (msg, self.expect_set_no, result))
     306  
     307      def check_lno_name(self):
     308          """Check the line number and function co_name."""
     309          s = len(self.expect)
     310          if s > 1:
     311              lineno = self.lno_abs2rel()
     312              self.check_equal(self.expect[1], lineno, 'Wrong line number')
     313          if s > 2:
     314              self.check_equal(self.expect[2], self.frame.f_code.co_name,
     315                                                  'Wrong function name')
     316  
     317      def check_expect_max_size(self, size):
     318          if len(self.expect) > size:
     319              raise BdbSyntaxError('Invalid size of the %s expect tuple: %s' %
     320                                   (self.event, self.expect))
     321  
     322      def lno_abs2rel(self):
     323          fname = self.canonic(self.frame.f_code.co_filename)
     324          lineno = self.frame.f_lineno
     325          return ((lineno - self.frame.f_code.co_firstlineno + 1)
     326              if fname == self.canonic(__file__) else lineno)
     327  
     328      def lno_rel2abs(self, fname, lineno):
     329          return (self.frame.f_code.co_firstlineno + lineno - 1
     330              if (lineno and self.canonic(fname) == self.canonic(__file__))
     331              else lineno)
     332  
     333      def get_state(self):
     334          lineno = self.lno_abs2rel()
     335          co_name = self.frame.f_code.co_name
     336          state = "('%s', %d, '%s'" % (self.event, lineno, co_name)
     337          if self.breakpoint_hits:
     338              bps = '{'
     339              for n in self.breakpoint_hits[0]:
     340                  if bps != '{':
     341                      bps += ', '
     342                  bps += '%s: %s' % (n, self.get_bpbynumber(n).hits)
     343              bps += '}'
     344              bps = '(' + bps + ', ' + str(self.breakpoint_hits[1]) + ')'
     345              state += ', ' + bps
     346          elif self.event == 'exception':
     347              state += ', ' + self.exc_info[0].__name__
     348          state += '), '
     349          return state.ljust(32) + str(self.set_tuple) + ','
     350  
     351      def print_state(self, header=None):
     352          if header is not None and self.expect_set_no == 1:
     353              print()
     354              print(header)
     355          print('%d: %s' % (self.expect_set_no, self.get_state()))
     356  
     357      def raise_not_expected(self, msg):
     358          msg += '\n'
     359          msg += '  Expected: %s\n' % str(self.expect)
     360          msg += '  Got:      ' + self.get_state()
     361          raise BdbNotExpectedError(msg)
     362  
     363      def next_set_method(self):
     364          set_type = self.set_tuple[0]
     365          args = self.set_tuple[1] if len(self.set_tuple) == 2 else None
     366          set_method = getattr(self, 'set_' + set_type)
     367  
     368          # The following set methods give back control to the tracer.
     369          if set_type in ('step', 'continue', 'quit'):
     370              set_method()
     371              return
     372          elif set_type in ('next', 'return'):
     373              set_method(self.frame)
     374              return
     375          elif set_type == 'until':
     376              lineno = None
     377              if args:
     378                  lineno = self.lno_rel2abs(self.frame.f_code.co_filename,
     379                                            args[0])
     380              set_method(self.frame, lineno)
     381              return
     382  
     383          # The following set methods do not give back control to the tracer and
     384          # next_set_method() is called recursively.
     385          if (args and set_type in ('break', 'clear', 'ignore', 'enable',
     386                                      'disable')) or set_type in ('up', 'down'):
     387              if set_type in ('break', 'clear'):
     388                  fname, lineno, *remain = args
     389                  lineno = self.lno_rel2abs(fname, lineno)
     390                  args = [fname, lineno]
     391                  args.extend(remain)
     392                  set_method(*args)
     393              elif set_type in ('ignore', 'enable', 'disable'):
     394                  set_method(*args)
     395              elif set_type in ('up', 'down'):
     396                  set_method()
     397  
     398              # Process the next expect_set item.
     399              # It is not expected that a test may reach the recursion limit.
     400              self.event= None
     401              self.pop_next()
     402              if self.dry_run:
     403                  self.print_state()
     404              else:
     405                  if self.expect:
     406                      self.check_lno_name()
     407                  self.check_expect_max_size(3)
     408              self.next_set_method()
     409          else:
     410              raise BdbSyntaxError('"%s" is an invalid set_tuple' %
     411                                   self.set_tuple)
     412  
     413  class ESC[4;38;5;81mTracerRun():
     414      """Provide a context for running a Tracer instance with a test case."""
     415  
     416      def __init__(self, test_case, skip=None):
     417          self.test_case = test_case
     418          self.dry_run = test_case.dry_run
     419          self.tracer = Tracer(test_case.expect_set, skip=skip,
     420                               dry_run=self.dry_run, test_case=test_case.id())
     421          self._original_tracer = None
     422  
     423      def __enter__(self):
     424          # test_pdb does not reset Breakpoint class attributes on exit :-(
     425          reset_Breakpoint()
     426          self._original_tracer = sys.gettrace()
     427          return self.tracer
     428  
     429      def __exit__(self, type_=None, value=None, traceback=None):
     430          reset_Breakpoint()
     431          sys.settrace(self._original_tracer)
     432  
     433          not_empty = ''
     434          if self.tracer.set_list:
     435              not_empty += 'All paired tuples have not been processed, '
     436              not_empty += ('the last one was number %d\n' %
     437                            self.tracer.expect_set_no)
     438              not_empty += repr(self.tracer.set_list)
     439  
     440          # Make a BdbNotExpectedError a unittest failure.
     441          if type_ is not None and issubclass(BdbNotExpectedError, type_):
     442              if isinstance(value, BaseException) and value.args:
     443                  err_msg = value.args[0]
     444                  if not_empty:
     445                      err_msg += '\n' + not_empty
     446                  if self.dry_run:
     447                      print(err_msg)
     448                      return True
     449                  else:
     450                      self.test_case.fail(err_msg)
     451              else:
     452                  assert False, 'BdbNotExpectedError with empty args'
     453  
     454          if not_empty:
     455              if self.dry_run:
     456                  print(not_empty)
     457              else:
     458                  self.test_case.fail(not_empty)
     459  
     460  def run_test(modules, set_list, skip=None):
     461      """Run a test and print the dry-run results.
     462  
     463      'modules':  A dictionary mapping module names to their source code as a
     464                  string. The dictionary MUST include one module named
     465                  'test_module' with a main() function.
     466      'set_list': A list of set_type tuples to be run on the module.
     467  
     468      For example, running the following script outputs the following results:
     469  
     470      *****************************   SCRIPT   ********************************
     471  
     472      from test.test_bdb import run_test, break_in_func
     473  
     474      code = '''
     475          def func():
     476              lno = 3
     477  
     478          def main():
     479              func()
     480              lno = 7
     481      '''
     482  
     483      set_list = [
     484                  break_in_func('func', 'test_module.py'),
     485                  ('continue', ),
     486                  ('step', ),
     487                  ('step', ),
     488                  ('step', ),
     489                  ('quit', ),
     490              ]
     491  
     492      modules = { 'test_module': code }
     493      run_test(modules, set_list)
     494  
     495      ****************************   results   ********************************
     496  
     497      1: ('line', 2, 'tfunc_import'),    ('next',),
     498      2: ('line', 3, 'tfunc_import'),    ('step',),
     499      3: ('call', 5, 'main'),            ('break', ('test_module.py', None, False, None, 'func')),
     500      4: ('None', 5, 'main'),            ('continue',),
     501      5: ('line', 3, 'func', ({1: 1}, [])), ('step',),
     502        BpNum Temp Enb Hits Ignore Where
     503        1     no   yes 1    0      at test_module.py:2
     504      6: ('return', 3, 'func'),          ('step',),
     505      7: ('line', 7, 'main'),            ('step',),
     506      8: ('return', 7, 'main'),          ('quit',),
     507  
     508      *************************************************************************
     509  
     510      """
     511      def gen(a, b):
     512          try:
     513              while 1:
     514                  x = next(a)
     515                  y = next(b)
     516                  yield x
     517                  yield y
     518          except StopIteration:
     519              return
     520  
     521      # Step over the import statement in tfunc_import using 'next' and step
     522      # into main() in test_module.
     523      sl = [('next', ), ('step', )]
     524      sl.extend(set_list)
     525  
     526      test = BaseTestCase()
     527      test.dry_run = True
     528      test.id = lambda : None
     529      test.expect_set = list(gen(repeat(()), iter(sl)))
     530      with create_modules(modules):
     531          with TracerRun(test, skip=skip) as tracer:
     532              tracer.runcall(tfunc_import)
     533  
     534  @contextmanager
     535  def create_modules(modules):
     536      with os_helper.temp_cwd():
     537          sys.path.append(os.getcwd())
     538          try:
     539              for m in modules:
     540                  fname = m + '.py'
     541                  with open(fname, 'w', encoding="utf-8") as f:
     542                      f.write(textwrap.dedent(modules[m]))
     543                  linecache.checkcache(fname)
     544              importlib.invalidate_caches()
     545              yield
     546          finally:
     547              for m in modules:
     548                  import_helper.forget(m)
     549              sys.path.pop()
     550  
     551  def break_in_func(funcname, fname=__file__, temporary=False, cond=None):
     552      return 'break', (fname, None, temporary, cond, funcname)
     553  
     554  TEST_MODULE = 'test_module_for_bdb'
     555  TEST_MODULE_FNAME = TEST_MODULE + '.py'
     556  def tfunc_import():
     557      import test_module_for_bdb
     558      test_module_for_bdb.main()
     559  
     560  def tfunc_main():
     561      lno = 2
     562      tfunc_first()
     563      tfunc_second()
     564      lno = 5
     565      lno = 6
     566      lno = 7
     567  
     568  def tfunc_first():
     569      lno = 2
     570      lno = 3
     571      lno = 4
     572  
     573  def tfunc_second():
     574      lno = 2
     575  
     576  class ESC[4;38;5;81mBaseTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     577      """Base class for all tests."""
     578  
     579      dry_run = dry_run
     580  
     581      def fail(self, msg=None):
     582          # Override fail() to use 'raise from None' to avoid repetition of the
     583          # error message and traceback.
     584          raise self.failureException(msg) from None
     585  
     586  class ESC[4;38;5;81mStateTestCase(ESC[4;38;5;149mBaseTestCase):
     587      """Test the step, next, return, until and quit 'set_' methods."""
     588  
     589      def test_step(self):
     590          self.expect_set = [
     591              ('line', 2, 'tfunc_main'),  ('step', ),
     592              ('line', 3, 'tfunc_main'),  ('step', ),
     593              ('call', 1, 'tfunc_first'), ('step', ),
     594              ('line', 2, 'tfunc_first'), ('quit', ),
     595          ]
     596          with TracerRun(self) as tracer:
     597              tracer.runcall(tfunc_main)
     598  
     599      def test_step_next_on_last_statement(self):
     600          for set_type in ('step', 'next'):
     601              with self.subTest(set_type=set_type):
     602                  self.expect_set = [
     603                      ('line', 2, 'tfunc_main'),               ('step', ),
     604                      ('line', 3, 'tfunc_main'),               ('step', ),
     605                      ('call', 1, 'tfunc_first'),              ('break', (__file__, 3)),
     606                      ('None', 1, 'tfunc_first'),              ('continue', ),
     607                      ('line', 3, 'tfunc_first', ({1:1}, [])), (set_type, ),
     608                      ('line', 4, 'tfunc_first'),              ('quit', ),
     609                  ]
     610                  with TracerRun(self) as tracer:
     611                      tracer.runcall(tfunc_main)
     612  
     613      def test_next(self):
     614          self.expect_set = [
     615              ('line', 2, 'tfunc_main'),   ('step', ),
     616              ('line', 3, 'tfunc_main'),   ('next', ),
     617              ('line', 4, 'tfunc_main'),   ('step', ),
     618              ('call', 1, 'tfunc_second'), ('step', ),
     619              ('line', 2, 'tfunc_second'), ('quit', ),
     620          ]
     621          with TracerRun(self) as tracer:
     622              tracer.runcall(tfunc_main)
     623  
     624      def test_next_over_import(self):
     625          code = """
     626              def main():
     627                  lno = 3
     628          """
     629          modules = { TEST_MODULE: code }
     630          with create_modules(modules):
     631              self.expect_set = [
     632                  ('line', 2, 'tfunc_import'), ('next', ),
     633                  ('line', 3, 'tfunc_import'), ('quit', ),
     634              ]
     635              with TracerRun(self) as tracer:
     636                  tracer.runcall(tfunc_import)
     637  
     638      def test_next_on_plain_statement(self):
     639          # Check that set_next() is equivalent to set_step() on a plain
     640          # statement.
     641          self.expect_set = [
     642              ('line', 2, 'tfunc_main'),  ('step', ),
     643              ('line', 3, 'tfunc_main'),  ('step', ),
     644              ('call', 1, 'tfunc_first'), ('next', ),
     645              ('line', 2, 'tfunc_first'), ('quit', ),
     646          ]
     647          with TracerRun(self) as tracer:
     648              tracer.runcall(tfunc_main)
     649  
     650      def test_next_in_caller_frame(self):
     651          # Check that set_next() in the caller frame causes the tracer
     652          # to stop next in the caller frame.
     653          self.expect_set = [
     654              ('line', 2, 'tfunc_main'),  ('step', ),
     655              ('line', 3, 'tfunc_main'),  ('step', ),
     656              ('call', 1, 'tfunc_first'), ('up', ),
     657              ('None', 3, 'tfunc_main'),  ('next', ),
     658              ('line', 4, 'tfunc_main'),  ('quit', ),
     659          ]
     660          with TracerRun(self) as tracer:
     661              tracer.runcall(tfunc_main)
     662  
     663      def test_return(self):
     664          self.expect_set = [
     665              ('line', 2, 'tfunc_main'),    ('step', ),
     666              ('line', 3, 'tfunc_main'),    ('step', ),
     667              ('call', 1, 'tfunc_first'),   ('step', ),
     668              ('line', 2, 'tfunc_first'),   ('return', ),
     669              ('return', 4, 'tfunc_first'), ('step', ),
     670              ('line', 4, 'tfunc_main'),    ('quit', ),
     671          ]
     672          with TracerRun(self) as tracer:
     673              tracer.runcall(tfunc_main)
     674  
     675      def test_return_in_caller_frame(self):
     676          self.expect_set = [
     677              ('line', 2, 'tfunc_main'),   ('step', ),
     678              ('line', 3, 'tfunc_main'),   ('step', ),
     679              ('call', 1, 'tfunc_first'),  ('up', ),
     680              ('None', 3, 'tfunc_main'),   ('return', ),
     681              ('return', 7, 'tfunc_main'), ('quit', ),
     682          ]
     683          with TracerRun(self) as tracer:
     684              tracer.runcall(tfunc_main)
     685  
     686      def test_until(self):
     687          self.expect_set = [
     688              ('line', 2, 'tfunc_main'),  ('step', ),
     689              ('line', 3, 'tfunc_main'),  ('step', ),
     690              ('call', 1, 'tfunc_first'), ('step', ),
     691              ('line', 2, 'tfunc_first'), ('until', (4, )),
     692              ('line', 4, 'tfunc_first'), ('quit', ),
     693          ]
     694          with TracerRun(self) as tracer:
     695              tracer.runcall(tfunc_main)
     696  
     697      def test_until_with_too_large_count(self):
     698          self.expect_set = [
     699              ('line', 2, 'tfunc_main'),               break_in_func('tfunc_first'),
     700              ('None', 2, 'tfunc_main'),               ('continue', ),
     701              ('line', 2, 'tfunc_first', ({1:1}, [])), ('until', (9999, )),
     702              ('return', 4, 'tfunc_first'),            ('quit', ),
     703          ]
     704          with TracerRun(self) as tracer:
     705              tracer.runcall(tfunc_main)
     706  
     707      def test_until_in_caller_frame(self):
     708          self.expect_set = [
     709              ('line', 2, 'tfunc_main'),  ('step', ),
     710              ('line', 3, 'tfunc_main'),  ('step', ),
     711              ('call', 1, 'tfunc_first'), ('up', ),
     712              ('None', 3, 'tfunc_main'),  ('until', (6, )),
     713              ('line', 6, 'tfunc_main'),  ('quit', ),
     714          ]
     715          with TracerRun(self) as tracer:
     716              tracer.runcall(tfunc_main)
     717  
     718      @patch_list(sys.meta_path)
     719      def test_skip(self):
     720          # Check that tracing is skipped over the import statement in
     721          # 'tfunc_import()'.
     722  
     723          # Remove all but the standard importers.
     724          sys.meta_path[:] = (
     725              item
     726              for item in sys.meta_path
     727              if item.__module__.startswith('_frozen_importlib')
     728          )
     729  
     730          code = """
     731              def main():
     732                  lno = 3
     733          """
     734          modules = { TEST_MODULE: code }
     735          with create_modules(modules):
     736              self.expect_set = [
     737                  ('line', 2, 'tfunc_import'), ('step', ),
     738                  ('line', 3, 'tfunc_import'), ('quit', ),
     739              ]
     740              skip = ('importlib*', 'zipimport', 'encodings.*', TEST_MODULE)
     741              with TracerRun(self, skip=skip) as tracer:
     742                  tracer.runcall(tfunc_import)
     743  
     744      def test_skip_with_no_name_module(self):
     745          # some frames have `globals` with no `__name__`
     746          # for instance the second frame in this traceback
     747          # exec(compile('raise ValueError()', '', 'exec'), {})
     748          bdb = Bdb(skip=['anything*'])
     749          self.assertIs(bdb.is_skipped_module(None), False)
     750  
     751      def test_down(self):
     752          # Check that set_down() raises BdbError at the newest frame.
     753          self.expect_set = [
     754              ('line', 2, 'tfunc_main'), ('down', ),
     755          ]
     756          with TracerRun(self) as tracer:
     757              self.assertRaises(BdbError, tracer.runcall, tfunc_main)
     758  
     759      def test_up(self):
     760          self.expect_set = [
     761              ('line', 2, 'tfunc_main'),  ('step', ),
     762              ('line', 3, 'tfunc_main'),  ('step', ),
     763              ('call', 1, 'tfunc_first'), ('up', ),
     764              ('None', 3, 'tfunc_main'),  ('quit', ),
     765          ]
     766          with TracerRun(self) as tracer:
     767              tracer.runcall(tfunc_main)
     768  
     769  class ESC[4;38;5;81mBreakpointTestCase(ESC[4;38;5;149mBaseTestCase):
     770      """Test the breakpoint set method."""
     771  
     772      def test_bp_on_non_existent_module(self):
     773          self.expect_set = [
     774              ('line', 2, 'tfunc_import'), ('break', ('/non/existent/module.py', 1))
     775          ]
     776          with TracerRun(self) as tracer:
     777              self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     778  
     779      def test_bp_after_last_statement(self):
     780          code = """
     781              def main():
     782                  lno = 3
     783          """
     784          modules = { TEST_MODULE: code }
     785          with create_modules(modules):
     786              self.expect_set = [
     787                  ('line', 2, 'tfunc_import'), ('break', (TEST_MODULE_FNAME, 4))
     788              ]
     789              with TracerRun(self) as tracer:
     790                  self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     791  
     792      def test_temporary_bp(self):
     793          code = """
     794              def func():
     795                  lno = 3
     796  
     797              def main():
     798                  for i in range(2):
     799                      func()
     800          """
     801          modules = { TEST_MODULE: code }
     802          with create_modules(modules):
     803              self.expect_set = [
     804                  ('line', 2, 'tfunc_import'),
     805                      break_in_func('func', TEST_MODULE_FNAME, True),
     806                  ('None', 2, 'tfunc_import'),
     807                      break_in_func('func', TEST_MODULE_FNAME, True),
     808                  ('None', 2, 'tfunc_import'),       ('continue', ),
     809                  ('line', 3, 'func', ({1:1}, [1])), ('continue', ),
     810                  ('line', 3, 'func', ({2:1}, [2])), ('quit', ),
     811              ]
     812              with TracerRun(self) as tracer:
     813                  tracer.runcall(tfunc_import)
     814  
     815      def test_disabled_temporary_bp(self):
     816          code = """
     817              def func():
     818                  lno = 3
     819  
     820              def main():
     821                  for i in range(3):
     822                      func()
     823          """
     824          modules = { TEST_MODULE: code }
     825          with create_modules(modules):
     826              self.expect_set = [
     827                  ('line', 2, 'tfunc_import'),
     828                      break_in_func('func', TEST_MODULE_FNAME),
     829                  ('None', 2, 'tfunc_import'),
     830                      break_in_func('func', TEST_MODULE_FNAME, True),
     831                  ('None', 2, 'tfunc_import'),       ('disable', (2, )),
     832                  ('None', 2, 'tfunc_import'),       ('continue', ),
     833                  ('line', 3, 'func', ({1:1}, [])),  ('enable', (2, )),
     834                  ('None', 3, 'func'),               ('disable', (1, )),
     835                  ('None', 3, 'func'),               ('continue', ),
     836                  ('line', 3, 'func', ({2:1}, [2])), ('enable', (1, )),
     837                  ('None', 3, 'func'),               ('continue', ),
     838                  ('line', 3, 'func', ({1:2}, [])),  ('quit', ),
     839              ]
     840              with TracerRun(self) as tracer:
     841                  tracer.runcall(tfunc_import)
     842  
     843      def test_bp_condition(self):
     844          code = """
     845              def func(a):
     846                  lno = 3
     847  
     848              def main():
     849                  for i in range(3):
     850                      func(i)
     851          """
     852          modules = { TEST_MODULE: code }
     853          with create_modules(modules):
     854              self.expect_set = [
     855                  ('line', 2, 'tfunc_import'),
     856                      break_in_func('func', TEST_MODULE_FNAME, False, 'a == 2'),
     857                  ('None', 2, 'tfunc_import'),       ('continue', ),
     858                  ('line', 3, 'func', ({1:3}, [])),  ('quit', ),
     859              ]
     860              with TracerRun(self) as tracer:
     861                  tracer.runcall(tfunc_import)
     862  
     863      def test_bp_exception_on_condition_evaluation(self):
     864          code = """
     865              def func(a):
     866                  lno = 3
     867  
     868              def main():
     869                  func(0)
     870          """
     871          modules = { TEST_MODULE: code }
     872          with create_modules(modules):
     873              self.expect_set = [
     874                  ('line', 2, 'tfunc_import'),
     875                      break_in_func('func', TEST_MODULE_FNAME, False, '1 / 0'),
     876                  ('None', 2, 'tfunc_import'),       ('continue', ),
     877                  ('line', 3, 'func', ({1:1}, [])),  ('quit', ),
     878              ]
     879              with TracerRun(self) as tracer:
     880                  tracer.runcall(tfunc_import)
     881  
     882      def test_bp_ignore_count(self):
     883          code = """
     884              def func():
     885                  lno = 3
     886  
     887              def main():
     888                  for i in range(2):
     889                      func()
     890          """
     891          modules = { TEST_MODULE: code }
     892          with create_modules(modules):
     893              self.expect_set = [
     894                  ('line', 2, 'tfunc_import'),
     895                      break_in_func('func', TEST_MODULE_FNAME),
     896                  ('None', 2, 'tfunc_import'),      ('ignore', (1, )),
     897                  ('None', 2, 'tfunc_import'),      ('continue', ),
     898                  ('line', 3, 'func', ({1:2}, [])), ('quit', ),
     899              ]
     900              with TracerRun(self) as tracer:
     901                  tracer.runcall(tfunc_import)
     902  
     903      def test_ignore_count_on_disabled_bp(self):
     904          code = """
     905              def func():
     906                  lno = 3
     907  
     908              def main():
     909                  for i in range(3):
     910                      func()
     911          """
     912          modules = { TEST_MODULE: code }
     913          with create_modules(modules):
     914              self.expect_set = [
     915                  ('line', 2, 'tfunc_import'),
     916                      break_in_func('func', TEST_MODULE_FNAME),
     917                  ('None', 2, 'tfunc_import'),
     918                      break_in_func('func', TEST_MODULE_FNAME),
     919                  ('None', 2, 'tfunc_import'),      ('ignore', (1, )),
     920                  ('None', 2, 'tfunc_import'),      ('disable', (1, )),
     921                  ('None', 2, 'tfunc_import'),      ('continue', ),
     922                  ('line', 3, 'func', ({2:1}, [])), ('enable', (1, )),
     923                  ('None', 3, 'func'),              ('continue', ),
     924                  ('line', 3, 'func', ({2:2}, [])), ('continue', ),
     925                  ('line', 3, 'func', ({1:2}, [])), ('quit', ),
     926              ]
     927              with TracerRun(self) as tracer:
     928                  tracer.runcall(tfunc_import)
     929  
     930      def test_clear_two_bp_on_same_line(self):
     931          code = """
     932              def func():
     933                  lno = 3
     934                  lno = 4
     935  
     936              def main():
     937                  for i in range(3):
     938                      func()
     939          """
     940          modules = { TEST_MODULE: code }
     941          with create_modules(modules):
     942              self.expect_set = [
     943                  ('line', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)),
     944                  ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)),
     945                  ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 4)),
     946                  ('None', 2, 'tfunc_import'),      ('continue', ),
     947                  ('line', 3, 'func', ({1:1}, [])), ('continue', ),
     948                  ('line', 4, 'func', ({3:1}, [])), ('clear', (TEST_MODULE_FNAME, 3)),
     949                  ('None', 4, 'func'),              ('continue', ),
     950                  ('line', 4, 'func', ({3:2}, [])), ('quit', ),
     951              ]
     952              with TracerRun(self) as tracer:
     953                  tracer.runcall(tfunc_import)
     954  
     955      def test_clear_at_no_bp(self):
     956          self.expect_set = [
     957              ('line', 2, 'tfunc_import'), ('clear', (__file__, 1))
     958          ]
     959          with TracerRun(self) as tracer:
     960              self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     961  
     962      def test_load_bps_from_previous_Bdb_instance(self):
     963          reset_Breakpoint()
     964          db1 = Bdb()
     965          fname = db1.canonic(__file__)
     966          db1.set_break(__file__, 1)
     967          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     968  
     969          db2 = Bdb()
     970          db2.set_break(__file__, 2)
     971          db2.set_break(__file__, 3)
     972          db2.set_break(__file__, 4)
     973          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     974          self.assertEqual(db2.get_all_breaks(), {fname: [1, 2, 3, 4]})
     975          db2.clear_break(__file__, 1)
     976          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     977          self.assertEqual(db2.get_all_breaks(), {fname: [2, 3, 4]})
     978  
     979          db3 = Bdb()
     980          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     981          self.assertEqual(db2.get_all_breaks(), {fname: [2, 3, 4]})
     982          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     983          db2.clear_break(__file__, 2)
     984          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     985          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
     986          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     987  
     988          db4 = Bdb()
     989          db4.set_break(__file__, 5)
     990          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     991          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
     992          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     993          self.assertEqual(db4.get_all_breaks(), {fname: [3, 4, 5]})
     994          reset_Breakpoint()
     995  
     996          db5 = Bdb()
     997          db5.set_break(__file__, 6)
     998          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     999          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
    1000          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
    1001          self.assertEqual(db4.get_all_breaks(), {fname: [3, 4, 5]})
    1002          self.assertEqual(db5.get_all_breaks(), {fname: [6]})
    1003  
    1004  
    1005  class ESC[4;38;5;81mRunTestCase(ESC[4;38;5;149mBaseTestCase):
    1006      """Test run, runeval and set_trace."""
    1007  
    1008      def test_run_step(self):
    1009          # Check that the bdb 'run' method stops at the first line event.
    1010          code = """
    1011              lno = 2
    1012          """
    1013          self.expect_set = [
    1014              ('line', 2, '<module>'),   ('step', ),
    1015              ('return', 2, '<module>'), ('quit', ),
    1016          ]
    1017          with TracerRun(self) as tracer:
    1018              tracer.run(compile(textwrap.dedent(code), '<string>', 'exec'))
    1019  
    1020      def test_runeval_step(self):
    1021          # Test bdb 'runeval'.
    1022          code = """
    1023              def main():
    1024                  lno = 3
    1025          """
    1026          modules = { TEST_MODULE: code }
    1027          with create_modules(modules):
    1028              self.expect_set = [
    1029                  ('line', 1, '<module>'),   ('step', ),
    1030                  ('call', 2, 'main'),       ('step', ),
    1031                  ('line', 3, 'main'),       ('step', ),
    1032                  ('return', 3, 'main'),     ('step', ),
    1033                  ('return', 1, '<module>'), ('quit', ),
    1034              ]
    1035              import test_module_for_bdb
    1036              with TracerRun(self) as tracer:
    1037                  tracer.runeval('test_module_for_bdb.main()', globals(), locals())
    1038  
    1039  class ESC[4;38;5;81mIssuesTestCase(ESC[4;38;5;149mBaseTestCase):
    1040      """Test fixed bdb issues."""
    1041  
    1042      def test_step_at_return_with_no_trace_in_caller(self):
    1043          # Issue #13183.
    1044          # Check that the tracer does step into the caller frame when the
    1045          # trace function is not set in that frame.
    1046          code_1 = """
    1047              from test_module_for_bdb_2 import func
    1048              def main():
    1049                  func()
    1050                  lno = 5
    1051          """
    1052          code_2 = """
    1053              def func():
    1054                  lno = 3
    1055          """
    1056          modules = {
    1057              TEST_MODULE: code_1,
    1058              'test_module_for_bdb_2': code_2,
    1059          }
    1060          with create_modules(modules):
    1061              self.expect_set = [
    1062                  ('line', 2, 'tfunc_import'),
    1063                      break_in_func('func', 'test_module_for_bdb_2.py'),
    1064                  ('None', 2, 'tfunc_import'),      ('continue', ),
    1065                  ('line', 3, 'func', ({1:1}, [])), ('step', ),
    1066                  ('return', 3, 'func'),            ('step', ),
    1067                  ('line', 5, 'main'),              ('quit', ),
    1068              ]
    1069              with TracerRun(self) as tracer:
    1070                  tracer.runcall(tfunc_import)
    1071  
    1072      def test_next_until_return_in_generator(self):
    1073          # Issue #16596.
    1074          # Check that set_next(), set_until() and set_return() do not treat the
    1075          # `yield` and `yield from` statements as if they were returns and stop
    1076          # instead in the current frame.
    1077          code = """
    1078              def test_gen():
    1079                  yield 0
    1080                  lno = 4
    1081                  return 123
    1082  
    1083              def main():
    1084                  it = test_gen()
    1085                  next(it)
    1086                  next(it)
    1087                  lno = 11
    1088          """
    1089          modules = { TEST_MODULE: code }
    1090          for set_type in ('next', 'until', 'return'):
    1091              with self.subTest(set_type=set_type):
    1092                  with create_modules(modules):
    1093                      self.expect_set = [
    1094                          ('line', 2, 'tfunc_import'),
    1095                              break_in_func('test_gen', TEST_MODULE_FNAME),
    1096                          ('None', 2, 'tfunc_import'),          ('continue', ),
    1097                          ('line', 3, 'test_gen', ({1:1}, [])), (set_type, ),
    1098                      ]
    1099  
    1100                      if set_type == 'return':
    1101                          self.expect_set.extend(
    1102                              [('exception', 10, 'main', StopIteration), ('step',),
    1103                               ('return', 10, 'main'),                   ('quit', ),
    1104                              ]
    1105                          )
    1106                      else:
    1107                          self.expect_set.extend(
    1108                              [('line', 4, 'test_gen'), ('quit', ),]
    1109                          )
    1110                      with TracerRun(self) as tracer:
    1111                          tracer.runcall(tfunc_import)
    1112  
    1113      def test_next_command_in_generator_for_loop(self):
    1114          # Issue #16596.
    1115          code = """
    1116              def test_gen():
    1117                  yield 0
    1118                  lno = 4
    1119                  yield 1
    1120                  return 123
    1121  
    1122              def main():
    1123                  for i in test_gen():
    1124                      lno = 10
    1125                  lno = 11
    1126          """
    1127          modules = { TEST_MODULE: code }
    1128          with create_modules(modules):
    1129              self.expect_set = [
    1130                  ('line', 2, 'tfunc_import'),
    1131                      break_in_func('test_gen', TEST_MODULE_FNAME),
    1132                  ('None', 2, 'tfunc_import'),             ('continue', ),
    1133                  ('line', 3, 'test_gen', ({1:1}, [])),    ('next', ),
    1134                  ('line', 4, 'test_gen'),                 ('next', ),
    1135                  ('line', 5, 'test_gen'),                 ('next', ),
    1136                  ('line', 6, 'test_gen'),                 ('next', ),
    1137                  ('exception', 9, 'main', StopIteration), ('step', ),
    1138                  ('line', 11, 'main'),                    ('quit', ),
    1139  
    1140              ]
    1141              with TracerRun(self) as tracer:
    1142                  tracer.runcall(tfunc_import)
    1143  
    1144      def test_next_command_in_generator_with_subiterator(self):
    1145          # Issue #16596.
    1146          code = """
    1147              def test_subgen():
    1148                  yield 0
    1149                  return 123
    1150  
    1151              def test_gen():
    1152                  x = yield from test_subgen()
    1153                  return 456
    1154  
    1155              def main():
    1156                  for i in test_gen():
    1157                      lno = 12
    1158                  lno = 13
    1159          """
    1160          modules = { TEST_MODULE: code }
    1161          with create_modules(modules):
    1162              self.expect_set = [
    1163                  ('line', 2, 'tfunc_import'),
    1164                      break_in_func('test_gen', TEST_MODULE_FNAME),
    1165                  ('None', 2, 'tfunc_import'),              ('continue', ),
    1166                  ('line', 7, 'test_gen', ({1:1}, [])),     ('next', ),
    1167                  ('line', 8, 'test_gen'),                  ('next', ),
    1168                  ('exception', 11, 'main', StopIteration), ('step', ),
    1169                  ('line', 13, 'main'),                     ('quit', ),
    1170  
    1171              ]
    1172              with TracerRun(self) as tracer:
    1173                  tracer.runcall(tfunc_import)
    1174  
    1175      def test_return_command_in_generator_with_subiterator(self):
    1176          # Issue #16596.
    1177          code = """
    1178              def test_subgen():
    1179                  yield 0
    1180                  return 123
    1181  
    1182              def test_gen():
    1183                  x = yield from test_subgen()
    1184                  return 456
    1185  
    1186              def main():
    1187                  for i in test_gen():
    1188                      lno = 12
    1189                  lno = 13
    1190          """
    1191          modules = { TEST_MODULE: code }
    1192          with create_modules(modules):
    1193              self.expect_set = [
    1194                  ('line', 2, 'tfunc_import'),
    1195                      break_in_func('test_subgen', TEST_MODULE_FNAME),
    1196                  ('None', 2, 'tfunc_import'),                  ('continue', ),
    1197                  ('line', 3, 'test_subgen', ({1:1}, [])),      ('return', ),
    1198                  ('exception', 7, 'test_gen', StopIteration),  ('return', ),
    1199                  ('exception', 11, 'main', StopIteration),     ('step', ),
    1200                  ('line', 13, 'main'),                         ('quit', ),
    1201  
    1202              ]
    1203              with TracerRun(self) as tracer:
    1204                  tracer.runcall(tfunc_import)
    1205  
    1206  
    1207  class ESC[4;38;5;81mTestRegressions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1208      def test_format_stack_entry_no_lineno(self):
    1209          # See gh-101517
    1210          self.assertIn('Warning: lineno is None',
    1211                        Bdb().format_stack_entry((sys._getframe(), None)))
    1212  
    1213  
    1214  if __name__ == "__main__":
    1215      unittest.main()