code: def deprecated_params(
      old_name,
      new_name=None,
      since="",
      until="",
      version_comparator=cmp_pkg_version,
      arg_in_kwargs=False,
      warn_class=ArgsDeprecationWarning,
      error_class=ExpiredDeprecationError,
      alternative="",
  ):
      """Deprecate a *renamed* or *removed* function argument.
  
      The decorator assumes that the argument with the ``old_name`` was removed
      from the function signature and the ``new_name`` replaced it at the
      **same position** in the signature.  If the ``old_name`` argument is
      given when calling the decorated function the decorator will catch it and
      issue a deprecation warning and pass it on as ``new_name`` argument.
  
      Parameters
      ----------
      old_name : str or list/tuple thereof
          The old name of the argument.
      new_name : str or list/tuple thereof or ``None``, optional
          The new name of the argument. Set this to `None` to remove the
          argument ``old_name`` instead of renaming it.
      since : str or number or list/tuple thereof, optional
          The release at which the old argument became deprecated.
      until : str or number or list/tuple thereof, optional
          Last released version at which this function will still raise a
          deprecation warning.  Versions higher than this will raise an
          error.
      version_comparator : callable
          Callable accepting string as argument, and return 1 if string
          represents a higher version than encoded in the ``version_comparator``,
          0 if the version is equal, and -1 if the version is lower. For example,
          the ``version_comparator`` may compare the input version string to the
          current package version string.
      arg_in_kwargs : bool or list/tuple thereof, optional
          If the argument is not a named argument (for example it
          was meant to be consumed by ``**kwargs``) set this to
          ``True``.  Otherwise the decorator will throw an Exception
          if the ``new_name`` cannot be found in the signature of
          the decorated function.
          Default is ``False``.
      warn_class : warning, optional
          Warning to be issued.
      error_class : Exception, optional
          Error to be issued
      alternative : str, optional
          An alternative function or class name that the user may use in
          place of the deprecated object if ``new_name`` is None. The deprecation
          warning will tell the user about this alternative if provided.
  
      Raises
      ------
      TypeError
          If the new argument name cannot be found in the function
          signature and arg_in_kwargs was False or if it is used to
          deprecate the name of the ``*args``-, ``**kwargs``-like arguments.
          At runtime such an Error is raised if both the new_name
          and old_name were specified when calling the function and
          "relax=False".
  
      Notes
      -----
      This function is based on the Astropy (major modification).
      https://github.com/astropy/astropy. See COPYING file distributed along with
      the astropy package for the copyright and license terms.
  
      Examples
      --------
      The deprecation warnings are not shown in the following examples.
      To deprecate a positional or keyword argument::
      >>> from dipy.utils.deprecator import deprecated_params
      >>> @deprecated_params('sig', 'sigma', '0.3')
      ... def test(sigma):
      ...     return sigma
      >>> test(2)
      2
      >>> test(sigma=2)
      2
      >>> test(sig=2)  # doctest: +SKIP
      2
  
      It is also possible to replace multiple arguments. The ``old_name``,
      ``new_name`` and ``since`` have to be `tuple` or `list` and contain the
      same number of entries::
      >>> @deprecated_params(['a', 'b'], ['alpha', 'beta'],
      ...                    ['0.2', 0.4])
      ... def test(alpha, beta):
      ...     return alpha, beta
      >>> test(a=2, b=3)  # doctest: +SKIP
      (2, 3)
  
      """
      if isinstance(old_name, (list, tuple)):
          # Normalize input parameters
          if not isinstance(arg_in_kwargs, (list, tuple)):
              arg_in_kwargs = [arg_in_kwargs] * len(old_name)
          if not isinstance(since, (list, tuple)):
              since = [since] * len(old_name)
          if not isinstance(until, (list, tuple)):
              until = [until] * len(old_name)
          if not isinstance(new_name, (list, tuple)):
              new_name = [new_name] * len(old_name)
  
          if (
              len(
                  {
                      len(old_name),
                      len(new_name),
                      len(since),
                      len(until),
                      len(arg_in_kwargs),
                  }
              )
              != 1
          ):
              raise ValueError(
                  "All parameters should have the same length"
              )
      else:
          # To allow a uniform approach later on, wrap all arguments in lists.
          old_name = [old_name]
          new_name = [new_name]
          since = [since]
          until = [until]
          arg_in_kwargs = [arg_in_kwargs]
  
      def deprecator(function):
          # The named arguments of the function.
          arguments = signature(function).parameters
          positions = [None] * len(old_name)
  
          for i, (o_name, n_name, in_keywords) in enumerate(
              zip(old_name, new_name, arg_in_kwargs)
          ):
              # Determine the position of the argument.
              if in_keywords:
                  continue
  
              if n_name is not None and n_name not in arguments:
                  # In case the argument is not found in the list of arguments
                  # the only remaining possibility is that it should be caught
                  # by some kind of **kwargs argument.
                  msg = (
                      '"{}" was not specified in the function '.format(
                          n_name
                      )
                  )
                  msg += "signature. If it was meant to be part of "
                  msg += '"**kwargs" then set "arg_in_kwargs" to "True"'
                  raise TypeError(msg)
  
              key = o_name if n_name is None else n_name
              param = arguments[key]
  
              if param.kind == param.POSITIONAL_OR_KEYWORD:
                  key = o_name if n_name is None else n_name
                  positions[i] = list(arguments.keys()).index(key)
              elif param.kind == param.KEYWORD_ONLY:
                  # These cannot be specified by position.
                  positions[i] = None
              else:
                  # positional-only argument, varargs, varkwargs or some
                  # unknown type:
                  msg = 'cannot replace argument "{}" '.format(n_name)
                  msg += "of kind {}.".format(repr(param.kind))
                  raise TypeError(msg)
  
          @functools.wraps(function)
          def wrapper(*args, **kwargs):
              for i, (o_name, n_name) in enumerate(
                  zip(old_name, new_name)
              ):
                  messages = [
                      '"{}" was deprecated'.format(o_name),
                  ]
                  if (since[i], until[i]) != ("", ""):
                      messages.append("")
                  if since[i]:
                      messages.append(
                          "* deprecated from version: " + str(since[i])
                      )
                  if until[i]:
                      messages.append(
                          "* {0} {1} as of version: {2}".format(
                              "Raises"
                              if is_bad_version(until[i])
                              else "Will raise",
                              error_class,
                              until[i],
                          )
                      )
                  messages.append("")
                  message = "\n".join(messages)
  
                  # The only way to have oldkeyword inside the function is
                  # that it is passed as kwarg because the oldkeyword
                  # parameter was renamed to newkeyword.
                  if o_name in kwargs:
                      value = kwargs.pop(o_name)
                      # Check if the newkeyword was given as well.
                      newarg_in_args = (
                          positions[i] is not None
                          and len(args) > positions[i]
                      )
                      newarg_in_kwargs = n_name in kwargs
  
                      if newarg_in_args or newarg_in_kwargs:
                          msg = 'cannot specify both "{}"'.format(
                              o_name
                          )
                          msg += " (deprecated parameter) and "
                          msg += '"{}" (new parameter name).'.format(
                              n_name
                          )
                          raise TypeError(msg)
  
                      # Pass the value of the old argument with the
                      # name of the new argument to the function
                      key = n_name or o_name
                      kwargs[key] = value
  
                      if n_name is not None:
                          message += (
                              '* Use argument "{}" instead.'.format(
                                  n_name
                              )
                          )
                      elif alternative:
                          message += "* Use {} instead.".format(
                              alternative
                          )
  
                      if until[i] and is_bad_version(
                          until[i], version_comparator
                      ):
                          raise error_class(message)
                      warnings.warn(message, warn_class, stacklevel=2)
  
                  # Deprecated keyword without replacement is given as
                  # positional argument.
                  elif (
                      not n_name
                      and positions[i]
                      and len(args) > positions[i]
                  ):
                      if alternative:
                          message += "* Use {} instead.".format(
                              alternative
                          )
                      if until[i] and is_bad_version(
                          until[i], version_comparator
                      ):
                          raise error_class(message)
  
                      warnings.warn(message, warn_class, stacklevel=2)
  
              return function(*args, **kwargs)
  
          return wrapper
  
      return deprecator
  
file_path: dipy/dipy/utils/deprecator.py
imports: import functools
  import warnings
  import re
  from inspect import signature
  from dipy import __version__
  from packaging.version import parse
label_desc: Use image node_id 6 for calling a global function with example usage: deprecated_params(old_name, new_name, since, until, version_comparator, arg_in_kwargs, warn_class, error_class, alternative) and returns: deprecator, wrapper, function