You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2019/05/31 13:55:45 UTC

[incubator-superset] branch master updated: Add relative start param for time filters (#7525)

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

villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new c1712e5  Add relative start param for time filters (#7525)
c1712e5 is described below

commit c1712e5d1080c2ca4d80cf581256fd1b9e23e59c
Author: Ville Brofeldt <33...@users.noreply.github.com>
AuthorDate: Fri May 31 16:55:26 2019 +0300

    Add relative start param for time filters (#7525)
    
    * Add relative start param for time filters
    
    * Fix typo and add types to parse_human_datetime
    
    * Add relative start/end to query_object
    
    * Fix linting error
---
 superset/common/query_object.py |  9 ++++++++-
 superset/config.py              |  7 ++++++-
 superset/utils/core.py          | 22 ++++++++++++----------
 superset/viz.py                 |  7 +++++--
 tests/utils_tests.py            | 22 +++++++++++++++++++---
 5 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/superset/common/query_object.py b/superset/common/query_object.py
index 47abbf2..553c0b9 100644
--- a/superset/common/query_object.py
+++ b/superset/common/query_object.py
@@ -51,9 +51,16 @@ class QueryObject:
             is_prequery: bool = False,
             columns: List[str] = None,
             orderby: List[List] = None,
+            relative_start: str = app.config.get('DEFAULT_RELATIVE_START_TIME', 'today'),
+            relative_end: str = app.config.get('DEFAULT_RELATIVE_END_TIME', 'today'),
     ):
         self.granularity = granularity
-        self.from_dttm, self.to_dttm = utils.get_since_until(time_range, time_shift)
+        self.from_dttm, self.to_dttm = utils.get_since_until(
+            relative_start=relative_start,
+            relative_end=relative_end,
+            time_range=time_range,
+            time_shift=time_shift,
+        )
         self.is_timeseries = is_timeseries
         self.time_range = time_range
         self.time_shift = utils.parse_human_timedelta(time_shift)
diff --git a/superset/config.py b/superset/config.py
index fc287b7..7d6ca33 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -599,8 +599,13 @@ BUG_REPORT_URL = None
 DOCUMENTATION_URL = None
 
 # What is the Last N days relative in the time selector to:
-# 'today' means it is midnight (00:00:00) of today in the local timezone
+# 'today' means it is midnight (00:00:00) in the local timezone
 # 'now' means it is relative to the query issue time
+# If both start and end time is set to now, this will make the time
+# filter a moving window. By only setting the end time to now,
+# start time will be set to midnight, while end will be relative to
+# the query issue time.
+DEFAULT_RELATIVE_START_TIME = 'today'
 DEFAULT_RELATIVE_END_TIME = 'today'
 
 # Is epoch_s/epoch_ms datetime format supposed to be considered since UTC ?
diff --git a/superset/utils/core.py b/superset/utils/core.py
index 2defa70..df25500 100644
--- a/superset/utils/core.py
+++ b/superset/utils/core.py
@@ -237,14 +237,14 @@ def parse_human_datetime(s):
             # when time is not extracted, we 'reset to midnight'
             if parsed_flags & 2 == 0:
                 parsed_dttm = parsed_dttm.replace(hour=0, minute=0, second=0)
-            dttm = dttm_from_timtuple(parsed_dttm.utctimetuple())
+            dttm = dttm_from_timetuple(parsed_dttm.utctimetuple())
         except Exception as e:
             logging.exception(e)
             raise ValueError("Couldn't parse date string [{}]".format(s))
     return dttm
 
 
-def dttm_from_timtuple(d: struct_time) -> datetime:
+def dttm_from_timetuple(d: struct_time) -> datetime:
     return datetime(
         d.tm_year, d.tm_mon, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)
 
@@ -306,7 +306,7 @@ def parse_human_timedelta(s: str):
     True
     """
     cal = parsedatetime.Calendar()
-    dttm = dttm_from_timtuple(datetime.now().timetuple())
+    dttm = dttm_from_timetuple(datetime.now().timetuple())
     d = cal.parse(s or '', dttm)[0]
     d = datetime(d.tm_year, d.tm_mon, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)
     return d - dttm
@@ -939,6 +939,7 @@ def get_since_until(time_range: Optional[str] = None,
                     since: Optional[str] = None,
                     until: Optional[str] = None,
                     time_shift: Optional[str] = None,
+                    relative_start: Optional[str] = None,
                     relative_end: Optional[str] = None) -> Tuple[datetime, datetime]:
     """Return `since` and `until` date time tuple from string representations of
     time_range, since, until and time_shift.
@@ -965,13 +966,14 @@ def get_since_until(time_range: Optional[str] = None,
 
     """
     separator = ' : '
+    relative_start = parse_human_datetime(relative_start if relative_start else 'today')
     relative_end = parse_human_datetime(relative_end if relative_end else 'today')
     common_time_frames = {
-        'Last day': (relative_end - relativedelta(days=1), relative_end),  # noqa: T400
-        'Last week': (relative_end - relativedelta(weeks=1), relative_end),  # noqa: T400
-        'Last month': (relative_end - relativedelta(months=1), relative_end),  # noqa: E501, T400
-        'Last quarter': (relative_end - relativedelta(months=3), relative_end),  # noqa: E501, T400
-        'Last year': (relative_end - relativedelta(years=1), relative_end),  # noqa: T400
+        'Last day': (relative_start - relativedelta(days=1), relative_end),  # noqa: T400
+        'Last week': (relative_start - relativedelta(weeks=1), relative_end),  # noqa: E501, T400
+        'Last month': (relative_start - relativedelta(months=1), relative_end),  # noqa: E501, T400
+        'Last quarter': (relative_start - relativedelta(months=3), relative_end),  # noqa: E501, T400
+        'Last year': (relative_start - relativedelta(years=1), relative_end),  # noqa: E501, T400
     }
 
     if time_range:
@@ -988,10 +990,10 @@ def get_since_until(time_range: Optional[str] = None,
         else:
             rel, num, grain = time_range.split()
             if rel == 'Last':
-                since = relative_end - relativedelta(**{grain: int(num)})  # noqa: T400
+                since = relative_start - relativedelta(**{grain: int(num)})  # noqa: T400
                 until = relative_end
             else:  # rel == 'Next'
-                since = relative_end
+                since = relative_start
                 until = relative_end + relativedelta(**{grain: int(num)})  # noqa: T400
     else:
         since = since or ''
diff --git a/superset/viz.py b/superset/viz.py
index 8eb0620..a6864d3 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -59,6 +59,7 @@ from superset.utils.core import (
 
 config = app.config
 stats_logger = config.get('STATS_LOGGER')
+relative_start = config.get('DEFAULT_RELATIVE_START_TIME', 'today')
 relative_end = config.get('DEFAULT_RELATIVE_END_TIME', 'today')
 
 METRIC_KEYS = [
@@ -274,7 +275,8 @@ class BaseViz(object):
         # default order direction
         order_desc = form_data.get('order_desc', True)
 
-        since, until = utils.get_since_until(relative_end=relative_end,
+        since, until = utils.get_since_until(relative_start=relative_start,
+                                             relative_end=relative_end,
                                              time_range=form_data.get('time_range'),
                                              since=form_data.get('since'),
                                              until=form_data.get('until'))
@@ -800,7 +802,8 @@ class CalHeatmapViz(BaseViz):
                 values[str(v / 10**9)] = obj.get(metric)
             data[metric] = values
 
-        start, end = utils.get_since_until(relative_end=relative_end,
+        start, end = utils.get_since_until(relative_start=relative_start,
+                                           relative_end=relative_end,
                                            time_range=form_data.get('time_range'),
                                            since=form_data.get('since'),
                                            until=form_data.get('until'))
diff --git a/tests/utils_tests.py b/tests/utils_tests.py
index 40dedaf..a39631b 100644
--- a/tests/utils_tests.py
+++ b/tests/utils_tests.py
@@ -43,7 +43,9 @@ from superset.utils.core import (
 
 
 def mock_parse_human_datetime(s):
-    if s in ['now', 'today']:
+    if s == 'now':
+        return datetime(2016, 11, 7, 9, 30, 10)
+    elif s == 'today':
         return datetime(2016, 11, 7)
     elif s == 'yesterday':
         return datetime(2016, 11, 6)
@@ -51,6 +53,8 @@ def mock_parse_human_datetime(s):
         return datetime(2016, 11, 8)
     elif s == 'Last year':
         return datetime(2015, 11, 7)
+    elif s == 'Last week':
+        return datetime(2015, 10, 31)
     elif s == 'Last 5 months':
         return datetime(2016, 6, 7)
     elif s == 'Next 5 months':
@@ -600,7 +604,7 @@ class UtilsTestCase(unittest.TestCase):
         self.assertEqual(result, expected)
 
         result = get_since_until(' : now')
-        expected = None, datetime(2016, 11, 7)
+        expected = None, datetime(2016, 11, 7, 9, 30, 10)
         self.assertEqual(result, expected)
 
         result = get_since_until('yesterday : tomorrow')
@@ -636,7 +640,19 @@ class UtilsTestCase(unittest.TestCase):
         self.assertEqual(result, expected)
 
         result = get_since_until(time_range='5 days : now')
-        expected = datetime(2016, 11, 2), datetime(2016, 11, 7)
+        expected = datetime(2016, 11, 2), datetime(2016, 11, 7, 9, 30, 10)
+        self.assertEqual(result, expected)
+
+        result = get_since_until('Last week', relative_end='now')
+        expected = datetime(2016, 10, 31), datetime(2016, 11, 7, 9, 30, 10)
+        self.assertEqual(result, expected)
+
+        result = get_since_until('Last week', relative_start='now')
+        expected = datetime(2016, 10, 31, 9, 30, 10), datetime(2016, 11, 7)
+        self.assertEqual(result, expected)
+
+        result = get_since_until('Last week', relative_start='now', relative_end='now')
+        expected = datetime(2016, 10, 31, 9, 30, 10), datetime(2016, 11, 7, 9, 30, 10)
         self.assertEqual(result, expected)
 
         with self.assertRaises(ValueError):