| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  | """ Test the bdb module.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     A test defines a list of tuples that may be seen as paired tuples, each | 
					
						
							|  |  |  |     pair being defined by 'expect_tuple, set_tuple' as follows: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ([event, [lineno[, co_name[, eargs]]]]), (set_type, [sargs]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * 'expect_tuple' describes the expected current state of the Bdb instance. | 
					
						
							|  |  |  |       It may be the empty tuple and no check is done in that case. | 
					
						
							|  |  |  |     * 'set_tuple' defines the set_*() method to be invoked when the Bdb | 
					
						
							|  |  |  |       instance reaches this state. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Example of an 'expect_tuple, set_tuple' pair: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ('line', 2, 'tfunc_main'), ('step', ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Definitions of the members of the 'expect_tuple': | 
					
						
							|  |  |  |         event: | 
					
						
							|  |  |  |             Name of the trace event. The set methods that do not give back | 
					
						
							|  |  |  |             control to the tracer [1] do not trigger a tracer event and in | 
					
						
							|  |  |  |             that case the next 'event' may be 'None' by convention, its value | 
					
						
							|  |  |  |             is not checked. | 
					
						
							|  |  |  |             [1] Methods that trigger a trace event are set_step(), set_next(), | 
					
						
							|  |  |  |             set_return(), set_until() and set_continue(). | 
					
						
							|  |  |  |         lineno: | 
					
						
							|  |  |  |             Line number. Line numbers are relative to the start of the | 
					
						
							|  |  |  |             function when tracing a function in the test_bdb module (i.e. this | 
					
						
							|  |  |  |             module). | 
					
						
							|  |  |  |         co_name: | 
					
						
							|  |  |  |             Name of the function being currently traced. | 
					
						
							|  |  |  |         eargs: | 
					
						
							|  |  |  |             A tuple: | 
					
						
							|  |  |  |             * On an 'exception' event the tuple holds a class object, the | 
					
						
							|  |  |  |               current exception must be an instance of this class. | 
					
						
							|  |  |  |             * On a 'line' event, the tuple holds a dictionary and a list. The | 
					
						
							|  |  |  |               dictionary maps each breakpoint number that has been hit on this | 
					
						
							|  |  |  |               line to its hits count. The list holds the list of breakpoint | 
					
						
							|  |  |  |               number temporaries that are being deleted. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Definitions of the members of the 'set_tuple': | 
					
						
							|  |  |  |         set_type: | 
					
						
							|  |  |  |             The type of the set method to be invoked. This may | 
					
						
							|  |  |  |             be the type of one of the Bdb set methods: 'step', 'next', | 
					
						
							|  |  |  |             'until', 'return', 'continue', 'break', 'quit', or the type of one | 
					
						
							|  |  |  |             of the set methods added by test_bdb.Bdb: 'ignore', 'enable', | 
					
						
							|  |  |  |             'disable', 'clear', 'up', 'down'. | 
					
						
							|  |  |  |         sargs: | 
					
						
							|  |  |  |             The arguments of the set method if any, packed in a tuple. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import bdb as _bdb | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import unittest | 
					
						
							|  |  |  | import textwrap | 
					
						
							|  |  |  | import importlib | 
					
						
							|  |  |  | import linecache | 
					
						
							|  |  |  | from contextlib import contextmanager | 
					
						
							|  |  |  | from itertools import islice, repeat | 
					
						
							|  |  |  | import test.support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BdbException(Exception): pass | 
					
						
							|  |  |  | class BdbError(BdbException): """Error raised by the Bdb instance.""" | 
					
						
							|  |  |  | class BdbSyntaxError(BdbException): """Syntax error in the test case.""" | 
					
						
							|  |  |  | class BdbNotExpectedError(BdbException): """Unexpected result.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # When 'dry_run' is set to true, expect tuples are ignored and the actual | 
					
						
							|  |  |  | # state of the tracer is printed after running each set_*() method of the test | 
					
						
							|  |  |  | # case. The full list of breakpoints and their attributes is also printed | 
					
						
							|  |  |  | # after each 'line' event where a breakpoint has been hit. | 
					
						
							|  |  |  | dry_run = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def reset_Breakpoint(): | 
					
						
							|  |  |  |     _bdb.Breakpoint.next = 1 | 
					
						
							|  |  |  |     _bdb.Breakpoint.bplist = {} | 
					
						
							|  |  |  |     _bdb.Breakpoint.bpbynumber = [None] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def info_breakpoints(): | 
					
						
							|  |  |  |     bp_list = [bp for  bp in _bdb.Breakpoint.bpbynumber if bp] | 
					
						
							|  |  |  |     if not bp_list: | 
					
						
							|  |  |  |         return '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     header_added = False | 
					
						
							|  |  |  |     for bp in bp_list: | 
					
						
							|  |  |  |         if not header_added: | 
					
						
							|  |  |  |             info = 'BpNum Temp Enb Hits Ignore Where\n' | 
					
						
							|  |  |  |             header_added = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         disp = 'yes ' if bp.temporary else 'no  ' | 
					
						
							|  |  |  |         enab = 'yes' if bp.enabled else 'no ' | 
					
						
							|  |  |  |         info += ('%-5d %s %s %-4d %-6d at %s:%d' % | 
					
						
							|  |  |  |                     (bp.number, disp, enab, bp.hits, bp.ignore, | 
					
						
							|  |  |  |                      os.path.basename(bp.file), bp.line)) | 
					
						
							|  |  |  |         if bp.cond: | 
					
						
							|  |  |  |             info += '\n\tstop only if %s' % (bp.cond,) | 
					
						
							|  |  |  |         info += '\n' | 
					
						
							|  |  |  |     return info | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Bdb(_bdb.Bdb): | 
					
						
							|  |  |  |     """Extend Bdb to enhance test coverage.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def trace_dispatch(self, frame, event, arg): | 
					
						
							|  |  |  |         self.currentbp = None | 
					
						
							|  |  |  |         return super().trace_dispatch(frame, event, arg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_break(self, filename, lineno, temporary=False, cond=None, | 
					
						
							|  |  |  |                   funcname=None): | 
					
						
							|  |  |  |         if isinstance(funcname, str): | 
					
						
							|  |  |  |             if filename == __file__: | 
					
						
							|  |  |  |                 globals_ = globals() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 module = importlib.import_module(filename[:-3]) | 
					
						
							|  |  |  |                 globals_ = module.__dict__ | 
					
						
							|  |  |  |             func = eval(funcname, globals_) | 
					
						
							|  |  |  |             code = func.__code__ | 
					
						
							|  |  |  |             filename = code.co_filename | 
					
						
							|  |  |  |             lineno = code.co_firstlineno | 
					
						
							|  |  |  |             funcname = code.co_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = super().set_break(filename, lineno, temporary=temporary, | 
					
						
							|  |  |  |                                  cond=cond, funcname=funcname) | 
					
						
							|  |  |  |         if isinstance(res, str): | 
					
						
							|  |  |  |             raise BdbError(res) | 
					
						
							|  |  |  |         return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_stack(self, f, t): | 
					
						
							|  |  |  |         self.stack, self.index = super().get_stack(f, t) | 
					
						
							|  |  |  |         self.frame = self.stack[self.index][0] | 
					
						
							|  |  |  |         return self.stack, self.index | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_ignore(self, bpnum): | 
					
						
							|  |  |  |         """Increment the ignore count of Breakpoint number 'bpnum'.""" | 
					
						
							|  |  |  |         bp = self.get_bpbynumber(bpnum) | 
					
						
							|  |  |  |         bp.ignore += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_enable(self, bpnum): | 
					
						
							|  |  |  |         bp = self.get_bpbynumber(bpnum) | 
					
						
							|  |  |  |         bp.enabled = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_disable(self, bpnum): | 
					
						
							|  |  |  |         bp = self.get_bpbynumber(bpnum) | 
					
						
							|  |  |  |         bp.enabled = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_clear(self, fname, lineno): | 
					
						
							|  |  |  |         err = self.clear_break(fname, lineno) | 
					
						
							|  |  |  |         if err: | 
					
						
							|  |  |  |             raise BdbError(err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_up(self): | 
					
						
							|  |  |  |         """Move up in the frame stack.""" | 
					
						
							|  |  |  |         if not self.index: | 
					
						
							|  |  |  |             raise BdbError('Oldest frame') | 
					
						
							|  |  |  |         self.index -= 1 | 
					
						
							|  |  |  |         self.frame = self.stack[self.index][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_down(self): | 
					
						
							|  |  |  |         """Move down in the frame stack.""" | 
					
						
							|  |  |  |         if self.index + 1 == len(self.stack): | 
					
						
							|  |  |  |             raise BdbError('Newest frame') | 
					
						
							|  |  |  |         self.index += 1 | 
					
						
							|  |  |  |         self.frame = self.stack[self.index][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Tracer(Bdb): | 
					
						
							|  |  |  |     """A tracer for testing the bdb module.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, expect_set, skip=None, dry_run=False, test_case=None): | 
					
						
							|  |  |  |         super().__init__(skip=skip) | 
					
						
							|  |  |  |         self.expect_set = expect_set | 
					
						
							|  |  |  |         self.dry_run = dry_run | 
					
						
							|  |  |  |         self.header = ('Dry-run results for %s:' % test_case if | 
					
						
							|  |  |  |                        test_case is not None else None) | 
					
						
							|  |  |  |         self.init_test() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def init_test(self): | 
					
						
							|  |  |  |         self.cur_except = None | 
					
						
							|  |  |  |         self.expect_set_no = 0 | 
					
						
							|  |  |  |         self.breakpoint_hits = None | 
					
						
							|  |  |  |         self.expected_list = list(islice(self.expect_set, 0, None, 2)) | 
					
						
							|  |  |  |         self.set_list = list(islice(self.expect_set, 1, None, 2)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def trace_dispatch(self, frame, event, arg): | 
					
						
							|  |  |  |         # On an 'exception' event, call_exc_trace() in Python/ceval.c discards | 
					
						
							|  |  |  |         # a BdbException raised by the Tracer instance, so we raise it on the | 
					
						
							|  |  |  |         # next trace_dispatch() call that occurs unless the set_quit() or | 
					
						
							|  |  |  |         # set_continue() method has been invoked on the 'exception' event. | 
					
						
							|  |  |  |         if self.cur_except is not None: | 
					
						
							|  |  |  |             raise self.cur_except | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if event == 'exception': | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 res = super().trace_dispatch(frame, event, arg) | 
					
						
							|  |  |  |                 return res | 
					
						
							|  |  |  |             except BdbException as e: | 
					
						
							|  |  |  |                 self.cur_except = e | 
					
						
							|  |  |  |                 return self.trace_dispatch | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return super().trace_dispatch(frame, event, arg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def user_call(self, frame, argument_list): | 
					
						
							|  |  |  |         # Adopt the same behavior as pdb and, as a side effect, skip also the | 
					
						
							|  |  |  |         # first 'call' event when the Tracer is started with Tracer.runcall() | 
					
						
							|  |  |  |         # which may be possibly considered as a bug. | 
					
						
							|  |  |  |         if not self.stop_here(frame): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.process_event('call', frame, argument_list) | 
					
						
							|  |  |  |         self.next_set_method() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def user_line(self, frame): | 
					
						
							|  |  |  |         self.process_event('line', frame) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.dry_run and self.breakpoint_hits: | 
					
						
							|  |  |  |             info = info_breakpoints().strip('\n') | 
					
						
							|  |  |  |             # Indent each line. | 
					
						
							|  |  |  |             for line in info.split('\n'): | 
					
						
							|  |  |  |                 print('  ' + line) | 
					
						
							|  |  |  |         self.delete_temporaries() | 
					
						
							|  |  |  |         self.breakpoint_hits = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.next_set_method() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def user_return(self, frame, return_value): | 
					
						
							|  |  |  |         self.process_event('return', frame, return_value) | 
					
						
							|  |  |  |         self.next_set_method() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def user_exception(self, frame, exc_info): | 
					
						
							|  |  |  |         self.exc_info = exc_info | 
					
						
							|  |  |  |         self.process_event('exception', frame) | 
					
						
							|  |  |  |         self.next_set_method() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def do_clear(self, arg): | 
					
						
							|  |  |  |         # The temporary breakpoints are deleted in user_line(). | 
					
						
							|  |  |  |         bp_list = [self.currentbp] | 
					
						
							|  |  |  |         self.breakpoint_hits = (bp_list, bp_list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def delete_temporaries(self): | 
					
						
							|  |  |  |         if self.breakpoint_hits: | 
					
						
							|  |  |  |             for n in self.breakpoint_hits[1]: | 
					
						
							|  |  |  |                 self.clear_bpbynumber(n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pop_next(self): | 
					
						
							|  |  |  |         self.expect_set_no += 1 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.expect = self.expected_list.pop(0) | 
					
						
							|  |  |  |         except IndexError: | 
					
						
							|  |  |  |             raise BdbNotExpectedError( | 
					
						
							|  |  |  |                 'expect_set list exhausted, cannot pop item %d' % | 
					
						
							|  |  |  |                 self.expect_set_no) | 
					
						
							|  |  |  |         self.set_tuple = self.set_list.pop(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_event(self, event, frame, *args): | 
					
						
							|  |  |  |         # Call get_stack() to enable walking the stack with set_up() and | 
					
						
							|  |  |  |         # set_down(). | 
					
						
							|  |  |  |         tb = None | 
					
						
							|  |  |  |         if event == 'exception': | 
					
						
							|  |  |  |             tb = self.exc_info[2] | 
					
						
							|  |  |  |         self.get_stack(frame, tb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # A breakpoint has been hit and it is not a temporary. | 
					
						
							|  |  |  |         if self.currentbp is not None and not self.breakpoint_hits: | 
					
						
							|  |  |  |             bp_list = [self.currentbp] | 
					
						
							|  |  |  |             self.breakpoint_hits = (bp_list, []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Pop next event. | 
					
						
							|  |  |  |         self.event= event | 
					
						
							|  |  |  |         self.pop_next() | 
					
						
							|  |  |  |         if self.dry_run: | 
					
						
							|  |  |  |             self.print_state(self.header) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Validate the expected results. | 
					
						
							|  |  |  |         if self.expect: | 
					
						
							|  |  |  |             self.check_equal(self.expect[0], event, 'Wrong event type') | 
					
						
							|  |  |  |             self.check_lno_name() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if event in ('call', 'return'): | 
					
						
							|  |  |  |             self.check_expect_max_size(3) | 
					
						
							|  |  |  |         elif len(self.expect) > 3: | 
					
						
							|  |  |  |             if event == 'line': | 
					
						
							|  |  |  |                 bps, temporaries = self.expect[3] | 
					
						
							|  |  |  |                 bpnums = sorted(bps.keys()) | 
					
						
							|  |  |  |                 if not self.breakpoint_hits: | 
					
						
							|  |  |  |                     self.raise_not_expected( | 
					
						
							|  |  |  |                         'No breakpoints hit at expect_set item %d' % | 
					
						
							|  |  |  |                         self.expect_set_no) | 
					
						
							|  |  |  |                 self.check_equal(bpnums, self.breakpoint_hits[0], | 
					
						
							|  |  |  |                     'Breakpoint numbers do not match') | 
					
						
							|  |  |  |                 self.check_equal([bps[n] for n in bpnums], | 
					
						
							|  |  |  |                     [self.get_bpbynumber(n).hits for | 
					
						
							|  |  |  |                         n in self.breakpoint_hits[0]], | 
					
						
							|  |  |  |                     'Wrong breakpoint hit count') | 
					
						
							|  |  |  |                 self.check_equal(sorted(temporaries), self.breakpoint_hits[1], | 
					
						
							|  |  |  |                     'Wrong temporary breakpoints') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             elif event == 'exception': | 
					
						
							|  |  |  |                 if not isinstance(self.exc_info[1], self.expect[3]): | 
					
						
							|  |  |  |                     self.raise_not_expected( | 
					
						
							|  |  |  |                         "Wrong exception at expect_set item %d, got '%s'" % | 
					
						
							|  |  |  |                         (self.expect_set_no, self.exc_info)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_equal(self, expected, result, msg): | 
					
						
							|  |  |  |         if expected == result: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.raise_not_expected("%s at expect_set item %d, got '%s'" % | 
					
						
							|  |  |  |                                 (msg, self.expect_set_no, result)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_lno_name(self): | 
					
						
							|  |  |  |         """Check the line number and function co_name.""" | 
					
						
							|  |  |  |         s = len(self.expect) | 
					
						
							|  |  |  |         if s > 1: | 
					
						
							|  |  |  |             lineno = self.lno_abs2rel() | 
					
						
							|  |  |  |             self.check_equal(self.expect[1], lineno, 'Wrong line number') | 
					
						
							|  |  |  |         if s > 2: | 
					
						
							|  |  |  |             self.check_equal(self.expect[2], self.frame.f_code.co_name, | 
					
						
							|  |  |  |                                                 'Wrong function name') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_expect_max_size(self, size): | 
					
						
							|  |  |  |         if len(self.expect) > size: | 
					
						
							|  |  |  |             raise BdbSyntaxError('Invalid size of the %s expect tuple: %s' % | 
					
						
							|  |  |  |                                  (self.event, self.expect)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def lno_abs2rel(self): | 
					
						
							|  |  |  |         fname = self.canonic(self.frame.f_code.co_filename) | 
					
						
							|  |  |  |         lineno = self.frame.f_lineno | 
					
						
							|  |  |  |         return ((lineno - self.frame.f_code.co_firstlineno + 1) | 
					
						
							|  |  |  |             if fname == self.canonic(__file__) else lineno) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def lno_rel2abs(self, fname, lineno): | 
					
						
							|  |  |  |         return (self.frame.f_code.co_firstlineno + lineno - 1 | 
					
						
							|  |  |  |             if (lineno and self.canonic(fname) == self.canonic(__file__)) | 
					
						
							|  |  |  |             else lineno) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_state(self): | 
					
						
							|  |  |  |         lineno = self.lno_abs2rel() | 
					
						
							|  |  |  |         co_name = self.frame.f_code.co_name | 
					
						
							|  |  |  |         state = "('%s', %d, '%s'" % (self.event, lineno, co_name) | 
					
						
							|  |  |  |         if self.breakpoint_hits: | 
					
						
							|  |  |  |             bps = '{' | 
					
						
							|  |  |  |             for n in self.breakpoint_hits[0]: | 
					
						
							|  |  |  |                 if bps != '{': | 
					
						
							|  |  |  |                     bps += ', ' | 
					
						
							|  |  |  |                 bps += '%s: %s' % (n, self.get_bpbynumber(n).hits) | 
					
						
							|  |  |  |             bps += '}' | 
					
						
							|  |  |  |             bps = '(' + bps + ', ' + str(self.breakpoint_hits[1]) + ')' | 
					
						
							|  |  |  |             state += ', ' + bps | 
					
						
							|  |  |  |         elif self.event == 'exception': | 
					
						
							|  |  |  |             state += ', ' + self.exc_info[0].__name__ | 
					
						
							|  |  |  |         state += '), ' | 
					
						
							|  |  |  |         return state.ljust(32) + str(self.set_tuple) + ',' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def print_state(self, header=None): | 
					
						
							|  |  |  |         if header is not None and self.expect_set_no == 1: | 
					
						
							|  |  |  |             print() | 
					
						
							|  |  |  |             print(header) | 
					
						
							|  |  |  |         print('%d: %s' % (self.expect_set_no, self.get_state())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def raise_not_expected(self, msg): | 
					
						
							|  |  |  |         msg += '\n' | 
					
						
							|  |  |  |         msg += '  Expected: %s\n' % str(self.expect) | 
					
						
							|  |  |  |         msg += '  Got:      ' + self.get_state() | 
					
						
							|  |  |  |         raise BdbNotExpectedError(msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def next_set_method(self): | 
					
						
							|  |  |  |         set_type = self.set_tuple[0] | 
					
						
							|  |  |  |         args = self.set_tuple[1] if len(self.set_tuple) == 2 else None | 
					
						
							|  |  |  |         set_method = getattr(self, 'set_' + set_type) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # The following set methods give back control to the tracer. | 
					
						
							|  |  |  |         if set_type in ('step', 'continue', 'quit'): | 
					
						
							|  |  |  |             set_method() | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         elif set_type in ('next', 'return'): | 
					
						
							|  |  |  |             set_method(self.frame) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         elif set_type == 'until': | 
					
						
							|  |  |  |             lineno = None | 
					
						
							|  |  |  |             if args: | 
					
						
							|  |  |  |                 lineno = self.lno_rel2abs(self.frame.f_code.co_filename, | 
					
						
							|  |  |  |                                           args[0]) | 
					
						
							|  |  |  |             set_method(self.frame, lineno) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # The following set methods do not give back control to the tracer and | 
					
						
							|  |  |  |         # next_set_method() is called recursively. | 
					
						
							|  |  |  |         if (args and set_type in ('break', 'clear', 'ignore', 'enable', | 
					
						
							|  |  |  |                                     'disable')) or set_type in ('up', 'down'): | 
					
						
							|  |  |  |             if set_type in ('break', 'clear'): | 
					
						
							|  |  |  |                 fname, lineno, *remain = args | 
					
						
							|  |  |  |                 lineno = self.lno_rel2abs(fname, lineno) | 
					
						
							|  |  |  |                 args = [fname, lineno] | 
					
						
							|  |  |  |                 args.extend(remain) | 
					
						
							|  |  |  |                 set_method(*args) | 
					
						
							|  |  |  |             elif set_type in ('ignore', 'enable', 'disable'): | 
					
						
							|  |  |  |                 set_method(*args) | 
					
						
							|  |  |  |             elif set_type in ('up', 'down'): | 
					
						
							|  |  |  |                 set_method() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Process the next expect_set item. | 
					
						
							|  |  |  |             # It is not expected that a test may reach the recursion limit. | 
					
						
							|  |  |  |             self.event= None | 
					
						
							|  |  |  |             self.pop_next() | 
					
						
							|  |  |  |             if self.dry_run: | 
					
						
							|  |  |  |                 self.print_state() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if self.expect: | 
					
						
							|  |  |  |                     self.check_lno_name() | 
					
						
							|  |  |  |                 self.check_expect_max_size(3) | 
					
						
							|  |  |  |             self.next_set_method() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise BdbSyntaxError('"%s" is an invalid set_tuple' % | 
					
						
							|  |  |  |                                  self.set_tuple) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TracerRun(): | 
					
						
							|  |  |  |     """Provide a context for running a Tracer instance with a test case.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, test_case, skip=None): | 
					
						
							|  |  |  |         self.test_case = test_case | 
					
						
							|  |  |  |         self.dry_run = test_case.dry_run | 
					
						
							|  |  |  |         self.tracer = Tracer(test_case.expect_set, skip=skip, | 
					
						
							|  |  |  |                              dry_run=self.dry_run, test_case=test_case.id()) | 
					
						
							| 
									
										
										
										
											2018-05-16 17:50:29 -04:00
										 |  |  |         self._original_tracer = None | 
					
						
							| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         # test_pdb does not reset Breakpoint class attributes on exit :-( | 
					
						
							|  |  |  |         reset_Breakpoint() | 
					
						
							| 
									
										
										
										
											2018-05-16 17:50:29 -04:00
										 |  |  |         self._original_tracer = sys.gettrace() | 
					
						
							| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  |         return self.tracer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, type_=None, value=None, traceback=None): | 
					
						
							|  |  |  |         reset_Breakpoint() | 
					
						
							| 
									
										
										
										
											2018-05-16 17:50:29 -04:00
										 |  |  |         sys.settrace(self._original_tracer) | 
					
						
							| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         not_empty = '' | 
					
						
							|  |  |  |         if self.tracer.set_list: | 
					
						
							|  |  |  |             not_empty += 'All paired tuples have not been processed, ' | 
					
						
							|  |  |  |             not_empty += ('the last one was number %d' % | 
					
						
							|  |  |  |                           self.tracer.expect_set_no) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Make a BdbNotExpectedError a unittest failure. | 
					
						
							|  |  |  |         if type_ is not None and issubclass(BdbNotExpectedError, type_): | 
					
						
							|  |  |  |             if isinstance(value, BaseException) and value.args: | 
					
						
							|  |  |  |                 err_msg = value.args[0] | 
					
						
							|  |  |  |                 if not_empty: | 
					
						
							|  |  |  |                     err_msg += '\n' + not_empty | 
					
						
							|  |  |  |                 if self.dry_run: | 
					
						
							|  |  |  |                     print(err_msg) | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     self.test_case.fail(err_msg) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 assert False, 'BdbNotExpectedError with empty args' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not_empty: | 
					
						
							|  |  |  |             if self.dry_run: | 
					
						
							|  |  |  |                 print(not_empty) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.test_case.fail(not_empty) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def run_test(modules, set_list, skip=None): | 
					
						
							|  |  |  |     """Run a test and print the dry-run results.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     'modules':  A dictionary mapping module names to their source code as a | 
					
						
							|  |  |  |                 string. The dictionary MUST include one module named | 
					
						
							|  |  |  |                 'test_module' with a main() function. | 
					
						
							|  |  |  |     'set_list': A list of set_type tuples to be run on the module. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     For example, running the following script outputs the following results: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *****************************   SCRIPT   ******************************** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     from test.test_bdb import run_test, break_in_func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     code = '''
 | 
					
						
							|  |  |  |         def func(): | 
					
						
							|  |  |  |             lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def main(): | 
					
						
							|  |  |  |             func() | 
					
						
							|  |  |  |             lno = 7 | 
					
						
							|  |  |  |     '''
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     set_list = [ | 
					
						
							|  |  |  |                 break_in_func('func', 'test_module.py'), | 
					
						
							|  |  |  |                 ('continue', ), | 
					
						
							|  |  |  |                 ('step', ), | 
					
						
							|  |  |  |                 ('step', ), | 
					
						
							|  |  |  |                 ('step', ), | 
					
						
							|  |  |  |                 ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     modules = { 'test_module': code } | 
					
						
							|  |  |  |     run_test(modules, set_list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ****************************   results   ******************************** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     1: ('line', 2, 'tfunc_import'),    ('next',), | 
					
						
							|  |  |  |     2: ('line', 3, 'tfunc_import'),    ('step',), | 
					
						
							|  |  |  |     3: ('call', 5, 'main'),            ('break', ('test_module.py', None, False, None, 'func')), | 
					
						
							|  |  |  |     4: ('None', 5, 'main'),            ('continue',), | 
					
						
							|  |  |  |     5: ('line', 3, 'func', ({1: 1}, [])), ('step',), | 
					
						
							|  |  |  |       BpNum Temp Enb Hits Ignore Where | 
					
						
							|  |  |  |       1     no   yes 1    0      at test_module.py:2 | 
					
						
							|  |  |  |     6: ('return', 3, 'func'),          ('step',), | 
					
						
							|  |  |  |     7: ('line', 7, 'main'),            ('step',), | 
					
						
							|  |  |  |     8: ('return', 7, 'main'),          ('quit',), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ************************************************************************* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def gen(a, b): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             while 1: | 
					
						
							|  |  |  |                 x = next(a) | 
					
						
							|  |  |  |                 y = next(b) | 
					
						
							|  |  |  |                 yield x | 
					
						
							|  |  |  |                 yield y | 
					
						
							|  |  |  |         except StopIteration: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Step over the import statement in tfunc_import using 'next' and step | 
					
						
							|  |  |  |     # into main() in test_module. | 
					
						
							|  |  |  |     sl = [('next', ), ('step', )] | 
					
						
							|  |  |  |     sl.extend(set_list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     test = BaseTestCase() | 
					
						
							|  |  |  |     test.dry_run = True | 
					
						
							|  |  |  |     test.id = lambda : None | 
					
						
							|  |  |  |     test.expect_set = list(gen(repeat(()), iter(sl))) | 
					
						
							|  |  |  |     with create_modules(modules): | 
					
						
							|  |  |  |         with TracerRun(test, skip=skip) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @contextmanager | 
					
						
							|  |  |  | def create_modules(modules): | 
					
						
							|  |  |  |     with test.support.temp_cwd(): | 
					
						
							| 
									
										
										
										
											2018-03-25 23:03:10 +10:00
										 |  |  |         sys.path.append(os.getcwd()) | 
					
						
							| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             for m in modules: | 
					
						
							|  |  |  |                 fname = m + '.py' | 
					
						
							|  |  |  |                 with open(fname, 'w') as f: | 
					
						
							|  |  |  |                     f.write(textwrap.dedent(modules[m])) | 
					
						
							|  |  |  |                 linecache.checkcache(fname) | 
					
						
							|  |  |  |             importlib.invalidate_caches() | 
					
						
							|  |  |  |             yield | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             for m in modules: | 
					
						
							|  |  |  |                 test.support.forget(m) | 
					
						
							| 
									
										
										
										
											2018-03-25 23:03:10 +10:00
										 |  |  |             sys.path.pop() | 
					
						
							| 
									
										
										
										
											2018-03-18 21:02:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | def break_in_func(funcname, fname=__file__, temporary=False, cond=None): | 
					
						
							|  |  |  |     return 'break', (fname, None, temporary, cond, funcname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_MODULE = 'test_module' | 
					
						
							|  |  |  | TEST_MODULE_FNAME = TEST_MODULE + '.py' | 
					
						
							|  |  |  | def tfunc_import(): | 
					
						
							|  |  |  |     import test_module | 
					
						
							|  |  |  |     test_module.main() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def tfunc_main(): | 
					
						
							|  |  |  |     lno = 2 | 
					
						
							|  |  |  |     tfunc_first() | 
					
						
							|  |  |  |     tfunc_second() | 
					
						
							|  |  |  |     lno = 5 | 
					
						
							|  |  |  |     lno = 6 | 
					
						
							|  |  |  |     lno = 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def tfunc_first(): | 
					
						
							|  |  |  |     lno = 2 | 
					
						
							|  |  |  |     lno = 3 | 
					
						
							|  |  |  |     lno = 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def tfunc_second(): | 
					
						
							|  |  |  |     lno = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BaseTestCase(unittest.TestCase): | 
					
						
							|  |  |  |     """Base class for all tests.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dry_run = dry_run | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fail(self, msg=None): | 
					
						
							|  |  |  |         # Override fail() to use 'raise from None' to avoid repetition of the | 
					
						
							|  |  |  |         # error message and traceback. | 
					
						
							|  |  |  |         raise self.failureException(msg) from None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StateTestCase(BaseTestCase): | 
					
						
							|  |  |  |     """Test the step, next, return, until and quit 'set_' methods.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_step(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('step', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_first'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_step_next_on_last_statement(self): | 
					
						
							|  |  |  |         for set_type in ('step', 'next'): | 
					
						
							|  |  |  |             with self.subTest(set_type=set_type): | 
					
						
							|  |  |  |                 self.expect_set = [ | 
					
						
							|  |  |  |                     ('line', 2, 'tfunc_main'),               ('step', ), | 
					
						
							|  |  |  |                     ('line', 3, 'tfunc_main'),               ('step', ), | 
					
						
							|  |  |  |                     ('call', 1, 'tfunc_first'),              ('break', (__file__, 3)), | 
					
						
							|  |  |  |                     ('None', 1, 'tfunc_first'),              ('continue', ), | 
					
						
							|  |  |  |                     ('line', 3, 'tfunc_first', ({1:1}, [])), (set_type, ), | 
					
						
							|  |  |  |                     ('line', 4, 'tfunc_first'),              ('quit', ), | 
					
						
							|  |  |  |                 ] | 
					
						
							|  |  |  |                 with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                     tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),   ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),   ('next', ), | 
					
						
							|  |  |  |             ('line', 4, 'tfunc_main'),   ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_second'), ('step', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_second'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_over_import(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), ('next', ), | 
					
						
							|  |  |  |                 ('line', 3, 'tfunc_import'), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_on_plain_statement(self): | 
					
						
							|  |  |  |         # Check that set_next() is equivalent to set_step() on a plain | 
					
						
							|  |  |  |         # statement. | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('next', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_first'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_in_caller_frame(self): | 
					
						
							|  |  |  |         # Check that set_next() in the caller frame causes the tracer | 
					
						
							|  |  |  |         # to stop next in the caller frame. | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('up', ), | 
					
						
							|  |  |  |             ('None', 3, 'tfunc_main'),  ('next', ), | 
					
						
							|  |  |  |             ('line', 4, 'tfunc_main'),  ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_return(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),    ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),    ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'),   ('step', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_first'),   ('return', ), | 
					
						
							|  |  |  |             ('return', 4, 'tfunc_first'), ('step', ), | 
					
						
							|  |  |  |             ('line', 4, 'tfunc_main'),    ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_return_in_caller_frame(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),   ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),   ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'),  ('up', ), | 
					
						
							|  |  |  |             ('None', 3, 'tfunc_main'),   ('return', ), | 
					
						
							|  |  |  |             ('return', 7, 'tfunc_main'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_until(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('step', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_first'), ('until', (4, )), | 
					
						
							|  |  |  |             ('line', 4, 'tfunc_first'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_until_with_too_large_count(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),               break_in_func('tfunc_first'), | 
					
						
							|  |  |  |             ('None', 2, 'tfunc_main'),               ('continue', ), | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_first', ({1:1}, [])), ('until', (9999, )), | 
					
						
							|  |  |  |             ('return', 4, 'tfunc_first'),            ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_until_in_caller_frame(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('up', ), | 
					
						
							|  |  |  |             ('None', 3, 'tfunc_main'),  ('until', (6, )), | 
					
						
							|  |  |  |             ('line', 6, 'tfunc_main'),  ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_skip(self): | 
					
						
							|  |  |  |         # Check that tracing is skipped over the import statement in | 
					
						
							|  |  |  |         # 'tfunc_import()'. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), ('step', ), | 
					
						
							|  |  |  |                 ('line', 3, 'tfunc_import'), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             skip = ('importlib*', TEST_MODULE) | 
					
						
							|  |  |  |             with TracerRun(self, skip=skip) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_down(self): | 
					
						
							|  |  |  |         # Check that set_down() raises BdbError at the newest frame. | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'), ('down', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             self.assertRaises(BdbError, tracer.runcall, tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_up(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('line', 3, 'tfunc_main'),  ('step', ), | 
					
						
							|  |  |  |             ('call', 1, 'tfunc_first'), ('up', ), | 
					
						
							|  |  |  |             ('None', 3, 'tfunc_main'),  ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.runcall(tfunc_main) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BreakpointTestCase(BaseTestCase): | 
					
						
							|  |  |  |     """Test the breakpoint set method.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_bp_on_non_existent_module(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_import'), ('break', ('/non/existent/module.py', 1)) | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             self.assertRaises(BdbError, tracer.runcall, tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_bp_after_last_statement(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), ('break', (TEST_MODULE_FNAME, 4)) | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 self.assertRaises(BdbError, tracer.runcall, tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_temporary_bp(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(2): | 
					
						
							|  |  |  |                     func() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME, True), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME, True), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),       ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:1}, [1])), ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({2:1}, [2])), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_disabled_temporary_bp(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(3): | 
					
						
							|  |  |  |                     func() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME, True), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),       ('disable', (2, )), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),       ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:1}, [])),  ('enable', (2, )), | 
					
						
							|  |  |  |                 ('None', 3, 'func'),               ('disable', (1, )), | 
					
						
							|  |  |  |                 ('None', 3, 'func'),               ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({2:1}, [2])), ('enable', (1, )), | 
					
						
							|  |  |  |                 ('None', 3, 'func'),               ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:2}, [])),  ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_bp_condition(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(a): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(3): | 
					
						
							|  |  |  |                     func(i) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME, False, 'a == 2'), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),       ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:3}, [])),  ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_bp_exception_on_condition_evaluation(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(a): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 func(0) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME, False, '1 / 0'), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),       ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:1}, [])),  ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_bp_ignore_count(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(2): | 
					
						
							|  |  |  |                     func() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('ignore', (1, )), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:2}, [])), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_ignore_count_on_disabled_bp(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(3): | 
					
						
							|  |  |  |                     func() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('ignore', (1, )), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('disable', (1, )), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({2:1}, [])), ('enable', (1, )), | 
					
						
							|  |  |  |                 ('None', 3, 'func'),              ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({2:2}, [])), ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:2}, [])), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_clear_two_bp_on_same_line(self): | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |                 lno = 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in range(3): | 
					
						
							|  |  |  |                     func() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 4)), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:1}, [])), ('continue', ), | 
					
						
							|  |  |  |                 ('line', 4, 'func', ({3:1}, [])), ('clear', (TEST_MODULE_FNAME, 3)), | 
					
						
							|  |  |  |                 ('None', 4, 'func'),              ('continue', ), | 
					
						
							|  |  |  |                 ('line', 4, 'func', ({3:2}, [])), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_clear_at_no_bp(self): | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, 'tfunc_import'), ('clear', (__file__, 1)) | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             self.assertRaises(BdbError, tracer.runcall, tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RunTestCase(BaseTestCase): | 
					
						
							|  |  |  |     """Test run, runeval and set_trace.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_run_step(self): | 
					
						
							|  |  |  |         # Check that the bdb 'run' method stops at the first line event. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             lno = 2 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.expect_set = [ | 
					
						
							|  |  |  |             ('line', 2, '<module>'),   ('step', ), | 
					
						
							|  |  |  |             ('return', 2, '<module>'), ('quit', ), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         with TracerRun(self) as tracer: | 
					
						
							|  |  |  |             tracer.run(compile(textwrap.dedent(code), '<string>', 'exec')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_runeval_step(self): | 
					
						
							|  |  |  |         # Test bdb 'runeval'. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 1, '<module>'),   ('step', ), | 
					
						
							|  |  |  |                 ('call', 2, 'main'),       ('step', ), | 
					
						
							|  |  |  |                 ('line', 3, 'main'),       ('step', ), | 
					
						
							|  |  |  |                 ('return', 3, 'main'),     ('step', ), | 
					
						
							|  |  |  |                 ('return', 1, '<module>'), ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             import test_module | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runeval('test_module.main()', globals(), locals()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class IssuesTestCase(BaseTestCase): | 
					
						
							|  |  |  |     """Test fixed bdb issues.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_step_at_return_with_no_trace_in_caller(self): | 
					
						
							|  |  |  |         # Issue #13183. | 
					
						
							|  |  |  |         # Check that the tracer does step into the caller frame when the | 
					
						
							|  |  |  |         # trace function is not set in that frame. | 
					
						
							|  |  |  |         code_1 = """
 | 
					
						
							|  |  |  |             from test_module_2 import func | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 func() | 
					
						
							|  |  |  |                 lno = 5 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         code_2 = """
 | 
					
						
							|  |  |  |             def func(): | 
					
						
							|  |  |  |                 lno = 3 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { | 
					
						
							|  |  |  |             TEST_MODULE: code_1, | 
					
						
							|  |  |  |             'test_module_2': code_2, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('func', 'test_module_2.py'), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),      ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'func', ({1:1}, [])), ('step', ), | 
					
						
							|  |  |  |                 ('return', 3, 'func'),            ('step', ), | 
					
						
							|  |  |  |                 ('line', 5, 'main'),              ('quit', ), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_until_return_in_generator(self): | 
					
						
							|  |  |  |         # Issue #16596. | 
					
						
							|  |  |  |         # Check that set_next(), set_until() and set_return() do not treat the | 
					
						
							|  |  |  |         # `yield` and `yield from` statements as if they were returns and stop | 
					
						
							|  |  |  |         # instead in the current frame. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def test_gen(): | 
					
						
							|  |  |  |                 yield 0 | 
					
						
							|  |  |  |                 lno = 4 | 
					
						
							|  |  |  |                 return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 it = test_gen() | 
					
						
							|  |  |  |                 next(it) | 
					
						
							|  |  |  |                 next(it) | 
					
						
							|  |  |  |                 lno = 11 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         for set_type in ('next', 'until', 'return'): | 
					
						
							|  |  |  |             with self.subTest(set_type=set_type): | 
					
						
							|  |  |  |                 with create_modules(modules): | 
					
						
							|  |  |  |                     self.expect_set = [ | 
					
						
							|  |  |  |                         ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                             break_in_func('test_gen', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                         ('None', 2, 'tfunc_import'),          ('continue', ), | 
					
						
							|  |  |  |                         ('line', 3, 'test_gen', ({1:1}, [])), (set_type, ), | 
					
						
							|  |  |  |                     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if set_type == 'return': | 
					
						
							|  |  |  |                         self.expect_set.extend( | 
					
						
							|  |  |  |                             [('exception', 10, 'main', StopIteration), ('step',), | 
					
						
							|  |  |  |                              ('return', 10, 'main'),                   ('quit', ), | 
					
						
							|  |  |  |                             ] | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         self.expect_set.extend( | 
					
						
							|  |  |  |                             [('line', 4, 'test_gen'), ('quit', ),] | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                     with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                         tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_command_in_generator_for_loop(self): | 
					
						
							|  |  |  |         # Issue #16596. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def test_gen(): | 
					
						
							|  |  |  |                 yield 0 | 
					
						
							|  |  |  |                 lno = 4 | 
					
						
							|  |  |  |                 yield 1 | 
					
						
							|  |  |  |                 return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in test_gen(): | 
					
						
							|  |  |  |                     lno = 10 | 
					
						
							|  |  |  |                 lno = 11 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('test_gen', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),             ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'test_gen', ({1:1}, [])),    ('next', ), | 
					
						
							|  |  |  |                 ('line', 4, 'test_gen'),                 ('next', ), | 
					
						
							|  |  |  |                 ('line', 5, 'test_gen'),                 ('next', ), | 
					
						
							|  |  |  |                 ('line', 6, 'test_gen'),                 ('next', ), | 
					
						
							|  |  |  |                 ('exception', 9, 'main', StopIteration), ('step', ), | 
					
						
							|  |  |  |                 ('line', 11, 'main'),                    ('quit', ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_command_in_generator_with_subiterator(self): | 
					
						
							|  |  |  |         # Issue #16596. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def test_subgen(): | 
					
						
							|  |  |  |                 yield 0 | 
					
						
							|  |  |  |                 return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def test_gen(): | 
					
						
							|  |  |  |                 x = yield from test_subgen() | 
					
						
							|  |  |  |                 return 456 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in test_gen(): | 
					
						
							|  |  |  |                     lno = 12 | 
					
						
							|  |  |  |                 lno = 13 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('test_gen', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),              ('continue', ), | 
					
						
							|  |  |  |                 ('line', 7, 'test_gen', ({1:1}, [])),     ('next', ), | 
					
						
							|  |  |  |                 ('line', 8, 'test_gen'),                  ('next', ), | 
					
						
							|  |  |  |                 ('exception', 11, 'main', StopIteration), ('step', ), | 
					
						
							|  |  |  |                 ('line', 13, 'main'),                     ('quit', ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_return_command_in_generator_with_subiterator(self): | 
					
						
							|  |  |  |         # Issue #16596. | 
					
						
							|  |  |  |         code = """
 | 
					
						
							|  |  |  |             def test_subgen(): | 
					
						
							|  |  |  |                 yield 0 | 
					
						
							|  |  |  |                 return 123 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def test_gen(): | 
					
						
							|  |  |  |                 x = yield from test_subgen() | 
					
						
							|  |  |  |                 return 456 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def main(): | 
					
						
							|  |  |  |                 for i in test_gen(): | 
					
						
							|  |  |  |                     lno = 12 | 
					
						
							|  |  |  |                 lno = 13 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         modules = { TEST_MODULE: code } | 
					
						
							|  |  |  |         with create_modules(modules): | 
					
						
							|  |  |  |             self.expect_set = [ | 
					
						
							|  |  |  |                 ('line', 2, 'tfunc_import'), | 
					
						
							|  |  |  |                     break_in_func('test_subgen', TEST_MODULE_FNAME), | 
					
						
							|  |  |  |                 ('None', 2, 'tfunc_import'),                  ('continue', ), | 
					
						
							|  |  |  |                 ('line', 3, 'test_subgen', ({1:1}, [])),      ('return', ), | 
					
						
							|  |  |  |                 ('exception', 7, 'test_gen', StopIteration),  ('return', ), | 
					
						
							|  |  |  |                 ('exception', 11, 'main', StopIteration),     ('step', ), | 
					
						
							|  |  |  |                 ('line', 13, 'main'),                         ('quit', ), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             with TracerRun(self) as tracer: | 
					
						
							|  |  |  |                 tracer.runcall(tfunc_import) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_main(): | 
					
						
							|  |  |  |     test.support.run_unittest( | 
					
						
							|  |  |  |         StateTestCase, | 
					
						
							|  |  |  |         RunTestCase, | 
					
						
							|  |  |  |         BreakpointTestCase, | 
					
						
							|  |  |  |         IssuesTestCase, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     test_main() |