|
import enum |
|
import inspect |
|
import warnings |
|
from functools import wraps |
|
from typing import Callable, Optional |
|
|
|
from .logging import get_logger |
|
|
|
|
|
_emitted_deprecation_warnings = set() |
|
logger = get_logger(__name__) |
|
|
|
|
|
def deprecated(help_message: Optional[str] = None): |
|
"""Decorator to mark a class or a function as deprecated. |
|
|
|
Args: |
|
help_message (:obj:`str`, optional): An optional message to guide the user on how to |
|
switch to non-deprecated usage of the library. |
|
""" |
|
|
|
def decorator(deprecated_class_or_function: Callable): |
|
global _emitted_deprecation_warnings |
|
|
|
if inspect.isclass(deprecated_class_or_function): |
|
deprecated_function = deprecated_class_or_function.__init__ |
|
name = deprecated_class_or_function.__name__ |
|
else: |
|
deprecated_function = deprecated_class_or_function |
|
name = deprecated_function.__name__ |
|
|
|
name = name if name != "__init__" else deprecated_function.__qualname__.split(".")[-2] |
|
|
|
warning_msg = ( |
|
f"{name} is deprecated and will be removed in the next major version of datasets." + f" {help_message}" |
|
if help_message |
|
else "" |
|
) |
|
|
|
@wraps(deprecated_function) |
|
def wrapper(*args, **kwargs): |
|
func_hash = hash(deprecated_function) |
|
if func_hash not in _emitted_deprecation_warnings: |
|
warnings.warn(warning_msg, category=FutureWarning, stacklevel=2) |
|
_emitted_deprecation_warnings.add(func_hash) |
|
return deprecated_function(*args, **kwargs) |
|
|
|
wrapper._decorator_name_ = "deprecated" |
|
|
|
if inspect.isclass(deprecated_class_or_function): |
|
deprecated_class_or_function.__init__ = wrapper |
|
return deprecated_class_or_function |
|
else: |
|
return wrapper |
|
|
|
return decorator |
|
|
|
|
|
class OnAccess(enum.EnumMeta): |
|
""" |
|
Enum metaclass that calls a user-specified function whenever a member is accessed. |
|
""" |
|
|
|
def __getattribute__(cls, name): |
|
obj = super().__getattribute__(name) |
|
if isinstance(obj, enum.Enum) and obj._on_access: |
|
obj._on_access() |
|
return obj |
|
|
|
def __getitem__(cls, name): |
|
member = super().__getitem__(name) |
|
if member._on_access: |
|
member._on_access() |
|
return member |
|
|
|
def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1): |
|
obj = super().__call__(value, names, module=module, qualname=qualname, type=type, start=start) |
|
if isinstance(obj, enum.Enum) and obj._on_access: |
|
obj._on_access() |
|
return obj |
|
|
|
|
|
class DeprecatedEnum(enum.Enum, metaclass=OnAccess): |
|
""" |
|
Enum class that calls `deprecate` method whenever a member is accessed. |
|
""" |
|
|
|
def __new__(cls, value): |
|
member = object.__new__(cls) |
|
member._value_ = value |
|
member._on_access = member.deprecate |
|
return member |
|
|
|
@property |
|
def help_message(self): |
|
return "" |
|
|
|
def deprecate(self): |
|
help_message = f" {self.help_message}" if self.help_message else "" |
|
warnings.warn( |
|
f"'{self.__objclass__.__name__}' is deprecated and will be removed in the next major version of datasets." |
|
+ help_message, |
|
FutureWarning, |
|
stacklevel=3, |
|
) |
|
|