Skip to content

Commit

Permalink
Refactoring code
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneTorap committed Jan 27, 2023
1 parent a9b00fd commit 9e3da1b
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 124 deletions.
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ wtforms==2.3.3
# wtforms-json
wtforms-json==0.3.3
# via apache-superset
xlsxwriter==3.0.3
# via apache-superset

# The following packages are considered to be unsafe in a requirements file:
# setuptools
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def get_git_sha() -> str:
"tabulate>=0.8.9, <0.9",
"typing-extensions>=4, <5",
"wtforms-json",
"xlsxwriter",
],
extras_require={
"athena": ["pyathena[pandas]>=2, <3"],
Expand Down Expand Up @@ -173,8 +174,6 @@ def get_git_sha() -> str:
"thumbnails": ["Pillow>=9.1.1, <10.0.0"],
"vertica": ["sqlalchemy-vertica-python>=0.5.9, < 0.6"],
"netezza": ["nzalchemy>=11.0.2"],
"xls": ["xlwt>=1.3.0, < 1.4"],
"xlsx": ["xlsxwriter>=3.0.0, < 3.1"],
},
python_requires="~=3.8",
author="Apache Software Foundation",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ const MENU_KEYS = {
EXPORT_TO_CSV: 'export_to_csv',
EXPORT_TO_CSV_PIVOTED: 'export_to_csv_pivoted',
EXPORT_TO_JSON: 'export_to_json',
EXPORT_TO_XLS: 'export_to_xls',
EXPORT_TO_XLSX: 'export_to_xlsx',
DOWNLOAD_AS_IMAGE: 'download_as_image',
SHARE_SUBMENU: 'share_submenu',
Expand Down Expand Up @@ -159,29 +158,15 @@ export const useExploreAdditionalActionsMenu = (
}),
[latestQueryFormData],
);
const exportXLS = useCallback(
() =>
canDownloadCSV
? exportChart({
formData: latestQueryFormData,
ownState,
resultType: 'full',
resultFormat: 'xls',
})
: null,
[canDownloadCSV, latestQueryFormData],
);
const exportXLSX = useCallback(

const exportExcel = useCallback(
() =>
canDownloadCSV
? exportChart({
formData: latestQueryFormData,
ownState,
resultType: 'full',
resultFormat: 'xlsx',
})
: null,
[canDownloadCSV, latestQueryFormData],
exportChart({
formData: latestQueryFormData,
resultType: 'results',
resultFormat: 'xlsx',
}),
[latestQueryFormData],
);

const copyLink = useCallback(async () => {
Expand Down Expand Up @@ -218,14 +203,9 @@ export const useExploreAdditionalActionsMenu = (
setIsDropdownVisible(false);
setOpenSubmenus([]);

break;
case MENU_KEYS.EXPORT_TO_XLS:
exportXLS();
setIsDropdownVisible(false);
setOpenSubmenus([]);
break;
case MENU_KEYS.EXPORT_TO_XLSX:
exportXLSX();
exportExcel();
setIsDropdownVisible(false);
setOpenSubmenus([]);
break;
Expand Down Expand Up @@ -332,18 +312,15 @@ export const useExploreAdditionalActionsMenu = (
<Menu.Item key={MENU_KEYS.EXPORT_TO_JSON} icon={<FileOutlined />}>
{t('Export to .JSON')}
</Menu.Item>
<Menu.Item key={MENU_KEYS.EXPORT_TO_XLS} icon={<FileOutlined />}>
{t('Export to .XLS')}
</Menu.Item>
<Menu.Item key={MENU_KEYS.EXPORT_TO_XLSX} icon={<FileOutlined />}>
{t('Export to .XLSX')}
</Menu.Item>
<Menu.Item
key={MENU_KEYS.DOWNLOAD_AS_IMAGE}
icon={<FileImageOutlined />}
>
{t('Download as image')}
</Menu.Item>
<Menu.Item key={MENU_KEYS.EXPORT_TO_XLSX} icon={<FileOutlined />}>
{t('Export to Excel')}
</Menu.Item>
</Menu.SubMenu>
<Menu.SubMenu title={t('Share')} key={MENU_KEYS.SHARE_SUBMENU}>
<Menu.Item key={MENU_KEYS.COPY_PERMALINK}>
Expand Down
28 changes: 11 additions & 17 deletions superset/charts/data/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@
from superset.extensions import event_logger
from superset.utils.async_query_manager import AsyncQueryTokenException
from superset.utils.core import create_zip, get_user_id, json_int_dttm_ser
from superset.views.base import (
CsvResponse,
generate_download_headers,
XlsResponse,
XlsxResponse,
)
from superset.views.base import CsvResponse, generate_download_headers, XlsxResponse
from superset.views.base_api import statsd_metrics

if TYPE_CHECKING:
Expand Down Expand Up @@ -355,27 +350,26 @@ def _send_chart_response(
if not result["queries"]:
return self.response_400(_("Empty query result"))

is_csv_format = result_format == ChartDataResultFormat.CSV

if len(result["queries"]) == 1:
# return single query results
data = result["queries"][0]["data"]
if result_format == ChartDataResultFormat.CSV:
if is_csv_format:
return CsvResponse(data, headers=generate_download_headers("csv"))
elif result_format == ChartDataResultFormat.XLS:
return XlsResponse(data, headers=generate_download_headers("xls"))
elif result_format == ChartDataResultFormat.XLSX:
return XlsxResponse(data, headers=generate_download_headers("xlsx"))

# return multi-query results bundled as a zip file
return XlsxResponse(data, headers=generate_download_headers("xlsx"))

def _process_data(d: Any) -> Any:
# return multi-query results bundled as a zip file
def _process_data(query_data: Any) -> Any:
if result_format == ChartDataResultFormat.CSV:
encoding = current_app.config["CSV_EXPORT"].get("encoding", "utf-8")
return d.encode(encoding)
return d
return query_data.encode(encoding)
return query_data

files = {
f"query_{idx + 1}.{result_format}": _process_data(result["data"])
for idx, result in enumerate(result["queries"])
f"query_{idx + 1}.{result_format}": _process_data(query["data"])
for idx, query in enumerate(result["queries"])
}
return Response(
create_zip(files),
Expand Down
7 changes: 1 addition & 6 deletions superset/common/chart_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,11 @@ class ChartDataResultFormat(str, Enum):

CSV = "csv"
JSON = "json"
XLS = "xls"
XLSX = "xlsx"

@classmethod
def excel(cls) -> Set["ChartDataResultFormat"]:
return {cls.XLS, cls.XLSX}

@classmethod
def table_like(cls) -> Set["ChartDataResultFormat"]:
return {cls.CSV} | {cls.XLS, cls.XLSX}
return {cls.CSV} | {cls.XLSX}


class ChartDataResultType(str, Enum):
Expand Down
12 changes: 5 additions & 7 deletions superset/common/query_context_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,16 +452,14 @@ def get_data(self, df: pd.DataFrame) -> Union[str, List[Dict[str, Any]]]:
verbose_map = self._qc_datasource.data.get("verbose_map", {})
if verbose_map:
df.columns = [verbose_map.get(column, column) for column in columns]
if self._query_context.result_type == ChartDataResultFormat.CSV:

result = None
if self._query_context.result_format == ChartDataResultFormat.CSV:
result = csv.df_to_escaped_csv(
df, index=include_index, **config["CSV_EXPORT"]
)
else:
result = excel.df_to_excel(
df,
excel_format=self._query_context.result_format,
**config["EXCEL_EXPORT"],
)
elif self._query_context.result_format == ChartDataResultFormat.XLSX:
result = excel.df_to_excel(df, **config["EXCEL_EXPORT"])
return result or ""

return df.to_dict(orient="records")
Expand Down
29 changes: 20 additions & 9 deletions superset/utils/excel.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
# 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 io
from typing import Any

import pandas as pd

from superset.common.chart_data import ChartDataResultFormat


def df_to_excel(
df: pd.DataFrame,
excel_format: ChartDataResultFormat = ChartDataResultFormat.XLSX,
**kwargs: Any
) -> bytes:
def df_to_excel(df: pd.DataFrame, **kwargs: Any) -> Any:
output = io.BytesIO()
engine = "xlwt" if excel_format == ChartDataResultFormat.XLS else "xlsxwriter"
with pd.ExcelWriter(output, engine=engine) as writer:
# pylint: disable=abstract-class-instantiated
with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
df.to_excel(writer, **kwargs)

return output.getvalue()
9 changes: 0 additions & 9 deletions superset/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,15 +666,6 @@ class CsvResponse(Response):
default_mimetype = "text/csv"


class XlsResponse(Response):
"""
Override Response to use xls mimetype
"""

charset = "utf-8"
default_mimetype = "application/vnd.ms-excel"


class XlsxResponse(Response):
"""
Override Response to use xlsx mimetype
Expand Down
7 changes: 0 additions & 7 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@
json_errors_response,
json_success,
validate_sqlatable,
XlsResponse,
XlsxResponse,
)
from superset.views.sql_lab.schemas import SqlJsonPayloadSchema
Expand Down Expand Up @@ -497,12 +496,6 @@ def generate_json(
viz_obj.get_csv(), headers=generate_download_headers("csv")
)

if response_type == ChartDataResultFormat.XLS:
return XlsResponse(
viz_obj.get_excel(ChartDataResultFormat(response_type)),
headers=generate_download_headers("xls"),
)

if response_type == ChartDataResultFormat.XLSX:
return XlsxResponse(
viz_obj.get_excel(ChartDataResultFormat(response_type)),
Expand Down
Loading

0 comments on commit 9e3da1b

Please sign in to comment.