codeant-ai-for-open-source[bot] commented on code in PR #39914: URL: https://github.com/apache/superset/pull/39914#discussion_r3476539154
########## superset/utils/slack.py: ########## @@ -34,6 +36,33 @@ logger = logging.getLogger(__name__) +_SLACK_V1_DEPRECATION_MESSAGE = ( + "Slack v1 (the legacy `Slack` recipient type and `files.upload` API) is " + "deprecated and will be removed in the next major release. Slack retired " + "the `files.upload` endpoint in 2025, so v1 file uploads no longer work; " + "only text-only `chat_postMessage` sends still succeed. Grant your Slack " + "bot the `channels:read` (and `groups:read` if you use private channels) " + "scopes so existing v1 recipients can be auto-upgraded to SlackV2 on " + "their next send." +) + + +# functools.cache gives us a process-lifetime, thread-safe one-shot guard +# without the read-then-write race that bare module globals would have under +# multi-threaded WSGI workers. The cached return value (None) is irrelevant — +# we only care that the body executes at most once per process. [email protected] +def _emit_v1_flag_off_deprecation() -> None: + warnings.warn(_SLACK_V1_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=3) + logger.warning( + "ALERT_REPORT_SLACK_V2 is disabled; %s", _SLACK_V1_DEPRECATION_MESSAGE + ) + + [email protected] +def _emit_v1_scope_missing_deprecation() -> None: + warnings.warn(_SLACK_V1_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=3) + Review Comment: **Suggestion:** Add an inline docstring to this newly introduced helper function to clarify that it emits the scope-related deprecation warning once per process. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This is also a newly added Python function and it lacks a docstring. The rule explicitly flags new functions/classes without docstrings, so the suggestion correctly identifies a valid violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=ff3817987da24b038cae8b7eacdfb167&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=ff3817987da24b038cae8b7eacdfb167&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/utils/slack.py **Line:** 62:65 **Comment:** *Custom Rule: Add an inline docstring to this newly introduced helper function to clarify that it emits the scope-related deprecation warning once per process. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=39d4a88bb53f3ad67ca0dfafc2363467a449b68feb9fb258bda13fe9c3c1fc15&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=39d4a88bb53f3ad67ca0dfafc2363467a449b68feb9fb258bda13fe9c3c1fc15&reaction=dislike'>👎</a> ########## superset/utils/slack.py: ########## @@ -34,6 +36,33 @@ logger = logging.getLogger(__name__) +_SLACK_V1_DEPRECATION_MESSAGE = ( + "Slack v1 (the legacy `Slack` recipient type and `files.upload` API) is " + "deprecated and will be removed in the next major release. Slack retired " + "the `files.upload` endpoint in 2025, so v1 file uploads no longer work; " + "only text-only `chat_postMessage` sends still succeed. Grant your Slack " + "bot the `channels:read` (and `groups:read` if you use private channels) " + "scopes so existing v1 recipients can be auto-upgraded to SlackV2 on " + "their next send." +) + + +# functools.cache gives us a process-lifetime, thread-safe one-shot guard +# without the read-then-write race that bare module globals would have under +# multi-threaded WSGI workers. The cached return value (None) is irrelevant — +# we only care that the body executes at most once per process. [email protected] +def _emit_v1_flag_off_deprecation() -> None: + warnings.warn(_SLACK_V1_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=3) + logger.warning( + "ALERT_REPORT_SLACK_V2 is disabled; %s", _SLACK_V1_DEPRECATION_MESSAGE + ) Review Comment: **Suggestion:** Add an inline docstring to this newly introduced helper function to document when the deprecation warning is emitted and why it is cached. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This is a newly added Python function and it has no docstring in the final file state. The custom rule requires newly introduced functions and classes to include docstrings, so this is a real violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=1bb40477a315477c99609c911356c91e&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=1bb40477a315477c99609c911356c91e&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** superset/utils/slack.py **Line:** 50:59 **Comment:** *Custom Rule: Add an inline docstring to this newly introduced helper function to document when the deprecation warning is emitted and why it is cached. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=d673f50b49d9863495463623d5e6d5ca2ea543cd7bc39612828b28021ada4581&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=d673f50b49d9863495463623d5e6d5ca2ea543cd7bc39612828b28021ada4581&reaction=dislike'>👎</a> ########## tests/unit_tests/reports/notifications/slack_tests.py: ########## @@ -431,3 +465,524 @@ def test_slack_mixin_get_body_truncates_large_table( ) body = notification._get_body(content=content) assert "(table was truncated)" in body + + +# --------------------------------------------------------------------------- +# Bulletproof v2 send-path coverage +# +# The tests above exercise the chat_postMessage path (text-only sends). The +# tests below cover files_upload_v2 across screenshots/CSV/PDF, multi-channel +# fan-out, exception mapping, backoff, statsd, and logs propagation. Together +# they guarantee that every observable behavior of SlackV2Notification.send() +# is locked down before Slack v1 is removed. +# --------------------------------------------------------------------------- + + +def _make_v2_notification(content, target: str = "C12345"): + """Helper to build a SlackV2Notification with a given target string.""" + from superset.reports.models import ReportRecipients, ReportRecipientType + + return SlackV2Notification( + recipient=ReportRecipients( + type=ReportRecipientType.SLACKV2, + recipient_config_json=f'{{"target": "{target}"}}', + ), + content=content, + ) + + +def _make_content(mock_header_data, **overrides): + """Helper to build a minimal NotificationContent.""" + from superset.reports.notifications.base import NotificationContent + + defaults: dict = { + "name": "test alert", + "header_data": mock_header_data, + "description": "desc", + } + defaults.update(overrides) + return NotificationContent(**defaults) + + +@patch("superset.reports.notifications.slackv2.g") +@patch("superset.reports.notifications.slackv2.get_slack_client") +def test_v2_send_with_single_screenshot_calls_files_upload_v2( + slack_client_mock: MagicMock, + flask_global_mock: MagicMock, + mock_header_data, +) -> None: + flask_global_mock.logs_context = {"execution_id": uuid.uuid4()} + content = _make_content(mock_header_data, screenshots=[b"screenshot-bytes"]) + notification = _make_v2_notification(content, target="C12345") + + notification.send() + + upload = slack_client_mock.return_value.files_upload_v2 + upload.assert_called_once() + kwargs = upload.call_args.kwargs + assert kwargs["channel"] == "C12345" + assert kwargs["file"] == b"screenshot-bytes" + assert kwargs["title"] == "test alert" + assert kwargs["filename"] == "test alert.png" + assert "test alert" in kwargs["initial_comment"] + # chat_postMessage should NOT be called when files are present + slack_client_mock.return_value.chat_postMessage.assert_not_called() + + +@patch("superset.reports.notifications.slackv2.g") +@patch("superset.reports.notifications.slackv2.get_slack_client") +def test_v2_send_with_multiple_screenshots_uploads_each( + slack_client_mock: MagicMock, + flask_global_mock: MagicMock, + mock_header_data, +) -> None: + flask_global_mock.logs_context = {} + content = _make_content( + mock_header_data, screenshots=[b"shot-1", b"shot-2", b"shot-3"] + ) + notification = _make_v2_notification(content, target="C12345") + + notification.send() + + upload = slack_client_mock.return_value.files_upload_v2 + assert upload.call_count == 3 + uploaded_files = [c.kwargs["file"] for c in upload.call_args_list] + assert uploaded_files == [b"shot-1", b"shot-2", b"shot-3"] + # All three uploads target the same single channel + for c in upload.call_args_list: + assert c.kwargs["channel"] == "C12345" + assert c.kwargs["filename"] == "test alert.png" + + +@patch("superset.reports.notifications.slackv2.g") +@patch("superset.reports.notifications.slackv2.get_slack_client") +def test_v2_send_with_csv_calls_files_upload_v2( + slack_client_mock: MagicMock, + flask_global_mock: MagicMock, + mock_header_data, +) -> None: + flask_global_mock.logs_context = {} Review Comment: **Suggestion:** Add a short docstring describing the scenario and assertion intent for this newly introduced test function. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This newly introduced test function has no docstring. The custom rule requires newly added Python functions and classes to include docstrings, so the suggestion correctly identifies a real violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=95b366198a0d4d4aaa529f6b094322dd&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=95b366198a0d4d4aaa529f6b094322dd&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/reports/notifications/slack_tests.py **Line:** 559:564 **Comment:** *Custom Rule: Add a short docstring describing the scenario and assertion intent for this newly introduced test function. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=39165f686390284545e0730d7035f8c378f2c3199d62a9af5ed15d911a957496&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=39165f686390284545e0730d7035f8c378f2c3199d62a9af5ed15d911a957496&reaction=dislike'>👎</a> ########## tests/unit_tests/reports/notifications/slack_tests.py: ########## @@ -431,3 +465,524 @@ def test_slack_mixin_get_body_truncates_large_table( ) body = notification._get_body(content=content) assert "(table was truncated)" in body + + +# --------------------------------------------------------------------------- +# Bulletproof v2 send-path coverage +# +# The tests above exercise the chat_postMessage path (text-only sends). The +# tests below cover files_upload_v2 across screenshots/CSV/PDF, multi-channel +# fan-out, exception mapping, backoff, statsd, and logs propagation. Together +# they guarantee that every observable behavior of SlackV2Notification.send() +# is locked down before Slack v1 is removed. +# --------------------------------------------------------------------------- + + +def _make_v2_notification(content, target: str = "C12345"): + """Helper to build a SlackV2Notification with a given target string.""" + from superset.reports.models import ReportRecipients, ReportRecipientType + + return SlackV2Notification( + recipient=ReportRecipients( + type=ReportRecipientType.SLACKV2, + recipient_config_json=f'{{"target": "{target}"}}', + ), + content=content, + ) + + +def _make_content(mock_header_data, **overrides): + """Helper to build a minimal NotificationContent.""" + from superset.reports.notifications.base import NotificationContent + + defaults: dict = { + "name": "test alert", + "header_data": mock_header_data, + "description": "desc", + } + defaults.update(overrides) + return NotificationContent(**defaults) + + +@patch("superset.reports.notifications.slackv2.g") +@patch("superset.reports.notifications.slackv2.get_slack_client") +def test_v2_send_with_single_screenshot_calls_files_upload_v2( + slack_client_mock: MagicMock, + flask_global_mock: MagicMock, + mock_header_data, +) -> None: Review Comment: **Suggestion:** Add a concrete type hint for `mock_header_data` in this new test signature to keep new function parameters fully typed. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This newly added test function leaves `mock_header_data` untyped while surrounding code in the same file is being changed. The custom rule explicitly flags new or modified Python functions that omit type hints, so the suggestion is valid. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=69eebef1f6a8469d8ee59f726bf2c103&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=69eebef1f6a8469d8ee59f726bf2c103&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/reports/notifications/slack_tests.py **Line:** 509:513 **Comment:** *Custom Rule: Add a concrete type hint for `mock_header_data` in this new test signature to keep new function parameters fully typed. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=3acc9ea098c4860326a35c7fcf7e4964198e9003522353e50d9edc1de2adb64e&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=3acc9ea098c4860326a35c7fcf7e4964198e9003522353e50d9edc1de2adb64e&reaction=dislike'>👎</a> ########## tests/unit_tests/reports/notifications/slack_tests.py: ########## @@ -431,3 +465,524 @@ def test_slack_mixin_get_body_truncates_large_table( ) body = notification._get_body(content=content) assert "(table was truncated)" in body + + +# --------------------------------------------------------------------------- +# Bulletproof v2 send-path coverage +# +# The tests above exercise the chat_postMessage path (text-only sends). The +# tests below cover files_upload_v2 across screenshots/CSV/PDF, multi-channel +# fan-out, exception mapping, backoff, statsd, and logs propagation. Together +# they guarantee that every observable behavior of SlackV2Notification.send() +# is locked down before Slack v1 is removed. +# --------------------------------------------------------------------------- + + +def _make_v2_notification(content, target: str = "C12345"): Review Comment: **Suggestion:** Add explicit type hints for the `content` parameter and return type so this new helper is fully typed. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This is a newly added Python helper function and it omits type hints for the `content` parameter and the return value. The rule requires new Python code to be fully typed, so this is a real violation. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=c204c08fa6e945a7848ae4e15fd98426&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=c204c08fa6e945a7848ae4e15fd98426&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/reports/notifications/slack_tests.py **Line:** 481:481 **Comment:** *Custom Rule: Add explicit type hints for the `content` parameter and return type so this new helper is fully typed. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=ee3801e1dcccb3aee9782a266c69d4edb9475f46cf2c37961ba2457f7782e7db&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=ee3801e1dcccb3aee9782a266c69d4edb9475f46cf2c37961ba2457f7782e7db&reaction=dislike'>👎</a> ########## tests/unit_tests/reports/notifications/slack_tests.py: ########## @@ -431,3 +465,524 @@ def test_slack_mixin_get_body_truncates_large_table( ) body = notification._get_body(content=content) assert "(table was truncated)" in body + + +# --------------------------------------------------------------------------- +# Bulletproof v2 send-path coverage +# +# The tests above exercise the chat_postMessage path (text-only sends). The +# tests below cover files_upload_v2 across screenshots/CSV/PDF, multi-channel +# fan-out, exception mapping, backoff, statsd, and logs propagation. Together +# they guarantee that every observable behavior of SlackV2Notification.send() +# is locked down before Slack v1 is removed. +# --------------------------------------------------------------------------- + + +def _make_v2_notification(content, target: str = "C12345"): + """Helper to build a SlackV2Notification with a given target string.""" + from superset.reports.models import ReportRecipients, ReportRecipientType + + return SlackV2Notification( + recipient=ReportRecipients( + type=ReportRecipientType.SLACKV2, + recipient_config_json=f'{{"target": "{target}"}}', + ), + content=content, + ) + + +def _make_content(mock_header_data, **overrides): Review Comment: **Suggestion:** Add type annotations for `mock_header_data`, `overrides`, and the function return value to comply with full typing requirements for new functions. [custom_rule] **Severity Level:** Minor ⚠️ <details> <summary><b>Why it matters? 🤔 </b></summary> This newly added helper function has no type hints for `mock_header_data`, the variadic `overrides`, or the return type. That violates the rule requiring new Python code to be fully typed. </details> [](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=6f913561f0324481b555033d1061c1c3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=6f913561f0324481b555033d1061c1c3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) *(Use Cmd/Ctrl + Click for best experience)* <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** tests/unit_tests/reports/notifications/slack_tests.py **Line:** 494:494 **Comment:** *Custom Rule: Add type annotations for `mock_header_data`, `overrides`, and the function return value to comply with full typing requirements for new functions. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix ``` </details> <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=354c6afd29385112a7239f0ada4305b90fb06016880dd6b968c74f1a7687d3d4&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39914&comment_hash=354c6afd29385112a7239f0ada4305b90fb06016880dd6b968c74f1a7687d3d4&reaction=dislike'>👎</a> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
