Repository: ibis-project/ibis

Issue:
bug: Applying ibis.desc()/asc() does not work with window function when referencing column with dot notation
### What happened?

To duplicate:
t = ibis.memtable({"values": [1, 2, 1, 2, 3, 2]})
t.mutate(rank=ibis.rank().over(order_by=ibis.desc(t.values)))  # This does not work

t.mutate(rank=ibis.rank().over(order_by=ibis.desc("values"))  # This works
t.mutate(rank=ibis.rank().over(order_by=ibis.desc(_.values))  # This also works

### What version of ibis are you using?

7.1

### What backend(s) are you using, if any?

DuckDB

### Relevant log output

_No response_

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:
Thanks for reporting this @pybokeh !

Interestingly, this appears to be something that only trips in interactive mode (and only when _creating_ the window expression):

```python
[ins] In [1]: import ibis

[ins] In [2]: t = ibis.memtable({"values": [1, 2, 1, 2, 3, 2]})

[ins] In [3]: expr = t.mutate(rank=ibis.rank().over(order_by=ibis.desc(t.values)))

[ins] In [4]: expr.to_pyarrow()
Out[4]: 
pyarrow.Table
values: int64
rank: int64
----
values: [[3,2,2,2,1,1]]
rank: [[0,1,1,1,4,4]]

[ins] In [5]: ibis.options.interactive = True

[ins] In [6]: expr
Out[6]: 
┏━━━━━━━━┳━━━━━━━┓
┃ values ┃ rank  ┃
┡━━━━━━━━╇━━━━━━━┩
│ int64  │ int64 │
├────────┼───────┤
│      3 │     0 │
│      2 │     1 │
│      2 │     1 │
│      2 │     1 │
│      1 │     4 │
│      1 │     4 │
└────────┴───────┘
```

but, if I try to re-run the `expr` assignment with interactive mode on:

```python
[ins] In [7]: expr = t.mutate(rank=ibis.rank().over(order_by=ibis.desc(t.values)))
---------------------------------------------------------------------------
ParserException                           Traceback (most recent call last)

<snip> 


File ~/github.com/ibis-project/ibis/ibis/expr/types/core.py:421, in Expr.to_pyarrow(self, params, limit, **kwargs)
    393 @experimental
    394 def to_pyarrow(
    395     self,
   (...)
    399     **kwargs: Any,
    400 ) -> pa.Table:
    401     """Execute expression and return results in as a pyarrow table.
    402 
    403     This method is eager and will execute the associated expression
   (...)
    419         A pyarrow table holding the results of the executed expression.
    420     """
--> 421     return self._find_backend(use_default=True).to_pyarrow(
    422         self, params=params, limit=limit, **kwargs
    423     )

File ~/github.com/ibis-project/ibis/ibis/backends/duckdb/__init__.py:1002, in Backend.to_pyarrow(self, expr, params, limit, **_)
    995 sql = str(
    996     query_ast.compile().compile(
    997         dialect=self.con.dialect, compile_kwargs={"literal_binds": True}
    998     )
    999 )
   1001 with self.begin() as con:
-> 1002     table = con.connection.sql(sql).to_arrow_table()
   1004 return expr.__pyarrow_result__(table)

ParserException: Parser Error: syntax error at or near "DESC"
LINE 1: SELECT t0.values DESC AS values 
```
Wow, that's wild.

During the construction of the `Window` in `WindowBuilder` we attempt to match and that attempt raises a `CoercionError`, which we are expecting and which we catch in an `except` block, but the error message (which will _NOT_ be seen by the user) is an f-string and it tries to render the fragment of the window by itself, and so the failure to render the string in the exception prevents the _actual_ exception from being thrown.

Resolving patch:
diff --git a/ibis/common/deferred.py b/ibis/common/deferred.py
--- a/ibis/common/deferred.py
+++ b/ibis/common/deferred.py
@@ -51,7 +51,9 @@ def __coerce__(cls, value):
         elif isinstance(value, Deferred):
             return value._resolver
         else:
-            raise CoercionError(f"Cannot coerce {value!r} to {cls.__name__!r}")
+            raise CoercionError(
+                f"Cannot coerce {type(value).__name__!r} to {cls.__name__!r}"
+            )
 
 
 class Deferred(Slotted, Immutable, Final):


Test patch: