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 c503f92642a fix(charts): restrict Prophet time grain schema validation 
to supported Prophet grains (#43585)
c503f92642a is described below

commit c503f92642ac5566f4dc0e6a91079477abdd01f5
Author: Francesco.Castaldi <[email protected]>
AuthorDate: Wed Sep 9 06:43:33 2026 +0200

    fix(charts): restrict Prophet time grain schema validation to supported 
Prophet grains (#43585)
    
    Co-authored-by: FrancescoCastaldi <[email protected]>
---
 superset/charts/schemas.py              | 14 ++++++++++++--
 tests/unit_tests/charts/test_schemas.py | 24 +++++++++++++++++-------
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py
index 75c3320b705..cd43524f20c 100644
--- a/superset/charts/schemas.py
+++ b/superset/charts/schemas.py
@@ -48,6 +48,7 @@ from superset.utils.core import (
     PostProcessingBoxplotWhiskerType,
     PostProcessingContributionOrientation,
 )
+from superset.utils.pandas_postprocessing.utils import PROPHET_TIME_GRAIN_MAP
 
 if TYPE_CHECKING:
     from superset.common.query_context import QueryContext
@@ -73,6 +74,15 @@ def get_time_grain_choices() -> Any:
     ]
 
 
+def validate_time_grain_sqla(value: Any) -> None:
+    """Ensure the time grain is supported by the configured engine specs."""
+    choices = get_time_grain_choices()
+    validate.OneOf(
+        choices=choices,
+        error=_("Must be one of: {choices}."),
+    )(value)
+
+
 # Fallback upper bound for the number of Prophet forecast periods when the
 # application config cannot be read (for example, outside of an app context).
 DEFAULT_MAX_PROPHET_PERIODS = 10000
@@ -778,7 +788,7 @@ class 
ChartDataProphetOptionsSchema(ChartDataPostProcessingOperationOptionsSchem
             "[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) 
durations.",
             "example": "P1D",
         },
-        validate=validate.OneOf(choices=get_time_grain_choices()),
+        validate=validate.OneOf(choices=tuple(PROPHET_TIME_GRAIN_MAP.keys())),
         required=True,
     )
     periods = fields.Integer(
@@ -1167,7 +1177,7 @@ class ChartDataExtrasSchema(Schema):
             "[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) 
durations.",
             "example": "P1D",
         },
-        validate=validate.OneOf(choices=get_time_grain_choices()),
+        validate=validate_time_grain_sqla,
         allow_none=True,
     )
     instant_time_comparison_range = fields.String(
diff --git a/tests/unit_tests/charts/test_schemas.py 
b/tests/unit_tests/charts/test_schemas.py
index 6610ab18147..9960b0cc2e2 100644
--- a/tests/unit_tests/charts/test_schemas.py
+++ b/tests/unit_tests/charts/test_schemas.py
@@ -352,21 +352,31 @@ def 
test_chart_data_query_object_schema_deprecated_fields_renamed(
 
 @pytest.mark.parametrize(
     "app",
-    [{"TIME_GRAIN_ADDONS": {"PT10M": "10 minutes"}}],
+    [{"TIME_GRAIN_ADDONS": {"PT7M": "7 minutes"}}],
     indirect=True,
 )
 def test_time_grain_validation_with_config_addons(app_context: None) -> None:
-    """Test that validation includes TIME_GRAIN_ADDONS from config"""
-    schema = ChartDataProphetOptionsSchema()
+    """
+    Test that custom TIME_GRAIN_ADDONS are accepted by ChartDataExtrasSchema
+    (SQLA) but rejected by ChartDataProphetOptionsSchema (which only supports
+    mapped Prophet grains).
+    """
+    # Custom addon grain is valid for SQLA time grain
+    extras_schema = ChartDataExtrasSchema()
+    extras_result = extras_schema.load({"time_grain_sqla": "PT7M"})
+    assert extras_result["time_grain_sqla"] == "PT7M"
 
-    # Custom time grain should now be valid
+    # Custom addon grain is not supported by Prophet and should be rejected
+    prophet_schema = ChartDataProphetOptionsSchema()
     custom_data = {
-        "time_grain": "PT10M",
+        "time_grain": "PT7M",
         "periods": 5,
         "confidence_interval": 0.9,
     }
-    result = schema.load(custom_data)
-    assert result["time_grain"] == "PT10M"
+    with pytest.raises(ValidationError) as exc_info:
+        prophet_schema.load(custom_data)
+    assert "time_grain" in exc_info.value.messages
+    assert "Must be one of" in str(exc_info.value.messages["time_grain"])
 
 
 def test_prophet_periods_within_bound(app_context: None) -> None:

Reply via email to