| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- # Copyright 2024 The HuggingFace Team. All rights reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import inspect
- import warnings
- from functools import wraps
- from typing import Optional
- import packaging.version
- from .. import __version__
- from . import ExplicitEnum
- class Action(ExplicitEnum):
- NONE = "none"
- NOTIFY = "notify"
- NOTIFY_ALWAYS = "notify_always"
- RAISE = "raise"
- def deprecate_kwarg(
- old_name: str,
- version: str,
- new_name: Optional[str] = None,
- warn_if_greater_or_equal_version: bool = False,
- raise_if_greater_or_equal_version: bool = False,
- raise_if_both_names: bool = False,
- additional_message: Optional[str] = None,
- ):
- """
- Function or method decorator to notify users about deprecated keyword arguments, replacing them with a new name if specified.
- This decorator allows you to:
- - Notify users when a keyword argument is deprecated.
- - Automatically replace deprecated keyword arguments with new ones.
- - Raise an error if deprecated arguments are used, depending on the specified conditions.
- By default, the decorator notifies the user about the deprecated argument while the `transformers.__version__` < specified `version`
- in the decorator. To keep notifications with any version `warn_if_greater_or_equal_version=True` can be set.
- Parameters:
- old_name (`str`):
- Name of the deprecated keyword argument.
- version (`str`):
- The version in which the keyword argument was (or will be) deprecated.
- new_name (`Optional[str]`, *optional*):
- The new name for the deprecated keyword argument. If specified, the deprecated keyword argument will be replaced with this new name.
- warn_if_greater_or_equal_version (`bool`, *optional*, defaults to `False`):
- Whether to show warning if current `transformers` version is greater or equal to the deprecated version.
- raise_if_greater_or_equal_version (`bool`, *optional*, defaults to `False`):
- Whether to raise `ValueError` if current `transformers` version is greater or equal to the deprecated version.
- raise_if_both_names (`bool`, *optional*, defaults to `False`):
- Whether to raise `ValueError` if both deprecated and new keyword arguments are set.
- additional_message (`Optional[str]`, *optional*):
- An additional message to append to the default deprecation message.
- Raises:
- ValueError:
- If raise_if_greater_or_equal_version is True and the current version is greater than or equal to the deprecated version, or if raise_if_both_names is True and both old and new keyword arguments are provided.
- Returns:
- Callable:
- A wrapped function that handles the deprecated keyword arguments according to the specified parameters.
- Example usage with renaming argument:
- ```python
- @deprecate_kwarg("reduce_labels", new_name="do_reduce_labels", version="6.0.0")
- def my_function(do_reduce_labels):
- print(do_reduce_labels)
- my_function(reduce_labels=True) # Will show a deprecation warning and use do_reduce_labels=True
- ```
- Example usage without renaming argument:
- ```python
- @deprecate_kwarg("max_size", version="6.0.0")
- def my_function(max_size):
- print(max_size)
- my_function(max_size=1333) # Will show a deprecation warning
- ```
- """
- deprecated_version = packaging.version.parse(version)
- current_version = packaging.version.parse(__version__)
- is_greater_or_equal_version = current_version >= deprecated_version
- if is_greater_or_equal_version:
- version_message = f"and removed starting from version {version}"
- else:
- version_message = f"and will be removed in version {version}"
- def wrapper(func):
- # Required for better warning message
- sig = inspect.signature(func)
- function_named_args = set(sig.parameters.keys())
- is_instance_method = "self" in function_named_args
- is_class_method = "cls" in function_named_args
- @wraps(func)
- def wrapped_func(*args, **kwargs):
- # Get class + function name (just for better warning message)
- func_name = func.__name__
- if is_instance_method:
- func_name = f"{args[0].__class__.__name__}.{func_name}"
- elif is_class_method:
- func_name = f"{args[0].__name__}.{func_name}"
- minimum_action = Action.NONE
- message = None
- # deprecated kwarg and its new version are set for function call -> replace it with new name
- if old_name in kwargs and new_name in kwargs:
- minimum_action = Action.RAISE if raise_if_both_names else Action.NOTIFY_ALWAYS
- message = f"Both `{old_name}` and `{new_name}` are set for `{func_name}`. Using `{new_name}={kwargs[new_name]}` and ignoring deprecated `{old_name}={kwargs[old_name]}`."
- kwargs.pop(old_name)
- # only deprecated kwarg is set for function call -> replace it with new name
- elif old_name in kwargs and new_name is not None and new_name not in kwargs:
- minimum_action = Action.NOTIFY
- message = f"`{old_name}` is deprecated {version_message} for `{func_name}`. Use `{new_name}` instead."
- kwargs[new_name] = kwargs.pop(old_name)
- # deprecated kwarg is not set for function call and new name is not specified -> just notify
- elif old_name in kwargs:
- minimum_action = Action.NOTIFY
- message = f"`{old_name}` is deprecated {version_message} for `{func_name}`."
- if message is not None and additional_message is not None:
- message = f"{message} {additional_message}"
- # update minimum_action if argument is ALREADY deprecated (current version >= deprecated version)
- if is_greater_or_equal_version:
- # change to (NOTIFY, NOTIFY_ALWAYS) -> RAISE if specified
- # in case we want to raise error for already deprecated arguments
- if raise_if_greater_or_equal_version and minimum_action != Action.NONE:
- minimum_action = Action.RAISE
- # change to NOTIFY -> NONE if specified (NOTIFY_ALWAYS can't be changed to NONE)
- # in case we want to ignore notifications for already deprecated arguments
- elif not warn_if_greater_or_equal_version and minimum_action == Action.NOTIFY:
- minimum_action = Action.NONE
- # raise error or notify user
- if minimum_action == Action.RAISE:
- raise ValueError(message)
- elif minimum_action in (Action.NOTIFY, Action.NOTIFY_ALWAYS):
- # DeprecationWarning is ignored by default, so we use FutureWarning instead
- warnings.warn(message, FutureWarning, stacklevel=2)
- return func(*args, **kwargs)
- return wrapped_func
- return wrapper
|