diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index ca955a7c8d..4ad6a6f951 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -980,9 +980,9 @@ class DruidDatasource(Model, BaseDatasource): eq = eq[0] if len(eq) > 0 else '' if col in self.num_cols: if op in ('in', 'not in'): - eq = [utils.js_string_to_num(v) for v in eq] + eq = [utils.string_to_num(v) for v in eq] else: - eq = utils.js_string_to_num(eq) + eq = utils.string_to_num(eq) if op == '==': cond = Dimension(col) == eq elif op == '!=': diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index c853b59139..913ee59579 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -1,6 +1,7 @@ from datetime import datetime import logging import sqlparse +from past.builtins import basestring import pandas as pd @@ -467,9 +468,19 @@ class SqlaTable(Model, BaseDatasource): col_obj = cols.get(col) if col_obj: if op in ('in', 'not in'): - values = [types.strip("'").strip('"') for types in eq] - if col_obj.is_num: - values = [utils.js_string_to_num(s) for s in values] + values = [] + for v in eq: + # For backwards compatibility and edge cases + # where a column data type might have changed + if isinstance(v, basestring): + v = v.strip("'").strip('"') + if col_obj.is_num: + v = utils.string_to_num(v) + + # Removing empty strings and non numeric values + # targeting numeric columns + if v is not None: + values.append(v) cond = col_obj.sqla_col.in_(values) if op == 'not in': cond = ~cond diff --git a/superset/utils.py b/superset/utils.py index ec4c18d896..2cfd7a5992 100644 --- a/superset/utils.py +++ b/superset/utils.py @@ -128,14 +128,32 @@ class memoized(object): # noqa def js_string_to_python(item): return None if item in ('null', 'undefined') else item -def js_string_to_num(item): - if item.isdigit(): - return int(item) - s = item - try: - s = float(item) - except ValueError: + +def string_to_num(s): + """Converts a string to an int/float + + Returns ``None`` if it can't be converted + + >>> string_to_num('5') + 5 + >>> string_to_num('5.2') + 5.2 + >>> string_to_num(10) + 10 + >>> string_to_num(10.1) + 10.1 + >>> string_to_num('this is not a string') is None + True + """ + if isinstance(s, (int, float)): return s + if s.isdigit(): + return int(s) + try: + return float(s) + except ValueError: + return None + class DimSelector(Having): def __init__(self, **args):