You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2026/07/02 23:10:43 UTC
(superset) branch master updated: fix(views): emit deprecated-endpoint log warning once per endpoint per process (#41286)
This is an automated email from the ASF dual-hosted git repository.
eschutho pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new d8832c382d4 fix(views): emit deprecated-endpoint log warning once per endpoint per process (#41286)
d8832c382d4 is described below
commit d8832c382d41f5a734d2c86a2772e4320fa4bcdb
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Thu Jul 2 16:10:37 2026 -0700
fix(views): emit deprecated-endpoint log warning once per endpoint per process (#41286)
---
superset/views/base.py | 31 ++++++++++++++++++-------------
tests/unit_tests/views/test_base.py | 21 +++++++++++++++++++++
2 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/superset/views/base.py b/superset/views/base.py
index 6b6f662fa9b..1cc51100c34 100644
--- a/superset/views/base.py
+++ b/superset/views/base.py
@@ -174,20 +174,25 @@ def deprecated(
"""
def _deprecated(f: Callable[..., FlaskResponse]) -> Callable[..., FlaskResponse]:
+ _warned = False
+
def wraps(self: BaseSupersetView, *args: Any, **kwargs: Any) -> FlaskResponse:
- message = (
- "%s.%s "
- "This API endpoint is deprecated and will be removed in version %s"
- )
- logger_args = [
- self.__class__.__name__,
- f.__name__,
- eol_version,
- ]
- if new_target:
- message += " . Use the following API endpoint instead: %s"
- logger_args.append(new_target)
- logger.warning(message, *logger_args)
+ nonlocal _warned
+ if not _warned:
+ _warned = True
+ message = (
+ "%s.%s "
+ "This API endpoint is deprecated and will be removed in version %s"
+ )
+ logger_args = [
+ self.__class__.__name__,
+ f.__name__,
+ eol_version,
+ ]
+ if new_target:
+ message += " . Use the following API endpoint instead: %s"
+ logger_args.append(new_target)
+ logger.warning(message, *logger_args)
return f(self, *args, **kwargs)
return functools.update_wrapper(wraps, f)
diff --git a/tests/unit_tests/views/test_base.py b/tests/unit_tests/views/test_base.py
index fc315c5b848..dc28209a983 100644
--- a/tests/unit_tests/views/test_base.py
+++ b/tests/unit_tests/views/test_base.py
@@ -272,3 +272,24 @@ def test_csv_response_leaves_bytes_untouched() -> None:
payload = "Ürün\n".encode("utf-8-sig")
assert CsvResponse(payload).get_data() == payload
+
+
+def test_deprecated_logs_warning_exactly_once() -> None:
+ from superset.views.base import BaseSupersetView, deprecated
+
+ @deprecated(eol_version="5.0.0", new_target="/api/v1/chart/data")
+ def endpoint(self: BaseSupersetView) -> None:
+ return None
+
+ view = MagicMock(spec=BaseSupersetView)
+ view.__class__.__name__ = "Superset"
+
+ with patch("superset.views.base.logger") as mock_logger:
+ endpoint(view)
+ endpoint(view)
+
+ assert mock_logger.warning.call_count == 1
+ # logger.warning uses lazy %-style formatting, so the version is a
+ # separate positional arg rather than being interpolated into the
+ # message template string itself.
+ assert "5.0.0" in mock_logger.warning.call_args[0]