|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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): |
|
|
|
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): |
|
|
|
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 |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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}" |
|
|
|
|
|
if is_greater_or_equal_version: |
|
|
|
|
|
if raise_if_greater_or_equal_version and minimum_action != Action.NONE: |
|
minimum_action = Action.RAISE |
|
|
|
|
|
|
|
elif not warn_if_greater_or_equal_version and minimum_action == Action.NOTIFY: |
|
minimum_action = Action.NONE |
|
|
|
|
|
if minimum_action == Action.RAISE: |
|
raise ValueError(message) |
|
elif minimum_action in (Action.NOTIFY, Action.NOTIFY_ALWAYS): |
|
|
|
warnings.warn(message, FutureWarning, stacklevel=2) |
|
|
|
return func(*args, **kwargs) |
|
|
|
return wrapped_func |
|
|
|
return wrapper |
|
|