This function implements a few ugly things so that we can patch the traceback objects. The function returned allows resetting `tb_next` on any python traceback object. Do not attempt to use this on non cpython interpreters
()
| 296 | |
| 297 | |
| 298 | def _init_ugly_crap(): |
| 299 | """This function implements a few ugly things so that we can patch the |
| 300 | traceback objects. The function returned allows resetting `tb_next` on |
| 301 | any python traceback object. Do not attempt to use this on non cpython |
| 302 | interpreters |
| 303 | """ |
| 304 | import ctypes |
| 305 | from types import TracebackType |
| 306 | |
| 307 | if PY2: |
| 308 | # figure out size of _Py_ssize_t for Python 2: |
| 309 | if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'): |
| 310 | _Py_ssize_t = ctypes.c_int64 |
| 311 | else: |
| 312 | _Py_ssize_t = ctypes.c_int |
| 313 | else: |
| 314 | # platform ssize_t on Python 3 |
| 315 | _Py_ssize_t = ctypes.c_ssize_t |
| 316 | |
| 317 | # regular python |
| 318 | class _PyObject(ctypes.Structure): |
| 319 | pass |
| 320 | _PyObject._fields_ = [ |
| 321 | ('ob_refcnt', _Py_ssize_t), |
| 322 | ('ob_type', ctypes.POINTER(_PyObject)) |
| 323 | ] |
| 324 | |
| 325 | # python with trace |
| 326 | if hasattr(sys, 'getobjects'): |
| 327 | class _PyObject(ctypes.Structure): |
| 328 | pass |
| 329 | _PyObject._fields_ = [ |
| 330 | ('_ob_next', ctypes.POINTER(_PyObject)), |
| 331 | ('_ob_prev', ctypes.POINTER(_PyObject)), |
| 332 | ('ob_refcnt', _Py_ssize_t), |
| 333 | ('ob_type', ctypes.POINTER(_PyObject)) |
| 334 | ] |
| 335 | |
| 336 | class _Traceback(_PyObject): |
| 337 | pass |
| 338 | _Traceback._fields_ = [ |
| 339 | ('tb_next', ctypes.POINTER(_Traceback)), |
| 340 | ('tb_frame', ctypes.POINTER(_PyObject)), |
| 341 | ('tb_lasti', ctypes.c_int), |
| 342 | ('tb_lineno', ctypes.c_int) |
| 343 | ] |
| 344 | |
| 345 | def tb_set_next(tb, next): |
| 346 | """Set the tb_next attribute of a traceback object.""" |
| 347 | if not (isinstance(tb, TracebackType) and |
| 348 | (next is None or isinstance(next, TracebackType))): |
| 349 | raise TypeError('tb_set_next arguments must be traceback objects') |
| 350 | obj = _Traceback.from_address(id(tb)) |
| 351 | if tb.tb_next is not None: |
| 352 | old = _Traceback.from_address(id(tb.tb_next)) |
| 353 | old.ob_refcnt -= 1 |
| 354 | if next is None: |
| 355 | obj.tb_next = ctypes.POINTER(_Traceback)() |
no outgoing calls
no test coverage detected
searching dependent graphs…