You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by be...@apache.org on 2023/07/14 23:05:16 UTC

[superset] branch migrate-charts-on-import created (now 0f5d96f860)

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

beto pushed a change to branch migrate-charts-on-import
in repository https://gitbox.apache.org/repos/asf/superset.git


      at 0f5d96f860 feat: migrate charts on import

This branch includes the following new commits:

     new 0f5d96f860 feat: migrate charts on import

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[superset] 01/01: feat: migrate charts on import

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch migrate-charts-on-import
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 0f5d96f86072d245161b048fe1df4c5b3de154c4
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Fri Jul 14 16:01:59 2023 -0700

    feat: migrate charts on import
---
 superset/charts/commands/importers/v1/utils.py     |  48 +++++++++
 .../migrations/shared/migrate_viz/processors.py    |   3 +
 .../charts/commands/importers/v1/utils_test.py     | 118 +++++++++++++++++++++
 3 files changed, 169 insertions(+)

diff --git a/superset/charts/commands/importers/v1/utils.py b/superset/charts/commands/importers/v1/utils.py
index 399e6c2243..079376fab6 100644
--- a/superset/charts/commands/importers/v1/utils.py
+++ b/superset/charts/commands/importers/v1/utils.py
@@ -15,7 +15,9 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import copy
 import json
+from inspect import isclass
 from typing import Any
 
 from flask import g
@@ -23,6 +25,8 @@ from sqlalchemy.orm import Session
 
 from superset import security_manager
 from superset.commands.exceptions import ImportFailedError
+from superset.migrations.shared.migrate_viz import processors
+from superset.migrations.shared.migrate_viz.base import MigrateViz
 from superset.models.slice import Slice
 
 
