Skip to content

Commit

Permalink
Remove deprecate_function and deprecate_arguments decorators (dep…
Browse files Browse the repository at this point in the history
…recated in 0.24) (#13448)

* remove deprecated_function and deprecated_argument decorators

* reno

* Update releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml

Co-authored-by: Elena Peña Tapia <[email protected]>

---------

Co-authored-by: Elena Peña Tapia <[email protected]>
(cherry picked from commit 1ae287b)
  • Loading branch information
1ucian0 authored and mergify[bot] committed Dec 2, 2024
1 parent 896d1c8 commit 6ce5be4
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 208 deletions.
6 changes: 0 additions & 6 deletions qiskit/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
.. autofunction:: add_deprecation_to_docstring
.. autofunction:: deprecate_arg
.. autofunction:: deprecate_arguments
.. autofunction:: deprecate_func
.. autofunction:: deprecate_function
SI unit conversion
==================
Expand Down Expand Up @@ -58,9 +56,7 @@
from .deprecation import (
add_deprecation_to_docstring,
deprecate_arg,
deprecate_arguments,
deprecate_func,
deprecate_function,
)
from .multiprocessing import local_hardware_info
from .multiprocessing import is_main_process
Expand All @@ -78,9 +74,7 @@
"LazySubprocessTester",
"add_deprecation_to_docstring",
"deprecate_arg",
"deprecate_arguments",
"deprecate_func",
"deprecate_function",
"local_hardware_info",
"is_main_process",
"apply_prefix",
Expand Down
108 changes: 0 additions & 108 deletions qiskit/utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,114 +205,6 @@ def wrapper(*args, **kwargs):
return decorator


def deprecate_arguments(
kwarg_map: dict[str, str | None],
category: Type[Warning] = DeprecationWarning,
*,
since: str | None = None,
):
"""Deprecated. Instead, use `@deprecate_arg`.
Args:
kwarg_map: A dictionary of the old argument name to the new name.
category: Usually either DeprecationWarning or PendingDeprecationWarning.
since: The version the deprecation started at. Only Optional for backwards
compatibility - this should always be set. If the deprecation is pending, set
the version to when that started; but later, when switching from pending to
deprecated, update `since` to the new version.
Returns:
Callable: The decorated callable.
"""

def decorator(func):
func_name = func.__qualname__
old_kwarg_to_msg = {}
for old_arg, new_arg in kwarg_map.items():
msg_suffix = (
"will in the future be removed." if new_arg is None else f"replaced with {new_arg}."
)
old_kwarg_to_msg[old_arg] = (
f"{func_name} keyword argument {old_arg} is deprecated and {msg_suffix}"
)

@functools.wraps(func)
def wrapper(*args, **kwargs):
for old, new in kwarg_map.items():
_maybe_warn_and_rename_kwarg(
args,
kwargs,
func_name=func_name,
original_func_co_varnames=wrapper.__original_func_co_varnames,
old_arg_name=old,
new_alias=new,
warning_msg=old_kwarg_to_msg[old],
category=category,
predicate=None,
)
return func(*args, **kwargs)

# When decorators get called repeatedly, `func` refers to the result of the prior
# decorator, not the original underlying function. This trick allows us to record the
# original function's variable names regardless of how many decorators are used.
#
# If it's the very first decorator call, we also check that *args and **kwargs are not used.
if hasattr(func, "__original_func_co_varnames"):
wrapper.__original_func_co_varnames = func.__original_func_co_varnames
else:
wrapper.__original_func_co_varnames = func.__code__.co_varnames
param_kinds = {param.kind for param in inspect.signature(func).parameters.values()}
if inspect.Parameter.VAR_POSITIONAL in param_kinds:
raise ValueError(
"@deprecate_arg cannot be used with functions that take variable *args. Use "
"warnings.warn() directly instead."
)

for msg in old_kwarg_to_msg.values():
add_deprecation_to_docstring(
wrapper, msg, since=since, pending=issubclass(category, PendingDeprecationWarning)
)
return wrapper

return decorator


def deprecate_function(
msg: str,
stacklevel: int = 2,
category: Type[Warning] = DeprecationWarning,
*,
since: str | None = None,
):
"""Deprecated. Instead, use `@deprecate_func`.
Args:
msg: Warning message to emit.
stacklevel: The warning stacklevel to use, defaults to 2.
category: Usually either DeprecationWarning or PendingDeprecationWarning.
since: The version the deprecation started at. Only Optional for backwards
compatibility - this should always be set. If the deprecation is pending, set
the version to when that started; but later, when switching from pending to
deprecated, update `since` to the new version.
Returns:
Callable: The decorated, deprecated callable.
"""

def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel)
return func(*args, **kwargs)

