Skip to content

Commit

Permalink
more thoroughly test deprecation warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiasertl committed Jun 29, 2024
1 parent e6d501f commit 3afe24b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 33 deletions.
2 changes: 1 addition & 1 deletion ca/django_ca/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def deprecate_type(
types: Union[type[Any], tuple[type[Any], ...]],
category: DeprecationWarningType,
stacklevel: int = 2,
) -> typing.Callable[[F], F]: # pragma: no cover # not used at the beginning of 1.24.0 development
) -> typing.Callable[[F], F]:
"""Decorator to mark a type for an argument as deprecated."""

def decorator_deprecate(func: F) -> F:
Expand Down
97 changes: 65 additions & 32 deletions ca/django_ca/tests/test_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@

"""Test :py:mod:`django_ca.deprecation`."""

import contextlib
from collections.abc import Iterator
from typing import Any

from django.test import TestCase
import re
from typing import Any, Union

import pytest

Expand All @@ -26,46 +23,82 @@
RemovedInDjangoCA200Warning,
RemovedInDjangoCA210Warning,
RemovedInDjangoCA220Warning,
RemovedInNextVersionWarning,
deprecate_argument,
deprecate_function,
deprecate_type,
)


@pytest.mark.parametrize(
"cls", (RemovedInDjangoCA200Warning, RemovedInDjangoCA210Warning, RemovedInDjangoCA220Warning)
WARNING_TYPES: tuple[DeprecationWarningType, ...] = (
RemovedInDjangoCA200Warning,
RemovedInDjangoCA210Warning,
RemovedInDjangoCA220Warning,
)
def test_deprecation_warnings(cls: DeprecationWarningType) -> None:


@pytest.mark.parametrize("cls", WARNING_TYPES)
def test_deprecation_warning_version(cls: DeprecationWarningType) -> None:
"""Test versions in deprecation warnings."""
assert cls.__name__ == f"RemovedInDjangoCA{cls.version.replace('.', '')}0Warning"


class DeprecateArgumentTestCase(TestCase):
"""Test the `@deprecate_argument` decorator."""
@pytest.mark.parametrize("warning", WARNING_TYPES)
def test_deprecate_function(warning: DeprecationWarningType) -> None:
"""Test deprecate_function() decorator."""
version = re.escape(warning.version)
match = rf"^deprecated\(\) is deprecated and will be removed in django-ca {version}\.$"

@deprecate_function(warning)
def deprecated() -> None:
pass

with pytest.warns(warning, match=match):
deprecated()

@deprecate_argument("kw", RemovedInNextVersionWarning)
def func(self, unused: Any, kw: str = "default") -> str: # pylint: disable=all

@pytest.mark.parametrize("warning", WARNING_TYPES)
def test_deprecated_argument(warning: DeprecationWarningType) -> None:
"""Test deprecate_argument() decorator."""
version = re.escape(warning.version)
match = rf"^Argument kw is deprecated and will be removed in django-ca {version}\.$"

@deprecate_argument("kw", warning)
def func_with_deprecated_kw(unused: Any, kw: str = "default") -> str: # pylint: disable=all
"""Just a test function with a deprecated argument (used in tests)."""
return kw

@contextlib.contextmanager
def assertWarning( # pylint: disable=invalid-name
self, arg: str, cls: DeprecationWarningType = RemovedInNextVersionWarning
) -> Iterator[None]:
"""Shortcut for testing the deprecation warning emitted."""
message = rf"Argument {arg} is deprecated and will be removed"
with self.assertWarnsRegex(cls, message) as warn_cm:
yield
with pytest.warns(warning, match=match):
assert func_with_deprecated_kw("arg", "foobar") == "foobar"
with pytest.warns(warning, match=match):
assert func_with_deprecated_kw("arg", kw="foobar") == "foobar"


@pytest.mark.parametrize("warning", WARNING_TYPES)
def test_deprecated_argument_not_passed(warning: DeprecationWarningType) -> None:
"""Test deprecate_argument() decorator when deprecated argument is not passed."""

@deprecate_argument("kw", warning)
def func_with_deprecated_kw(unused: Any, kw: str = "default") -> str: # pylint: disable=all
"""Just a test function with a deprecated argument (used in tests)."""
return kw

assert func_with_deprecated_kw("arg") == "default"


# make sure that the stacklevel is correct and the warning is issue from this file (= file where
# function is called)
self.assertEqual(warn_cm.filename, __file__)
@pytest.mark.parametrize("typ", (int, (int, set)))
@pytest.mark.parametrize("warning", WARNING_TYPES)
def test_deprecate_type(
typ: Union[type[Any], tuple[type[Any], ...]], warning: DeprecationWarningType
) -> None:
"""Test the deprecate_type() operator."""
version = re.escape(warning.version)
match = rf"^Passing int for arg is deprecated and will be removed in django-ca {version}\.$"

def test_basic(self) -> None:
"""Really basic test of the decorator."""
self.assertEqual(self.func("arg"), "default") # no kwarg -> no warning
@deprecate_type("arg", typ, warning)
def func_with_deprecated_type(arg: str) -> None:
pass

with self.assertWarning("kw"):
self.assertEqual(self.func("arg", "foobar"), "foobar")
with pytest.warns(warning, match=match):
func_with_deprecated_type(3) # type: ignore[arg-type] # what we're testing

with self.assertWarning("kw"):
self.assertEqual(self.func("arg", kw="foobar"), "foobar")
# no warning if called with correct type:
func_with_deprecated_type("foo")

0 comments on commit 3afe24b

Please sign in to comment.