def _build_filter(self, q): result = None if type(q) is not list: return unicode(q) if not q: raise_malformed("Empty expression not allowed", q) op = q[0] if op == "!": assert_len(q, 2, "! is a single arity operator, invalid number of arguments") result = "not " + self._build_filter(q[1]) elif op == "isnull": assert_len(q, 2, "isnull is a single arity operator, invalid number of arguments") # Slightly hacky but the only way I've come up with so far. result = "({arg} != {arg})".format(arg=q[1]) elif op in COMPARISON_OPERATORS: assert_len(q, 3) _, arg1, arg2 = q result = self._build_filter(arg1) + " " + op + " " + self._build_filter(arg2) elif op in JOINING_OPERATORS: if len(q) < 2: raise_malformed("Invalid number of arguments", q) elif len(q) == 2: # Conjunctions and disjunctions with only one clause are OK result = self._build_filter(q[1]) else: result = ' {op} '.format(op=op).join(self._build_filter(x) for x in q[1:]) elif op == 'in': col_name, args = prepare_in_clause(q, FILTER_ENGINE_NUMEXPR) var_name = self._insert_in_env(args) result = '{col_name} in @env.{var_name}'.format(col_name=col_name, var_name=var_name) else: raise_malformed("Unknown operator", q) return "({result})".format(result=result)
def _in_filter(df, q): col_name, args = prepare_in_clause(q, FILTER_ENGINE_PANDAS) return df[col_name].isin(args)