diff --git a/ibis/expr/types/relations.py b/ibis/expr/types/relations.py index a46ace3196ec..bd4212c97fce 100644 --- a/ibis/expr/types/relations.py +++ b/ibis/expr/types/relations.py @@ -1710,23 +1710,29 @@ def select( import ibis.expr.analysis as an from ibis.selectors import Selector - exprs = list( - itertools.chain( - itertools.chain.from_iterable( - util.promote_list(e.expand(self) if isinstance(e, Selector) else e) - for e in exprs - ), - ( - self._ensure_expr(expr).name(name) - for name, expr in named_exprs.items() - ), + exprs = [ + e + for expr in exprs + for e in ( + expr.expand(self) + if isinstance(expr, Selector) + else map(self._ensure_expr, util.promote_list(expr)) ) + ] + exprs.extend( + self._ensure_expr(expr).name(name) for name, expr in named_exprs.items() ) if not exprs: raise com.IbisTypeError( "You must select at least one column for a valid projection" ) + for ex in exprs: + if not isinstance(ex, Expr): + raise com.IbisTypeError( + "All arguments to `.select` must be coerceable to " + f"expressions - got {type(ex)!r}" + ) op = an.Projector(self, exprs).get_result() diff --git a/ibis/tests/expr/test_table.py b/ibis/tests/expr/test_table.py index e1f6f8648952..6252fdfe0f1a 100644 --- a/ibis/tests/expr/test_table.py +++ b/ibis/tests/expr/test_table.py @@ -243,6 +243,16 @@ def test_projection_no_expr(table, empty): table.select(empty) +def test_projection_invalid_nested_list(table): + errmsg = "must be coerceable to expressions" + with pytest.raises(com.IbisTypeError, match=errmsg): + table.select(["a", ["b"]]) + with pytest.raises(com.IbisTypeError, match=errmsg): + table[["a", ["b"]]] + with pytest.raises(com.IbisTypeError, match=errmsg): + table["a", ["b"]] + + def test_mutate(table): expr = table.mutate( [