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 2020/09/11 12:07:24 UTC

[incubator-superset] 26/34: fix: dashboard extra filters (#10692)

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

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

commit 5fbe751085117afe728754b66a3cc1d33b1891f8
Author: John Bodley <45...@users.noreply.github.com>
AuthorDate: Wed Sep 2 16:03:25 2020 -0700

    fix: dashboard extra filters (#10692)
    
    Co-authored-by: John Bodley <jo...@airbnb.com>
---
 superset/examples/world_bank.py |   2 +-
 superset/views/utils.py         |  37 +++++-
 tests/strategy_tests.py         |   2 +-
 tests/utils_tests.py            | 279 +++++-----------------------------------
 4 files changed, 65 insertions(+), 255 deletions(-)

diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py
index 8a696e7..3f7509b 100644
--- a/superset/examples/world_bank.py
+++ b/superset/examples/world_bank.py
@@ -153,7 +153,7 @@ def load_world_bank_health_n_pop(  # pylint: disable=too-many-locals, too-many-s
                         "column": "region",
                         "key": "2s98dfu",
                         "metric": "sum__SP_POP_TOTL",
-                        "multiple": True,
+                        "multiple": False,
                     },
                     {
                         "asc": False,
diff --git a/superset/views/utils.py b/superset/views/utils.py
index 7e50800..eaecc5f 100644
--- a/superset/views/utils.py
+++ b/superset/views/utils.py
@@ -336,7 +336,7 @@ def get_dashboard_extra_filters(
     return []
 
 
-def build_extra_filters(
+def build_extra_filters(  # pylint: disable=too-many-locals,too-many-nested-blocks
     layout: Dict[str, Dict[str, Any]],
     filter_scopes: Dict[str, Dict[str, Any]],
     default_filters: Dict[str, Dict[str, List[Any]]],
@@ -344,11 +344,22 @@ def build_extra_filters(
 ) -> List[Dict[str, Any]]:
     extra_filters = []
 
-    # do not apply filters if chart is not in filter's scope or
-    # chart is immune to the filter
+    # do not apply filters if chart is not in filter's scope or chart is immune to the
+    # filter.
     for filter_id, columns in default_filters.items():
+        filter_slice = db.session.query(Slice).filter_by(id=filter_id).one_or_none()
+
+        filter_configs = (
+            json.loads(filter_slice.params or "{}").get("filter_configs") or []
+            if filter_slice
+            else []
+        )
+
         scopes_by_filter_field = filter_scopes.get(filter_id, {})
         for col, val in columns.items():
+            if not val:
+                continue
+
             current_field_scopes = scopes_by_filter_field.get(col, {})
             scoped_container_ids = current_field_scopes.get("scope", ["ROOT_ID"])
             immune_slice_ids = current_field_scopes.get("immune", [])
@@ -357,7 +368,25 @@ def build_extra_filters(
                 if slice_id not in immune_slice_ids and is_slice_in_container(
                     layout, container_id, slice_id
                 ):
-                    extra_filters.append({"col": col, "op": "in", "val": val})
+                    # Ensure that the filter value encoding adheres to the filter select
+                    # type.
+                    for filter_config in filter_configs:
+                        if filter_config["column"] == col:
+                            is_multiple = filter_config["multiple"]
+
+                            if not is_multiple and isinstance(val, list):
+                                val = val[0]
+                            elif is_multiple and not isinstance(val, list):
+                                val = [val]
+                            break
+
+                    extra_filters.append(
+                        {
+                            "col": col,
+                            "op": "in" if isinstance(val, list) else "==",
+                            "val": val,
+                        }
+                    )
 
     return extra_filters
 
diff --git a/tests/strategy_tests.py b/tests/strategy_tests.py
index c4f0019..f8cea8b 100644
--- a/tests/strategy_tests.py
+++ b/tests/strategy_tests.py
@@ -168,7 +168,7 @@ class TestCacheWarmUp(SupersetTestCase):
             "slice_id": chart_id,
             "extra_filters": [
                 {"col": "name", "op": "in", "val": ["Alice", "Bob"]},
-                {"col": "__time_range", "op": "in", "val": "100 years ago : today"},
+                {"col": "__time_range", "op": "==", "val": "100 years ago : today"},
             ],
         }
         self.assertEqual(result, expected)
diff --git a/tests/utils_tests.py b/tests/utils_tests.py
index 4d78064..91d1ad3 100644
--- a/tests/utils_tests.py
+++ b/tests/utils_tests.py
@@ -35,6 +35,8 @@ import tests.test_app
 from superset import app, db, security_manager
 from superset.exceptions import CertificateException, SupersetException
 from superset.models.core import Database, Log
+from superset.models.dashboard import Dashboard
+from superset.models.slice import Slice
 from superset.utils.cache_manager import CacheManager
 from superset.utils.core import (
     base_json_conv,
@@ -965,268 +967,47 @@ class TestUtils(SupersetTestCase):
         self.assertListEqual(get_iterable("foo"), ["foo"])
 
     def test_build_extra_filters(self):
-        layout = {
-            "CHART-2ee52f30": {
-                "children": [],
-                "id": "CHART-2ee52f30",
-                "meta": {
-                    "chartId": 1020,
-                    "height": 38,
-                    "sliceName": "Chart 927",
-                    "width": 6,
-                },
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                    "TAB-asWdJzKmTN",
-                    "ROW-i_sG4ccXE",
-                ],
-                "type": "CHART",
-            },
-            "CHART-36bfc934": {
-                "children": [],
-                "id": "CHART-36bfc934",
-                "meta": {
-                    "chartId": 1018,
-                    "height": 26,
-                    "sliceName": "Region Filter",
-                    "width": 2,
-                },
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-W62P60D88",
-                    "ROW-1e064e3c",
-                    "COLUMN-fe3914b8",
-                ],
-                "type": "CHART",
-            },
-            "CHART-E_y2cuNHTv": {
-                "children": [],
-                "id": "CHART-E_y2cuNHTv",
-                "meta": {"chartId": 998, "height": 55, "sliceName": "MAP", "width": 6},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-W62P60D88",
-                    "ROW-1e064e3c",
-                ],
-                "type": "CHART",
-            },
-            "CHART-JNxDOsAfEb": {
-                "children": [],
-                "id": "CHART-JNxDOsAfEb",
-                "meta": {
-                    "chartId": 1015,
-                    "height": 27,
-                    "sliceName": "Population",
-                    "width": 4,
-                },
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-W62P60D88",
-                    "ROW-1e064e3c",
-                    "COLUMN-fe3914b8",
-                ],
-                "type": "CHART",
-            },
-            "CHART-KoOwqalV80": {
-                "children": [],
-                "id": "CHART-KoOwqalV80",
-                "meta": {
-                    "chartId": 927,
-                    "height": 20,
-                    "sliceName": "Chart 927",
-                    "width": 4,
-                },
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                    "TAB-cHNWcBZC9",
-                    "ROW-9b9vrWKPY",
-                ],
-                "type": "CHART",
-            },
-            "CHART-YCQAPVK7mQ": {
-                "children": [],
-                "id": "CHART-YCQAPVK7mQ",
-                "meta": {
-                    "chartId": 1023,
-                    "height": 38,
-                    "sliceName": "World's Population",
-                    "width": 4,
-                },
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "ROW-UfxFT36oV5",
-                ],
-                "type": "CHART",
-            },
-            "COLUMN-fe3914b8": {
-                "children": ["CHART-36bfc934", "CHART-JNxDOsAfEb"],
-                "id": "COLUMN-fe3914b8",
-                "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 6},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-W62P60D88",
-                    "ROW-1e064e3c",
-                ],
-                "type": "COLUMN",
-            },
-            "DASHBOARD_VERSION_KEY": "v2",
-            "GRID_ID": {
-                "children": [],
-                "id": "GRID_ID",
-                "parents": ["ROOT_ID"],
-                "type": "GRID",
-            },
-            "HEADER_ID": {
-                "id": "HEADER_ID",
-                "meta": {"text": "Test warmup 1023"},
-                "type": "HEADER",
-            },
-            "ROOT_ID": {
-                "children": ["TABS-Qq4sdkANSY"],
-                "id": "ROOT_ID",
-                "type": "ROOT",
-            },
-            "ROW-1e064e3c": {
-                "children": ["COLUMN-fe3914b8", "CHART-E_y2cuNHTv"],
-                "id": "ROW-1e064e3c",
-                "meta": {"background": "BACKGROUND_TRANSPARENT"},
-                "parents": ["ROOT_ID", "TABS-Qq4sdkANSY", "TAB-W62P60D88"],
-                "type": "ROW",
-            },
-            "ROW-9b9vrWKPY": {
-                "children": ["CHART-KoOwqalV80"],
-                "id": "ROW-9b9vrWKPY",
-                "meta": {"background": "BACKGROUND_TRANSPARENT"},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                    "TAB-cHNWcBZC9",
-                ],
-                "type": "ROW",
-            },
-            "ROW-UfxFT36oV5": {
-                "children": ["CHART-YCQAPVK7mQ"],
-                "id": "ROW-UfxFT36oV5",
-                "meta": {"background": "BACKGROUND_TRANSPARENT"},
-                "parents": ["ROOT_ID", "TABS-Qq4sdkANSY", "TAB-VrhTX2WUlO"],
-                "type": "ROW",
-            },
-            "ROW-i_sG4ccXE": {
-                "children": ["CHART-2ee52f30"],
-                "id": "ROW-i_sG4ccXE",
-                "meta": {"background": "BACKGROUND_TRANSPARENT"},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                    "TAB-asWdJzKmTN",
-                ],
-                "type": "ROW",
-            },
-            "TAB-VrhTX2WUlO": {
-                "children": ["ROW-UfxFT36oV5", "TABS-N1zN4CIZP0"],
-                "id": "TAB-VrhTX2WUlO",
-                "meta": {"text": "New Tab"},
-                "parents": ["ROOT_ID", "TABS-Qq4sdkANSY"],
-                "type": "TAB",
-            },
-            "TAB-W62P60D88": {
-                "children": ["ROW-1e064e3c"],
-                "id": "TAB-W62P60D88",
-                "meta": {"text": "Tab 2"},
-                "parents": ["ROOT_ID", "TABS-Qq4sdkANSY"],
-                "type": "TAB",
-            },
-            "TAB-asWdJzKmTN": {
-                "children": ["ROW-i_sG4ccXE"],
-                "id": "TAB-asWdJzKmTN",
-                "meta": {"text": "nested tab 1"},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                ],
-                "type": "TAB",
-            },
-            "TAB-cHNWcBZC9": {
-                "children": ["ROW-9b9vrWKPY"],
-                "id": "TAB-cHNWcBZC9",
-                "meta": {"text": "test2d tab 2"},
-                "parents": [
-                    "ROOT_ID",
-                    "TABS-Qq4sdkANSY",
-                    "TAB-VrhTX2WUlO",
-                    "TABS-N1zN4CIZP0",
-                ],
-                "type": "TAB",
-            },
-            "TABS-N1zN4CIZP0": {
-                "children": ["TAB-asWdJzKmTN", "TAB-cHNWcBZC9"],
-                "id": "TABS-N1zN4CIZP0",
-                "meta": {},
-                "parents": ["ROOT_ID", "TABS-Qq4sdkANSY", "TAB-VrhTX2WUlO"],
-                "type": "TABS",
-            },
-            "TABS-Qq4sdkANSY": {
-                "children": ["TAB-VrhTX2WUlO", "TAB-W62P60D88"],
-                "id": "TABS-Qq4sdkANSY",
-                "meta": {},
-                "parents": ["ROOT_ID"],
-                "type": "TABS",
-            },
-        }
+        world_health = db.session.query(Dashboard).filter_by(slug="world_health").one()
+        layout = json.loads(world_health.position_json)
+        filter_ = db.session.query(Slice).filter_by(slice_name="Region Filter").one()
+        world = db.session.query(Slice).filter_by(slice_name="World's Population").one()
+        box_plot = db.session.query(Slice).filter_by(slice_name="Box plot").one()
+        treemap = db.session.query(Slice).filter_by(slice_name="Treemap").one()
+
         filter_scopes = {
-            "1018": {
-                "region": {"scope": ["TAB-W62P60D88"], "immune": [998]},
-                "country_name": {"scope": ["ROOT_ID"], "immune": [927, 998]},
+            str(filter_.id): {
+                "region": {"scope": ["ROOT_ID"], "immune": [treemap.id]},
+                "country_name": {
+                    "scope": ["ROOT_ID"],
+                    "immune": [treemap.id, box_plot.id],
+                },
             }
         }
+
         default_filters = {
-            "1018": {"region": ["North America"], "country_name": ["United States"]}
+            str(filter_.id): {
+                "region": ["North America"],
+                "country_name": ["United States"],
+            }
         }
 
         # immune to all filters
-        slice_id = 998
-        extra_filters = build_extra_filters(
-            layout, filter_scopes, default_filters, slice_id
+        assert (
+            build_extra_filters(layout, filter_scopes, default_filters, treemap.id)
+            == []
         )
-        expected = []
-        self.assertEqual(extra_filters, expected)
 
         # in scope
-        slice_id = 1015
-        extra_filters = build_extra_filters(
-            layout, filter_scopes, default_filters, slice_id
-        )
-        expected = [
-            {"col": "region", "op": "in", "val": ["North America"]},
+        assert build_extra_filters(
+            layout, filter_scopes, default_filters, world.id
+        ) == [
+            {"col": "region", "op": "==", "val": "North America"},
             {"col": "country_name", "op": "in", "val": ["United States"]},
         ]
-        self.assertEqual(extra_filters, expected)
 
-        # not in scope
-        slice_id = 927
-        extra_filters = build_extra_filters(
-            layout, filter_scopes, default_filters, slice_id
-        )
-        expected = []
-        self.assertEqual(extra_filters, expected)
+        assert build_extra_filters(
+            layout, filter_scopes, default_filters, box_plot.id
+        ) == [{"col": "region", "op": "==", "val": "North America"}]
 
     def test_ssl_certificate_parse(self):
         parsed_certificate = parse_ssl_cert(ssl_certificate)