diff --git a/superset/dataframe.py b/superset/dataframe.py index 62d6cf45d..38c4fb535 100644 --- a/superset/dataframe.py +++ b/superset/dataframe.py @@ -19,6 +19,7 @@ from pandas.core.common import _maybe_box_datetimelike from pandas.core.dtypes.dtypes import ExtensionDtype from past.builtins import basestring +from superset.utils import JS_MAX_INTEGER INFER_COL_TYPES_THRESHOLD = 95 INFER_COL_TYPES_SAMPLE_SIZE = 100 @@ -51,9 +52,17 @@ class SupersetDataFrame(object): @property def data(self): # work around for https://github.com/pandas-dev/pandas/issues/18372 - return [dict((k, _maybe_box_datetimelike(v)) - for k, v in zip(self.__df.columns, np.atleast_1d(row))) + data = [dict((k, _maybe_box_datetimelike(v)) + for k, v in zip(self.__df.columns, np.atleast_1d(row))) for row in self.__df.values] + for d in data: + for k, v in list(d.items()): + # if an int is too big for Java Script to handle + # convert it to a string + if isinstance(v, int): + if abs(v) > JS_MAX_INTEGER: + d[k] = str(v) + return data @classmethod def db_type(cls, dtype): diff --git a/superset/utils.py b/superset/utils.py index 828111f6b..8e99f699a 100644 --- a/superset/utils.py +++ b/superset/utils.py @@ -48,6 +48,8 @@ PY3K = sys.version_info >= (3, 0) EPOCH = datetime(1970, 1, 1) DTTM_ALIAS = '__timestamp' +JS_MAX_INTEGER = 9007199254740991 # Largest int Java Script can handle 2^53-1 + def flasher(msg, severity=None): """Flask's flash if available, logging call if not""" diff --git a/superset/viz.py b/superset/viz.py index cb20e1181..af8a149e2 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -35,7 +35,7 @@ from six import string_types, text_type from six.moves import cPickle as pkl, reduce from superset import app, cache, get_manifest_file, utils -from superset.utils import DTTM_ALIAS, merge_extra_filters +from superset.utils import DTTM_ALIAS, JS_MAX_INTEGER, merge_extra_filters config = app.config @@ -88,6 +88,17 @@ class BaseViz(object): self._any_cached_dttm = None self._extra_chart_data = None + @staticmethod + def handle_js_int_overflow(data): + for d in data.get('records', dict()): + for k, v in list(d.items()): + if isinstance(v, int): + # if an int is too big for Java Script to handle + # convert it to a string + if abs(v) > JS_MAX_INTEGER: + d[k] = str(v) + return data + def run_extra_queries(self): """Lyfecycle method to use when more than one query is needed @@ -515,10 +526,13 @@ class TableViz(BaseViz): ): del df[m] - return dict( - records=df.to_dict(orient='records'), - columns=list(df.columns), - ) + data = self.handle_js_int_overflow( + dict( + records=df.to_dict(orient='records'), + columns=list(df.columns), + )) + + return data def json_dumps(self, obj, sort_keys=False): if self.form_data.get('all_columns'): @@ -1033,7 +1047,12 @@ class NVD3TimeSeriesViz(NVD3Viz): ys = series[name] if df[name].dtype.kind not in 'biufc': continue - series_title = name + if isinstance(name, list): + series_title = [str(title) for title in name] + elif isinstance(name, tuple): + series_title = tuple(str(title) for title in name) + else: + series_title = str(name) if ( isinstance(series_title, (list, tuple)) and len(series_title) > 1 and