@@ -46,6 +50,9 @@ def import_chart(
     # TODO (betodealmeida): move this logic to import_from_dict
     config["params"] = json.dumps(config["params"])
 
+    # migrate old viz types to new ones
+    config = migrate_chart(config)
+
     chart = Slice.import_from_dict(session, config, recursive=False)
     if chart.id is None:
         session.flush()
@@ -54,3 +61,44 @@ def import_chart(
         chart.owners.append(g.user)
 
     return chart
+
+
+def migrate_chart(config: dict[str, Any]) -> dict[str, Any]:
+    """
+    Used to migrate old viz types to new ones.
+    """
+    migrators = {
+        class_.source_viz_type: class_
+        for class_ in processors.__dict__.values()
+        if isclass(class_) and issubclass(class_, MigrateViz) and class_ != MigrateViz
+    }
+
+    output = copy.deepcopy(config)
+    if config["viz_type"] not in migrators:
+        return output
+
+    migrator = migrators[config["viz_type"]](output["params"])
+    # pylint: disable=protected-access
+    migrator._pre_action()
+    migrator._migrate()
+    migrator._post_action()
+    params = migrator.data
+
+    params["viz_type"] = migrator.target_viz_type
+    output.update(
+        {
+            "params": json.dumps(params),
+            "viz_type": migrator.target_viz_type,
+        }
+    )
+
+    # also update `query_context`
+    try:
+        query_context = json.loads(output.get("query_context", "{}"))
+    except json.decoder.JSONDecodeError:
+        query_context = {}
+    if "form_data" in query_context:
+        query_context["form_data"] = output["params"]
+        output["query_context"] = json.dumps(query_context)
+
+    return output
diff --git a/superset/migrations/shared/migrate_viz/processors.py b/superset/migrations/shared/migrate_viz/processors.py
index fa7043fc38..4db308e04c 100644
--- a/superset/migrations/shared/migrate_viz/processors.py
+++ b/superset/migrations/shared/migrate_viz/processors.py
@@ -51,6 +51,9 @@ class MigrateAreaChart(MigrateViz):
             self.data["show_extra_controls"] = True
             self.data["stack"] = stacked_map.get(stacked)
 
+        if x_axis := self.data.get("granularity_sqla"):
+            self.data["x_axis"] = x_axis
+
         if x_axis_label := self.data.get("x_axis_label"):
             self.data["x_axis_title"] = x_axis_label
             self.data["x_axis_title_margin"] = 30
diff --git a/tests/unit_tests/charts/commands/importers/v1/utils_test.py b/tests/unit_tests/charts/commands/importers/v1/utils_test.py
new file mode 100644
index 0000000000..ab8fd0d1f7
--- /dev/null
+++ b/tests/unit_tests/charts/commands/importers/v1/utils_test.py
@@ -0,0 +1,118 @@
+# 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
+
+from superset.charts.commands.importers.v1.utils import migrate_chart
+
+
+def test_migrate_chart() -> None:
+    """
+    Test the ``migrate_chart`` command when importing a chart.
+    """
+    chart_config = {
+        "slice_name": "Birth names by state",
+        "description": None,
+        "certified_by": None,
+        "certification_details": None,
+        "viz_type": "area",
+        "params": json.dumps(
+            {
+                "datasource": "21__table",
+                "viz_type": "area",
+                "granularity_sqla": "ds",
+                "time_grain_sqla": "P1D",
+                "time_range": "No filter",
+                "metrics": ["count"],
+                "adhoc_filters": [],
+                "groupby": ["state"],
+                "order_desc": True,
+                "row_limit": 10000,
+                "show_brush": "auto",
+                "show_legend": True,
+                "line_interpolation": "linear",
+                "stacked_style": "stack",
+                "color_scheme": "supersetColors",
+                "rich_tooltip": True,
+                "bottom_margin": "auto",
+                "x_ticks_layout": "auto",
+                "x_axis_format": "smart_date",
+                "y_axis_format": "SMART_NUMBER",
+                "y_axis_bounds": [None, None],
+                "rolling_type": "None",
+                "comparison_type": "values",
+                "annotation_layers": [],
+                "extra_form_data": {},
+                "dashboards": [],
+            }
+        ),
+        "cache_timeout": None,
+        "uuid": "ffd15af2-2188-425c-b6b4-df28aac45872",
+        "version": "1.0.0",
+        "dataset_uuid": "a18b9cb0-b8d3-42ed-bd33-0f0fadbf0f6d",
+    }
+
+    new_config = migrate_chart(chart_config)
+    assert new_config == {
+        "slice_name": "Birth names by state",
+        "description": None,
+        "certified_by": None,
+        "certification_details": None,
+        "viz_type": "echarts_area",
+        "params": json.dumps(
+            {
+                "datasource": "21__table",
+                "viz_type": "echarts_area",
+                "time_grain_sqla": "P1D",
+                "metrics": ["count"],
+                "adhoc_filters": [
+                    {
+                        "clause": "WHERE",
+                        "subject": "ds",
+                        "operator": "TEMPORAL_RANGE",
+                        "comparator": "No filter",
+                        "expressionType": "SIMPLE",
+                    }
+                ],
+                "groupby": ["state"],
+                "order_desc": True,
+                "row_limit": 10000,
+                "show_brush": "auto",
+                "show_legend": True,
+                "line_interpolation": "linear",
+                "color_scheme": "supersetColors",
+                "rich_tooltip": True,
+                "bottom_margin": "auto",
+                "x_ticks_layout": "auto",
+                "x_axis_format": "smart_date",
+                "y_axis_format": "SMART_NUMBER",
+                "y_axis_bounds": [None, None],
+                "rolling_type": "None",
+                "comparison_type": "values",
+                "annotation_layers": [],
+                "extra_form_data": {},
+                "dashboards": [],
+                "show_extra_controls": True,
+                "stack": "Stack",
+                "x_axis": "ds",
+            }
+        ),
+        "cache_timeout": None,
+        "uuid": "ffd15af2-2188-425c-b6b4-df28aac45872",
+        "version": "1.0.0",
+        "dataset_uuid": "a18b9cb0-b8d3-42ed-bd33-0f0fadbf0f6d",
+    }