| 1322 | |
| 1323 | |
| 1324 | def _make_invoke_excepthook(): |
| 1325 | # Create a local namespace to ensure that variables remain alive |
| 1326 | # when _invoke_excepthook() is called, even if it is called late during |
| 1327 | # Python shutdown. It is mostly needed for daemon threads. |
| 1328 | |
| 1329 | old_excepthook = excepthook |
| 1330 | old_sys_excepthook = _sys.excepthook |
| 1331 | if old_excepthook is None: |
| 1332 | raise RuntimeError("threading.excepthook is None") |
| 1333 | if old_sys_excepthook is None: |
| 1334 | raise RuntimeError("sys.excepthook is None") |
| 1335 | |
| 1336 | sys_exc_info = _sys.exc_info |
| 1337 | local_print = print |
| 1338 | local_sys = _sys |
| 1339 | |
| 1340 | def invoke_excepthook(thread): |
| 1341 | global excepthook |
| 1342 | try: |
| 1343 | hook = excepthook |
| 1344 | if hook is None: |
| 1345 | hook = old_excepthook |
| 1346 | |
| 1347 | args = ExceptHookArgs([*sys_exc_info(), thread]) |
| 1348 | |
| 1349 | hook(args) |
| 1350 | except Exception as exc: |
| 1351 | exc.__suppress_context__ = True |
| 1352 | del exc |
| 1353 | |
| 1354 | if local_sys is not None and local_sys.stderr is not None: |
| 1355 | stderr = local_sys.stderr |
| 1356 | else: |
| 1357 | stderr = thread._stderr |
| 1358 | |
| 1359 | local_print("Exception in threading.excepthook:", |
| 1360 | file=stderr, flush=True) |
| 1361 | |
| 1362 | if local_sys is not None and local_sys.excepthook is not None: |
| 1363 | sys_excepthook = local_sys.excepthook |
| 1364 | else: |
| 1365 | sys_excepthook = old_sys_excepthook |
| 1366 | |
| 1367 | sys_excepthook(*sys_exc_info()) |
| 1368 | finally: |
| 1369 | # Break reference cycle (exception stored in a variable) |
| 1370 | args = None |
| 1371 | |
| 1372 | return invoke_excepthook |
| 1373 | |
| 1374 | |
| 1375 | # The timer class was contributed by Itamar Shtull-Trauring |