Skip to content

Commit 0da8c8c

Browse files
authored
chore: Add decorator @deprecated and @pending_deprecation (#2889)
1 parent 2cc79f8 commit 0da8c8c

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

samtranslator/internal/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""
2+
The module for samtranslator internal implementations.
3+
4+
External packages should not import anything from it
5+
as all interfaces are subject to change without warning.
6+
"""
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Utils for deprecating our code using warning.warn().
3+
The warning message is written to stderr when shown.
4+
5+
For the difference between DeprecationWarning
6+
and other deprecation warning classes, refer to
7+
https://peps.python.org/pep-0565/#additional-use-case-for-futurewarning
8+
9+
If external packages import deprecated interfaces,
10+
it is their responsibility to detect and remove them.
11+
"""
12+
import warnings
13+
from functools import wraps
14+
from typing import Callable, Optional, TypeVar
15+
16+
RT = TypeVar("RT") # return type
17+
18+
19+
def _make_message(message: str, replacement: Optional[str]) -> str:
20+
return f"{message}, please use {replacement}" if replacement else message
21+
22+
23+
def deprecated(replacement: Optional[str]) -> Callable[[Callable[..., RT]], Callable[..., RT]]:
24+
"""
25+
Mark a function/method as deprecated.
26+
27+
The warning is shown by default when triggered directly
28+
by code in __main__.
29+
"""
30+
31+
def decorator(func: Callable[..., RT]) -> Callable[..., RT]:
32+
@wraps(func)
33+
def wrapper(*args, **kwargs) -> RT: # type: ignore
34+
warning_message = _make_message(
35+
f"{func.__name__} is deprecated and will be removed in a future release", replacement
36+
)
37+
# Setting stacklevel=2 to let Python print the line that calls
38+
# this wrapper, not the line below.
39+
warnings.warn(warning_message, DeprecationWarning, stacklevel=2)
40+
return func(*args, **kwargs)
41+
42+
return wrapper
43+
44+
return decorator

samtranslator/model/types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any, Callable, Type, Union
1212

1313
import samtranslator.model.exceptions
14+
from samtranslator.internal.deprecation_control import deprecated
1415

1516
# Validator always looks like def ...(value: Any, should_raise: bool = True) -> bool,
1617
# However, Python type hint doesn't support functions with optional keyword argument
@@ -137,6 +138,7 @@ def validate(value: Any, should_raise: bool = False) -> bool:
137138
return validate
138139

139140

141+
@deprecated(replacement="IS_STR")
140142
def is_str() -> Validator:
141143
"""
142144
For compatibility reason, we need this `is_str()` as it
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import warnings
2+
from unittest import TestCase
3+
4+
from samtranslator.internal.deprecation_control import deprecated
5+
6+
7+
def replacement_function(x, y):
8+
return x + y
9+
10+
11+
@deprecated(replacement="replacement_function")
12+
def deprecated_function(x, y):
13+
return x + y
14+
15+
16+
class TestDeprecationControl(TestCase):
17+
def test_deprecated_decorator(self):
18+
with warnings.catch_warnings(record=True) as w:
19+
deprecated_function(1, 1)
20+
self.assertEqual(len(w), 1)
21+
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
22+
self.assertIn(
23+
"deprecated_function is deprecated and will be removed in a future release, "
24+
"please use replacement_function",
25+
str(w[-1].message),
26+
)

0 commit comments

Comments
 (0)