docs: def formatex(ex, msg='[!?] Caught exception',
               prefix=None, key_list=[], locals_=None, iswarning=False, tb=False,
               N=0, keys=None, colored=None):
      r"""
      Formats an exception with relevant info
  
      Args:
          ex (Exception): exception to print
          msg (unicode):  a message to display to the user (default = u'[!?] Caught exception')
          keys (None): a list of strings denoting variables or expressions of interest (default = [])
          iswarning (bool): prints as a warning rather than an error if True (default = False)
          tb (bool): if True prints the traceback in the error message (default = False)
          prefix (None): (default = None)
          locals_ (None): (default = None)
          N (int): (default = 0)
          colored (None): (default = None)
          key_list (list): DEPRICATED use keys
  
      Returns:
          str: formated exception
  
      CommandLine:
          python -m utool.util_dbg --exec-formatex
  
      Example:
          >>> # ENABLE_DOCTET
          >>> from utool.util_dbg import *  # NOQA
          >>> import utool as ut
          >>> msg = 'Testing Exception'
          >>> prefix = '[test]'
          >>> key_list = ['N', 'foo', 'tb']
          >>> locals_ = None
          >>> iswarning = True
          >>> keys = None
          >>> colored = None
          >>> def failfunc():
          >>>     tb = True
          >>>     N = 0
          >>>     try:
          >>>         raise Exception('test exception. This is not an error')
          >>>     except Exception as ex:
          >>>         result = formatex(ex, msg, prefix, key_list, locals_,
          >>>                           iswarning, tb, N, keys, colored)
          >>>         return result
          >>> result = failfunc().replace('\n\n', '')
          >>> print(result)
  
          <!!! WARNING !!!>
          Traceback (most recent call last):
            File "<string>", line 15, in failfunc
          Exception: test exception. This is not an error[test] Testing Exception
          <class 'Exception'>: test exception. This is not an error
          [test] N = 0
          [test] foo = NameError (this likely due to a misformatted printex and is not related to the exception)
          [test] tb = True
          </!!! WARNING !!!>
  
      """
      # 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
      if keys is not None:
          # shorthand for key_list
          key_list = keys
      # build exception message
      errstr_list = []  # list of exception strings
      ex_tag = 'WARNING' if iswarning else 'EXCEPTION'
      errstr_list.append('<!!! %s !!!>' % ex_tag)
      if tb or FORCE_TB:
          tbtext = traceback.format_exc()
          if colored or COLORED_EXCEPTIONS:
              from utool import util_str
              tbtext = util_str.highlight_text(tbtext, lexer_name='pytb', stripall=True)
          errstr_list.append(tbtext)
      errstr_list.append(prefix + ' ' + six.text_type(msg) + '\n%r: %s' % (type(ex), six.text_type(ex)))
      #errstr_list.append(prefix + ' ' + six.text_type(msg) + '\ntype(ex)=%r' % (type(ex),))
      parse_locals_keylist(locals_, key_list, errstr_list, prefix)
      errstr_list.append('</!!! %s !!!>' % ex_tag)
      return '\n'.join(errstr_list)