You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/04 19:03:44 UTC

(superset) branch master updated: fix(reports): stamp email subject date at send time, not import time (#40693)

This is an automated email from the ASF dual-hosted git repository.

rusackas 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 9a31362fa5e fix(reports): stamp email subject date at send time, not import time (#40693)
9a31362fa5e is described below

commit 9a31362fa5ed16c8a1b7daf092bb5d944f4eafa8
Author: Evan Rusackas <ev...@preset.io>
AuthorDate: Thu Jun 4 12:03:28 2026 -0700

    fix(reports): stamp email subject date at send time, not import time (#40693)
    
    Co-authored-by: Claude Opus 4.8 <no...@anthropic.com>
---
 superset/reports/notifications/email.py             | 16 +++++++++++++---
 .../unit_tests/reports/notifications/email_tests.py | 21 +++++++++++++++------
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/superset/reports/notifications/email.py b/superset/reports/notifications/email.py
index 4c172afd791..b0485d21828 100644
--- a/superset/reports/notifications/email.py
+++ b/superset/reports/notifications/email.py
@@ -28,8 +28,8 @@ from pytz import timezone
 
 from superset import is_feature_enabled
 from superset.exceptions import SupersetErrorsException
-from superset.reports.models import ReportRecipientType
-from superset.reports.notifications.base import BaseNotification
+from superset.reports.models import ReportRecipients, ReportRecipientType
+from superset.reports.notifications.base import BaseNotification, NotificationContent
 from superset.reports.notifications.exceptions import NotificationError
 from superset.utils import json
 from superset.utils.core import HeaderDataType, send_email_smtp
@@ -83,7 +83,17 @@ class EmailNotification(BaseNotification):  # pylint: disable=too-few-public-met
     """
 
     type = ReportRecipientType.EMAIL
-    now = datetime.now(timezone("UTC"))
+
+    def __init__(
+        self, recipient: ReportRecipients, content: NotificationContent
+    ) -> None:
+        super().__init__(recipient, content)
+        # Stamp each notification with its own timestamp at construction, which
+        # happens per recipient immediately before the email is dispatched. The
+        # date rendered into the subject (when DATE_FORMAT_IN_EMAIL_SUBJECT is
+        # enabled) therefore tracks the dispatch time. A module- or class-level
+        # value would instead freeze on the first import in a long-running worker.
+        self.now = datetime.now(timezone("UTC"))
 
     @property
     def _name(self) -> str:
diff --git a/tests/unit_tests/reports/notifications/email_tests.py b/tests/unit_tests/reports/notifications/email_tests.py
index 54fb2d4b30e..b7dcc1df2d7 100644
--- a/tests/unit_tests/reports/notifications/email_tests.py
+++ b/tests/unit_tests/reports/notifications/email_tests.py
@@ -17,6 +17,7 @@
 from datetime import datetime
 
 import pandas as pd
+from freezegun import freeze_time
 from pytz import timezone
 
 from tests.unit_tests.conftest import with_feature_flags
@@ -107,8 +108,6 @@ def test_email_subject_with_datetime() -> None:
     from superset.reports.notifications.base import NotificationContent
     from superset.reports.notifications.email import EmailNotification
 
-    now = datetime.now(timezone("UTC"))
-
     datetime_pattern = "%Y-%m-%d"
 
     content = NotificationContent(
@@ -130,8 +129,18 @@ def test_email_subject_with_datetime() -> None:
             "execution_id": "test-execution-id",
         },
     )
-    subject = EmailNotification(
-        recipient=ReportRecipients(type=ReportRecipientType.EMAIL), content=content
-    )._get_subject()
+    # Freeze the clock to a fixed, distinctive instant and construct the
+    # notification *under* the freeze. The subject date must reflect this
+    # frozen moment, which is only possible if the timestamp is stamped per
+    # instance at construction/send time. If the timestamp were a class
+    # attribute evaluated at import time (the regression this fixes), it would
+    # carry the real import-time date instead and this assertion would fail.
+    frozen_now = datetime(2021, 4, 22, 12, 0, 0, tzinfo=timezone("UTC"))
+    with freeze_time(frozen_now):
+        notification = EmailNotification(
+            recipient=ReportRecipients(type=ReportRecipientType.EMAIL),
+            content=content,
+        )
+        subject = notification._get_subject()
     assert datetime_pattern not in subject
-    assert now.strftime(datetime_pattern) in subject
+    assert frozen_now.strftime(datetime_pattern) in subject