A tracer for testing the bdb module.
| 162 | self.frame = self.stack[self.index][0] |
| 163 | |
| 164 | class Tracer(Bdb): |
| 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 |