raise AssertionError on deprecated when removed_in exceeded

As there was some worry raised over whether people would remember
to remove a deprecated function once the removed_in version had been
reached, I've decided to add functionality that will force the
issue. When a @deprecated function is tagged with a removed_in
release that is greater than or equal to the current release, the
@deprecated decorator will raise an AssertionError, which will
hopefully break CI/CD and force the function to be removed.
This commit is contained in:
Joel Gerber 2017-06-10 09:57:49 -04:00
parent 5c33aac9f2
commit 0b94c3ceec
Failed to generate hash of commit
3 changed files with 41 additions and 4 deletions

View file

@ -2,6 +2,17 @@
* ``xonsh.color_tools.make_palette()``
Simple rename of the pre-existing
``xonsh.color_tools.make_pallete()`` function.
* ``xonsh.tools.decorator()`` function/method decorator.
This allows for an API function to be annotated with a
decorator that documents deprecation, while also tying in
functionality that will warn a user that the function has
been deprecated, and, raise an ``AssertionError`` if the
function has passed its expiry date.
**Changed:** None
**Deprecated:**

View file

@ -9,6 +9,7 @@ import warnings
import pytest
from xonsh import __version__
from xonsh.platform import ON_WINDOWS
from xonsh.lexer import Lexer
@ -1313,3 +1314,12 @@ def test_deprecated_warning_contains_message():
my_function()
assert str(warning.pop().message) == 'my_function has been deprecated'
@pytest.mark.parametrize('expired_version', ['0.1.0', __version__])
def test_deprecated_past_expiry_raises_assertion_error(expired_version):
@deprecated(removed_in=expired_version)
def my_function(): pass
with pytest.raises(AssertionError):
my_function()

View file

@ -23,6 +23,7 @@ import collections.abc as cabc
import contextlib
import ctypes
import datetime
from distutils.version import StrictVersion
import functools
import glob
import itertools
@ -38,6 +39,7 @@ import operator
# adding imports from further xonsh modules is discouraged to avoid circular
# dependencies
from xonsh import __version__
from xonsh.lazyasd import LazyObject, LazyDict, lazyobject
from xonsh.platform import (has_prompt_toolkit, scandir, DEFAULT_ENCODING,
ON_LINUX, ON_WINDOWS, PYTHON_VERSION_INFO,
@ -1949,8 +1951,12 @@ def deprecated(deprecated_in=None, removed_in=None):
that deprecation occurred in and the version it will be removed
in if both of these values are passed.
In all circumstances, call ``warnings.warn`` with details, while
raising ``DeprecationWarning``.
When removed_in is not a release equal to or less than the current
release, call ``warnings.warn`` with details, while raising
``DeprecationWarning``.
When removed_in is a release equal to or less than the current release,
raise an ``AssertionError``.
Parameters
----------
@ -1959,7 +1965,7 @@ def deprecated(deprecated_in=None, removed_in=None):
removed_in : str
The version number that this function will be removed in.
"""
message_suffix = _deprecation_message_suffix(deprecated_in, removed_in)
message_suffix = _deprecated_message_suffix(deprecated_in, removed_in)
if not message_suffix:
message_suffix = ''
@ -1969,6 +1975,7 @@ def deprecated(deprecated_in=None, removed_in=None):
@functools.wraps(func)
def wrapped(*args, **kwargs):
_deprecated_error_on_expiration(func.__name__, removed_in)
func(*args, **kwargs)
warnings.warn(warning_message, DeprecationWarning)
@ -1980,7 +1987,7 @@ def deprecated(deprecated_in=None, removed_in=None):
return decorated
def _deprecation_message_suffix(deprecated_in, removed_in):
def _deprecated_message_suffix(deprecated_in, removed_in):
if deprecated_in and removed_in:
message_suffix = (
' in version {} and will be removed in version {}'.format(
@ -1995,3 +2002,12 @@ def _deprecation_message_suffix(deprecated_in, removed_in):
message_suffix = None
return message_suffix
def _deprecated_error_on_expiration(name, removed_in):
if not removed_in:
return
elif StrictVersion(__version__) >= StrictVersion(removed_in):
raise AssertionError(
'{} has passed its version {} expiry date!'.format(
name, removed_in))