deprecation.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import functools
  2. import warnings
  3. __all__ = ["_deprecated"]
  4. def _deprecated(msg, stacklevel=2):
  5. """Deprecate a function by emitting a warning on use."""
  6. def wrap(fun):
  7. if isinstance(fun, type):
  8. warnings.warn(
  9. "Trying to deprecate class {!r}".format(fun),
  10. category=RuntimeWarning, stacklevel=2)
  11. return fun
  12. @functools.wraps(fun)
  13. def call(*args, **kwargs):
  14. warnings.warn(msg, category=DeprecationWarning,
  15. stacklevel=stacklevel)
  16. return fun(*args, **kwargs)
  17. call.__doc__ = fun.__doc__
  18. return call
  19. return wrap
  20. class _DeprecationHelperStr:
  21. """
  22. Helper class used by deprecate_cython_api
  23. """
  24. def __init__(self, content, message):
  25. self._content = content
  26. self._message = message
  27. def __hash__(self):
  28. return hash(self._content)
  29. def __eq__(self, other):
  30. res = (self._content == other)
  31. if res:
  32. warnings.warn(self._message, category=DeprecationWarning,
  33. stacklevel=2)
  34. return res
  35. def deprecate_cython_api(module, routine_name, new_name=None, message=None):
  36. """
  37. Deprecate an exported cdef function in a public Cython API module.
  38. Only functions can be deprecated; typedefs etc. cannot.
  39. Parameters
  40. ----------
  41. module : module
  42. Public Cython API module (e.g. scipy.linalg.cython_blas).
  43. routine_name : str
  44. Name of the routine to deprecate. May also be a fused-type
  45. routine (in which case its all specializations are deprecated).
  46. new_name : str
  47. New name to include in the deprecation warning message
  48. message : str
  49. Additional text in the deprecation warning message
  50. Examples
  51. --------
  52. Usually, this function would be used in the top-level of the
  53. module ``.pyx`` file:
  54. >>> from scipy._lib.deprecation import deprecate_cython_api
  55. >>> import scipy.linalg.cython_blas as mod
  56. >>> deprecate_cython_api(mod, "dgemm", "dgemm_new",
  57. ... message="Deprecated in Scipy 1.5.0")
  58. >>> del deprecate_cython_api, mod
  59. After this, Cython modules that use the deprecated function emit a
  60. deprecation warning when they are imported.
  61. """
  62. old_name = "{}.{}".format(module.__name__, routine_name)
  63. if new_name is None:
  64. depdoc = "`%s` is deprecated!" % old_name
  65. else:
  66. depdoc = "`%s` is deprecated, use `%s` instead!" % \
  67. (old_name, new_name)
  68. if message is not None:
  69. depdoc += "\n" + message
  70. d = module.__pyx_capi__
  71. # Check if the function is a fused-type function with a mangled name
  72. j = 0
  73. has_fused = False
  74. while True:
  75. fused_name = "__pyx_fuse_{}{}".format(j, routine_name)
  76. if fused_name in d:
  77. has_fused = True
  78. d[_DeprecationHelperStr(fused_name, depdoc)] = d.pop(fused_name)
  79. j += 1
  80. else:
  81. break
  82. # If not, apply deprecation to the named routine
  83. if not has_fused:
  84. d[_DeprecationHelperStr(routine_name, depdoc)] = d.pop(routine_name)