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]