(self, frame, event, arg)
| 344 | # cdef tuple pydev_smart_step_into_variants |
| 345 | # ELSE |
| 346 | def trace_dispatch(self, frame, event, arg): |
| 347 | # ENDIF |
| 348 | # Note: this is a big function because most of the logic related to hitting a breakpoint and |
| 349 | # stepping is contained in it. Ideally this could be split among multiple functions, but the |
| 350 | # problem in this case is that in pure-python function calls are expensive and even more so |
| 351 | # when tracing is on (because each function call will get an additional tracing call). We |
| 352 | # try to address this by using the info.is_tracing for the fastest possible return, but the |
| 353 | # cost is still high (maybe we could use code-generation in the future and make the code |
| 354 | # generation be better split among what each part does). |
| 355 | |
| 356 | try: |
| 357 | # DEBUG = '_debugger_case_yield_from.py' in frame.f_code.co_filename |
| 358 | py_db, abs_path_canonical_path_and_base, info, thread, frame_skips_cache, frame_cache_key = self._args |
| 359 | # if DEBUG: print('frame trace_dispatch %s %s %s %s %s %s, stop: %s' % (frame.f_lineno, frame.f_code.co_name, frame.f_code.co_filename, event, constant_to_str(info.pydev_step_cmd), arg, info.pydev_step_stop)) |
| 360 | info.is_tracing += 1 |
| 361 | |
| 362 | # TODO: This shouldn't be needed. The fact that frame.f_lineno |
| 363 | # is None seems like a bug in Python 3.11. |
| 364 | # Reported in: https://github.com/python/cpython/issues/94485 |
| 365 | line = frame.f_lineno or 0 # Workaround or case where frame.f_lineno is None |
| 366 | line_cache_key = (frame_cache_key, line) |
| 367 | |
| 368 | if py_db.pydb_disposed: |
| 369 | return None if event == "call" else NO_FTRACE |
| 370 | |
| 371 | plugin_manager = py_db.plugin |
| 372 | has_exception_breakpoints = ( |
| 373 | py_db.break_on_caught_exceptions or py_db.break_on_user_uncaught_exceptions or py_db.has_plugin_exception_breaks |
| 374 | ) |
| 375 | |
| 376 | stop_frame = info.pydev_step_stop |
| 377 | step_cmd = info.pydev_step_cmd |
| 378 | function_breakpoint_on_call_event = None |
| 379 | |
| 380 | if frame.f_code.co_flags & 0xA0: # 0xa0 == CO_GENERATOR = 0x20 | CO_COROUTINE = 0x80 |
| 381 | # Dealing with coroutines and generators: |
| 382 | # When in a coroutine we change the perceived event to the debugger because |
| 383 | # a call, StopIteration exception and return are usually just pausing/unpausing it. |
| 384 | if event == "line": |
| 385 | is_line = True |
| 386 | is_call = False |
| 387 | is_return = False |
| 388 | is_exception_event = False |
| 389 | |
| 390 | elif event == "return": |
| 391 | is_line = False |
| 392 | is_call = False |
| 393 | is_return = True |
| 394 | is_exception_event = False |
| 395 | |
| 396 | returns_cache_key = (frame_cache_key, "returns") |
| 397 | return_lines = frame_skips_cache.get(returns_cache_key) |
| 398 | if return_lines is None: |
| 399 | # Note: we're collecting the return lines by inspecting the bytecode as |
| 400 | # there are multiple returns and multiple stop iterations when awaiting and |
| 401 | # it doesn't give any clear indication when a coroutine or generator is |
| 402 | # finishing or just pausing. |
| 403 | return_lines = set() |
no test coverage detected