deprecation.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import inspect
  2. import logging
  3. from typing import Optional, Union
  4. from ray.util import log_once
  5. logger = logging.getLogger(__name__)
  6. # A constant to use for any configuration that should be deprecated
  7. # (to check, whether this config has actually been assigned a proper value or
  8. # not).
  9. DEPRECATED_VALUE = -1
  10. def deprecation_warning(
  11. old: str,
  12. new: Optional[str] = None,
  13. *,
  14. help: Optional[str] = None,
  15. error: Optional[Union[bool, Exception]] = None) -> None:
  16. """Warns (via the `logger` object) or throws a deprecation warning/error.
  17. Args:
  18. old: A description of the "thing" that is to be deprecated.
  19. new: A description of the new "thing" that replaces it.
  20. help: An optional help text to tell the user, what to
  21. do instead of using `old`.
  22. error: Whether or which exception to raise. If True, raise ValueError.
  23. If False, just warn. If `error` is-a subclass of Exception,
  24. raise that Exception.
  25. Raises:
  26. ValueError: If `error=True`.
  27. Exception: Of type `error`, iff `error` is a sub-class of `Exception`.
  28. """
  29. msg = "`{}` has been deprecated.{}".format(
  30. old, (" Use `{}` instead.".format(new) if new else f" {help}"
  31. if help else ""))
  32. if error is True:
  33. raise ValueError(msg)
  34. elif error and issubclass(error, Exception):
  35. raise error(msg)
  36. else:
  37. logger.warning("DeprecationWarning: " + msg +
  38. " This will raise an error in the future!")
  39. def Deprecated(old=None, *, new=None, help=None, error):
  40. """Decorator for documenting a deprecated class, method, or function.
  41. Automatically adds a `deprecation.deprecation_warning(old=...,
  42. error=False)` to not break existing code at this point to the decorated
  43. class' constructor, method, or function.
  44. In a next major release, this warning should then be made an error
  45. (by setting error=True), which means at this point that the
  46. class/method/function is no longer supported, but will still inform
  47. the user about the deprecation event.
  48. In a further major release, the class, method, function should be erased
  49. entirely from the codebase.
  50. Examples:
  51. >>> # Deprecated class: Patches the constructor to warn if the class is
  52. ... # used.
  53. ... @Deprecated(new="NewAndMuchCoolerClass", error=False)
  54. ... class OldAndUncoolClass:
  55. ... ...
  56. >>> # Deprecated class method: Patches the method to warn if called.
  57. ... class StillCoolClass:
  58. ... ...
  59. ... @Deprecated(new="StillCoolClass.new_and_much_cooler_method()",
  60. ... error=False)
  61. ... def old_and_uncool_method(self, uncool_arg):
  62. ... ...
  63. >>> # Deprecated function: Patches the function to warn if called.
  64. ... @Deprecated(new="new_and_much_cooler_function", error=False)
  65. ... def old_and_uncool_function(*uncool_args):
  66. ... ...
  67. """
  68. def _inner(obj):
  69. # A deprecated class.
  70. if inspect.isclass(obj):
  71. # Patch the class' init method to raise the warning/error.
  72. obj_init = obj.__init__
  73. def patched_init(*args, **kwargs):
  74. if log_once(old or obj.__name__):
  75. deprecation_warning(
  76. old=old or obj.__name__,
  77. new=new,
  78. help=help,
  79. error=error,
  80. )
  81. return obj_init(*args, **kwargs)
  82. obj.__init__ = patched_init
  83. # Return the patched class (with the warning/error when
  84. # instantiated).
  85. return obj
  86. # A deprecated class method or function.
  87. # Patch with the warning/error at the beginning.
  88. def _ctor(*args, **kwargs):
  89. if log_once(old or obj.__name__):
  90. deprecation_warning(
  91. old=old or obj.__name__,
  92. new=new,
  93. help=help,
  94. error=error,
  95. )
  96. # Call the deprecated method/function.
  97. return obj(*args, **kwargs)
  98. # Return the patched class method/function.
  99. return _ctor
  100. # Return the prepared decorator.
  101. return _inner