docs: def preserve_sig(wrapper, orig_func, force=False):
      """
      Decorates a wrapper function.
  
      It seems impossible to presever signatures in python 2 without eval
      (Maybe another option is to write to a temporary module?)
  
      Args:
          wrapper: the function wrapping orig_func to change the signature of
          orig_func: the original function to take the signature from
  
      References:
          http://emptysqua.re/blog/copying-a-python-functions-signature/
          https://code.google.com/p/micheles/source/browse/decorator/src/decorator.py
  
      TODO:
          checkout funcsigs
          https://funcsigs.readthedocs.org/en/latest/
  
      CommandLine:
          python -m utool.util_decor --test-preserve_sig
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> import utool as ut
          >>> #ut.rrrr(False)
          >>> def myfunction(self, listinput_, arg1, *args, **kwargs):
          >>>     " just a test function "
          >>>     return [x + 1 for x in listinput_]
          >>> #orig_func = ut.take
          >>> orig_func = myfunction
          >>> wrapper = ut.accepts_scalar_input2([0])(orig_func)
          >>> _wrp_preserve1 = ut.preserve_sig(wrapper, orig_func, True)
          >>> _wrp_preserve2 = ut.preserve_sig(wrapper, orig_func, False)
          >>> print('_wrp_preserve2 = %r' % (_wrp_preserve1,))
          >>> print('_wrp_preserve2 = %r' % (_wrp_preserve2,))
          >>> #print('source _wrp_preserve1 = %s' % (ut.get_func_sourcecode(_wrp_preserve1),))
          >>> #print('source _wrp_preserve2 = %s' % (ut.get_func_sourcecode(_wrp_preserve2)),)
          >>> result = str(_wrp_preserve1)
          >>> print(result)
      """
      #if True:
      #    import functools
      #    return functools.wraps(orig_func)(wrapper)
      from utool._internal import meta_util_six
      from utool import util_str
      from utool import util_inspect
  
      if wrapper is orig_func:
          # nothing to do
          return orig_func
      orig_docstr = meta_util_six.get_funcdoc(orig_func)
      orig_docstr = '' if orig_docstr is None else orig_docstr
      orig_argspec = util_inspect.get_func_argspec(orig_func)
      wrap_name = meta_util_six.get_funccode(wrapper).co_name
      orig_name = meta_util_six.get_funcname(orig_func)
  
      # At the very least preserve info in a dictionary
      _utinfo = {}
      _utinfo['orig_func'] = orig_func
      _utinfo['wrap_name'] = wrap_name
      _utinfo['orig_name'] = orig_name
      _utinfo['orig_argspec'] = orig_argspec
  
      if hasattr(wrapper, '_utinfo'):
          parent_wrapper_utinfo = wrapper._utinfo
          _utinfo['parent_wrapper_utinfo'] = parent_wrapper_utinfo
      if hasattr(orig_func, '_utinfo'):
          parent_orig_utinfo = orig_func._utinfo
          _utinfo['parent_orig_utinfo'] = parent_orig_utinfo
  
      # environment variable is set if you are building documentation
      # preserve sig if building docs
      building_docs = os.environ.get('UTOOL_AUTOGEN_SPHINX_RUNNING', 'OFF') == 'ON'
  
      if force or SIG_PRESERVE or building_docs:
          # PRESERVES ALL SIGNATURES WITH EXECS
          src_fmt = r'''
          def _wrp_preserve{defsig}:
              """ {orig_docstr} """
              try:
                  return wrapper{callsig}
              except Exception as ex:
                  import utool as ut
                  msg = ('Failure in signature preserving wrapper:\n')
                  ut.printex(ex, msg)
                  raise
          '''
          # Put wrapped function into a scope
          globals_ =  {'wrapper': wrapper}
          locals_ = {}
          # argspec is :ArgSpec(args=['bar', 'baz'], varargs=None, keywords=None,
          # defaults=(True,))
          # get orig functions argspec
          # get functions signature
          # Get function call signature (no defaults)
          # Define an exec function
          argspec = inspect.getargspec(orig_func)
          (args, varargs, varkw, defaults) = argspec
          defsig = inspect.formatargspec(*argspec)
          callsig = inspect.formatargspec(*argspec[0:3])
          # TODO:
          # ut.func_defsig
          # ut.func_callsig
          src_fmtdict = dict(defsig=defsig, callsig=callsig, orig_docstr=orig_docstr)
          src = textwrap.dedent(src_fmt).format(**src_fmtdict)
          # Define the new function on the fly
          # (I wish there was a non exec / eval way to do this)
          #print(src)
          code = compile(src, '<string>', 'exec')
          six.exec_(code, globals_, locals_)
          #six.exec_(src, globals_, locals_)
          # Use functools.update_wapper to complete preservation
          _wrp_preserve = functools.update_wrapper(locals_['_wrp_preserve'], orig_func)
          # Keep debug info
          _utinfo['src'] = src
          # Set an internal sig variable that we may use
          #_wrp_preserve.__sig__ = defsig
      else:
          # PRESERVES SOME SIGNATURES NO EXEC
          # signature preservation is turned off. just preserve the name.
          # Does not use any exec or eval statments.
          _wrp_preserve = functools.update_wrapper(wrapper, orig_func)
          # Just do something to preserve signature
  
      DEBUG_WRAPPED_DOCSTRING = False
      if DEBUG_WRAPPED_DOCSTRING:
          new_docstr_fmtstr = util_str.codeblock(
              '''
              Wrapped function {wrap_name}({orig_name})
  
              orig_argspec = {orig_argspec}
  
              orig_docstr = {orig_docstr}
              '''
          )
      else:
          new_docstr_fmtstr = util_str.codeblock(
              '''
              {orig_docstr}
              '''
          )
      new_docstr = new_docstr_fmtstr.format(
          wrap_name=wrap_name, orig_name=orig_name, orig_docstr=orig_docstr,
          orig_argspec=orig_argspec)
      meta_util_six.set_funcdoc(_wrp_preserve, new_docstr)
      _wrp_preserve._utinfo = _utinfo
      return _wrp_preserve