Source code for jammy.utils.debug
import contextlib
import functools
import sys
import threading
from jammy.utils.env import jam_getenv
if jam_getenv("pdb", "ipdb").lower() == "ipdb":
import ipdb as pdb
else:
import pudb as pdb
__all__ = ["hook_exception_ipdb", "unhook_exception_ipdb", "exception_hook"]
# pylint: disable=invalid-name, redefined-builtin
def _custom_exception_hook(type, value, tb):
if hasattr(sys, "ps1") or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
# ...then start the debugger in post-mortem mode.
pdb.post_mortem(tb)
[docs]def hook_exception_ipdb():
if not hasattr(_custom_exception_hook, "origin_hook"):
_custom_exception_hook.origin_hook = sys.excepthook
sys.excepthook = _custom_exception_hook
[docs]def unhook_exception_ipdb():
assert hasattr(_custom_exception_hook, "origin_hook")
sys.excepthook = _custom_exception_hook.origin_hook
[docs]@contextlib.contextmanager
def exception_hook(enable=True):
if enable:
hook_exception_ipdb()
yield
unhook_exception_ipdb()
else:
yield
def decorate_exception_hook(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
with exception_hook():
return func(*args, **kwargs)
return wrapped
def _TimeoutEnterIpdbThread(locals_, cv, timeout):
del locals_
with cv:
if not cv.wait(timeout):
pdb.set_trace()
@contextlib.contextmanager
def timeout_ipdb(locals_, timeout=3):
cv = threading.Condition()
thread = threading.Thread(
target=_TimeoutEnterIpdbThread, args=(locals_, cv, timeout)
)
thread.start()
yield
with cv:
cv.notify_all()