"""The ucb module contains functions specific to 61A at UC Berkeley.""" import code import functools import inspect import re import signal import sys def main(fn): """Call fn with command line arguments. Used as a decorator. The main decorator marks the function that starts a program. For example, @main def my_run_function(): # function body Use this instead of the typical __name__ == "__main__" predicate. """ if inspect.stack()[1][0].f_locals['__name__'] == '__main__': args = sys.argv[1:] # Discard the script name from command line fn(*args) # Call the main function return fn _PREFIX = '' def trace(fn): """A decorator that prints a function's name, its arguments, and its return values each time the function is called. For example, @trace def compute_something(x, y): # function body """ @functools.wraps(fn) def wrapped(*args, **kwds): global _PREFIX reprs = [repr(e) for e in args] reprs += [repr(k) + '=' + repr(v) for k, v in kwds.items()] log('{0}({1})'.format(fn.__name__, ', '.join(reprs)) + ':') _PREFIX += ' ' try: result = fn(*args, **kwds) _PREFIX = _PREFIX[:-4] except Exception as e: log(fn.__name__ + ' exited via exception') _PREFIX = _PREFIX[:-4] raise # Here, print out the return value. log('{0}({1}) -> {2}'.format(fn.__name__, ', '.join(reprs), result)) return result return wrapped def log(message): """Print an indented message (used with trace).""" if type(message) is not str: message = str(message) print(_PREFIX + re.sub('\n', '\n' + _PREFIX, message)) def log_current_line(): """Print information about the current line of code.""" frame = inspect.stack()[1] log('Current line: File "{f[1]}", line {f[2]}, in {f[3]}'.format(f=frame)) def interact(msg=None): """Start an interactive interpreter session in the current environment. On Unix: -D exits the interactive session and returns to normal execution. In Windows: -Z exists the interactive session and returns to normal execution. """ # use exception trick to pick up the current frame try: raise None except: frame = sys.exc_info()[2].tb_frame.f_back # evaluate commands in current namespace namespace = frame.f_globals.copy() namespace.update(frame.f_locals) # exit on interrupt def handler(signum, frame): print() exit(0) signal.signal(signal.SIGINT, handler) if not msg: _, filename, line, _, _, _ = inspect.stack()[1] msg = 'Interacting at File "{0}", line {1} \n'.format(filename, line) msg += ' Unix: -D continues the program; \n' msg += ' Windows: -Z continues the program; \n' msg += ' exit() or -C exits the program' code.interact(msg, None, namespace)