docs: def proxify_routine(routine, impl=None):
      """Proxify a routine with input impl.
  
      :param routine: routine to proxify.
      :param impl: new impl to use. If None, use routine.
      """
  
      # init impl
      impl = routine if impl is None else impl
  
      is_method = ismethod(routine)
      if is_method:
          function = get_method_function(routine)
      else:
          function = routine
  
      # flag which indicates that the function is not a pure python function
      # and has to be wrapped
      wrap_function = not hasattr(function, '__code__')
  
      try:
          # get params from routine
          args, varargs, kwargs, _ = getargspec(function)
      except TypeError:
          # in case of error, wrap the function
          wrap_function = True
  
      if wrap_function:
          # if function is not pure python, create a generic one
          # with assignments
          assigned = []
          for wrapper_assignment in WRAPPER_ASSIGNMENTS:
              if hasattr(function, wrapper_assignment):
                  assigned.append(wrapper_assignment)
          # and updates
          updated = []
          for wrapper_update in WRAPPER_UPDATES:
              if hasattr(function, wrapper_update):
                  updated.append(wrapper_update)
  
          @wraps(function, assigned=assigned, updated=updated)
          def wrappedfunction(*args, **kwargs):
              """Default wrap function."""
  
          function = wrappedfunction
          # get params from function
          args, varargs, kwargs, _ = getargspec(function)
  
      name = function.__name__
  
      result = _compilecode(
          function=function, name=name, impl=impl,
          args=args, varargs=varargs, kwargs=kwargs
      )
  
      # set wrapping assignments
      for wrapper_assignment in WRAPPER_ASSIGNMENTS:
          try:
              value = getattr(function, wrapper_assignment)
          except AttributeError:
              pass
          else:
              setattr(result, wrapper_assignment, value)
  
      # set proxy module
      result.__module__ = proxify_routine.__module__
  
      # update wrapping updating
      for wrapper_update in WRAPPER_UPDATES:
          try:
              value = getattr(function, wrapper_update)
          except AttributeError:
              pass
          else:
              getattr(result, wrapper_update).update(value)
  
      # set proxyfied element on proxy
      setattr(result, __PROXIFIED__, routine)
  
      if is_method:  # create a new method
          args = [result, get_method_self(routine)]
          if PY2:
              args.append(routine.im_class)
          result = MethodType(*args)
  
      return result