From 07ede1437ba9cd6a6cbc91612c0b522a211f3211 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 7 Jun 2018 14:33:16 +0200 Subject: [PATCH] Various fixes to deprecated and warn_deprecated. - Make `pending=True` actually emit a PendingDeprecationWarning, as advertised, and make it incompatible with `removal`, which seems semantically reasonable (`removal` itself is a new API in 3.0 so that's not an API break). - Restore use of %-formatting instead of .format for the message formatting, to restore accidentally broken backcompat (which was never released). - Restore support for the `addendum` kwarg, whose effect had accidentally been removed. - The `@deprecated` decorator has always ignored `obj_type` (forcefully overwriting it with the type of whatever is actually being decorated) so we may as well make it not support `obj_type` at all. - Remove a Py2 branch. --- .../2018-02-15-AL-deprecations.rst | 3 +- lib/matplotlib/cbook/deprecation.py | 67 +++++++++++-------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst b/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst index 64c82e4cb358..5d799c5587ec 100644 --- a/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst +++ b/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst @@ -42,4 +42,5 @@ The following rcParams are deprecated: - ``pgf.debug`` (the pgf backend relies on logging), The following keyword arguments are deprecated: -- passing ``verts`` to ``scatter`` (use ``marker`` instead), +- passing ``verts`` to ``Axes.scatter`` (use ``marker`` instead), +- passing ``obj_type`` to ``cbook.deprecated``, diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index 30accf7c1ca5..ae7f51d598c6 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -14,7 +14,6 @@ class MatplotlibDeprecationWarning(UserWarning): https://docs.python.org/dev/whatsnew/2.7.html#the-future-for-python-2-x """ - pass mplDeprecation = MatplotlibDeprecationWarning @@ -28,29 +27,34 @@ def _generate_deprecation_message( removal = {"2.2": "in 3.1", "3.0": "in 3.2"}.get( since, "two minor releases later") elif removal: + if pending: + raise ValueError( + "A pending deprecation cannot have a scheduled removal") removal = "in {}".format(removal) if not message: message = ( - "The {name} {obj_type}" + "The %(name)s %(obj_type)s" + (" will be deprecated in a future version" if pending else - (" was deprecated in Matplotlib {since}" - + (" and will be removed {removal}" + (" was deprecated in Matplotlib %(since)s" + + (" and will be removed %(removal)s" if removal else ""))) + "." - + (" Use {alternative} instead." if alternative else "")) + + (" Use %(alternative)s instead." if alternative else "")) - return message.format(func=name, name=name, obj_type=obj_type, since=since, - removal=removal, alternative=alternative) + return ( + message % dict(func=name, name=name, obj_type=obj_type, since=since, + removal=removal, alternative=alternative) + + addendum) def warn_deprecated( since, message='', name='', alternative='', pending=False, obj_type='attribute', addendum='', *, removal=''): """ - Used to display deprecation warning in a standard way. + Used to display deprecation in a standard way. Parameters ---------- @@ -69,18 +73,19 @@ def warn_deprecated( The name of the deprecated object. alternative : str, optional - An alternative function that the user may use in place of the - deprecated function. The deprecation warning will tell the user - about this alternative if provided. + An alternative API that the user may use in place of the deprecated + API. The deprecation warning will tell the user about this alternative + if provided. pending : bool, optional If True, uses a PendingDeprecationWarning instead of a - DeprecationWarning. + DeprecationWarning. Cannot be used together with *removal*. removal : str, optional The expected removal version. With the default (an empty string), a removal version is automatically computed from *since*. Set to other - Falsy values to not schedule a removal date. + Falsy values to not schedule a removal date. Cannot be used together + with *pending*. obj_type : str, optional The object type being deprecated. @@ -101,7 +106,9 @@ def warn_deprecated( message = _generate_deprecation_message( since, message, name, alternative, pending, obj_type, removal=removal) message = '\n' + message - warnings.warn(message, mplDeprecation, stacklevel=2) + category = (PendingDeprecationWarning if pending + else MatplotlibDeprecationWarning) + warnings.warn(message, category, stacklevel=2) def deprecated(since, message='', name='', alternative='', pending=False, @@ -120,8 +127,7 @@ def deprecated(since, message='', name='', alternative='', pending=False, specifier `%(name)s` may be used for the name of the object, and `%(alternative)s` may be used in the deprecation message to insert the name of an alternative to the deprecated - object. `%(obj_type)s` may be used to insert a friendly name - for the type of object being deprecated. + object. name : str, optional The name of the deprecated object; if not provided the name @@ -135,18 +141,19 @@ def new_function(): oldFunction = new_function alternative : str, optional - An alternative object that the user may use in place of the - deprecated object. The deprecation warning will tell the user - about this alternative if provided. + An alternative API that the user may use in place of the deprecated + API. The deprecation warning will tell the user about this alternative + if provided. pending : bool, optional If True, uses a PendingDeprecationWarning instead of a - DeprecationWarning. + DeprecationWarning. Cannot be used together with *removal*. removal : str, optional The expected removal version. With the default (an empty string), a removal version is automatically computed from *since*. Set to other - Falsy values to not schedule a removal date. + Falsy values to not schedule a removal date. Cannot be used together + with *pending*. addendum : str, optional Additional text appended directly to the final message. @@ -159,9 +166,14 @@ def new_function(): @deprecated('1.4.0') def the_function_to_deprecate(): pass - """ + if obj_type is not None: + warn_deprecated( + "3.0", "Passing 'obj_type' to the 'deprecated' decorator has no " + "effect, and is deprecated since Matplotlib %(since)s; support " + "for it will be removed %(removal)s.") + def deprecate(obj, message=message, name=name, alternative=alternative, pending=pending, addendum=addendum): @@ -174,12 +186,7 @@ def deprecate(obj, message=message, name=name, alternative=alternative, func = obj.__init__ def finalize(wrapper, new_doc): - try: - obj.__doc__ = new_doc - except (AttributeError, TypeError): - # cls.__doc__ is not writeable on Py2. - # TypeError occurs on PyPy - pass + obj.__doc__ = new_doc obj.__init__ = wrapper return obj else: @@ -204,9 +211,11 @@ def finalize(wrapper, new_doc): message = _generate_deprecation_message( since, message, name, alternative, pending, obj_type, addendum, removal=removal) + category = (PendingDeprecationWarning if pending + else MatplotlibDeprecationWarning) def wrapper(*args, **kwargs): - warnings.warn(message, mplDeprecation, stacklevel=2) + warnings.warn(message, category, stacklevel=2) return func(*args, **kwargs) old_doc = textwrap.dedent(old_doc or '').strip('\n')