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

vavila pushed a commit to branch feat/to_datetime_jinja_filter
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 369f1e3f11514b999ae6ad698d8cfd4549604e03
Author: Vitor Avila <[email protected]>
AuthorDate: Thu Mar 20 18:27:03 2025 -0300

    feat(Jinja): to_datetime filter
---
 superset/jinja_context.py              | 19 +++++++++++++
 tests/unit_tests/jinja_context_test.py | 50 ++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/superset/jinja_context.py b/superset/jinja_context.py
index a4d8e6d6a4..0f56886dd2 100644
--- a/superset/jinja_context.py
+++ b/superset/jinja_context.py
@@ -561,6 +561,24 @@ class WhereInMacro:  # pylint: 
disable=too-few-public-methods
         return result
 
 
+def to_datetime(
+    value: str | None, format: str = "%Y-%m-%d %H:%M:%S"
+) -> datetime | None:
+    """
+    Parses a string into a datetime object.
+
+    :param value: the string to parse.
+    :param format: the format to parse the string with.
+    :returns: the parsed datetime object.
+    """
+    if not value:
+        return None
+
+    # This value might come from a macro that could be including wrapping 
quotes
+    value = value.strip("'\"")
+    return datetime.strptime(value, format)
+
+
 class BaseTemplateProcessor:
     """
     Base class for database-specific jinja context
@@ -596,6 +614,7 @@ class BaseTemplateProcessor:
 
         # custom filters
         self.env.filters["where_in"] = WhereInMacro(database.get_dialect())
+        self.env.filters["to_datetime"] = to_datetime
 
     def set_context(self, **kwargs: Any) -> None:
         self._context.update(kwargs)
diff --git a/tests/unit_tests/jinja_context_test.py 
b/tests/unit_tests/jinja_context_test.py
index be6e5fb55e..8764aafc92 100644
--- a/tests/unit_tests/jinja_context_test.py
+++ b/tests/unit_tests/jinja_context_test.py
@@ -17,6 +17,7 @@
 # pylint: disable=invalid-name, unused-argument
 from __future__ import annotations
 
+from datetime import datetime
 from typing import Any
 
 import pytest
@@ -38,6 +39,7 @@ from superset.jinja_context import (
     metric_macro,
     safe_proxy,
     TimeFilter,
+    to_datetime,
     WhereInMacro,
 )
 from superset.models.core import Database
@@ -429,6 +431,54 @@ def test_where_in_empty_list() -> None:
     assert where_in([], default_to_none=True) is None
 
 
+def test_to_datetime() -> None:
+    """
+    Test the ``to_datetime`` Jinja2 filter.
+    """
+
+    result = to_datetime("2025-03-20 15:55:00")
+    assert result == datetime(2025, 3, 20, 15, 55)
+
+    assert to_datetime(None) is None
+
+
+def test_to_datetime_custom_format() -> None:
+    """
+    Test the ``to_datetime`` Jinja2 filter when specifying a format.
+    """
+    result = to_datetime("2025-03-20", format="%Y-%m-%d")
+    assert result == datetime(2025, 3, 20)
+
+
+def test_to_datetime_including_quotes() -> None:
+    """
+    Test the ``to_datetime`` Jinja2 when a string wrapped
+    in quotes is used.
+
+    This might happen when passing a value from a temporal macro.
+    """
+    result = to_datetime("'2025-03-20'", format="%Y-%m-%d")
+    assert result == datetime(2025, 3, 20)
+
+
+def test_to_datetime_raises() -> None:
+    """
+    Test the ``to_datetime`` Jinja2 raises with an incorrect
+    format.
+    """
+    with pytest.raises(
+        ValueError,
+        match="time data '2025-03-20' does not match format '%Y-%m-%d 
%H:%M:%S'",
+    ):
+        to_datetime("2025-03-20")
+
+    with pytest.raises(
+        ValueError,
+        match="unconverted data remains:  15:55:00",
+    ):
+        to_datetime("2025-03-20 15:55:00", format="%Y-%m-%d")
+
+
 def test_dataset_macro(mocker: MockerFixture) -> None:
     """
     Test the ``dataset_macro`` macro.

Reply via email to