Repository: ibis-project/ibis

Issue:
bug(pandas): TypeError: pipe() missing 1 required positional argument: 'f' when calling `.seconds()` on Interval
If I to subtract two timestamp columns to get an interval, it works and I'm able to execute on the pandas backend. If I then try to call `.seconds()` or `.milliseconds()` on that interval, the pandas backend fails with `TypeError: pipe() missing 1 required positional argument: 'f'`

Working code:

```python
import ibis
import pandas


source_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-06-30T16:00:00Z")]})
target_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-07-01T16:00:00Z")]})

client = ibis.pandas.connect(
    {"source": source_df, "target": target_df}
)

source = client.table("source")
target = client.table("target")
joined = source.cross_join(target)
difference = joined[
    (
        target["timecol"] - source["timecol"]
    ).name("difference")
]

print(difference.execute())
```

Output:

```
$ python interval.py
  difference
0     1 days
```

Broken code:

```python
import ibis
import pandas


source_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-06-30T16:00:00Z")]})
target_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-07-01T16:00:00Z")]})

client = ibis.pandas.connect(
    {"source": source_df, "target": target_df}
)

source = client.table("source")
target = client.table("target")
joined = source.cross_join(target)
difference_seconds = joined[
    (
        target["timecol"] - source["timecol"]
    ).seconds().name("difference")
]

print(difference_seconds.execute())
```

Output:

```
$ python interval.py
Traceback (most recent call last):
  File "interval.py", line 17, in <module>
    target["timecol"] - source["timecol"]
TypeError: pipe() missing 1 required positional argument: 'f'
```


Discussion:
Maybe Ibis should be calling `df["difference"].dt.total_seconds()` instead of whatever it's currently doing for the `seconds()`
Hey @tswast -- thanks for the convenient test case!

It works if we remove the method call on `seconds`:

```
import ibis
import pandas


source_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-06-30T16:00:00Z")]})
target_df = pandas.DataFrame({"timecol": [pandas.Timestamp("2020-07-01T16:00:00Z")]})

client = ibis.pandas.connect(
    {"source": source_df, "target": target_df}
)

source = client.table("source")
target = client.table("target")
joined = source.cross_join(target)
difference_seconds = joined[
    (
        target["timecol"] - source["timecol"]
    ).seconds.name("difference")
]
```

We're going to remove the blanket `__call__` on expressions to avoid these errors moving forward

Resolving patch:
diff --git a/ibis/expr/types/core.py b/ibis/expr/types/core.py
--- a/ibis/expr/types/core.py
+++ b/ibis/expr/types/core.py
@@ -187,8 +187,6 @@ def pipe(self, f, *args: Any, **kwargs: Any) -> Expr:
         else:
             return f(self, *args, **kwargs)
 
-    __call__ = pipe
-
     def op(self) -> ops.Node:
         return self._arg
 


Test patch:
diff --git a/ibis/tests/expr/test_pipe.py b/ibis/tests/expr/test_pipe.py
--- a/ibis/tests/expr/test_pipe.py
+++ b/ibis/tests/expr/test_pipe.py
@@ -58,9 +58,3 @@ def my_func(x, y, data=None):
     expected = pipe_table['value'] + 4
 
     assert result.equals(expected)
-
-
-def test_call_pipe_equivalence(pipe_table):
-    result = pipe_table(lambda x: x['key1'].cast('double').sum())
-    expected = pipe_table.key1.cast('double').sum()
-    assert result.equals(expected)