docs: def printex(ex, msg='[!?] Caught exception', prefix=None, key_list=[],
              locals_=None, iswarning=False, tb=TB, pad_stdout=True, N=0,
              use_stdout=False, reraise=False, msg_=None, keys=None,
              colored=None):
      """
      Prints (and/or logs) an exception with relevant info
  
      Args:
          ex (Exception): exception to print
          msg (str): a message to display to the user
          keys (None): a list of strings denoting variables or expressions of interest
          iswarning (bool): prints as a warning rather than an error if True (defaults to False)
          tb (bool): if True prints the traceback in the error message
          pad_stdout (bool): separate the error message from the rest of stdout with newlines
          prefix (None):
          locals_ (None):
          N (int):
          use_stdout (bool):
          reraise (bool):
          msg_ (None):
          key_list (list): DEPRICATED use keys
  
      Returns:
          None
      """
      import utool as ut
      if isinstance(ex, MemoryError):
          ut.print_resource_usage()
      if keys is not None:
          # shorthand for key_list
          key_list = keys
      # Get error prefix and local info
      if prefix is None:
          prefix = get_caller_prefix(aserror=True, N=N)
      if locals_ is None:
          locals_ = get_parent_frame(N=N).f_locals
      # build exception message
      if msg is True:
          key_list = get_parent_frame().f_locals
          msg = msg_
      exstr = formatex(ex, msg, prefix, key_list, locals_, iswarning, tb=tb, colored=colored)
      # get requested print function
      if use_stdout:
          def print_func(*args):
              msg = ', '.join(list(map(six.text_type, args)))
              sys.stdout.write(msg + '\n')
              sys.stdout.flush()
      else:
          print_func = ut.partial(ut.colorprint, color='yellow' if iswarning else 'red')
          # print_func = print
      if pad_stdout:
          print_func('\n+------\n')
      # print the execption
      print_func(exstr)
      if pad_stdout:
          print_func('\nL______\n')
      # If you dont know where an error is coming from raise-all
      if (reraise and not iswarning) or RAISE_ALL:
          sys.stdout.flush()
          sys.stderr.flush()
          raise ex
      if ut.get_argflag('--exit-on-error'):
          print('WARNING: dont use this flag. Some errors are meant to be caught')
          ut.print_traceback()
          print('REQUESTED EXIT ON ERROR')
          sys.exit(1)