add_deprecation_to_docstring(
wrapper, msg, since=since, pending=issubclass(category, PendingDeprecationWarning)
)
return wrapper

return decorator


def _maybe_warn_and_rename_kwarg(
args: tuple[Any, ...],
kwargs: dict[str, Any],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
upgrade_misc:
- |
The ``deprecate_function`` and ``deprecate_arguments`` decorators had been deprecated since 0.24, released
on May 2023, and have been removed in 2.0.
Current :func:`deprecate_func`` replaces ``@deprecate_function`` and current
:func:`deprecate_arg` replaces ``@deprecate_arguments``.
94 changes: 0 additions & 94 deletions test/python/utils/test_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
from qiskit.utils.deprecation import (
add_deprecation_to_docstring,
deprecate_arg,
deprecate_arguments,
deprecate_func,
deprecate_function,
)
from test import QiskitTestCase # pylint: disable=wrong-import-order

Expand Down Expand Up @@ -164,51 +162,6 @@ def my_func() -> None:
),
)

def test_deprecate_arguments_docstring(self) -> None:
"""Test that `@deprecate_arguments` adds the correct message to the docstring."""

@deprecate_arguments(
{"old_arg1": "new_arg1", "old_arg2": None},
category=PendingDeprecationWarning,
since="9.99",
)
def my_func() -> None:
pass

self.assertEqual(
my_func.__doc__,
dedent(
f"""\
.. deprecated:: 9.99_pending
{my_func.__qualname__} keyword argument old_arg1 is deprecated and replaced with \
new_arg1.
.. deprecated:: 9.99_pending
{my_func.__qualname__} keyword argument old_arg2 is deprecated and will in the \
future be removed.
"""
),
)

def test_deprecate_function_docstring(self) -> None:
"""Test that `@deprecate_function` adds the correct message to the docstring."""

@deprecate_function("Stop using my_func!", since="9.99")
def my_func() -> None:
pass

self.assertEqual(
my_func.__doc__,
dedent(
"""\
.. deprecated:: 9.99
Stop using my_func!
"""
),
)

def test_deprecate_func_runtime_warning(self) -> None:
"""Test that `@deprecate_func` warns whenever the function is used."""

Expand Down Expand Up @@ -313,53 +266,6 @@ def my_func2(my_kwarg: int | None = None, **kwargs) -> None:
with self.assertWarnsRegex(DeprecationWarning, "my_kwarg"):
my_func2(my_kwarg=5, another_arg=0, yet_another=0)

def test_deprecate_arguments_runtime_warning(self) -> None:
"""Test that `@deprecate_arguments` warns whenever the arguments are used.
Also check that old arguments are passed in as their new alias.
"""

@deprecate_arguments({"arg1": "new_arg1", "arg2": None}, since="9.99")
def my_func(arg1: str = "a", arg2: str = "a", new_arg1: str | None = None) -> None:
del arg2
# If the old arg was set, we should set its `new_alias` to that value.
if arg1 != "a":
self.assertEqual(new_arg1, "z")
if new_arg1 is not None:
self.assertEqual(new_arg1, "z")

# No warnings if no deprecated args used.
my_func()
my_func(new_arg1="z")

# Warn if argument is specified, regardless of positional vs kwarg.
with self.assertWarnsRegex(DeprecationWarning, "arg1"):
my_func("z")
with self.assertWarnsRegex(DeprecationWarning, "arg1"):
my_func(arg1="z")
with self.assertWarnsRegex(DeprecationWarning, "arg2"):
my_func("z", "z")
with self.assertWarnsRegex(DeprecationWarning, "arg2"):
my_func(arg2="z")

# Error if new_alias specified at the same time as old argument name.
with self.assertRaises(TypeError):
my_func("a", new_arg1="z")
with self.assertRaises(TypeError):
my_func(arg1="a", new_arg1="z")
with self.assertRaises(TypeError):
my_func("a", "a", "z")

def test_deprecate_function_runtime_warning(self) -> None:
"""Test that `@deprecate_function` warns whenever the function is used."""

@deprecate_function("Stop using my_func!", since="9.99")
def my_func() -> None:
pass

with self.assertWarnsRegex(DeprecationWarning, "Stop using my_func!"):
my_func()


class AddDeprecationDocstringTest(QiskitTestCase):
"""Test that we correctly insert the deprecation directive at the right location.
Expand Down

0 comments on commit 6ce5be4

Please sign in to comment.