If an error is thrown in the scope of this function's stack frame then the
    decorated function name and the arguments passed to it will be printed to
    the utool print function.

def on_exception_report_input(func_=None, force=False, keys=None):
    """
    If an error is thrown in the scope of this function's stack frame then the
    decorated function name and the arguments passed to it will be printed to
    the utool print function.
    """
    def _closure_onexceptreport(func):
        if not ONEX_REPORT_INPUT and not force:
            return func
        @ignores_exc_tb(outer_wrapper=False)
        #@wraps(func)
        def wrp_onexceptreport(*args, **kwargs):
            try:
                #import utool
                #if utool.DEBUG:
                #    print('[IN EXCPRPT] args=%r' % (args,))
                #    print('[IN EXCPRPT] kwargs=%r' % (kwargs,))
                return func(*args, **kwargs)
            except Exception as ex:
                from utool import util_str
                print('ERROR occured! Reporting input to function')
                if keys is not None:
                    from utool import util_inspect
                    from utool import util_list
                    from utool import util_dict
                    argspec = util_inspect.get_func_argspec(func)
                    in_kwargs_flags = [key in kwargs for key in keys]
                    kwarg_keys = util_list.compress(keys, in_kwargs_flags)
                    kwarg_vals = [kwargs.get(key) for key in kwarg_keys]
                    flags = util_list.not_list(in_kwargs_flags)
                    arg_keys = util_list.compress(keys, flags)
                    arg_idxs = [argspec.args.index(key) for key in arg_keys]
                    num_nodefault = len(argspec.args) - len(argspec.defaults)
                    default_vals = (([None] * (num_nodefault)) +
                                    list(argspec.defaults))
                    args_ = list(args) + default_vals[len(args) + 1:]
                    arg_vals = util_list.take(args_, arg_idxs)
                    requested_dict = dict(util_list.flatten(
                        [zip(kwarg_keys, kwarg_vals), zip(arg_keys, arg_vals)]))
                    print('input dict = ' + util_str.repr4(
                        util_dict.dict_subset(requested_dict, keys)))
                    # (print out specific keys only)
                    pass
                arg_strs = ', '.join([repr(util_str.truncate_str(str(arg)))
                                      for arg in args])
                kwarg_strs = ', '.join([
                    util_str.truncate_str('%s=%r' % (key, val))
                    for key, val in six.iteritems(kwargs)])
                msg = ('\nERROR: funcname=%r,\n * args=%s,\n * kwargs=%r\n' % (
                    meta_util_six.get_funcname(func), arg_strs, kwarg_strs))
                msg += ' * len(args) = %r\n' % len(args)
                msg += ' * len(kwargs) = %r\n' % len(kwargs)
                util_dbg.printex(ex, msg, pad_stdout=True)
                raise
        wrp_onexceptreport = preserve_sig(wrp_onexceptreport, func)
        return wrp_onexceptreport
    if func_ is None:
        return _closure_onexceptreport
    else:
        return _closure_onexceptreport(func_)