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 2021/01/25 13:12:00 UTC
[superset] 24/38: test: World bank examples (#12161)
This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch 1.0
in repository https://gitbox.apache.org/repos/asf/superset.git
commit bc53be95a521e4120244f17b1977474183bb4e09
Author: Karol Kostrzewa <ka...@gmail.com>
AuthorDate: Wed Jan 13 23:20:05 2021 +0100
test: World bank examples (#12161)
* add world bank data fixture
* fix fixture cleanup, add fixture to dashboard_tests
* apply world bank fixtures, fix tests
* fix fixture typo, dashboard ids
* fix export dashboard metadata
* fix test_export_dashboard_command_key_order
* fix export dash tests, not add row when no orphans
* debug timeout
* fixes after merge
* fix lint
* run pre-commit
* comment test for debug
* fix save.test.js
Co-authored-by: Karol Kostrzewa <ka...@polidea.com>
---
.../cypress/integration/dashboard/save.test.js | 11 +-
.../integration/dashboard/url_params.test.js | 2 +-
superset/dashboards/commands/export.py | 4 +-
superset/examples/world_bank.py | 233 ++++------
tests/access_tests.py | 2 +
tests/base_api_tests.py | 4 +
tests/charts/api_tests.py | 27 +-
tests/conftest.py | 2 -
tests/core_tests.py | 9 +-
tests/dashboard_tests.py | 3 +
tests/dashboard_utils.py | 10 +-
tests/dashboards/api_tests.py | 9 +-
tests/dashboards/commands_tests.py | 179 ++++++--
tests/dashboards/dao_tests.py | 4 +
tests/databases/api_tests.py | 2 +
tests/datasets/commands_tests.py | 3 +
tests/fixtures/unicode_dashboard.py | 2 +-
tests/fixtures/world_bank_dashboard.py | 484 +++++++++++++++++++++
tests/import_export_tests.py | 9 +-
tests/schedules_test.py | 20 +-
tests/security_tests.py | 11 +
tests/utils_tests.py | 2 +
22 files changed, 807 insertions(+), 225 deletions(-)
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
index 757a118..0822081 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
@@ -31,9 +31,6 @@ describe('Dashboard save action', () => {
cy.server();
cy.login();
cy.visit(WORLD_HEALTH_DASHBOARD);
- });
-
- it('should save as new dashboard', () => {
cy.get('#app').then(data => {
const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
const dashboard = bootstrapData.dashboard_data;
@@ -50,6 +47,14 @@ describe('Dashboard save action', () => {
});
});
+ it('should save as new dashboard', () => {
+ cy.wait('@copyRequest').then(xhr => {
+ expect(xhr.response.body.dashboard_title).to.not.equal(
+ `World Bank's Data`,
+ );
+ });
+ });
+
it('should save/overwrite dashboard', () => {
cy.get('[data-test="grid-row-background--transparent"]').within(() => {
cy.get('.box_plot', { timeout: 10000 }).should('be.visible');
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.js
index 37dda04..43eb022 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.js
@@ -39,7 +39,7 @@ describe('Dashboard form data', () => {
it('should apply url params to slice requests', () => {
const aliases = getChartAliases(dashboard.slices);
// wait and verify one-by-one
- cy.wait(aliases).then(requests =>
+ cy.wait(aliases, { timeout: 18000 }).then(requests =>
Promise.all(
requests.map(async xhr => {
expect(xhr.status).to.eq(200);
diff --git a/superset/dashboards/commands/export.py b/superset/dashboards/commands/export.py
index 3021197..09ddb75 100644
--- a/superset/dashboards/commands/export.py
+++ b/superset/dashboards/commands/export.py
@@ -137,7 +137,9 @@ class ExportDashboardsCommand(ExportModelsCommand):
orphan_charts = {
chart for chart in model.slices if str(chart.uuid) not in referenced_charts
}
- payload["position"] = append_charts(payload["position"], orphan_charts)
+
+ if orphan_charts:
+ payload["position"] = append_charts(payload["position"], orphan_charts)
payload["version"] = EXPORT_VERSION
diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py
index 0596142..f9c3aeb 100644
--- a/superset/examples/world_bank.py
+++ b/superset/examples/world_bank.py
@@ -17,7 +17,7 @@
"""Loads datasets, dashboards and slices in a new superset instance"""
import json
import os
-import textwrap
+from typing import List
import pandas as pd
from sqlalchemy import DateTime, String
@@ -29,6 +29,7 @@ from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
from superset.utils import core as utils
+from ..connectors.base.models import BaseDatasource
from .helpers import (
config,
EXAMPLES_FOLDER,
@@ -105,6 +106,32 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
db.session.commit()
tbl.fetch_metadata()
+ slices = create_slices(tbl)
+ misc_dash_slices.add(slices[-1].slice_name)
+ for slc in slices:
+ merge_slice(slc)
+
+ print("Creating a World's Health Bank dashboard")
+ dash_name = "World Bank's Data"
+ slug = "world_health"
+ dash = db.session.query(Dashboard).filter_by(slug=slug).first()
+
+ if not dash:
+ dash = Dashboard()
+ dash.published = True
+ pos = dashboard_positions
+ update_slice_ids(pos, slices)
+
+ dash.dashboard_title = dash_name
+ dash.position_json = json.dumps(pos, indent=4)
+ dash.slug = slug
+
+ dash.slices = slices[:-1]
+ db.session.merge(dash)
+ db.session.commit()
+
+
+def create_slices(tbl: BaseDatasource) -> List[Slice]:
metric = "sum__SP_POP_TOTL"
metrics = ["sum__SP_POP_TOTL"]
secondary_metric = {
@@ -118,7 +145,6 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"hasCustomLabel": True,
"label": "Rural Population",
}
-
defaults = {
"compare_lag": "10",
"compare_suffix": "o10Y",
@@ -136,8 +162,7 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"show_bubbles": True,
}
- print("Creating slices")
- slices = [
+ return [
Slice(
slice_name="Region Filter",
viz_type="filter_box",
@@ -340,31 +365,14 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
),
),
]
- misc_dash_slices.add(slices[-1].slice_name)
- for slc in slices:
- merge_slice(slc)
- print("Creating a World's Health Bank dashboard")
- dash_name = "World Bank's Data"
- slug = "world_health"
- dash = db.session.query(Dashboard).filter_by(slug=slug).first()
- if not dash:
- dash = Dashboard()
- dash.published = True
- js = textwrap.dedent(
- """\
-{
+dashboard_positions = {
"CHART-36bfc934": {
"children": [],
"id": "CHART-36bfc934",
- "meta": {
- "chartId": 40,
- "height": 25,
- "sliceName": "Region Filter",
- "width": 2
- },
- "type": "CHART"
+ "meta": {"chartId": 40, "height": 25, "sliceName": "Region Filter", "width": 2},
+ "type": "CHART",
},
"CHART-37982887": {
"children": [],
@@ -373,9 +381,9 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"chartId": 41,
"height": 25,
"sliceName": "World's Population",
- "width": 2
+ "width": 2,
},
- "type": "CHART"
+ "type": "CHART",
},
"CHART-17e0f8d8": {
"children": [],
@@ -384,31 +392,21 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"chartId": 42,
"height": 92,
"sliceName": "Most Populated Countries",
- "width": 3
+ "width": 3,
},
- "type": "CHART"
+ "type": "CHART",
},
"CHART-2ee52f30": {
"children": [],
"id": "CHART-2ee52f30",
- "meta": {
- "chartId": 43,
- "height": 38,
- "sliceName": "Growth Rate",
- "width": 6
- },
- "type": "CHART"
+ "meta": {"chartId": 43, "height": 38, "sliceName": "Growth Rate", "width": 6},
+ "type": "CHART",
},
"CHART-2d5b6871": {
"children": [],
"id": "CHART-2d5b6871",
- "meta": {
- "chartId": 44,
- "height": 52,
- "sliceName": "% Rural",
- "width": 7
- },
- "type": "CHART"
+ "meta": {"chartId": 44, "height": 52, "sliceName": "% Rural", "width": 7},
+ "type": "CHART",
},
"CHART-0fd0d252": {
"children": [],
@@ -417,9 +415,9 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"chartId": 45,
"height": 50,
"sliceName": "Life Expectancy VS Rural %",
- "width": 8
+ "width": 8,
},
- "type": "CHART"
+ "type": "CHART",
},
"CHART-97f4cb48": {
"children": [],
@@ -428,9 +426,9 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"chartId": 46,
"height": 38,
"sliceName": "Rural Breakdown",
- "width": 3
+ "width": 3,
},
- "type": "CHART"
+ "type": "CHART",
},
"CHART-b5e05d6f": {
"children": [],
@@ -439,145 +437,80 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals, too-many-s
"chartId": 47,
"height": 50,
"sliceName": "World's Pop Growth",
- "width": 4
+ "width": 4,
},
- "type": "CHART"
+ "type": "CHART",
},
"CHART-e76e9f5f": {
"children": [],
"id": "CHART-e76e9f5f",
- "meta": {
- "chartId": 48,
- "height": 50,
- "sliceName": "Box plot",
- "width": 4
- },
- "type": "CHART"
+ "meta": {"chartId": 48, "height": 50, "sliceName": "Box plot", "width": 4},
+ "type": "CHART",
},
"CHART-a4808bba": {
"children": [],
"id": "CHART-a4808bba",
- "meta": {
- "chartId": 49,
- "height": 50,
- "sliceName": "Treemap",
- "width": 8
- },
- "type": "CHART"
+ "meta": {"chartId": 49, "height": 50, "sliceName": "Treemap", "width": 8},
+ "type": "CHART",
+ },
+ "CHART-3nc0d8sk": {
+ "children": [],
+ "id": "CHART-3nc0d8sk",
+ "meta": {"chartId": 50, "height": 50, "sliceName": "Treemap", "width": 8},
+ "type": "CHART",
},
"COLUMN-071bbbad": {
- "children": [
- "ROW-1e064e3c",
- "ROW-afdefba9"
- ],
+ "children": ["ROW-1e064e3c", "ROW-afdefba9"],
"id": "COLUMN-071bbbad",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT",
- "width": 9
- },
- "type": "COLUMN"
+ "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 9},
+ "type": "COLUMN",
},
"COLUMN-fe3914b8": {
- "children": [
- "CHART-36bfc934",
- "CHART-37982887"
- ],
+ "children": ["CHART-36bfc934", "CHART-37982887"],
"id": "COLUMN-fe3914b8",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT",
- "width": 2
- },
- "type": "COLUMN"
+ "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 2},
+ "type": "COLUMN",
},
"GRID_ID": {
- "children": [
- "ROW-46632bc2",
- "ROW-3fa26c5d",
- "ROW-812b3f13"
- ],
+ "children": ["ROW-46632bc2", "ROW-3fa26c5d", "ROW-812b3f13"],
"id": "GRID_ID",
- "type": "GRID"
+ "type": "GRID",
},
"HEADER_ID": {
"id": "HEADER_ID",
- "meta": {
- "text": "World's Bank Data"
- },
- "type": "HEADER"
- },
- "ROOT_ID": {
- "children": [
- "GRID_ID"
- ],
- "id": "ROOT_ID",
- "type": "ROOT"
+ "meta": {"text": "World's Bank Data"},
+ "type": "HEADER",
},
+ "ROOT_ID": {"children": ["GRID_ID"], "id": "ROOT_ID", "type": "ROOT"},
"ROW-1e064e3c": {
- "children": [
- "COLUMN-fe3914b8",
- "CHART-2d5b6871"
- ],
+ "children": ["COLUMN-fe3914b8", "CHART-2d5b6871"],
"id": "ROW-1e064e3c",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT"
- },
- "type": "ROW"
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
},
"ROW-3fa26c5d": {
- "children": [
- "CHART-b5e05d6f",
- "CHART-0fd0d252"
- ],
+ "children": ["CHART-b5e05d6f", "CHART-0fd0d252"],
"id": "ROW-3fa26c5d",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT"
- },
- "type": "ROW"
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
},
"ROW-46632bc2": {
- "children": [
- "COLUMN-071bbbad",
- "CHART-17e0f8d8"
- ],
+ "children": ["COLUMN-071bbbad", "CHART-17e0f8d8"],
"id": "ROW-46632bc2",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT"
- },
- "type": "ROW"
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
},
"ROW-812b3f13": {
- "children": [
- "CHART-a4808bba",
- "CHART-e76e9f5f"
- ],
+ "children": ["CHART-a4808bba", "CHART-e76e9f5f"],
"id": "ROW-812b3f13",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT"
- },
- "type": "ROW"
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
},
"ROW-afdefba9": {
- "children": [
- "CHART-2ee52f30",
- "CHART-97f4cb48"
- ],
+ "children": ["CHART-2ee52f30", "CHART-97f4cb48"],
"id": "ROW-afdefba9",
- "meta": {
- "background": "BACKGROUND_TRANSPARENT"
- },
- "type": "ROW"
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
},
- "DASHBOARD_VERSION_KEY": "v2"
+ "DASHBOARD_VERSION_KEY": "v2",
}
- """
- )
- pos = json.loads(js)
- update_slice_ids(pos, slices)
-
- dash.dashboard_title = dash_name
- dash.position_json = json.dumps(pos, indent=4)
- dash.slug = slug
-
- dash.slices = slices[:-1]
- db.session.merge(dash)
- db.session.commit()
diff --git a/tests/access_tests.py b/tests/access_tests.py
index 4e568a5..d3cc55a 100644
--- a/tests/access_tests.py
+++ b/tests/access_tests.py
@@ -22,6 +22,7 @@ from unittest import mock
from tests.fixtures.birth_names_dashboard import load_birth_names_dashboard_with_slices
import pytest
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from tests.fixtures.energy_dashboard import load_energy_table_with_slice
from tests.test_app import app # isort:skip
@@ -321,6 +322,7 @@ class TestRequestAccess(SupersetTestCase):
gamma_user.roles.remove(security_manager.find_role(DB_ACCESS_ROLE))
session.commit()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_clean_requests_after_schema_grant(self):
session = db.session
diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py
index 1708cff..3dd21dc 100644
--- a/tests/base_api_tests.py
+++ b/tests/base_api_tests.py
@@ -16,7 +16,9 @@
# under the License.
# isort:skip_file
import json
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
+import pytest
from flask_appbuilder.models.sqla.interface import SQLAInterface
import prison
@@ -66,6 +68,7 @@ class TestOpenApiSpec(SupersetTestCase):
class TestBaseModelRestApi(SupersetTestCase):
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_default_missing_declaration_get(self):
"""
API: Test default missing declaration on get
@@ -148,6 +151,7 @@ class TestBaseModelRestApi(SupersetTestCase):
}
self.assertEqual(response, expected_response)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_default_missing_declaration_put(self):
"""
API: Test default missing declaration on put
diff --git a/tests/charts/api_tests.py b/tests/charts/api_tests.py
index 99ab93c..f7ba39a 100644
--- a/tests/charts/api_tests.py
+++ b/tests/charts/api_tests.py
@@ -33,6 +33,7 @@ import yaml
from sqlalchemy import and_, or_
from sqlalchemy.sql import func
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from tests.test_app import app
from superset.charts.commands.data import ChartDataCommand
from superset.connectors.connector_registry import ConnectorRegistry
@@ -435,7 +436,10 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
db.session.delete(user_alpha2)
db.session.commit()
- @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
+ @pytest.mark.usefixtures(
+ "load_world_bank_dashboard_with_slices",
+ "load_birth_names_dashboard_with_slices",
+ )
def test_create_chart(self):
"""
Chart API: Test create chart
@@ -544,15 +548,18 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
response, {"message": {"datasource_id": ["Datasource does not exist"]}}
)
+ @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
def test_update_chart(self):
"""
Chart API: Test update
"""
admin = self.get_user("admin")
gamma = self.get_user("gamma")
-
- chart_id = self.insert_chart("title", [admin.id], 1, admin).id
birth_names_table_id = SupersetTestCase.get_table_by_name("birth_names").id
+ chart_id = self.insert_chart(
+ "title", [admin.id], birth_names_table_id, admin
+ ).id
+ dash_id = db.session.query(Dashboard.id).filter_by(slug="births").first()[0]
chart_data = {
"slice_name": "title1_changed",
"description": "description1",
@@ -562,14 +569,14 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
"cache_timeout": 1000,
"datasource_id": birth_names_table_id,
"datasource_type": "table",
- "dashboards": [1],
+ "dashboards": [dash_id],
}
self.login(username="admin")
uri = f"api/v1/chart/{chart_id}"
rv = self.put_assert_metric(uri, chart_data, "put")
self.assertEqual(rv.status_code, 200)
model = db.session.query(Slice).get(chart_id)
- related_dashboard = db.session.query(Dashboard).get(1)
+ related_dashboard = db.session.query(Dashboard).filter_by(slug="births").first()
self.assertEqual(model.created_by, admin)
self.assertEqual(model.slice_name, "title1_changed")
self.assertEqual(model.description, "description1")
@@ -581,7 +588,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
self.assertEqual(model.datasource_id, birth_names_table_id)
self.assertEqual(model.datasource_type, "table")
self.assertEqual(model.datasource_name, "birth_names")
- self.assertIn(related_dashboard, model.dashboards)
+ self.assertIn(model.id, [slice.id for slice in related_dashboard.slices])
db.session.delete(model)
db.session.commit()
@@ -698,6 +705,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
expected_response = {"message": {"owners": ["Owners are invalid"]}}
self.assertEqual(response, expected_response)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_get_chart(self):
"""
Chart API: Test get chart
@@ -758,6 +766,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
"load_energy_table_with_slice",
"load_birth_names_dashboard_with_slices",
"load_unicode_dashboard_with_slice",
+ "load_world_bank_dashboard_with_slices",
)
def test_get_charts(self):
"""
@@ -798,7 +807,10 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
db.session.delete(chart)
db.session.commit()
- @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
+ @pytest.mark.usefixtures(
+ "load_world_bank_dashboard_with_slices",
+ "load_birth_names_dashboard_with_slices",
+ )
def test_get_charts_filter(self):
"""
Chart API: Test get charts filter
@@ -1008,6 +1020,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
@pytest.mark.usefixtures(
"load_unicode_dashboard_with_slice",
"load_energy_table_with_slice",
+ "load_world_bank_dashboard_with_slices",
"load_birth_names_dashboard_with_slices",
)
def test_get_charts_page(self):
diff --git a/tests/conftest.py b/tests/conftest.py
index efa549f..b854385 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -42,13 +42,11 @@ def setup_sample_data() -> Any:
from superset import examples
examples.load_css_templates()
- examples.load_world_bank_health_n_pop(sample=True)
yield
with app.app_context():
engine = get_example_database().get_sqla_engine()
- engine.execute("DROP TABLE wb_health_population")
# drop sqlachemy tables
diff --git a/tests/core_tests.py b/tests/core_tests.py
index 16620b4..2363ab0 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -66,6 +66,7 @@ from superset.views import core as views
from superset.views.database.views import DatabaseView
from .base_tests import SupersetTestCase
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
logger = logging.getLogger(__name__)
@@ -1223,6 +1224,7 @@ class TestCore(SupersetTestCase):
{"FOO": lambda x: 1},
clear=True,
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_feature_flag_serialization(self):
"""
Functions in feature flags don't break bootstrap data serialization.
@@ -1238,13 +1240,14 @@ class TestCore(SupersetTestCase):
.replace("'", "'")
.replace('"', """)
)
-
+ dash_id = db.session.query(Dashboard.id).first()[0]
+ tbl_id = self.table_ids.get("wb_health_population")
urls = [
"/superset/sqllab",
"/superset/welcome",
- "/superset/dashboard/1/",
+ f"/superset/dashboard/{dash_id}/",
"/superset/profile/admin/",
- "/superset/explore/table/1",
+ f"/superset/explore/table/{tbl_id}",
]
for url in urls:
data = self.get_resp(url)
diff --git a/tests/dashboard_tests.py b/tests/dashboard_tests.py
index 8d4df16..be3e0a9 100644
--- a/tests/dashboard_tests.py
+++ b/tests/dashboard_tests.py
@@ -34,6 +34,7 @@ from superset.models import core as models
from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
from tests.fixtures.energy_dashboard import load_energy_table_with_slice
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from .base_tests import SupersetTestCase
@@ -161,6 +162,7 @@ class TestDashboard(SupersetTestCase):
resp = self.get_resp(url, data=dict(data=json.dumps(data)))
self.assertIn("SUCCESS", resp)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_save_dash_with_filter(self, username="admin"):
self.login(username=username)
dash = db.session.query(Dashboard).filter_by(slug="world_health").first()
@@ -190,6 +192,7 @@ class TestDashboard(SupersetTestCase):
resp = self.get_resp(new_url)
self.assertIn("North America", resp)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_save_dash_with_invalid_filters(self, username="admin"):
self.login(username=username)
dash = db.session.query(Dashboard).filter_by(slug="world_health").first()
diff --git a/tests/dashboard_utils.py b/tests/dashboard_utils.py
index 36e329e..6944b63 100644
--- a/tests/dashboard_utils.py
+++ b/tests/dashboard_utils.py
@@ -17,7 +17,7 @@
"""Utils to provide dashboards for tests"""
import json
-from typing import Any, Dict
+from typing import Any, Dict, List
from pandas import DataFrame
@@ -71,7 +71,9 @@ def create_slice(
)
-def create_dashboard(slug: str, title: str, position: str, slice: Slice) -> Dashboard:
+def create_dashboard(
+ slug: str, title: str, position: str, slices: List[Slice]
+) -> Dashboard:
dash = db.session.query(Dashboard).filter_by(slug=slug).one_or_none()
if not dash:
@@ -82,8 +84,8 @@ def create_dashboard(slug: str, title: str, position: str, slice: Slice) -> Dash
pos = json.loads(js)
dash.position_json = json.dumps(pos, indent=4)
dash.slug = slug
- if slice is not None:
- dash.slices = [slice]
+ if slices is not None:
+ dash.slices = slices
db.session.merge(dash)
db.session.commit()
diff --git a/tests/dashboards/api_tests.py b/tests/dashboards/api_tests.py
index 299dd2d..38ce1ae 100644
--- a/tests/dashboards/api_tests.py
+++ b/tests/dashboards/api_tests.py
@@ -49,6 +49,7 @@ from tests.fixtures.importexport import (
dataset_metadata_config,
)
from tests.utils.get_dashboards import get_dashboards_ids
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
DASHBOARDS_FIXTURE_COUNT = 10
@@ -1102,13 +1103,17 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin):
db.session.delete(user_alpha2)
db.session.commit()
+ @pytest.mark.usefixtures(
+ "load_world_bank_dashboard_with_slices",
+ "load_birth_names_dashboard_with_slices",
+ )
def test_export(self):
"""
Dashboard API: Test dashboard export
"""
self.login(username="admin")
- argument = [1, 2]
- uri = f"api/v1/dashboard/export/?q={prison.dumps(argument)}"
+ dashboards_ids = get_dashboards_ids(db, ["world_health", "births"])
+ uri = f"api/v1/dashboard/export/?q={prison.dumps(dashboards_ids)}"
# freeze time to ensure filename is deterministic
with freeze_time("2020-01-01T00:00:00Z"):
diff --git a/tests/dashboards/commands_tests.py b/tests/dashboards/commands_tests.py
index f3d96f3..3449c00 100644
--- a/tests/dashboards/commands_tests.py
+++ b/tests/dashboards/commands_tests.py
@@ -48,16 +48,20 @@ from tests.fixtures.importexport import (
dataset_config,
dataset_metadata_config,
)
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
class TestExportDashboardsCommand(SupersetTestCase):
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@patch("superset.security.manager.g")
@patch("superset.views.base.g")
def test_export_dashboard_command(self, mock_g1, mock_g2):
mock_g1.user = security_manager.find_user("admin")
mock_g2.user = security_manager.find_user("admin")
- example_dashboard = db.session.query(Dashboard).filter_by(id=1).one()
+ example_dashboard = (
+ db.session.query(Dashboard).filter_by(slug="world_health").one()
+ )
command = ExportDashboardsCommand([example_dashboard.id])
contents = dict(command.run())
@@ -83,82 +87,152 @@ class TestExportDashboardsCommand(SupersetTestCase):
assert metadata == {
"dashboard_title": "World Bank's Data",
"description": None,
- "css": "",
+ "css": None,
"slug": "world_health",
"uuid": str(example_dashboard.uuid),
"position": {
- "DASHBOARD_CHART_TYPE-0": {
+ "CHART-36bfc934": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-0",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-36bfc934",
+ "meta": {"height": 25, "sliceName": "Region Filter", "width": 2},
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-1": {
+ "CHART-37982887": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-1",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-37982887",
+ "meta": {
+ "height": 25,
+ "sliceName": "World's Population",
+ "width": 2,
+ },
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-2": {
+ "CHART-17e0f8d8": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-2",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-17e0f8d8",
+ "meta": {
+ "height": 92,
+ "sliceName": "Most Populated Countries",
+ "width": 3,
+ },
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-3": {
+ "CHART-2ee52f30": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-3",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-2ee52f30",
+ "meta": {"height": 38, "sliceName": "Growth Rate", "width": 6},
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-4": {
+ "CHART-2d5b6871": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-4",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-2d5b6871",
+ "meta": {"height": 52, "sliceName": "% Rural", "width": 7},
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-5": {
+ "CHART-0fd0d252": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-5",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-0fd0d252",
+ "meta": {
+ "height": 50,
+ "sliceName": "Life Expectancy VS Rural %",
+ "width": 8,
+ },
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-6": {
+ "CHART-97f4cb48": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-6",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-97f4cb48",
+ "meta": {"height": 38, "sliceName": "Rural Breakdown", "width": 3},
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-7": {
+ "CHART-b5e05d6f": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-7",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-b5e05d6f",
+ "meta": {
+ "height": 50,
+ "sliceName": "World's Pop Growth",
+ "width": 4,
+ },
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-8": {
+ "CHART-e76e9f5f": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-8",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-e76e9f5f",
+ "meta": {"height": 50, "sliceName": "Box plot", "width": 4},
"type": "CHART",
},
- "DASHBOARD_CHART_TYPE-9": {
+ "CHART-a4808bba": {
"children": [],
- "id": "DASHBOARD_CHART_TYPE-9",
- "meta": {"height": 50, "width": 4},
+ "id": "CHART-a4808bba",
+ "meta": {"height": 50, "sliceName": "Treemap", "width": 8},
"type": "CHART",
},
+ "CHART-3nc0d8sk": {
+ "children": [],
+ "id": "CHART-3nc0d8sk",
+ "meta": {"height": 50, "sliceName": "Treemap", "width": 8},
+ "type": "CHART",
+ },
+ "COLUMN-071bbbad": {
+ "children": ["ROW-1e064e3c", "ROW-afdefba9"],
+ "id": "COLUMN-071bbbad",
+ "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 9},
+ "type": "COLUMN",
+ },
+ "COLUMN-fe3914b8": {
+ "children": ["CHART-36bfc934", "CHART-37982887"],
+ "id": "COLUMN-fe3914b8",
+ "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 2},
+ "type": "COLUMN",
+ },
+ "GRID_ID": {
+ "children": ["ROW-46632bc2", "ROW-3fa26c5d", "ROW-812b3f13"],
+ "id": "GRID_ID",
+ "type": "GRID",
+ },
+ "HEADER_ID": {
+ "id": "HEADER_ID",
+ "meta": {"text": "World's Bank Data"},
+ "type": "HEADER",
+ },
+ "ROOT_ID": {"children": ["GRID_ID"], "id": "ROOT_ID", "type": "ROOT"},
+ "ROW-1e064e3c": {
+ "children": ["COLUMN-fe3914b8", "CHART-2d5b6871"],
+ "id": "ROW-1e064e3c",
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
+ },
+ "ROW-3fa26c5d": {
+ "children": ["CHART-b5e05d6f", "CHART-0fd0d252"],
+ "id": "ROW-3fa26c5d",
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
+ },
+ "ROW-46632bc2": {
+ "children": ["COLUMN-071bbbad", "CHART-17e0f8d8"],
+ "id": "ROW-46632bc2",
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
+ },
+ "ROW-812b3f13": {
+ "children": ["CHART-a4808bba", "CHART-e76e9f5f"],
+ "id": "ROW-812b3f13",
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
+ },
+ "ROW-afdefba9": {
+ "children": ["CHART-2ee52f30", "CHART-97f4cb48"],
+ "id": "ROW-afdefba9",
+ "meta": {"background": "BACKGROUND_TRANSPARENT"},
+ "type": "ROW",
+ },
"DASHBOARD_VERSION_KEY": "v2",
},
- "metadata": {
- "timed_refresh_immune_slices": [],
- "expanded_slices": {},
- "refresh_frequency": 0,
- "default_filters": "{}",
- "color_scheme": None,
- },
+ "metadata": {"mock_key": "mock_value"},
"version": "1.0.0",
}
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@patch("superset.security.manager.g")
@patch("superset.views.base.g")
def test_export_dashboard_command_no_access(self, mock_g1, mock_g2):
@@ -166,12 +240,15 @@ class TestExportDashboardsCommand(SupersetTestCase):
mock_g1.user = security_manager.find_user("gamma")
mock_g2.user = security_manager.find_user("gamma")
- example_dashboard = db.session.query(Dashboard).filter_by(id=1).one()
+ example_dashboard = (
+ db.session.query(Dashboard).filter_by(slug="world_health").one()
+ )
command = ExportDashboardsCommand([example_dashboard.id])
contents = command.run()
with self.assertRaises(DashboardNotFoundError):
next(contents)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@patch("superset.security.manager.g")
@patch("superset.views.base.g")
def test_export_dashboard_command_invalid_dataset(self, mock_g1, mock_g2):
@@ -183,6 +260,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
with self.assertRaises(DashboardNotFoundError):
next(contents)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@patch("superset.security.manager.g")
@patch("superset.views.base.g")
def test_export_dashboard_command_key_order(self, mock_g1, mock_g2):
@@ -190,7 +268,9 @@ class TestExportDashboardsCommand(SupersetTestCase):
mock_g1.user = security_manager.find_user("admin")
mock_g2.user = security_manager.find_user("admin")
- example_dashboard = db.session.query(Dashboard).filter_by(id=1).one()
+ example_dashboard = (
+ db.session.query(Dashboard).filter_by(slug="world_health").one()
+ )
command = ExportDashboardsCommand([example_dashboard.id])
contents = dict(command.run())
@@ -206,6 +286,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"version",
]
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
@patch("superset.dashboards.commands.export.suffix")
def test_append_charts(self, mock_suffix):
"""Test that oprhaned charts are added to the dashbaord position"""
@@ -213,7 +294,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
mock_suffix.side_effect = (str(i) for i in itertools.count(1))
position = get_default_position("example")
- chart_1 = db.session.query(Slice).filter_by(id=1).one()
+ chart_1 = db.session.query(Slice).filter_by(slice_name="Region Filter").one()
new_position = append_charts(position, {chart_1})
assert new_position == {
"DASHBOARD_VERSION_KEY": "v2",
@@ -240,7 +321,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"children": [],
"id": "CHART-1",
"meta": {
- "chartId": 1,
+ "chartId": chart_1.id,
"height": 50,
"sliceName": "Region Filter",
"uuid": str(chart_1.uuid),
@@ -251,7 +332,9 @@ class TestExportDashboardsCommand(SupersetTestCase):
},
}
- chart_2 = db.session.query(Slice).filter_by(id=2).one()
+ chart_2 = (
+ db.session.query(Slice).filter_by(slice_name="World's Population").one()
+ )
new_position = append_charts(new_position, {chart_2})
assert new_position == {
"DASHBOARD_VERSION_KEY": "v2",
@@ -285,7 +368,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"children": [],
"id": "CHART-1",
"meta": {
- "chartId": 1,
+ "chartId": chart_1.id,
"height": 50,
"sliceName": "Region Filter",
"uuid": str(chart_1.uuid),
@@ -298,7 +381,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"children": [],
"id": "CHART-3",
"meta": {
- "chartId": 2,
+ "chartId": chart_2.id,
"height": 50,
"sliceName": "World's Population",
"uuid": str(chart_2.uuid),
@@ -316,7 +399,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"children": [],
"id": "CHART-5",
"meta": {
- "chartId": 1,
+ "chartId": chart_1.id,
"height": 50,
"sliceName": "Region Filter",
"uuid": str(chart_1.uuid),
@@ -328,7 +411,7 @@ class TestExportDashboardsCommand(SupersetTestCase):
"children": [],
"id": "CHART-6",
"meta": {
- "chartId": 2,
+ "chartId": chart_2.id,
"height": 50,
"sliceName": "World's Population",
"uuid": str(chart_2.uuid),
diff --git a/tests/dashboards/dao_tests.py b/tests/dashboards/dao_tests.py
index 6bb22b8..48d058c 100644
--- a/tests/dashboards/dao_tests.py
+++ b/tests/dashboards/dao_tests.py
@@ -18,14 +18,18 @@
import copy
import json
+import pytest
+
import tests.test_app # pylint: disable=unused-import
from superset import db
from superset.dashboards.dao import DashboardDAO
from superset.models.dashboard import Dashboard
from tests.base_tests import SupersetTestCase
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
class TestDashboardDAO(SupersetTestCase):
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_set_dash_metadata(self):
dash = db.session.query(Dashboard).filter_by(slug="world_health").first()
data = dash.data
diff --git a/tests/databases/api_tests.py b/tests/databases/api_tests.py
index 46af4f0..82a5cb5 100644
--- a/tests/databases/api_tests.py
+++ b/tests/databases/api_tests.py
@@ -21,6 +21,7 @@ import json
from io import BytesIO
from unittest import mock
from zipfile import is_zipfile, ZipFile
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from tests.fixtures.birth_names_dashboard import load_birth_names_dashboard_with_slices
import prison
@@ -848,6 +849,7 @@ class TestDatabaseApi(SupersetTestCase):
@pytest.mark.usefixtures(
"load_unicode_dashboard_with_position",
"load_energy_table_with_slice",
+ "load_world_bank_dashboard_with_slices",
"load_birth_names_dashboard_with_slices",
)
def test_get_database_related_objects(self):
diff --git a/tests/datasets/commands_tests.py b/tests/datasets/commands_tests.py
index 01bc91c..f72e7f3 100644
--- a/tests/datasets/commands_tests.py
+++ b/tests/datasets/commands_tests.py
@@ -43,6 +43,7 @@ from tests.fixtures.importexport import (
dataset_metadata_config,
dataset_ui_export,
)
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
class TestExportDatasetsCommand(SupersetTestCase):
@@ -212,6 +213,7 @@ class TestExportDatasetsCommand(SupersetTestCase):
class TestImportDatasetsCommand(SupersetTestCase):
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_import_v0_dataset_cli_export(self):
num_datasets = db.session.query(SqlaTable).count()
@@ -251,6 +253,7 @@ class TestImportDatasetsCommand(SupersetTestCase):
db.session.delete(dataset)
db.session.commit()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_import_v0_dataset_ui_export(self):
num_datasets = db.session.query(SqlaTable).count()
diff --git a/tests/fixtures/unicode_dashboard.py b/tests/fixtures/unicode_dashboard.py
index 1393757..02dbd4c 100644
--- a/tests/fixtures/unicode_dashboard.py
+++ b/tests/fixtures/unicode_dashboard.py
@@ -87,7 +87,7 @@ def _create_unicode_dashboard(
if slice_title:
slice = _create_and_commit_unicode_slice(table, slice_title)
- return create_dashboard("unicode-test", "Unicode Test", position, slice)
+ return create_dashboard("unicode-test", "Unicode Test", position, [slice])
def _create_and_commit_unicode_slice(table: SqlaTable, title: str):
diff --git a/tests/fixtures/world_bank_dashboard.py b/tests/fixtures/world_bank_dashboard.py
new file mode 100644
index 0000000..4f27b56
--- /dev/null
+++ b/tests/fixtures/world_bank_dashboard.py
@@ -0,0 +1,484 @@
+# 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.
+import json
+import string
+from random import choice, randint, random, uniform
+from typing import Any, Dict, List
+
+import pandas as pd
+import pytest
+from pandas import DataFrame
+from sqlalchemy import DateTime, String, TIMESTAMP
+
+from superset import db
+from superset.connectors.sqla.models import SqlaTable
+from superset.models.core import Database
+from superset.models.dashboard import Dashboard
+from superset.models.slice import Slice
+from superset.utils.core import get_example_database
+from tests.dashboard_utils import create_dashboard, create_table_for_dashboard
+from tests.test_app import app
+
+
+@pytest.fixture()
+def load_world_bank_dashboard_with_slices():
+ dash_id_to_delete, slices_ids_to_delete = _load_data()
+ yield
+ with app.app_context():
+ _cleanup(dash_id_to_delete, slices_ids_to_delete)
+
+
+@pytest.fixture(scope="module")
+def load_world_bank_dashboard_with_slices_module_scope():
+ dash_id_to_delete, slices_ids_to_delete = _load_data()
+ yield
+ with app.app_context():
+ _cleanup(dash_id_to_delete, slices_ids_to_delete)
+
+
+def _load_data():
+ table_name = "wb_health_population"
+
+ with app.app_context():
+ database = get_example_database()
+ df = _get_dataframe(database)
+ dtype = {
+ "year": DateTime if database.backend != "presto" else String(255),
+ "country_code": String(3),
+ "country_name": String(255),
+ "region": String(255),
+ }
+ table = create_table_for_dashboard(df, table_name, database, dtype)
+ slices = _create_world_bank_slices(table)
+ dash = _create_world_bank_dashboard(table, slices)
+ slices_ids_to_delete = [slice.id for slice in slices]
+ dash_id_to_delete = dash.id
+ return dash_id_to_delete, slices_ids_to_delete
+
+
+def _create_world_bank_slices(table: SqlaTable) -> List[Slice]:
+ from superset.examples.world_bank import create_slices
+
+ slices = create_slices(table)
+ _commit_slices(slices)
+ return slices
+
+
+def _commit_slices(slices: List[Slice]):
+ for slice in slices:
+ o = db.session.query(Slice).filter_by(slice_name=slice.slice_name).one_or_none()
+ if o:
+ db.session.delete(o)
+ db.session.add(slice)
+ db.session.commit()
+
+
+def _create_world_bank_dashboard(table: SqlaTable, slices: List[Slice]) -> Dashboard:
+ from superset.examples.world_bank import dashboard_positions
+
+ pos = dashboard_positions
+ from superset.examples.helpers import update_slice_ids
+
+ update_slice_ids(pos, slices)
+
+ table.fetch_metadata()
+
+ dash = create_dashboard(
+ "world_health", "World Bank's Data", json.dumps(pos), slices
+ )
+ dash.json_metadata = '{"mock_key": "mock_value"}'
+ db.session.commit()
+ return dash
+
+
+def _cleanup(dash_id: int, slices_ids: List[int]) -> None:
+ engine = get_example_database().get_sqla_engine()
+ engine.execute("DROP TABLE IF EXISTS wb_health_population")
+ dash = db.session.query(Dashboard).filter_by(id=dash_id).first()
+ db.session.delete(dash)
+ for slice_id in slices_ids:
+ db.session.query(Slice).filter_by(id=slice_id).delete()
+ db.session.commit()
+
+
+def _get_dataframe(database: Database) -> DataFrame:
+ data = _get_world_bank_data()
+ df = pd.DataFrame.from_dict(data)
+ if database.backend == "presto":
+ df.year = pd.to_datetime(df.year)
+ df.year = df.year.dt.strftime("%Y-%m-%d %H:%M%:%S")
+ else:
+ df.year = pd.to_datetime(df.year)
+
+ return df
+
+
+def _get_world_bank_data() -> List[Dict[Any, Any]]:
+ data = []
+ for _ in range(100):
+ data.append(
+ {
+ "country_name": "".join(
+ choice(string.ascii_uppercase + string.ascii_lowercase + " ")
+ for _ in range(randint(3, 10))
+ ),
+ "country_code": "".join(
+ choice(string.ascii_uppercase + string.ascii_lowercase)
+ for _ in range(3)
+ ),
+ "region": "".join(
+ choice(string.ascii_uppercase + string.ascii_lowercase)
+ for _ in range(randint(3, 10))
+ ),
+ "year": "-".join(
+ [str(randint(1900, 2020)), str(randint(1, 12)), str(randint(1, 28))]
+ ),
+ "NY_GNP_PCAP_CD": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_1524_LT_FM_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_1524_LT_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_1524_LT_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_LITR_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_LITR_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ADT_LITR_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_ENR_ORPH": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_CMPT_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_CMPT_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_CMPT_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_ENRR": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_ENRR_FE": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_ENRR_MA": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_NENR": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_NENR_FE": get_random_float_or_none(0, 100, 0.3),
+ "SE_PRM_NENR_MA": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_ENRR": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_ENRR_FE": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_ENRR_MA": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_NENR": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_NENR_FE": get_random_float_or_none(0, 100, 0.3),
+ "SE_SEC_NENR_MA": get_random_float_or_none(0, 100, 0.3),
+ "SE_TER_ENRR": get_random_float_or_none(0, 100, 0.3),
+ "SE_TER_ENRR_FE": get_random_float_or_none(0, 100, 0.3),
+ "SE_XPD_TOTL_GD_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_ANM_CHLD_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_ANM_NPRG_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_CON_1524_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_CON_1524_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_CON_AIDS_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_CON_AIDS_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_COMM_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_IMRT": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_INJR_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_MORT": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_NCOM_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DTH_NMRT": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_AIDS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_AIDS_DH": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_AIDS_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_AIDS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_MORT": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_MORT_FE": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_MORT_MA": get_random_float_or_none(0, 100, 0.3),
+ "SH_DYN_NMRT": get_random_float_or_none(0, 100, 0.3),
+ "SH_FPL_SATI_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_H2O_SAFE_RU_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_H2O_SAFE_UR_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_H2O_SAFE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_0014": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_1524_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_1524_KW_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_1524_KW_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_1524_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_ARTC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_KNOW_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_KNOW_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_ORPH": get_random_float_or_none(0, 100, 0.3),
+ "SH_HIV_TOTL": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_HEPB": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_HIB3": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_IBCG": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_IDPT": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_MEAS": get_random_float_or_none(0, 100, 0.3),
+ "SH_IMM_POL3": get_random_float_or_none(0, 100, 0.3),
+ "SH_MED_BEDS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MED_CMHW_P3": get_random_float_or_none(0, 100, 0.3),
+ "SH_MED_NUMW_P3": get_random_float_or_none(0, 100, 0.3),
+ "SH_MED_PHYS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MLR_NETS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MLR_PREG_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MLR_SPF2_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MLR_TRET_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MMR_DTHS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MMR_LEVE": get_random_float_or_none(0, 100, 0.3),
+ "SH_MMR_RISK": get_random_float_or_none(0, 100, 0.3),
+ "SH_MMR_RISK_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_MMR_WAGE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_PRG_ANEM": get_random_float_or_none(0, 100, 0.3),
+ "SH_PRG_ARTC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_PRG_SYPH_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_PRV_SMOK_FE": get_random_float_or_none(0, 100, 0.3),
+ "SH_PRV_SMOK_MA": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ACSN": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ACSN_RU": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ACSN_UR": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ANV4_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ANVC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ARIC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_BFED_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_BRTC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_BRTW_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_DIAB_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_IYCF_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MALN_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MALN_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MALN_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MALR": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MMRT": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_MMRT_NE": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ORCF_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_ORTH": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OW15_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OW15_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OW15_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OWGH_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OWGH_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_OWGH_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_PNVC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_STNT_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_STNT_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_STNT_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_WAST_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_WAST_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_STA_WAST_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_SVR_WAST_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_SVR_WAST_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_SVR_WAST_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_TBS_CURE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_TBS_DTEC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_TBS_INCD": get_random_float_or_none(0, 100, 0.3),
+ "SH_TBS_MORT": get_random_float_or_none(0, 100, 0.3),
+ "SH_TBS_PREV": get_random_float_or_none(0, 100, 0.3),
+ "SH_VAC_TTNS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_EXTR_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_OOPC_TO_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_OOPC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PCAP": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PCAP_PP_KD": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PRIV": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PRIV_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PUBL": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PUBL_GX_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_PUBL_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_TOTL_CD": get_random_float_or_none(0, 100, 0.3),
+ "SH_XPD_TOTL_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SI_POV_NAHC": get_random_float_or_none(0, 100, 0.3),
+ "SI_POV_RUHC": get_random_float_or_none(0, 100, 0.3),
+ "SI_POV_URHC": get_random_float_or_none(0, 100, 0.3),
+ "SL_EMP_INSV_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SL_TLF_TOTL_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SL_TLF_TOTL_IN": get_random_float_or_none(0, 100, 0.3),
+ "SL_UEM_TOTL_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SL_UEM_TOTL_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SL_UEM_TOTL_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SM_POP_NETM": get_random_float_or_none(0, 100, 0.3),
+ "SN_ITK_DEFC": get_random_float_or_none(0, 100, 0.3),
+ "SN_ITK_DEFC_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SN_ITK_SALT_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SN_ITK_VITA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_ADO_TFRT": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_AMRT_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_AMRT_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_CBRT_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_CDRT_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_CONU_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_IMRT_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_IMRT_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_IMRT_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_LE00_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_LE00_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_LE00_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_SMAM_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_SMAM_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_TFRT_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_TO65_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_TO65_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_DYN_WFRT": get_random_float_or_none(0, 100, 0.3),
+ "SP_HOU_FEMA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_MTR_1519_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0004_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0004_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0004_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0004_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0014_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0014_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0014_TO": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0014_TO_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0509_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0509_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0509_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_0509_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1014_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1014_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1014_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1014_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1519_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1519_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1519_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1519_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1564_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1564_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1564_TO": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_1564_TO_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2024_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2024_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2024_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2024_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2529_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2529_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2529_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_2529_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3034_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3034_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3034_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3034_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3539_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3539_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3539_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_3539_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4044_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4044_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4044_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4044_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4549_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4549_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4549_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_4549_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5054_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5054_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5054_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5054_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5559_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5559_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5559_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_5559_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6064_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6064_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6064_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6064_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6569_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6569_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6569_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_6569_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_65UP_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_65UP_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_65UP_TO": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_65UP_TO_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7074_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7074_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7074_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7074_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7579_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7579_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7579_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_7579_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_80UP_FE": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_80UP_FE_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_80UP_MA": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_80UP_MA_5Y": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG00_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG00_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG01_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG01_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG02_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG02_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG03_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG03_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG04_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG04_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG05_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG05_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG06_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG06_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG07_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG07_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG08_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG08_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG09_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG09_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG10_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG10_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG11_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG11_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG12_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG12_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG13_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG13_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG14_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG14_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG15_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG15_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG16_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG16_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG17_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG17_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG18_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG18_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG19_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG19_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG20_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG20_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG21_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG21_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG22_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG22_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG23_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG23_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG24_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG24_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG25_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_AG25_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_BRTH_MF": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_DPND": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_DPND_OL": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_DPND_YG": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_GROW": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_TOTL": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_TOTL_FE_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_TOTL_FE_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_TOTL_MA_IN": get_random_float_or_none(0, 100, 0.3),
+ "SP_POP_TOTL_MA_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_REG_BRTH_RU_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_REG_BRTH_UR_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_REG_BRTH_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_REG_DTHS_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_RUR_TOTL": get_random_float_or_none(0, 100, 0.3),
+ "SP_RUR_TOTL_ZG": get_random_float_or_none(0, 100, 0.3),
+ "SP_RUR_TOTL_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_URB_GROW": get_random_float_or_none(0, 100, 0.3),
+ "SP_URB_TOTL": get_random_float_or_none(0, 100, 0.3),
+ "SP_URB_TOTL_IN_ZS": get_random_float_or_none(0, 100, 0.3),
+ "SP_UWT_TFRT": get_random_float_or_none(0, 100, 0.3),
+ }
+ )
+
+ return data
+
+
+def get_random_float_or_none(min_value, max_value, none_probability):
+ if random() < none_probability:
+ return None
+ else:
+ return uniform(min_value, max_value)
diff --git a/tests/import_export_tests.py b/tests/import_export_tests.py
index 2dc29f0..4aaf8fb 100644
--- a/tests/import_export_tests.py
+++ b/tests/import_export_tests.py
@@ -41,6 +41,7 @@ from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
from superset.utils.core import get_example_database
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from .base_tests import SupersetTestCase
@@ -270,7 +271,10 @@ class TestImportExport(SupersetTestCase):
self.get_table_by_name("birth_names"), exported_tables[0]
)
- @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
+ @pytest.mark.usefixtures(
+ "load_world_bank_dashboard_with_slices",
+ "load_birth_names_dashboard_with_slices",
+ )
def test_export_2_dashboards(self):
self.login("admin")
birth_dash = self.get_dash_by_slug("births")
@@ -311,6 +315,7 @@ class TestImportExport(SupersetTestCase):
self.get_table_by_name("wb_health_population"), exported_tables[1]
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_import_1_slice(self):
expected_slice = self.create_slice("Import Me", id=10001)
slc_id = import_chart(expected_slice, None, import_time=1989)
@@ -321,6 +326,7 @@ class TestImportExport(SupersetTestCase):
table_id = self.get_table_by_name("wb_health_population").id
self.assertEqual(table_id, self.get_slice(slc_id).datasource_id)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_import_2_slices_for_same_table(self):
table_id = self.get_table_by_name("wb_health_population").id
# table_id != 666, import func will have to find the table
@@ -363,6 +369,7 @@ class TestImportExport(SupersetTestCase):
imported_dash = self.get_dash(imported_dash_id)
self.assert_dash_equals(empty_dash, imported_dash, check_position=False)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_import_dashboard_1_slice(self):
slc = self.create_slice("health_slc", id=10006)
dash_with_1_slice = self.create_dashboard(
diff --git a/tests/schedules_test.py b/tests/schedules_test.py
index 8ff7a52..45693f4 100644
--- a/tests/schedules_test.py
+++ b/tests/schedules_test.py
@@ -23,6 +23,9 @@ import pytest
from selenium.common.exceptions import WebDriverException
from slack import errors, WebClient
+from tests.fixtures.world_bank_dashboard import (
+ load_world_bank_dashboard_with_slices_module_scope,
+)
from tests.test_app import app
from superset import db
from superset.models.dashboard import Dashboard
@@ -62,7 +65,6 @@ class TestSchedules(SupersetTestCase):
deliver_as_group=True,
delivery_type=EmailDeliveryType.inline,
)
-
# Pick up a sample slice and dashboard
slce = db.session.query(Slice).filter_by(slice_name="Participants").one()
dashboard = (
@@ -99,6 +101,7 @@ class TestSchedules(SupersetTestCase):
).delete()
db.session.commit()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
def test_crontab_scheduler(self):
crontab = "* * * * *"
@@ -126,6 +129,7 @@ class TestSchedules(SupersetTestCase):
self.assertEqual(schedules[-1], stop_at - timedelta(seconds=12 * 60))
self.assertEqual(len(schedules), 5)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
def test_wider_schedules(self):
crontab = "*/15 2,10 * * *"
@@ -141,7 +145,10 @@ class TestSchedules(SupersetTestCase):
else:
self.assertEqual(len(schedules), 0)
- @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices_module_scope")
+ @pytest.mark.usefixtures(
+ "load_world_bank_dashboard_with_slices_module_scope",
+ "load_birth_names_dashboard_with_slices_module_scope",
+ )
def test_complex_schedule(self):
# Run the job on every Friday of March and May
# On these days, run the job at
@@ -169,6 +176,7 @@ class TestSchedules(SupersetTestCase):
self.assertEqual(schedules[59], datetime.strptime("2018-03-30 17:40:00", fmt))
self.assertEqual(schedules[60], datetime.strptime("2018-05-04 17:10:00", fmt))
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
def test_create_driver(self, mock_driver_class):
mock_driver = Mock()
@@ -178,6 +186,7 @@ class TestSchedules(SupersetTestCase):
create_webdriver(db.session)
mock_driver.add_cookie.assert_called_once()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@patch("superset.tasks.schedules.time")
@@ -211,6 +220,7 @@ class TestSchedules(SupersetTestCase):
driver.screenshot.assert_not_called()
send_email_smtp.assert_called_once()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@patch("superset.tasks.schedules.time")
@@ -254,6 +264,7 @@ class TestSchedules(SupersetTestCase):
element.screenshot_as_png,
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@patch("superset.tasks.schedules.time")
@@ -297,6 +308,7 @@ class TestSchedules(SupersetTestCase):
driver.screenshot.return_value,
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@patch("superset.tasks.schedules.time")
@@ -338,6 +350,7 @@ class TestSchedules(SupersetTestCase):
self.assertEqual(send_email_smtp.call_count, 2)
self.assertEqual(send_email_smtp.call_args[1]["bcc"], self.BCC)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.slack_util.WebClient.files_upload")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@@ -391,6 +404,7 @@ class TestSchedules(SupersetTestCase):
},
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.slack_util.WebClient.files_upload")
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
@patch("superset.tasks.schedules.send_email_smtp")
@@ -445,6 +459,7 @@ class TestSchedules(SupersetTestCase):
},
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.slack_util.WebClient.files_upload")
@patch("superset.tasks.schedules.urllib.request.OpenerDirector.open")
@patch("superset.tasks.schedules.urllib.request.urlopen")
@@ -491,6 +506,7 @@ class TestSchedules(SupersetTestCase):
},
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices_module_scope")
@patch("superset.tasks.slack_util.WebClient.files_upload")
@patch("superset.tasks.schedules.urllib.request.urlopen")
@patch("superset.tasks.schedules.urllib.request.OpenerDirector.open")
diff --git a/tests/security_tests.py b/tests/security_tests.py
index 7ddc326..1b7e0b3 100644
--- a/tests/security_tests.py
+++ b/tests/security_tests.py
@@ -29,6 +29,9 @@ import random
from flask import current_app, g
from sqlalchemy import Float, Date, String
+from superset.models.dashboard import Dashboard
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
+
from superset import app, appbuilder, db, security_manager, viz, ConnectorRegistry
from superset.connectors.druid.models import DruidCluster, DruidDatasource
from superset.connectors.sqla.models import RowLevelSecurityFilter, SqlaTable
@@ -260,6 +263,7 @@ class TestRolePermission(SupersetTestCase):
session.delete(stored_table)
session.commit()
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_set_perm_druid_datasource(self):
self.create_druid_test_objects()
session = db.session
@@ -534,7 +538,12 @@ class TestRolePermission(SupersetTestCase):
self.assertIsNotNone(vm)
delete_schema_perm("[examples].[2]")
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_gamma_user_schema_access_to_dashboards(self):
+ dash = db.session.query(Dashboard).filter_by(slug="world_health").first()
+ dash.published = True
+ db.session.commit()
+
self.login(username="gamma")
data = str(self.client.get("api/v1/dashboard/").data)
self.assertIn("/superset/dashboard/world_health/", data)
@@ -546,6 +555,7 @@ class TestRolePermission(SupersetTestCase):
self.assertIn("wb_health_population", data)
self.assertNotIn("birth_names", data)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_gamma_user_schema_access_to_charts(self):
self.login(username="gamma")
data = str(self.client.get("api/v1/chart/").data)
@@ -820,6 +830,7 @@ class TestRolePermission(SupersetTestCase):
@unittest.skipUnless(
SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
)
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_admin_permissions(self):
self.assert_can_gamma(get_perm_tuples("Admin"))
self.assert_can_alpha(get_perm_tuples("Admin"))
diff --git a/tests/utils_tests.py b/tests/utils_tests.py
index a16db4b..1c6e6b2 100644
--- a/tests/utils_tests.py
+++ b/tests/utils_tests.py
@@ -70,6 +70,7 @@ from superset.views.utils import (
get_time_range_endpoints,
)
from tests.base_tests import SupersetTestCase
+from tests.fixtures.world_bank_dashboard import load_world_bank_dashboard_with_slices
from .fixtures.certificates import ssl_certificate
@@ -853,6 +854,7 @@ class TestUtils(SupersetTestCase):
self.assertListEqual(get_iterable([123]), [123])
self.assertListEqual(get_iterable("foo"), ["foo"])
+ @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
def test_build_extra_filters(self):
world_health = db.session.query(Dashboard).filter_by(slug="world_health").one()
layout = json.loads(world_health.position_json)