import functools
import logging
import os
-import pdb
import sys
-import traceback
# This module is commonly used by others in here and should avoid
# taking any unnecessary dependencies back on them.
default=False,
help='Break into pdb on top level unhandled exceptions.'
)
+args.add_argument(
+ '--show_random_seed',
+ action=ActionNoYes,
+ default=False,
+ help='Should we display (and log.debug) the global random seed?'
+)
+args.add_argument(
+ '--set_random_seed',
+ type=int,
+ nargs=1,
+ default=None,
+ metavar='SEED_INT',
+ help='Override the global random seed with a particular number.'
+)
+
+original_hook = sys.excepthook
-def handle_uncaught_exception(
- exc_type,
- exc_value,
- exc_traceback):
+def handle_uncaught_exception(exc_type, exc_value, exc_tb):
+ global original_hook
+ msg = f'Unhandled top level exception {exc_type}'
+ logger.exception(msg)
+ print(msg, file=sys.stderr)
if issubclass(exc_type, KeyboardInterrupt):
- sys.__excepthook__(exc_type, exc_value, exc_traceback)
+ sys.__excepthook__(exc_type, exc_value, exc_tb)
return
- logger.exception(f'Unhandled top level {exc_type}',
- exc_info=(exc_type, exc_value, exc_traceback))
- traceback.print_exception(exc_type, exc_value, exc_traceback)
- if config.config['debug_unhandled_exceptions']:
- logger.info("Invoking the debugger...")
- pdb.pm()
+ else:
+ if (
+ not sys.stderr.isatty() or
+ not sys.stdin.isatty()
+ ):
+ # stdin or stderr is redirected, just do the normal thing
+ original_hook(exc_type, exc_value, exc_tb)
+ else:
+ # a terminal is attached and stderr is not redirected, debug.
+ if config.config['debug_unhandled_exceptions']:
+ import traceback
+ import pdb
+ traceback.print_exception(exc_type, exc_value, exc_tb)
+ logger.info("Invoking the debugger...")
+ pdb.pm()
+ else:
+ original_hook(exc_type, exc_value, exc_tb)
def initialize(entry_point):
"""Remember to initialize config and logging before running main."""
@functools.wraps(entry_point)
def initialize_wrapper(*args, **kwargs):
- sys.excepthook = handle_uncaught_exception
+ if sys.excepthook == sys.__excepthook__:
+ sys.excepthook = handle_uncaught_exception
if (
'__globals__' in entry_point.__dict__ and
'__file__' in entry_point.__globals__
config.late_logging()
+ # Allow programs that don't bother to override the random seed
+ # to be replayed via the commandline.
+ import random
+ random_seed = config.config['set_random_seed']
+ if random_seed is not None:
+ random_seed = random_seed[0]
+ else:
+ random_seed = int.from_bytes(os.urandom(4), 'little')
+
+ if config.config['show_random_seed']:
+ msg = f'Global random seed is: {random_seed}'
+ print(msg)
+ logger.debug(msg)
+ random.seed(random_seed)
+
logger.debug(f'Starting {entry_point.__name__} (program entry point)')
ret = None