refactor: replace @deprecated decorator with upcoming native support (via typing-extensions), bump mypy (#1578)

* refactor: replace @deprecated decorator with upcoming native support (via typing-extensions)

* chore: fix tests

* chore: ruff fmt
This commit is contained in:
Erik Wrede 2024-09-29 13:31:24 +02:00 committed by GitHub
parent 48678afba4
commit f95e9221bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 8 additions and 137 deletions

View File

@ -1,67 +1,5 @@
import functools from warnings import warn
import inspect
import warnings
string_types = (type(b""), type(""))
def warn_deprecation(text): def warn_deprecation(text: str):
warnings.warn(text, category=DeprecationWarning, stacklevel=2) warn(text, category=DeprecationWarning, stacklevel=2)
def deprecated(reason):
"""
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used.
"""
if isinstance(reason, string_types):
# The @deprecated is used with a 'reason'.
#
# .. code-block:: python
#
# @deprecated("please, use another function")
# def old_function(x, y):
# pass
def decorator(func1):
if inspect.isclass(func1):
fmt1 = f"Call to deprecated class {func1.__name__} ({reason})."
else:
fmt1 = f"Call to deprecated function {func1.__name__} ({reason})."
@functools.wraps(func1)
def new_func1(*args, **kwargs):
warn_deprecation(fmt1)
return func1(*args, **kwargs)
return new_func1
return decorator
elif inspect.isclass(reason) or inspect.isfunction(reason):
# The @deprecated is used without any 'reason'.
#
# .. code-block:: python
#
# @deprecated
# def old_function(x, y):
# pass
func2 = reason
if inspect.isclass(func2):
fmt2 = f"Call to deprecated class {func2.__name__}."
else:
fmt2 = f"Call to deprecated function {func2.__name__}."
@functools.wraps(func2)
def new_func2(*args, **kwargs):
warn_deprecation(fmt2)
return func2(*args, **kwargs)
return new_func2
else:
raise TypeError(repr(type(reason)))

View File

@ -1,6 +1,5 @@
from functools import wraps from functools import wraps
from typing_extensions import deprecated
from .deprecated import deprecated
@deprecated("This function is deprecated") @deprecated("This function is deprecated")

View File

@ -1,75 +1,9 @@
from pytest import raises
from .. import deprecated from .. import deprecated
from ..deprecated import deprecated as deprecated_decorator
from ..deprecated import warn_deprecation from ..deprecated import warn_deprecation
def test_warn_deprecation(mocker): def test_warn_deprecation(mocker):
mocker.patch.object(deprecated.warnings, "warn") mocker.patch.object(deprecated, "warn")
warn_deprecation("OH!") warn_deprecation("OH!")
deprecated.warnings.warn.assert_called_with( deprecated.warn.assert_called_with("OH!", stacklevel=2, category=DeprecationWarning)
"OH!", stacklevel=2, category=DeprecationWarning
)
def test_deprecated_decorator(mocker):
mocker.patch.object(deprecated, "warn_deprecation")
@deprecated_decorator
def my_func():
return True
result = my_func()
assert result
deprecated.warn_deprecation.assert_called_with(
"Call to deprecated function my_func."
)
def test_deprecated_class(mocker):
mocker.patch.object(deprecated, "warn_deprecation")
@deprecated_decorator
class X:
pass
result = X()
assert result
deprecated.warn_deprecation.assert_called_with("Call to deprecated class X.")
def test_deprecated_decorator_text(mocker):
mocker.patch.object(deprecated, "warn_deprecation")
@deprecated_decorator("Deprecation text")
def my_func():
return True
result = my_func()
assert result
deprecated.warn_deprecation.assert_called_with(
"Call to deprecated function my_func (Deprecation text)."
)
def test_deprecated_class_text(mocker):
mocker.patch.object(deprecated, "warn_deprecation")
@deprecated_decorator("Deprecation text")
class X:
pass
result = X()
assert result
deprecated.warn_deprecation.assert_called_with(
"Call to deprecated class X (Deprecation text)."
)
def test_deprecated_other_object(mocker):
mocker.patch.object(deprecated, "warn_deprecation")
with raises(TypeError):
deprecated_decorator({})

View File

@ -9,6 +9,5 @@ def test_resolve_only_args(mocker):
return root, args return root, args
wrapped_resolver = resolve_only_args(resolver) wrapped_resolver = resolve_only_args(resolver)
assert deprecated.warn_deprecation.called
result = wrapped_resolver(1, 2, a=3) result = wrapped_resolver(1, 2, a=3)
assert result == (1, {"a": 3}) assert result == (1, {"a": 3})

View File

@ -83,6 +83,7 @@ setup(
install_requires=[ install_requires=[
"graphql-core>=3.1,<3.3", "graphql-core>=3.1,<3.3",
"graphql-relay>=3.1,<3.3", "graphql-relay>=3.1,<3.3",
"typing-extensions>=4.7.1,<5",
], ],
tests_require=tests_require, tests_require=tests_require,
extras_require={"test": tests_require, "dev": dev_requires}, extras_require={"test": tests_require, "dev": dev_requires},

View File

@ -20,7 +20,7 @@ commands =
[testenv:mypy] [testenv:mypy]
basepython = python3.10 basepython = python3.10
deps = deps =
mypy>=0.950,<1 mypy>=1.10,<2
commands = commands =
mypy graphene mypy graphene