2019-01-15 18:53:27 -05:00
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
# or more contributor license agreements. See the NOTICE file
|
|
|
|
# distributed with this work for additional information
|
|
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
|
|
# to you under the Apache License, Version 2.0 (the
|
|
|
|
# "License"); you may not use this file except in compliance
|
|
|
|
# with the License. You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing,
|
|
|
|
# software distributed under the License is distributed on an
|
|
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
# KIND, either express or implied. See the License for the
|
|
|
|
# specific language governing permissions and limitations
|
|
|
|
# under the License.
|
2020-02-06 19:45:37 -05:00
|
|
|
# isort:skip_file
|
2020-09-03 12:49:54 -04:00
|
|
|
from datetime import date, datetime, timezone
|
2020-02-08 02:38:48 -05:00
|
|
|
import logging
|
2019-12-03 19:11:15 -05:00
|
|
|
from math import nan
|
2019-03-27 17:08:36 -04:00
|
|
|
from unittest.mock import Mock, patch
|
2020-07-31 04:19:21 -04:00
|
|
|
from typing import Any, Dict, List, Set
|
2017-11-07 23:23:40 -05:00
|
|
|
|
2019-07-02 14:10:50 -04:00
|
|
|
import numpy as np
|
2017-09-26 18:11:35 -04:00
|
|
|
import pandas as pd
|
2020-08-13 13:51:03 -04:00
|
|
|
import pytest
|
2017-09-26 18:11:35 -04:00
|
|
|
|
2021-07-01 11:03:07 -04:00
|
|
|
import tests.integration_tests.test_app
|
2019-10-18 17:44:27 -04:00
|
|
|
import superset.viz as viz
|
2018-07-02 18:32:21 -04:00
|
|
|
from superset import app
|
2019-12-03 19:11:15 -05:00
|
|
|
from superset.constants import NULL_STRING
|
2020-08-13 13:51:03 -04:00
|
|
|
from superset.exceptions import QueryObjectValidationError, SpatialException
|
2018-10-16 20:59:34 -04:00
|
|
|
from superset.utils.core import DTTM_ALIAS
|
2019-10-18 17:44:27 -04:00
|
|
|
|
2018-08-29 00:04:06 -04:00
|
|
|
from .base_tests import SupersetTestCase
|
2018-04-15 19:21:33 -04:00
|
|
|
from .utils import load_fixture
|
2017-10-16 23:16:20 -04:00
|
|
|
|
2020-02-08 02:38:48 -05:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2017-11-08 23:34:33 -05:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestBaseViz(SupersetTestCase):
|
2017-10-16 23:16:20 -04:00
|
|
|
def test_constructor_exception_no_datasource(self):
|
|
|
|
form_data = {}
|
|
|
|
datasource = None
|
|
|
|
with self.assertRaises(Exception):
|
|
|
|
viz.BaseViz(datasource, form_data)
|
|
|
|
|
2018-10-04 11:53:26 -04:00
|
|
|
def test_process_metrics(self):
|
|
|
|
# test TableViz metrics in correct order
|
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"url_params": {},
|
|
|
|
"row_limit": 500,
|
|
|
|
"metric": "sum__SP_POP_TOTL",
|
|
|
|
"entity": "country_code",
|
|
|
|
"secondary_metric": "sum__SP_POP_TOTL",
|
|
|
|
"granularity_sqla": "year",
|
|
|
|
"page_length": 0,
|
|
|
|
"all_columns": [],
|
|
|
|
"viz_type": "table",
|
|
|
|
"since": "2014-01-01",
|
|
|
|
"until": "2014-01-02",
|
|
|
|
"metrics": ["sum__SP_POP_TOTL", "SUM(SE_PRM_NENR_MA)", "SUM(SP_URB_TOTL)"],
|
|
|
|
"country_fieldtype": "cca3",
|
|
|
|
"percent_metrics": ["count"],
|
|
|
|
"slice_id": 74,
|
|
|
|
"time_grain_sqla": None,
|
|
|
|
"order_by_cols": [],
|
|
|
|
"groupby": ["country_name"],
|
|
|
|
"compare_lag": "10",
|
|
|
|
"limit": "25",
|
|
|
|
"datasource": "2__table",
|
|
|
|
"table_timestamp_format": "%Y-%m-%d %H:%M:%S",
|
|
|
|
"markup_type": "markdown",
|
|
|
|
"where": "",
|
|
|
|
"compare_suffix": "o10Y",
|
2018-10-04 11:53:26 -04:00
|
|
|
}
|
|
|
|
datasource = Mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
datasource.type = "table"
|
2018-10-04 11:53:26 -04:00
|
|
|
test_viz = viz.BaseViz(datasource, form_data)
|
2019-06-25 16:34:48 -04:00
|
|
|
expect_metric_labels = [
|
2021-01-28 03:39:00 -05:00
|
|
|
"sum__SP_POP_TOTL",
|
|
|
|
"SUM(SE_PRM_NENR_MA)",
|
|
|
|
"SUM(SP_URB_TOTL)",
|
|
|
|
"count",
|
2019-06-25 16:34:48 -04:00
|
|
|
]
|
2018-10-04 11:53:26 -04:00
|
|
|
self.assertEqual(test_viz.metric_labels, expect_metric_labels)
|
|
|
|
self.assertEqual(test_viz.all_metrics, expect_metric_labels)
|
|
|
|
|
2017-10-16 23:16:20 -04:00
|
|
|
def test_get_df_returns_empty_df(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"dummy": 123}
|
|
|
|
query_obj = {"granularity": "day"}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz = viz.BaseViz(datasource, form_data)
|
|
|
|
result = test_viz.get_df(query_obj)
|
|
|
|
self.assertEqual(type(result), pd.DataFrame)
|
|
|
|
self.assertTrue(result.empty)
|
|
|
|
|
|
|
|
def test_get_df_handles_dttm_col(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"dummy": 123}
|
|
|
|
query_obj = {"granularity": "day"}
|
2017-10-16 23:16:20 -04:00
|
|
|
results = Mock()
|
|
|
|
results.query = Mock()
|
|
|
|
results.status = Mock()
|
|
|
|
results.error_message = Mock()
|
2018-06-27 12:09:42 -04:00
|
|
|
datasource = Mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
datasource.type = "table"
|
2017-10-16 23:16:20 -04:00
|
|
|
datasource.query = Mock(return_value=results)
|
2018-06-27 12:09:42 -04:00
|
|
|
mock_dttm_col = Mock()
|
2019-12-31 02:26:23 -05:00
|
|
|
datasource.get_column = Mock(return_value=mock_dttm_col)
|
2018-08-29 00:04:06 -04:00
|
|
|
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz = viz.BaseViz(datasource, form_data)
|
2018-04-03 00:48:14 -04:00
|
|
|
test_viz.df_metrics_to_num = Mock()
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz.get_fillna_for_columns = Mock(return_value=0)
|
2018-06-27 12:09:42 -04:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
results.df = pd.DataFrame(data={DTTM_ALIAS: ["1960-01-01 05:00:00"]})
|
2018-06-27 12:09:42 -04:00
|
|
|
datasource.offset = 0
|
2018-08-29 00:04:06 -04:00
|
|
|
mock_dttm_col = Mock()
|
2019-12-31 02:26:23 -05:00
|
|
|
datasource.get_column = Mock(return_value=mock_dttm_col)
|
2019-06-25 16:34:48 -04:00
|
|
|
mock_dttm_col.python_date_format = "epoch_ms"
|
2018-06-27 12:09:42 -04:00
|
|
|
result = test_viz.get_df(query_obj)
|
2018-08-29 00:04:06 -04:00
|
|
|
import logging
|
2019-06-25 16:34:48 -04:00
|
|
|
|
2020-02-08 02:38:48 -05:00
|
|
|
logger.info(result)
|
2018-06-27 12:09:42 -04:00
|
|
|
pd.testing.assert_series_equal(
|
2019-06-25 16:34:48 -04:00
|
|
|
result[DTTM_ALIAS], pd.Series([datetime(1960, 1, 1, 5, 0)], name=DTTM_ALIAS)
|
2018-06-27 12:09:42 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
mock_dttm_col.python_date_format = None
|
|
|
|
result = test_viz.get_df(query_obj)
|
|
|
|
pd.testing.assert_series_equal(
|
2019-06-25 16:34:48 -04:00
|
|
|
result[DTTM_ALIAS], pd.Series([datetime(1960, 1, 1, 5, 0)], name=DTTM_ALIAS)
|
2018-06-27 12:09:42 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
datasource.offset = 1
|
|
|
|
result = test_viz.get_df(query_obj)
|
|
|
|
pd.testing.assert_series_equal(
|
2019-06-25 16:34:48 -04:00
|
|
|
result[DTTM_ALIAS], pd.Series([datetime(1960, 1, 1, 6, 0)], name=DTTM_ALIAS)
|
2018-06-27 12:09:42 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
datasource.offset = 0
|
2019-06-25 16:34:48 -04:00
|
|
|
results.df = pd.DataFrame(data={DTTM_ALIAS: ["1960-01-01"]})
|
|
|
|
mock_dttm_col.python_date_format = "%Y-%m-%d"
|
2018-06-27 12:09:42 -04:00
|
|
|
result = test_viz.get_df(query_obj)
|
|
|
|
pd.testing.assert_series_equal(
|
2019-06-25 16:34:48 -04:00
|
|
|
result[DTTM_ALIAS], pd.Series([datetime(1960, 1, 1, 0, 0)], name=DTTM_ALIAS)
|
2018-06-27 12:09:42 -04:00
|
|
|
)
|
2017-10-16 23:16:20 -04:00
|
|
|
|
|
|
|
def test_cache_timeout(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-07-02 18:32:21 -04:00
|
|
|
datasource.cache_timeout = 0
|
|
|
|
test_viz = viz.BaseViz(datasource, form_data={})
|
|
|
|
self.assertEqual(0, test_viz.cache_timeout)
|
2018-08-29 00:04:06 -04:00
|
|
|
|
2017-10-16 23:16:20 -04:00
|
|
|
datasource.cache_timeout = 156
|
2018-01-12 15:05:12 -05:00
|
|
|
test_viz = viz.BaseViz(datasource, form_data={})
|
2017-10-16 23:16:20 -04:00
|
|
|
self.assertEqual(156, test_viz.cache_timeout)
|
2018-08-29 00:04:06 -04:00
|
|
|
|
2017-10-16 23:16:20 -04:00
|
|
|
datasource.cache_timeout = None
|
2018-07-02 18:32:21 -04:00
|
|
|
datasource.database.cache_timeout = 0
|
|
|
|
self.assertEqual(0, test_viz.cache_timeout)
|
2018-08-29 00:04:06 -04:00
|
|
|
|
2017-11-08 23:34:23 -05:00
|
|
|
datasource.database.cache_timeout = 1666
|
2017-10-16 23:16:20 -04:00
|
|
|
self.assertEqual(1666, test_viz.cache_timeout)
|
2018-08-29 00:04:06 -04:00
|
|
|
|
feat(SIP-39): Async query support for charts (#11499)
* Generate JWT in Flask app
* Refactor chart data API query logic, add JWT validation and async worker
* Add redis stream implementation, refactoring
* Add chart data cache endpoint, refactor QueryContext caching
* Typing, linting, refactoring
* pytest fixes and openapi schema update
* Enforce caching be configured for async query init
* Async query processing for explore_json endpoint
* Add /api/v1/async_event endpoint
* Async frontend for dashboards [WIP]
* Chart async error message support, refactoring
* Abstract asyncEvent middleware
* Async chart loading for Explore
* Pylint fixes
* asyncEvent middleware -> TypeScript, JS linting
* Chart data API: enforce forced_cache, add tests
* Add tests for explore_json endpoints
* Add test for chart data cache enpoint (no login)
* Consolidate set_and_log_cache and add STORE_CACHE_KEYS_IN_METADATA_DB flag
* Add tests for tasks/async_queries and address PR comments
* Bypass non-JSON result formats for async queries
* Add tests for redux middleware
* Remove debug statement
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
* Skip force_cached if no queryObj
* SunburstViz: don't modify self.form_data
* Fix failing annotation test
* Resolve merge/lint issues
* Reduce polling delay
* Fix new getClientErrorObject reference
* Fix flakey unit tests
* /api/v1/async_event: increment redis stream ID, add tests
* PR feedback: refactoring, configuration
* Fixup: remove debugging
* Fix typescript errors due to redux upgrade
* Update UPDATING.md
* Fix failing py tests
* asyncEvent_spec.js -> asyncEvent_spec.ts
* Refactor flakey Python 3.7 mock assertions
* Fix another shared state issue in Py tests
* Use 'sub' claim in JWT for user_id
* Refactor async middleware config
* Fixup: restore FeatureFlag boolean type
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
2020-12-10 23:21:56 -05:00
|
|
|
datasource.database.cache_timeout = None
|
|
|
|
test_viz = viz.BaseViz(datasource, form_data={})
|
|
|
|
self.assertEqual(
|
|
|
|
app.config["DATA_CACHE_CONFIG"]["CACHE_DEFAULT_TIMEOUT"],
|
|
|
|
test_viz.cache_timeout,
|
|
|
|
)
|
|
|
|
|
|
|
|
data_cache_timeout = app.config["DATA_CACHE_CONFIG"]["CACHE_DEFAULT_TIMEOUT"]
|
|
|
|
app.config["DATA_CACHE_CONFIG"]["CACHE_DEFAULT_TIMEOUT"] = None
|
2018-07-02 18:32:21 -04:00
|
|
|
datasource.database.cache_timeout = None
|
|
|
|
test_viz = viz.BaseViz(datasource, form_data={})
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(app.config["CACHE_DEFAULT_TIMEOUT"], test_viz.cache_timeout)
|
feat(SIP-39): Async query support for charts (#11499)
* Generate JWT in Flask app
* Refactor chart data API query logic, add JWT validation and async worker
* Add redis stream implementation, refactoring
* Add chart data cache endpoint, refactor QueryContext caching
* Typing, linting, refactoring
* pytest fixes and openapi schema update
* Enforce caching be configured for async query init
* Async query processing for explore_json endpoint
* Add /api/v1/async_event endpoint
* Async frontend for dashboards [WIP]
* Chart async error message support, refactoring
* Abstract asyncEvent middleware
* Async chart loading for Explore
* Pylint fixes
* asyncEvent middleware -> TypeScript, JS linting
* Chart data API: enforce forced_cache, add tests
* Add tests for explore_json endpoints
* Add test for chart data cache enpoint (no login)
* Consolidate set_and_log_cache and add STORE_CACHE_KEYS_IN_METADATA_DB flag
* Add tests for tasks/async_queries and address PR comments
* Bypass non-JSON result formats for async queries
* Add tests for redux middleware
* Remove debug statement
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
* Skip force_cached if no queryObj
* SunburstViz: don't modify self.form_data
* Fix failing annotation test
* Resolve merge/lint issues
* Reduce polling delay
* Fix new getClientErrorObject reference
* Fix flakey unit tests
* /api/v1/async_event: increment redis stream ID, add tests
* PR feedback: refactoring, configuration
* Fixup: remove debugging
* Fix typescript errors due to redux upgrade
* Update UPDATING.md
* Fix failing py tests
* asyncEvent_spec.js -> asyncEvent_spec.ts
* Refactor flakey Python 3.7 mock assertions
* Fix another shared state issue in Py tests
* Use 'sub' claim in JWT for user_id
* Refactor async middleware config
* Fixup: restore FeatureFlag boolean type
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
2020-12-10 23:21:56 -05:00
|
|
|
# restore DATA_CACHE_CONFIG timeout
|
|
|
|
app.config["DATA_CACHE_CONFIG"]["CACHE_DEFAULT_TIMEOUT"] = data_cache_timeout
|
2017-10-16 23:16:20 -04:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestTableViz(SupersetTestCase):
|
2017-10-16 23:16:20 -04:00
|
|
|
def test_get_data_applies_percentage(self):
|
|
|
|
form_data = {
|
2020-02-17 01:51:35 -05:00
|
|
|
"groupby": ["groupA", "groupB"],
|
|
|
|
"metrics": [
|
2019-06-25 16:34:48 -04:00
|
|
|
{
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "SUM(value1)",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
},
|
2020-02-17 01:51:35 -05:00
|
|
|
"count",
|
|
|
|
"avg__C",
|
2019-06-25 16:34:48 -04:00
|
|
|
],
|
2020-02-17 01:51:35 -05:00
|
|
|
"percent_metrics": [
|
2019-06-25 16:34:48 -04:00
|
|
|
{
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "SUM(value1)",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
},
|
2020-02-17 01:51:35 -05:00
|
|
|
"avg__B",
|
2019-06-25 16:34:48 -04:00
|
|
|
],
|
2017-10-16 23:16:20 -04:00
|
|
|
}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2020-02-17 01:51:35 -05:00
|
|
|
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"SUM(value1)": [15, 20, 25, 40],
|
|
|
|
"avg__B": [10, 20, 5, 15],
|
|
|
|
"avg__C": [11, 22, 33, 44],
|
|
|
|
"count": [6, 7, 8, 9],
|
|
|
|
"groupA": ["A", "B", "C", "C"],
|
|
|
|
"groupB": ["x", "x", "y", "z"],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
# Check method correctly transforms data and computes percents
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(
|
2020-02-17 01:51:35 -05:00
|
|
|
[
|
|
|
|
"groupA",
|
|
|
|
"groupB",
|
|
|
|
"SUM(value1)",
|
|
|
|
"count",
|
|
|
|
"avg__C",
|
|
|
|
"%SUM(value1)",
|
|
|
|
"%avg__B",
|
|
|
|
],
|
|
|
|
list(data["columns"]),
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2017-10-16 23:16:20 -04:00
|
|
|
expected = [
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"groupA": "A",
|
|
|
|
"groupB": "x",
|
|
|
|
"SUM(value1)": 15,
|
2020-02-17 01:51:35 -05:00
|
|
|
"count": 6,
|
2019-06-25 16:34:48 -04:00
|
|
|
"avg__C": 11,
|
|
|
|
"%SUM(value1)": 0.15,
|
|
|
|
"%avg__B": 0.2,
|
2017-10-16 23:16:20 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"groupA": "B",
|
|
|
|
"groupB": "x",
|
|
|
|
"SUM(value1)": 20,
|
2020-02-17 01:51:35 -05:00
|
|
|
"count": 7,
|
2019-06-25 16:34:48 -04:00
|
|
|
"avg__C": 22,
|
|
|
|
"%SUM(value1)": 0.2,
|
|
|
|
"%avg__B": 0.4,
|
2017-10-16 23:16:20 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"groupA": "C",
|
|
|
|
"groupB": "y",
|
|
|
|
"SUM(value1)": 25,
|
2020-02-17 01:51:35 -05:00
|
|
|
"count": 8,
|
2019-06-25 16:34:48 -04:00
|
|
|
"avg__C": 33,
|
|
|
|
"%SUM(value1)": 0.25,
|
|
|
|
"%avg__B": 0.1,
|
2017-10-16 23:16:20 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"groupA": "C",
|
|
|
|
"groupB": "z",
|
|
|
|
"SUM(value1)": 40,
|
2020-02-17 01:51:35 -05:00
|
|
|
"count": 9,
|
2019-06-25 16:34:48 -04:00
|
|
|
"avg__C": 44,
|
2020-02-17 01:51:35 -05:00
|
|
|
"%SUM(value1)": 0.4,
|
2019-06-25 16:34:48 -04:00
|
|
|
"%avg__B": 0.3,
|
2017-10-16 23:16:20 -04:00
|
|
|
},
|
|
|
|
]
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(expected, data["records"])
|
2017-10-16 23:16:20 -04:00
|
|
|
|
2018-05-10 13:41:10 -04:00
|
|
|
def test_parse_adhoc_filters(self):
|
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"metrics": [
|
|
|
|
{
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "SUM(value1)",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"adhoc_filters": [
|
2018-05-10 13:41:10 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"clause": "WHERE",
|
|
|
|
"subject": "value2",
|
|
|
|
"operator": ">",
|
|
|
|
"comparator": "100",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"clause": "HAVING",
|
|
|
|
"subject": "SUM(value1)",
|
|
|
|
"operator": "<",
|
|
|
|
"comparator": "10",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SQL",
|
|
|
|
"clause": "HAVING",
|
|
|
|
"sqlExpression": "SUM(value1) > 5",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SQL",
|
|
|
|
"clause": "WHERE",
|
|
|
|
"sqlExpression": "value3 in ('North America')",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-05-10 13:41:10 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
query_obj = test_viz.query_obj()
|
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
[{"col": "value2", "val": "100", "op": ">"}], query_obj["filter"]
|
2018-05-10 13:41:10 -04:00
|
|
|
)
|
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
[{"op": "<", "val": "10", "col": "SUM(value1)"}],
|
|
|
|
query_obj["extras"]["having_druid"],
|
2018-05-10 13:41:10 -04:00
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("(value3 in ('North America'))", query_obj["extras"]["where"])
|
|
|
|
self.assertEqual("(SUM(value1) > 5)", query_obj["extras"]["having"])
|
2018-05-10 13:41:10 -04:00
|
|
|
|
|
|
|
def test_adhoc_filters_overwrite_legacy_filters(self):
|
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"metrics": [
|
|
|
|
{
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "SUM(value1)",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"adhoc_filters": [
|
2018-05-10 13:41:10 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"clause": "WHERE",
|
|
|
|
"subject": "value2",
|
|
|
|
"operator": ">",
|
|
|
|
"comparator": "100",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"expressionType": "SQL",
|
|
|
|
"clause": "WHERE",
|
|
|
|
"sqlExpression": "value3 in ('North America')",
|
2018-05-10 13:41:10 -04:00
|
|
|
},
|
|
|
|
],
|
2019-06-25 16:34:48 -04:00
|
|
|
"having": "SUM(value1) > 5",
|
2018-05-10 13:41:10 -04:00
|
|
|
}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-05-10 13:41:10 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
query_obj = test_viz.query_obj()
|
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
[{"col": "value2", "val": "100", "op": ">"}], query_obj["filter"]
|
2018-05-10 13:41:10 -04:00
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual([], query_obj["extras"]["having_druid"])
|
|
|
|
self.assertEqual("(value3 in ('North America'))", query_obj["extras"]["where"])
|
|
|
|
self.assertEqual("", query_obj["extras"]["having"])
|
2018-05-10 13:41:10 -04:00
|
|
|
|
2020-06-29 00:37:04 -04:00
|
|
|
def test_query_obj_merges_percent_metrics(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-10-16 23:16:20 -04:00
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"metrics": ["sum__A", "count", "avg__C"],
|
2020-06-29 00:37:04 -04:00
|
|
|
"percent_metrics": ["sum__A", "avg__B", "max__Y"],
|
2017-10-16 23:16:20 -04:00
|
|
|
}
|
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
query_obj = test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(
|
|
|
|
["sum__A", "count", "avg__C", "avg__B", "max__Y"], query_obj["metrics"]
|
|
|
|
)
|
2017-10-16 23:16:20 -04:00
|
|
|
|
2020-06-29 00:37:04 -04:00
|
|
|
def test_query_obj_throws_columns_and_metrics(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"all_columns": ["A", "B"], "metrics": ["x", "y"]}
|
2017-10-16 23:16:20 -04:00
|
|
|
with self.assertRaises(Exception):
|
2020-06-29 00:37:04 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
del form_data["metrics"]
|
|
|
|
form_data["groupby"] = ["B", "C"]
|
2017-10-16 23:16:20 -04:00
|
|
|
with self.assertRaises(Exception):
|
2020-06-29 00:37:04 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz.query_obj()
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.viz.BaseViz.query_obj")
|
2017-10-16 23:16:20 -04:00
|
|
|
def test_query_obj_merges_all_columns(self, super_query_obj):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-10-16 23:16:20 -04:00
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"all_columns": ["colA", "colB", "colC"],
|
|
|
|
"order_by_cols": ['["colA", "colB"]', '["colC"]'],
|
2017-10-16 23:16:20 -04:00
|
|
|
}
|
|
|
|
super_query_obj.return_value = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"columns": ["colD", "colC"],
|
|
|
|
"groupby": ["colA", "colB"],
|
2017-10-16 23:16:20 -04:00
|
|
|
}
|
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
query_obj = test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(form_data["all_columns"], query_obj["columns"])
|
|
|
|
self.assertEqual([], query_obj["groupby"])
|
|
|
|
self.assertEqual([["colA", "colB"], ["colC"]], query_obj["orderby"])
|
2017-10-16 23:16:20 -04:00
|
|
|
|
2020-06-29 00:37:04 -04:00
|
|
|
def test_query_obj_uses_sortby(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2020-06-29 00:37:04 -04:00
|
|
|
form_data = {
|
|
|
|
"metrics": ["colA", "colB"],
|
|
|
|
"order_desc": False,
|
|
|
|
}
|
|
|
|
|
|
|
|
def run_test(metric):
|
|
|
|
form_data["timeseries_limit_metric"] = metric
|
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
query_obj = test_viz.query_obj()
|
|
|
|
self.assertEqual(["colA", "colB", metric], query_obj["metrics"])
|
|
|
|
self.assertEqual([(metric, True)], query_obj["orderby"])
|
|
|
|
|
|
|
|
run_test("simple_metric")
|
|
|
|
run_test(
|
|
|
|
{
|
|
|
|
"label": "adhoc_metric",
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"column": {"column_name": "sort_column",},
|
|
|
|
}
|
|
|
|
)
|
2017-10-16 23:16:20 -04:00
|
|
|
|
|
|
|
def test_should_be_timeseries_raises_when_no_granularity(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"include_time": True}
|
2017-10-16 23:16:20 -04:00
|
|
|
with self.assertRaises(Exception):
|
2020-06-29 00:37:04 -04:00
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
2017-10-16 23:16:20 -04:00
|
|
|
test_viz.should_be_timeseries()
|
2017-09-26 18:11:35 -04:00
|
|
|
|
2020-02-26 00:34:36 -05:00
|
|
|
def test_adhoc_metric_with_sortby(self):
|
|
|
|
metrics = [
|
|
|
|
{
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "sum_value",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
}
|
|
|
|
]
|
|
|
|
form_data = {
|
|
|
|
"metrics": metrics,
|
|
|
|
"timeseries_limit_metric": {
|
|
|
|
"expressionType": "SIMPLE",
|
|
|
|
"aggregate": "SUM",
|
|
|
|
"label": "SUM(value1)",
|
|
|
|
"column": {"column_name": "value1", "type": "DOUBLE"},
|
|
|
|
},
|
|
|
|
"order_desc": False,
|
|
|
|
}
|
|
|
|
|
|
|
|
df = pd.DataFrame({"SUM(value1)": [15], "sum_value": [15]})
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
test_viz = viz.TableViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
2020-05-20 13:20:54 -04:00
|
|
|
self.assertEqual(["sum_value"], data["columns"])
|
2020-02-26 00:34:36 -05:00
|
|
|
|
2017-09-26 18:11:35 -04:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestDistBarViz(SupersetTestCase):
|
2019-12-03 19:11:15 -05:00
|
|
|
def test_groupby_nulls(self):
|
|
|
|
form_data = {
|
|
|
|
"metrics": ["votes"],
|
|
|
|
"adhoc_filters": [],
|
|
|
|
"groupby": ["toppings"],
|
|
|
|
"columns": [],
|
2021-06-30 07:36:05 -04:00
|
|
|
"order_desc": True,
|
2019-12-03 19:11:15 -05:00
|
|
|
}
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"toppings": ["cheese", "pepperoni", "anchovies", None],
|
|
|
|
"votes": [3, 5, 1, 2],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
test_viz = viz.DistributionBarViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)[0]
|
|
|
|
self.assertEqual("votes", data["key"])
|
|
|
|
expected_values = [
|
|
|
|
{"x": "pepperoni", "y": 5},
|
|
|
|
{"x": "cheese", "y": 3},
|
|
|
|
{"x": NULL_STRING, "y": 2},
|
|
|
|
{"x": "anchovies", "y": 1},
|
|
|
|
]
|
|
|
|
self.assertEqual(expected_values, data["values"])
|
|
|
|
|
|
|
|
def test_groupby_nans(self):
|
|
|
|
form_data = {
|
|
|
|
"metrics": ["count"],
|
|
|
|
"adhoc_filters": [],
|
|
|
|
"groupby": ["beds"],
|
|
|
|
"columns": [],
|
2021-06-30 07:36:05 -04:00
|
|
|
"order_desc": True,
|
2019-12-03 19:11:15 -05:00
|
|
|
}
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame({"beds": [0, 1, nan, 2], "count": [30, 42, 3, 29]})
|
|
|
|
test_viz = viz.DistributionBarViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)[0]
|
|
|
|
self.assertEqual("count", data["key"])
|
|
|
|
expected_values = [
|
|
|
|
{"x": "1.0", "y": 42},
|
|
|
|
{"x": "0.0", "y": 30},
|
|
|
|
{"x": "2.0", "y": 29},
|
|
|
|
{"x": NULL_STRING, "y": 3},
|
|
|
|
]
|
2021-01-28 03:39:00 -05:00
|
|
|
|
2019-12-03 19:11:15 -05:00
|
|
|
self.assertEqual(expected_values, data["values"])
|
|
|
|
|
|
|
|
def test_column_nulls(self):
|
|
|
|
form_data = {
|
|
|
|
"metrics": ["votes"],
|
|
|
|
"adhoc_filters": [],
|
|
|
|
"groupby": ["toppings"],
|
|
|
|
"columns": ["role"],
|
2021-06-30 07:36:05 -04:00
|
|
|
"order_desc": True,
|
2019-12-03 19:11:15 -05:00
|
|
|
}
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"toppings": ["cheese", "pepperoni", "cheese", "pepperoni"],
|
|
|
|
"role": ["engineer", "engineer", None, None],
|
|
|
|
"votes": [3, 5, 1, 2],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
test_viz = viz.DistributionBarViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
expected = [
|
|
|
|
{
|
|
|
|
"key": NULL_STRING,
|
|
|
|
"values": [{"x": "pepperoni", "y": 2}, {"x": "cheese", "y": 1}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "engineer",
|
|
|
|
"values": [{"x": "pepperoni", "y": 5}, {"x": "cheese", "y": 3}],
|
|
|
|
},
|
|
|
|
]
|
|
|
|
self.assertEqual(expected, data)
|
|
|
|
|
2021-01-28 03:39:00 -05:00
|
|
|
def test_column_metrics_in_order(self):
|
|
|
|
form_data = {
|
|
|
|
"metrics": ["z_column", "votes", "a_column"],
|
|
|
|
"adhoc_filters": [],
|
|
|
|
"groupby": ["toppings"],
|
|
|
|
"columns": [],
|
2021-06-30 07:36:05 -04:00
|
|
|
"order_desc": True,
|
2021-01-28 03:39:00 -05:00
|
|
|
}
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"toppings": ["cheese", "pepperoni", "cheese", "pepperoni"],
|
|
|
|
"role": ["engineer", "engineer", None, None],
|
|
|
|
"votes": [3, 5, 1, 2],
|
|
|
|
"a_column": [3, 5, 1, 2],
|
|
|
|
"z_column": [3, 5, 1, 2],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
test_viz = viz.DistributionBarViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
|
|
|
|
expected = [
|
|
|
|
{
|
|
|
|
"key": "z_column",
|
|
|
|
"values": [{"x": "pepperoni", "y": 3.5}, {"x": "cheese", "y": 2.0}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "votes",
|
|
|
|
"values": [{"x": "pepperoni", "y": 3.5}, {"x": "cheese", "y": 2.0}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "a_column",
|
|
|
|
"values": [{"x": "pepperoni", "y": 3.5}, {"x": "cheese", "y": 2.0}],
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
self.assertEqual(expected, data)
|
|
|
|
|
|
|
|
def test_column_metrics_in_order_with_breakdowns(self):
|
|
|
|
form_data = {
|
|
|
|
"metrics": ["z_column", "votes", "a_column"],
|
|
|
|
"adhoc_filters": [],
|
|
|
|
"groupby": ["toppings"],
|
|
|
|
"columns": ["role"],
|
2021-06-30 07:36:05 -04:00
|
|
|
"order_desc": True,
|
2021-01-28 03:39:00 -05:00
|
|
|
}
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"toppings": ["cheese", "pepperoni", "cheese", "pepperoni"],
|
|
|
|
"role": ["engineer", "engineer", None, None],
|
|
|
|
"votes": [3, 5, 1, 2],
|
|
|
|
"a_column": [3, 5, 1, 2],
|
|
|
|
"z_column": [3, 5, 1, 2],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
test_viz = viz.DistributionBarViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
|
|
|
|
expected = [
|
|
|
|
{
|
|
|
|
"key": f"z_column, {NULL_STRING}",
|
|
|
|
"values": [{"x": "pepperoni", "y": 2}, {"x": "cheese", "y": 1}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "z_column, engineer",
|
|
|
|
"values": [{"x": "pepperoni", "y": 5}, {"x": "cheese", "y": 3}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": f"votes, {NULL_STRING}",
|
|
|
|
"values": [{"x": "pepperoni", "y": 2}, {"x": "cheese", "y": 1}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "votes, engineer",
|
|
|
|
"values": [{"x": "pepperoni", "y": 5}, {"x": "cheese", "y": 3}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": f"a_column, {NULL_STRING}",
|
|
|
|
"values": [{"x": "pepperoni", "y": 2}, {"x": "cheese", "y": 1}],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"key": "a_column, engineer",
|
|
|
|
"values": [{"x": "pepperoni", "y": 5}, {"x": "cheese", "y": 3}],
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
self.assertEqual(expected, data)
|
|
|
|
|
2019-12-03 19:11:15 -05:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestPairedTTest(SupersetTestCase):
|
2017-09-26 18:11:35 -04:00
|
|
|
def test_get_data_transforms_dataframe(self):
|
|
|
|
form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"groupby": ["groupA", "groupB", "groupC"],
|
|
|
|
"metrics": ["metric1", "metric2", "metric3"],
|
2017-09-26 18:11:35 -04:00
|
|
|
}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-09-26 18:11:35 -04:00
|
|
|
# Test data
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-09-26 18:11:35 -04:00
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
pairedTTestViz = viz.viz_types["paired_ttest"](datasource, form_data)
|
2017-09-26 18:11:35 -04:00
|
|
|
data = pairedTTestViz.get_data(df)
|
|
|
|
# Check method correctly transforms data
|
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"metric1": [
|
2017-09-26 18:11:35 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 1},
|
|
|
|
{"x": 200, "y": 2},
|
|
|
|
{"x": 300, "y": 3},
|
|
|
|
],
|
|
|
|
"group": ("a1", "a2", "a3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 4},
|
|
|
|
{"x": 200, "y": 5},
|
|
|
|
{"x": 300, "y": 6},
|
|
|
|
],
|
|
|
|
"group": ("b1", "b2", "b3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 7},
|
|
|
|
{"x": 200, "y": 8},
|
|
|
|
{"x": 300, "y": 9},
|
|
|
|
],
|
|
|
|
"group": ("c1", "c2", "c3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
],
|
2019-06-25 16:34:48 -04:00
|
|
|
"metric2": [
|
2017-09-26 18:11:35 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 10},
|
|
|
|
{"x": 200, "y": 20},
|
|
|
|
{"x": 300, "y": 30},
|
|
|
|
],
|
|
|
|
"group": ("a1", "a2", "a3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 40},
|
|
|
|
{"x": 200, "y": 50},
|
|
|
|
{"x": 300, "y": 60},
|
|
|
|
],
|
|
|
|
"group": ("b1", "b2", "b3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 70},
|
|
|
|
{"x": 200, "y": 80},
|
|
|
|
{"x": 300, "y": 90},
|
|
|
|
],
|
|
|
|
"group": ("c1", "c2", "c3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
],
|
2019-06-25 16:34:48 -04:00
|
|
|
"metric3": [
|
2017-09-26 18:11:35 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 100},
|
|
|
|
{"x": 200, "y": 200},
|
|
|
|
{"x": 300, "y": 300},
|
|
|
|
],
|
|
|
|
"group": ("a1", "a2", "a3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 400},
|
|
|
|
{"x": 200, "y": 500},
|
|
|
|
{"x": 300, "y": 600},
|
|
|
|
],
|
|
|
|
"group": ("b1", "b2", "b3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 700},
|
|
|
|
{"x": 200, "y": 800},
|
|
|
|
{"x": 300, "y": 900},
|
|
|
|
],
|
|
|
|
"group": ("c1", "c2", "c3"),
|
2017-09-26 18:11:35 -04:00
|
|
|
},
|
|
|
|
],
|
|
|
|
}
|
2017-10-16 23:16:20 -04:00
|
|
|
self.assertEqual(data, expected)
|
2017-09-26 18:11:35 -04:00
|
|
|
|
|
|
|
def test_get_data_empty_null_keys(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"groupby": [], "metrics": ["", None]}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-09-26 18:11:35 -04:00
|
|
|
# Test data
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw[""] = [1, 2, 3]
|
2017-09-26 18:11:35 -04:00
|
|
|
raw[None] = [10, 20, 30]
|
|
|
|
|
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
pairedTTestViz = viz.viz_types["paired_ttest"](datasource, form_data)
|
2017-09-26 18:11:35 -04:00
|
|
|
data = pairedTTestViz.get_data(df)
|
|
|
|
# Check method correctly transforms data
|
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"N/A": [
|
2017-09-26 18:11:35 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 1},
|
|
|
|
{"x": 200, "y": 2},
|
|
|
|
{"x": 300, "y": 3},
|
|
|
|
],
|
|
|
|
"group": "All",
|
|
|
|
}
|
2017-09-26 18:11:35 -04:00
|
|
|
],
|
2019-06-25 16:34:48 -04:00
|
|
|
"NULL": [
|
2017-09-26 18:11:35 -04:00
|
|
|
{
|
2019-06-25 16:34:48 -04:00
|
|
|
"values": [
|
|
|
|
{"x": 100, "y": 10},
|
|
|
|
{"x": 200, "y": 20},
|
|
|
|
{"x": 300, "y": 30},
|
|
|
|
],
|
|
|
|
"group": "All",
|
|
|
|
}
|
2017-09-26 18:11:35 -04:00
|
|
|
],
|
|
|
|
}
|
2017-10-16 23:16:20 -04:00
|
|
|
self.assertEqual(data, expected)
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestPartitionViz(SupersetTestCase):
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.viz.BaseViz.query_obj")
|
2017-10-13 00:54:59 -04:00
|
|
|
def test_query_obj_time_series_option(self, super_query_obj):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2017-10-13 00:54:59 -04:00
|
|
|
form_data = {}
|
|
|
|
test_viz = viz.PartitionViz(datasource, form_data)
|
|
|
|
super_query_obj.return_value = {}
|
|
|
|
query_obj = test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertFalse(query_obj["is_timeseries"])
|
|
|
|
test_viz.form_data["time_series_option"] = "agg_sum"
|
2017-10-13 00:54:59 -04:00
|
|
|
query_obj = test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertTrue(query_obj["is_timeseries"])
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
def test_levels_for_computes_levels(self):
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-10-13 00:54:59 -04:00
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
groups = ["groupA", "groupB", "groupC"]
|
|
|
|
time_op = "agg_sum"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz = viz.PartitionViz(Mock(), {})
|
|
|
|
levels = test_viz.levels_for(time_op, groups, df)
|
|
|
|
self.assertEqual(4, len(levels))
|
2019-06-25 16:34:48 -04:00
|
|
|
expected = {DTTM_ALIAS: 1800, "metric1": 45, "metric2": 450, "metric3": 4500}
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(expected, levels[0].to_dict())
|
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
DTTM_ALIAS: {"a1": 600, "b1": 600, "c1": 600},
|
|
|
|
"metric1": {"a1": 6, "b1": 15, "c1": 24},
|
|
|
|
"metric2": {"a1": 60, "b1": 150, "c1": 240},
|
|
|
|
"metric3": {"a1": 600, "b1": 1500, "c1": 2400},
|
2017-10-13 00:54:59 -04:00
|
|
|
}
|
|
|
|
self.assertEqual(expected, levels[1].to_dict())
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(["groupA", "groupB"], levels[2].index.names)
|
|
|
|
self.assertEqual(["groupA", "groupB", "groupC"], levels[3].index.names)
|
|
|
|
time_op = "agg_mean"
|
2017-10-13 00:54:59 -04:00
|
|
|
levels = test_viz.levels_for(time_op, groups, df)
|
|
|
|
self.assertEqual(4, len(levels))
|
|
|
|
expected = {
|
|
|
|
DTTM_ALIAS: 200.0,
|
2019-06-25 16:34:48 -04:00
|
|
|
"metric1": 5.0,
|
|
|
|
"metric2": 50.0,
|
|
|
|
"metric3": 500.0,
|
2017-10-13 00:54:59 -04:00
|
|
|
}
|
|
|
|
self.assertEqual(expected, levels[0].to_dict())
|
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
DTTM_ALIAS: {"a1": 200, "c1": 200, "b1": 200},
|
|
|
|
"metric1": {"a1": 2, "b1": 5, "c1": 8},
|
|
|
|
"metric2": {"a1": 20, "b1": 50, "c1": 80},
|
|
|
|
"metric3": {"a1": 200, "b1": 500, "c1": 800},
|
2017-10-13 00:54:59 -04:00
|
|
|
}
|
|
|
|
self.assertEqual(expected, levels[1].to_dict())
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(["groupA", "groupB"], levels[2].index.names)
|
|
|
|
self.assertEqual(["groupA", "groupB", "groupC"], levels[3].index.names)
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
def test_levels_for_diff_computes_difference(self):
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-10-13 00:54:59 -04:00
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
groups = ["groupA", "groupB", "groupC"]
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz = viz.PartitionViz(Mock(), {})
|
2019-06-25 16:34:48 -04:00
|
|
|
time_op = "point_diff"
|
2017-10-13 00:54:59 -04:00
|
|
|
levels = test_viz.levels_for_diff(time_op, groups, df)
|
2019-06-25 16:34:48 -04:00
|
|
|
expected = {"metric1": 6, "metric2": 60, "metric3": 600}
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(expected, levels[0].to_dict())
|
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"metric1": {"a1": 2, "b1": 2, "c1": 2},
|
|
|
|
"metric2": {"a1": 20, "b1": 20, "c1": 20},
|
|
|
|
"metric3": {"a1": 200, "b1": 200, "c1": 200},
|
2017-10-13 00:54:59 -04:00
|
|
|
}
|
|
|
|
self.assertEqual(expected, levels[1].to_dict())
|
|
|
|
self.assertEqual(4, len(levels))
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(["groupA", "groupB", "groupC"], levels[3].index.names)
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
def test_levels_for_time_calls_process_data_and_drops_cols(self):
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-10-13 00:54:59 -04:00
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
groups = ["groupA", "groupB", "groupC"]
|
|
|
|
test_viz = viz.PartitionViz(Mock(), {"groupby": groups})
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
def return_args(df_drop, aggregate):
|
|
|
|
return df_drop
|
2019-06-25 16:34:48 -04:00
|
|
|
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.process_data = Mock(side_effect=return_args)
|
|
|
|
levels = test_viz.levels_for_time(groups, df)
|
|
|
|
self.assertEqual(4, len(levels))
|
2019-06-25 16:34:48 -04:00
|
|
|
cols = [DTTM_ALIAS, "metric1", "metric2", "metric3"]
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(sorted(cols), sorted(levels[0].columns.tolist()))
|
2019-06-25 16:34:48 -04:00
|
|
|
cols += ["groupA"]
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(sorted(cols), sorted(levels[1].columns.tolist()))
|
2019-06-25 16:34:48 -04:00
|
|
|
cols += ["groupB"]
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(sorted(cols), sorted(levels[2].columns.tolist()))
|
2019-06-25 16:34:48 -04:00
|
|
|
cols += ["groupC"]
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(sorted(cols), sorted(levels[3].columns.tolist()))
|
|
|
|
self.assertEqual(4, len(test_viz.process_data.mock_calls))
|
|
|
|
|
|
|
|
def test_nest_values_returns_hierarchy(self):
|
|
|
|
raw = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-10-13 00:54:59 -04:00
|
|
|
df = pd.DataFrame(raw)
|
|
|
|
test_viz = viz.PartitionViz(Mock(), {})
|
2019-06-25 16:34:48 -04:00
|
|
|
groups = ["groupA", "groupB", "groupC"]
|
|
|
|
levels = test_viz.levels_for("agg_sum", groups, df)
|
2017-10-13 00:54:59 -04:00
|
|
|
nest = test_viz.nest_values(levels)
|
|
|
|
self.assertEqual(3, len(nest))
|
|
|
|
for i in range(0, 3):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("metric" + str(i + 1), nest[i]["name"])
|
|
|
|
self.assertEqual(3, len(nest[0]["children"]))
|
|
|
|
self.assertEqual(1, len(nest[0]["children"][0]["children"]))
|
|
|
|
self.assertEqual(1, len(nest[0]["children"][0]["children"][0]["children"]))
|
2017-10-13 00:54:59 -04:00
|
|
|
|
|
|
|
def test_nest_procs_returns_hierarchy(self):
|
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
2017-10-13 00:54:59 -04:00
|
|
|
df = pd.DataFrame(raw)
|
|
|
|
test_viz = viz.PartitionViz(Mock(), {})
|
2019-06-25 16:34:48 -04:00
|
|
|
groups = ["groupA", "groupB", "groupC"]
|
|
|
|
metrics = ["metric1", "metric2", "metric3"]
|
2017-10-13 00:54:59 -04:00
|
|
|
procs = {}
|
|
|
|
for i in range(0, 4):
|
|
|
|
df_drop = df.drop(groups[i:], 1)
|
|
|
|
pivot = df_drop.pivot_table(
|
2019-06-25 16:34:48 -04:00
|
|
|
index=DTTM_ALIAS, columns=groups[:i], values=metrics
|
2017-10-13 00:54:59 -04:00
|
|
|
)
|
|
|
|
procs[i] = pivot
|
|
|
|
nest = test_viz.nest_procs(procs)
|
|
|
|
self.assertEqual(3, len(nest))
|
|
|
|
for i in range(0, 3):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("metric" + str(i + 1), nest[i]["name"])
|
|
|
|
self.assertEqual(None, nest[i].get("val"))
|
|
|
|
self.assertEqual(3, len(nest[0]["children"]))
|
|
|
|
self.assertEqual(3, len(nest[0]["children"][0]["children"]))
|
|
|
|
self.assertEqual(1, len(nest[0]["children"][0]["children"][0]["children"]))
|
2017-11-10 15:06:22 -05:00
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
1, len(nest[0]["children"][0]["children"][0]["children"][0]["children"])
|
2017-10-13 00:54:59 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_get_data_calls_correct_method(self):
|
2020-07-19 10:19:30 -04:00
|
|
|
raw = {}
|
|
|
|
raw[DTTM_ALIAS] = [100, 200, 300, 100, 200, 300, 100, 200, 300]
|
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
raw["metric2"] = [10, 20, 30, 40, 50, 60, 70, 80, 90]
|
|
|
|
raw["metric3"] = [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
|
|
|
df = pd.DataFrame(raw)
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz = viz.PartitionViz(Mock(), {})
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
test_viz.get_data(df)
|
|
|
|
test_viz.levels_for = Mock(return_value=1)
|
|
|
|
test_viz.nest_values = Mock(return_value=1)
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz.form_data["groupby"] = ["groups"]
|
|
|
|
test_viz.form_data["time_series_option"] = "not_time"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("agg_sum", test_viz.levels_for.mock_calls[0][1][0])
|
|
|
|
test_viz.form_data["time_series_option"] = "agg_sum"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("agg_sum", test_viz.levels_for.mock_calls[1][1][0])
|
|
|
|
test_viz.form_data["time_series_option"] = "agg_mean"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("agg_mean", test_viz.levels_for.mock_calls[2][1][0])
|
|
|
|
test_viz.form_data["time_series_option"] = "point_diff"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.levels_for_diff = Mock(return_value=1)
|
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("point_diff", test_viz.levels_for_diff.mock_calls[0][1][0])
|
|
|
|
test_viz.form_data["time_series_option"] = "point_percent"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("point_percent", test_viz.levels_for_diff.mock_calls[1][1][0])
|
|
|
|
test_viz.form_data["time_series_option"] = "point_factor"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("point_factor", test_viz.levels_for_diff.mock_calls[2][1][0])
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.levels_for_time = Mock(return_value=1)
|
|
|
|
test_viz.nest_procs = Mock(return_value=1)
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz.form_data["time_series_option"] = "adv_anal"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
|
|
|
self.assertEqual(1, len(test_viz.levels_for_time.mock_calls))
|
|
|
|
self.assertEqual(1, len(test_viz.nest_procs.mock_calls))
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz.form_data["time_series_option"] = "time_series"
|
2017-10-13 00:54:59 -04:00
|
|
|
test_viz.get_data(df)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual("agg_sum", test_viz.levels_for.mock_calls[3][1][0])
|
2017-10-13 00:54:59 -04:00
|
|
|
self.assertEqual(7, len(test_viz.nest_values.mock_calls))
|
2018-02-03 23:18:24 -05:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestRoseVis(SupersetTestCase):
|
2018-02-03 23:18:24 -05:00
|
|
|
def test_rose_vis_get_data(self):
|
|
|
|
raw = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
t1 = pd.Timestamp("2000")
|
|
|
|
t2 = pd.Timestamp("2002")
|
|
|
|
t3 = pd.Timestamp("2004")
|
2018-02-03 23:18:24 -05:00
|
|
|
raw[DTTM_ALIAS] = [t1, t2, t3, t1, t2, t3, t1, t2, t3]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["groupA"] = ["a1", "a1", "a1", "b1", "b1", "b1", "c1", "c1", "c1"]
|
|
|
|
raw["groupB"] = ["a2", "a2", "a2", "b2", "b2", "b2", "c2", "c2", "c2"]
|
|
|
|
raw["groupC"] = ["a3", "a3", "a3", "b3", "b3", "b3", "c3", "c3", "c3"]
|
|
|
|
raw["metric1"] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
2018-02-03 23:18:24 -05:00
|
|
|
df = pd.DataFrame(raw)
|
2019-06-25 16:34:48 -04:00
|
|
|
fd = {"metrics": ["metric1"], "groupby": ["groupA"]}
|
2018-02-03 23:18:24 -05:00
|
|
|
test_viz = viz.RoseViz(Mock(), fd)
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz.metrics = fd["metrics"]
|
2018-02-03 23:18:24 -05:00
|
|
|
res = test_viz.get_data(df)
|
|
|
|
expected = {
|
|
|
|
946684800000000000: [
|
2019-06-25 16:34:48 -04:00
|
|
|
{"time": t1, "value": 1, "key": ("a1",), "name": ("a1",)},
|
|
|
|
{"time": t1, "value": 4, "key": ("b1",), "name": ("b1",)},
|
|
|
|
{"time": t1, "value": 7, "key": ("c1",), "name": ("c1",)},
|
2018-02-03 23:18:24 -05:00
|
|
|
],
|
|
|
|
1009843200000000000: [
|
2019-06-25 16:34:48 -04:00
|
|
|
{"time": t2, "value": 2, "key": ("a1",), "name": ("a1",)},
|
|
|
|
{"time": t2, "value": 5, "key": ("b1",), "name": ("b1",)},
|
|
|
|
{"time": t2, "value": 8, "key": ("c1",), "name": ("c1",)},
|
2018-02-03 23:18:24 -05:00
|
|
|
],
|
|
|
|
1072915200000000000: [
|
2019-06-25 16:34:48 -04:00
|
|
|
{"time": t3, "value": 3, "key": ("a1",), "name": ("a1",)},
|
|
|
|
{"time": t3, "value": 6, "key": ("b1",), "name": ("b1",)},
|
|
|
|
{"time": t3, "value": 9, "key": ("c1",), "name": ("c1",)},
|
2018-02-03 23:18:24 -05:00
|
|
|
],
|
|
|
|
}
|
|
|
|
self.assertEqual(expected, res)
|
2018-04-11 16:24:51 -04:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestTimeSeriesTableViz(SupersetTestCase):
|
2018-04-11 16:24:51 -04:00
|
|
|
def test_get_data_metrics(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"metrics": ["sum__A", "count"], "groupby": []}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-11 16:24:51 -04:00
|
|
|
raw = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
t1 = pd.Timestamp("2000")
|
|
|
|
t2 = pd.Timestamp("2002")
|
2018-04-11 16:24:51 -04:00
|
|
|
raw[DTTM_ALIAS] = [t1, t2]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["sum__A"] = [15, 20]
|
|
|
|
raw["count"] = [6, 7]
|
2018-04-11 16:24:51 -04:00
|
|
|
df = pd.DataFrame(raw)
|
|
|
|
test_viz = viz.TimeTableViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
# Check method correctly transforms data
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(set(["count", "sum__A"]), set(data["columns"]))
|
|
|
|
time_format = "%Y-%m-%d %H:%M:%S"
|
2018-04-11 16:24:51 -04:00
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
t1.strftime(time_format): {"sum__A": 15, "count": 6},
|
|
|
|
t2.strftime(time_format): {"sum__A": 20, "count": 7},
|
2018-04-11 16:24:51 -04:00
|
|
|
}
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(expected, data["records"])
|
2018-04-11 16:24:51 -04:00
|
|
|
|
|
|
|
def test_get_data_group_by(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"metrics": ["sum__A"], "groupby": ["groupby1"]}
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-11 16:24:51 -04:00
|
|
|
raw = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
t1 = pd.Timestamp("2000")
|
|
|
|
t2 = pd.Timestamp("2002")
|
2018-04-11 16:24:51 -04:00
|
|
|
raw[DTTM_ALIAS] = [t1, t1, t1, t2, t2, t2]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["sum__A"] = [15, 20, 25, 30, 35, 40]
|
|
|
|
raw["groupby1"] = ["a1", "a2", "a3", "a1", "a2", "a3"]
|
2018-04-11 16:24:51 -04:00
|
|
|
df = pd.DataFrame(raw)
|
|
|
|
test_viz = viz.TimeTableViz(datasource, form_data)
|
|
|
|
data = test_viz.get_data(df)
|
|
|
|
# Check method correctly transforms data
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(set(["a1", "a2", "a3"]), set(data["columns"]))
|
|
|
|
time_format = "%Y-%m-%d %H:%M:%S"
|
2018-04-11 16:24:51 -04:00
|
|
|
expected = {
|
2019-06-25 16:34:48 -04:00
|
|
|
t1.strftime(time_format): {"a1": 15, "a2": 20, "a3": 25},
|
|
|
|
t2.strftime(time_format): {"a1": 30, "a2": 35, "a3": 40},
|
2018-04-11 16:24:51 -04:00
|
|
|
}
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertEqual(expected, data["records"])
|
2018-04-11 16:24:51 -04:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.viz.BaseViz.query_obj")
|
2018-04-11 16:24:51 -04:00
|
|
|
def test_query_obj_throws_metrics_and_groupby(self, super_query_obj):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"groupby": ["a"]}
|
2018-04-11 16:24:51 -04:00
|
|
|
super_query_obj.return_value = {}
|
|
|
|
test_viz = viz.TimeTableViz(datasource, form_data)
|
|
|
|
with self.assertRaises(Exception):
|
|
|
|
test_viz.query_obj()
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data["metrics"] = ["x", "y"]
|
2018-04-11 16:24:51 -04:00
|
|
|
test_viz = viz.TimeTableViz(datasource, form_data)
|
|
|
|
with self.assertRaises(Exception):
|
|
|
|
test_viz.query_obj()
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestBaseDeckGLViz(SupersetTestCase):
|
2018-04-12 20:20:39 -04:00
|
|
|
def test_get_metrics(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-12 20:20:39 -04:00
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
result = test_viz_deckgl.get_metrics()
|
2019-06-25 16:34:48 -04:00
|
|
|
assert result == [form_data.get("size")]
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
form_data = {}
|
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
result = test_viz_deckgl.get_metrics()
|
|
|
|
assert result == []
|
|
|
|
|
|
|
|
def test_scatterviz_get_metrics(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
form_data = {}
|
|
|
|
test_viz_deckgl = viz.DeckScatterViz(datasource, form_data)
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz_deckgl.point_radius_fixed = {"type": "metric", "value": "int"}
|
2018-04-12 20:20:39 -04:00
|
|
|
result = test_viz_deckgl.get_metrics()
|
2019-06-25 16:34:48 -04:00
|
|
|
assert result == ["int"]
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
form_data = {}
|
|
|
|
test_viz_deckgl = viz.DeckScatterViz(datasource, form_data)
|
|
|
|
test_viz_deckgl.point_radius_fixed = {}
|
|
|
|
result = test_viz_deckgl.get_metrics()
|
2020-06-03 18:26:12 -04:00
|
|
|
assert result == []
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
def test_get_js_columns(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
mock_d = {"a": "dummy1", "b": "dummy2", "c": "dummy3"}
|
2018-04-12 20:20:39 -04:00
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
result = test_viz_deckgl.get_js_columns(mock_d)
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
assert result == {"color": None}
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
def test_get_properties(self):
|
|
|
|
mock_d = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-12 20:20:39 -04:00
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
|
|
|
|
with self.assertRaises(NotImplementedError) as context:
|
|
|
|
test_viz_deckgl.get_properties(mock_d)
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertTrue("" in str(context.exception))
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
def test_process_spatial_query_obj(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
mock_key = "spatial_key"
|
2018-04-12 20:20:39 -04:00
|
|
|
mock_gb = []
|
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
|
|
|
|
with self.assertRaises(ValueError) as context:
|
|
|
|
test_viz_deckgl.process_spatial_query_obj(mock_key, mock_gb)
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertTrue("Bad spatial key" in str(context.exception))
|
2018-04-12 20:20:39 -04:00
|
|
|
|
|
|
|
test_form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"latlong_key": {"type": "latlong", "lonCol": "lon", "latCol": "lat"},
|
|
|
|
"delimited_key": {"type": "delimited", "lonlatCol": "lonlat"},
|
|
|
|
"geohash_key": {"type": "geohash", "geohashCol": "geo"},
|
2018-04-12 20:20:39 -04:00
|
|
|
}
|
|
|
|
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-12 20:20:39 -04:00
|
|
|
expected_results = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"latlong_key": ["lon", "lat"],
|
|
|
|
"delimited_key": ["lonlat"],
|
|
|
|
"geohash_key": ["geo"],
|
2018-04-12 20:20:39 -04:00
|
|
|
}
|
2019-06-25 16:34:48 -04:00
|
|
|
for mock_key in ["latlong_key", "delimited_key", "geohash_key"]:
|
2018-04-12 20:20:39 -04:00
|
|
|
mock_gb = []
|
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, test_form_data)
|
|
|
|
test_viz_deckgl.process_spatial_query_obj(mock_key, mock_gb)
|
|
|
|
assert expected_results.get(mock_key) == mock_gb
|
|
|
|
|
|
|
|
def test_geojson_query_obj(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_geojson_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-04-12 20:20:39 -04:00
|
|
|
test_viz_deckgl = viz.DeckGeoJson(datasource, form_data)
|
|
|
|
results = test_viz_deckgl.query_obj()
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
assert results["metrics"] == []
|
|
|
|
assert results["groupby"] == []
|
|
|
|
assert results["columns"] == ["test_col"]
|
2018-07-16 16:42:07 -04:00
|
|
|
|
|
|
|
def test_parse_coordinates(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-07-16 16:42:07 -04:00
|
|
|
viz_instance = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
coord = viz_instance.parse_coordinates("1.23, 3.21")
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(coord, (1.23, 3.21))
|
2018-07-16 16:42:07 -04:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
coord = viz_instance.parse_coordinates("1.23 3.21")
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(coord, (1.23, 3.21))
|
2018-07-16 16:42:07 -04:00
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(viz_instance.parse_coordinates(None), None)
|
2018-07-16 16:42:07 -04:00
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(viz_instance.parse_coordinates(""), None)
|
2018-07-16 16:42:07 -04:00
|
|
|
|
|
|
|
def test_parse_coordinates_raises(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = load_fixture("deck_path_form_data.json")
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-07-16 16:42:07 -04:00
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, form_data)
|
|
|
|
|
|
|
|
with self.assertRaises(SpatialException):
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz_deckgl.parse_coordinates("NULL")
|
2018-07-16 16:42:07 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SpatialException):
|
2019-06-25 16:34:48 -04:00
|
|
|
test_viz_deckgl.parse_coordinates("fldkjsalkj,fdlaskjfjadlksj")
|
2018-07-26 16:18:35 -04:00
|
|
|
|
2021-04-28 15:14:55 -04:00
|
|
|
def test_filter_nulls(self):
|
2018-08-19 19:04:01 -04:00
|
|
|
test_form_data = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"latlong_key": {"type": "latlong", "lonCol": "lon", "latCol": "lat"},
|
|
|
|
"delimited_key": {"type": "delimited", "lonlatCol": "lonlat"},
|
|
|
|
"geohash_key": {"type": "geohash", "geohashCol": "geo"},
|
2018-08-19 19:04:01 -04:00
|
|
|
}
|
|
|
|
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2018-08-19 19:04:01 -04:00
|
|
|
expected_results = {
|
2019-06-25 16:34:48 -04:00
|
|
|
"latlong_key": [
|
|
|
|
{
|
|
|
|
"clause": "WHERE",
|
|
|
|
"expressionType": "SIMPLE",
|
2021-04-28 15:14:55 -04:00
|
|
|
"filterOptionName": "bfa3a42a6f3de3c781b7d4f8e8d6613d",
|
2019-06-25 16:34:48 -04:00
|
|
|
"comparator": "",
|
|
|
|
"operator": "IS NOT NULL",
|
|
|
|
"subject": "lat",
|
feat: [explore] don't save filters inherited from a dashboard (#9340)
* feat: [explore] don't save filters inherited from a dashboard
When navigating to explore from a dashboard context, the current
dashboard filter(s) are passed along to explore so that the context is
kept. So say you're filtering on "country=Romania", in your dashboard
and pivot to explore, that filter is still there and keep on exploring.
Now a common issue is that you'll want to make some tweak to your chart
that are unrelated to the filter, say toggling the legend off for
instance, and then save it. Now you back to your dashboard and even
though you started with an "all countries" dashboard, with a global
filter on country, now that one chart is stuck on "Romania". Typically
you notice this when filtering on something else, say "Italy" and then
that one chart now has two mutually exclusive filters, and show "No data".
Now, the fix is to flag the filter as "extra" (that's the not-so-good internal
name we use for these inherited filters) and make it clear that that
specific filter is special and won't be saved when saving the chart.
* fix build
2020-03-24 02:05:00 -04:00
|
|
|
"isExtra": False,
|
2019-06-25 16:34:48 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"clause": "WHERE",
|
|
|
|
"expressionType": "SIMPLE",
|
2021-04-28 15:14:55 -04:00
|
|
|
"filterOptionName": "2d35d87b57c6f1a5ae139f1a6b0cbd0a",
|
2019-06-25 16:34:48 -04:00
|
|
|
"comparator": "",
|
|
|
|
"operator": "IS NOT NULL",
|
|
|
|
"subject": "lon",
|
feat: [explore] don't save filters inherited from a dashboard (#9340)
* feat: [explore] don't save filters inherited from a dashboard
When navigating to explore from a dashboard context, the current
dashboard filter(s) are passed along to explore so that the context is
kept. So say you're filtering on "country=Romania", in your dashboard
and pivot to explore, that filter is still there and keep on exploring.
Now a common issue is that you'll want to make some tweak to your chart
that are unrelated to the filter, say toggling the legend off for
instance, and then save it. Now you back to your dashboard and even
though you started with an "all countries" dashboard, with a global
filter on country, now that one chart is stuck on "Romania". Typically
you notice this when filtering on something else, say "Italy" and then
that one chart now has two mutually exclusive filters, and show "No data".
Now, the fix is to flag the filter as "extra" (that's the not-so-good internal
name we use for these inherited filters) and make it clear that that
specific filter is special and won't be saved when saving the chart.
* fix build
2020-03-24 02:05:00 -04:00
|
|
|
"isExtra": False,
|
2019-06-25 16:34:48 -04:00
|
|
|
},
|
|
|
|
],
|
|
|
|
"delimited_key": [
|
|
|
|
{
|
|
|
|
"clause": "WHERE",
|
|
|
|
"expressionType": "SIMPLE",
|
2021-04-28 15:14:55 -04:00
|
|
|
"filterOptionName": "89cc0fafe39a4eabc5df2cd52e4d6514",
|
2019-06-25 16:34:48 -04:00
|
|
|
"comparator": "",
|
|
|
|
"operator": "IS NOT NULL",
|
|
|
|
"subject": "lonlat",
|
feat: [explore] don't save filters inherited from a dashboard (#9340)
* feat: [explore] don't save filters inherited from a dashboard
When navigating to explore from a dashboard context, the current
dashboard filter(s) are passed along to explore so that the context is
kept. So say you're filtering on "country=Romania", in your dashboard
and pivot to explore, that filter is still there and keep on exploring.
Now a common issue is that you'll want to make some tweak to your chart
that are unrelated to the filter, say toggling the legend off for
instance, and then save it. Now you back to your dashboard and even
though you started with an "all countries" dashboard, with a global
filter on country, now that one chart is stuck on "Romania". Typically
you notice this when filtering on something else, say "Italy" and then
that one chart now has two mutually exclusive filters, and show "No data".
Now, the fix is to flag the filter as "extra" (that's the not-so-good internal
name we use for these inherited filters) and make it clear that that
specific filter is special and won't be saved when saving the chart.
* fix build
2020-03-24 02:05:00 -04:00
|
|
|
"isExtra": False,
|
2019-06-25 16:34:48 -04:00
|
|
|
}
|
|
|
|
],
|
|
|
|
"geohash_key": [
|
|
|
|
{
|
|
|
|
"clause": "WHERE",
|
|
|
|
"expressionType": "SIMPLE",
|
2021-04-28 15:14:55 -04:00
|
|
|
"filterOptionName": "fa734d9a7bab254a53b41540d46cdb6c",
|
2019-06-25 16:34:48 -04:00
|
|
|
"comparator": "",
|
|
|
|
"operator": "IS NOT NULL",
|
|
|
|
"subject": "geo",
|
feat: [explore] don't save filters inherited from a dashboard (#9340)
* feat: [explore] don't save filters inherited from a dashboard
When navigating to explore from a dashboard context, the current
dashboard filter(s) are passed along to explore so that the context is
kept. So say you're filtering on "country=Romania", in your dashboard
and pivot to explore, that filter is still there and keep on exploring.
Now a common issue is that you'll want to make some tweak to your chart
that are unrelated to the filter, say toggling the legend off for
instance, and then save it. Now you back to your dashboard and even
though you started with an "all countries" dashboard, with a global
filter on country, now that one chart is stuck on "Romania". Typically
you notice this when filtering on something else, say "Italy" and then
that one chart now has two mutually exclusive filters, and show "No data".
Now, the fix is to flag the filter as "extra" (that's the not-so-good internal
name we use for these inherited filters) and make it clear that that
specific filter is special and won't be saved when saving the chart.
* fix build
2020-03-24 02:05:00 -04:00
|
|
|
"isExtra": False,
|
2019-06-25 16:34:48 -04:00
|
|
|
}
|
|
|
|
],
|
2018-08-19 19:04:01 -04:00
|
|
|
}
|
2019-06-25 16:34:48 -04:00
|
|
|
for mock_key in ["latlong_key", "delimited_key", "geohash_key"]:
|
|
|
|
test_viz_deckgl = viz.BaseDeckGLViz(datasource, test_form_data.copy())
|
2018-08-19 19:04:01 -04:00
|
|
|
test_viz_deckgl.spatial_control_keys = [mock_key]
|
|
|
|
test_viz_deckgl.add_null_filters()
|
2019-06-25 16:34:48 -04:00
|
|
|
adhoc_filters = test_viz_deckgl.form_data["adhoc_filters"]
|
2018-08-19 19:04:01 -04:00
|
|
|
assert expected_results.get(mock_key) == adhoc_filters
|
|
|
|
|
2018-07-26 16:18:35 -04:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestTimeSeriesViz(SupersetTestCase):
|
2018-07-26 16:18:35 -04:00
|
|
|
def test_timeseries_unicode_data(self):
|
2018-08-29 00:04:06 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
2019-06-25 16:34:48 -04:00
|
|
|
form_data = {"groupby": ["name"], "metrics": ["sum__payout"]}
|
2018-07-26 16:18:35 -04:00
|
|
|
raw = {}
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["name"] = [
|
|
|
|
"Real Madrid C.F.🇺🇸🇬🇧",
|
|
|
|
"Real Madrid C.F.🇺🇸🇬🇧",
|
|
|
|
"Real Madrid Basket",
|
|
|
|
"Real Madrid Basket",
|
2018-07-26 16:18:35 -04:00
|
|
|
]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["__timestamp"] = [
|
|
|
|
"2018-02-20T00:00:00",
|
|
|
|
"2018-03-09T00:00:00",
|
|
|
|
"2018-02-20T00:00:00",
|
|
|
|
"2018-03-09T00:00:00",
|
2018-07-26 16:18:35 -04:00
|
|
|
]
|
2019-06-25 16:34:48 -04:00
|
|
|
raw["sum__payout"] = [2, 2, 4, 4]
|
2018-07-26 16:18:35 -04:00
|
|
|
df = pd.DataFrame(raw)
|
|
|
|
|
|
|
|
test_viz = viz.NVD3TimeSeriesViz(datasource, form_data)
|
|
|
|
viz_data = {}
|
|
|
|
viz_data = test_viz.get_data(df)
|
|
|
|
expected = [
|
2019-06-25 16:34:48 -04:00
|
|
|
{
|
2021-01-28 03:39:00 -05:00
|
|
|
"values": [
|
|
|
|
{"y": 4, "x": "2018-02-20T00:00:00"},
|
|
|
|
{"y": 4, "x": "2018-03-09T00:00:00"},
|
2019-06-25 16:34:48 -04:00
|
|
|
],
|
2021-01-28 03:39:00 -05:00
|
|
|
"key": ("Real Madrid Basket",),
|
2019-06-25 16:34:48 -04:00
|
|
|
},
|
|
|
|
{
|
2021-01-28 03:39:00 -05:00
|
|
|
"values": [
|
|
|
|
{"y": 2, "x": "2018-02-20T00:00:00"},
|
|
|
|
{"y": 2, "x": "2018-03-09T00:00:00"},
|
2019-06-25 16:34:48 -04:00
|
|
|
],
|
2021-01-28 03:39:00 -05:00
|
|
|
"key": ("Real Madrid C.F.\U0001f1fa\U0001f1f8\U0001f1ec\U0001f1e7",),
|
2019-06-25 16:34:48 -04:00
|
|
|
},
|
2018-07-26 16:18:35 -04:00
|
|
|
]
|
|
|
|
self.assertEqual(expected, viz_data)
|
2019-07-02 14:10:50 -04:00
|
|
|
|
|
|
|
def test_process_data_resample(self):
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
|
|
|
|
df = pd.DataFrame(
|
|
|
|
{
|
|
|
|
"__timestamp": pd.to_datetime(
|
|
|
|
["2019-01-01", "2019-01-02", "2019-01-05", "2019-01-07"]
|
|
|
|
),
|
|
|
|
"y": [1.0, 2.0, 5.0, 7.0],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
viz.NVD3TimeSeriesViz(
|
|
|
|
datasource,
|
|
|
|
{"metrics": ["y"], "resample_method": "sum", "resample_rule": "1D"},
|
|
|
|
)
|
|
|
|
.process_data(df)["y"]
|
|
|
|
.tolist(),
|
|
|
|
[1.0, 2.0, 0.0, 0.0, 5.0, 0.0, 7.0],
|
|
|
|
)
|
|
|
|
|
|
|
|
np.testing.assert_equal(
|
|
|
|
viz.NVD3TimeSeriesViz(
|
|
|
|
datasource,
|
|
|
|
{"metrics": ["y"], "resample_method": "asfreq", "resample_rule": "1D"},
|
|
|
|
)
|
|
|
|
.process_data(df)["y"]
|
|
|
|
.tolist(),
|
|
|
|
[1.0, 2.0, np.nan, np.nan, 5.0, np.nan, 7.0],
|
|
|
|
)
|
2020-03-10 13:19:12 -04:00
|
|
|
|
|
|
|
def test_apply_rolling(self):
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
index=pd.to_datetime(
|
|
|
|
["2019-01-01", "2019-01-02", "2019-01-05", "2019-01-07"]
|
|
|
|
),
|
|
|
|
data={"y": [1.0, 2.0, 3.0, 4.0]},
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
viz.BigNumberViz(
|
|
|
|
datasource,
|
|
|
|
{
|
|
|
|
"metrics": ["y"],
|
|
|
|
"rolling_type": "cumsum",
|
|
|
|
"rolling_periods": 0,
|
|
|
|
"min_periods": 0,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.apply_rolling(df)["y"]
|
|
|
|
.tolist(),
|
|
|
|
[1.0, 3.0, 6.0, 10.0],
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
viz.BigNumberViz(
|
|
|
|
datasource,
|
|
|
|
{
|
|
|
|
"metrics": ["y"],
|
|
|
|
"rolling_type": "sum",
|
|
|
|
"rolling_periods": 2,
|
|
|
|
"min_periods": 0,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.apply_rolling(df)["y"]
|
|
|
|
.tolist(),
|
|
|
|
[1.0, 3.0, 5.0, 7.0],
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
viz.BigNumberViz(
|
|
|
|
datasource,
|
|
|
|
{
|
|
|
|
"metrics": ["y"],
|
|
|
|
"rolling_type": "mean",
|
|
|
|
"rolling_periods": 10,
|
|
|
|
"min_periods": 0,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.apply_rolling(df)["y"]
|
|
|
|
.tolist(),
|
|
|
|
[1.0, 1.5, 2.0, 2.5],
|
|
|
|
)
|
2020-03-17 13:46:59 -04:00
|
|
|
|
2020-08-13 13:51:03 -04:00
|
|
|
def test_apply_rolling_without_data(self):
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
index=pd.to_datetime(
|
|
|
|
["2019-01-01", "2019-01-02", "2019-01-05", "2019-01-07"]
|
|
|
|
),
|
|
|
|
data={"y": [1.0, 2.0, 3.0, 4.0]},
|
|
|
|
)
|
|
|
|
test_viz = viz.BigNumberViz(
|
|
|
|
datasource,
|
|
|
|
{
|
|
|
|
"metrics": ["y"],
|
|
|
|
"rolling_type": "cumsum",
|
|
|
|
"rolling_periods": 4,
|
|
|
|
"min_periods": 4,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
with pytest.raises(QueryObjectValidationError):
|
|
|
|
test_viz.apply_rolling(df)
|
|
|
|
|
2020-03-17 13:46:59 -04:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestBigNumberViz(SupersetTestCase):
|
2020-03-17 13:46:59 -04:00
|
|
|
def test_get_data(self):
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
data={
|
|
|
|
DTTM_ALIAS: pd.to_datetime(
|
|
|
|
["2019-01-01", "2019-01-02", "2019-01-05", "2019-01-07"]
|
|
|
|
),
|
|
|
|
"y": [1.0, 2.0, 3.0, 4.0],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
data = viz.BigNumberViz(datasource, {"metrics": ["y"]}).get_data(df)
|
|
|
|
self.assertEqual(data[2], {DTTM_ALIAS: pd.Timestamp("2019-01-05"), "y": 3})
|
|
|
|
|
|
|
|
def test_get_data_with_none(self):
|
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
df = pd.DataFrame(
|
|
|
|
data={
|
|
|
|
DTTM_ALIAS: pd.to_datetime(
|
|
|
|
["2019-01-01", "2019-01-02", "2019-01-05", "2019-01-07"]
|
|
|
|
),
|
|
|
|
"y": [1.0, 2.0, None, 4.0],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
data = viz.BigNumberViz(datasource, {"metrics": ["y"]}).get_data(df)
|
|
|
|
assert np.isnan(data[2]["y"])
|
2020-07-28 03:40:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
class TestPivotTableViz(SupersetTestCase):
|
|
|
|
df = pd.DataFrame(
|
|
|
|
data={
|
|
|
|
"intcol": [1, 2, 3, None],
|
|
|
|
"floatcol": [0.1, 0.2, 0.3, None],
|
|
|
|
"strcol": ["a", "b", "c", None],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_get_aggfunc_numeric(self):
|
|
|
|
# is a sum function
|
|
|
|
func = viz.PivotTableViz.get_aggfunc("intcol", self.df, {})
|
|
|
|
assert hasattr(func, "__call__")
|
|
|
|
assert func(self.df["intcol"]) == 6
|
|
|
|
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz.get_aggfunc("intcol", self.df, {"pandas_aggfunc": "min"})
|
|
|
|
== "min"
|
|
|
|
)
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz.get_aggfunc(
|
|
|
|
"floatcol", self.df, {"pandas_aggfunc": "max"}
|
|
|
|
)
|
|
|
|
== "max"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_get_aggfunc_non_numeric(self):
|
|
|
|
assert viz.PivotTableViz.get_aggfunc("strcol", self.df, {}) == "max"
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz.get_aggfunc("strcol", self.df, {"pandas_aggfunc": "sum"})
|
|
|
|
== "max"
|
|
|
|
)
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz.get_aggfunc("strcol", self.df, {"pandas_aggfunc": "min"})
|
|
|
|
== "min"
|
|
|
|
)
|
2020-07-31 04:19:21 -04:00
|
|
|
|
2020-09-03 12:49:54 -04:00
|
|
|
def test_format_datetime_from_pd_timestamp(self):
|
|
|
|
tstamp = pd.Timestamp(datetime(2020, 9, 3, tzinfo=timezone.utc))
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz._format_datetime(tstamp) == "__timestamp:1599091200000.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_format_datetime_from_datetime(self):
|
|
|
|
tstamp = datetime(2020, 9, 3, tzinfo=timezone.utc)
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz._format_datetime(tstamp) == "__timestamp:1599091200000.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_format_datetime_from_date(self):
|
|
|
|
tstamp = date(2020, 9, 3)
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz._format_datetime(tstamp) == "__timestamp:1599091200000.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_format_datetime_from_string(self):
|
|
|
|
tstamp = "2020-09-03T00:00:00"
|
|
|
|
assert (
|
|
|
|
viz.PivotTableViz._format_datetime(tstamp) == "__timestamp:1599091200000.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_format_datetime_from_invalid_string(self):
|
|
|
|
tstamp = "abracadabra"
|
|
|
|
assert viz.PivotTableViz._format_datetime(tstamp) == tstamp
|
|
|
|
|
|
|
|
def test_format_datetime_from_int(self):
|
|
|
|
assert viz.PivotTableViz._format_datetime(123) == 123
|
|
|
|
assert viz.PivotTableViz._format_datetime(123.0) == 123.0
|