internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: ibis-project/ibis

Issue:
bug: unable to repr empty schema
### What happened?

```py
In [1]: import ibis
In [2]: ibis.table({}, name="e")
```

results in

```
File ~/Workspace/ibis/ibis/expr/format.py:151, in fmt_schema(schema)
    138 """Format `schema`.
    139
    140 Parameters
   (...)
    148     Formatted schema
    149 """
    150 names = schema.names
--> 151 maxlen = max(map(len, names))
    152 cols = [f"{name:<{maxlen}} {typ}" for name, typ in schema.items()]
    153 depth = ibis.options.repr.table_columns
```

### What version of ibis are you using?

master

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

_No response_

### Relevant log output

_No response_

### Code of Conduct

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


Discussion:
This should raise an error. An empty schema should fail to construct.

Resolving patch:
diff --git a/ibis/expr/format.py b/ibis/expr/format.py
--- a/ibis/expr/format.py
+++ b/ibis/expr/format.py
@@ -108,6 +108,8 @@ def render_fields(fields, indent_level=0, limit_items=None):
 
 
 def render_schema(schema, indent_level=0, limit_items=None):
+    if not len(schema):
+        return util.indent("<empty schema>", spaces=indent_level * 2)
     if limit_items is None:
         limit_items = ibis.options.repr.table_columns
     return render(schema, indent_level, limit_items, key_separator="")


Test patch:
diff --git a/ibis/expr/tests/snapshots/test_format/test_format_table_with_empty_schema/repr.txt b/ibis/expr/tests/snapshots/test_format/test_format_table_with_empty_schema/repr.txt
new file mode 100644
--- /dev/null
+++ b/ibis/expr/tests/snapshots/test_format/test_format_table_with_empty_schema/repr.txt
@@ -0,0 +1,2 @@
+UnboundTable: t
+  <empty schema>
\ No newline at end of file
diff --git a/ibis/expr/tests/test_format.py b/ibis/expr/tests/test_format.py
--- a/ibis/expr/tests/test_format.py
+++ b/ibis/expr/tests/test_format.py
@@ -42,6 +42,13 @@ def test_format_projection(alltypes, snapshot):
     snapshot.assert_match(result, "repr.txt")
 
 
+def test_format_table_with_empty_schema(snapshot):
+    # GH #6837
+    schema = ibis.table({}, name="t")
+    result = fmt(schema)
+    snapshot.assert_match(result, "repr.txt")
+
+
 def test_table_type_output(snapshot):
     foo = ibis.table(
         [
Repository: ibis-project/ibis

Issue:
bug: docs: BackendBase API isn't public on website
### What happened?

APIs like Backend.list_tables() aren't anywhere

### What version of ibis are you using?

main

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

NA

### Relevant log output

_No response_

### Code of Conduct

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


Discussion:
@NickCrews Thanks! I will take this one.

Resolving patch:
diff --git a/docs/backends/_utils.py b/docs/backends/_utils.py
--- a/docs/backends/_utils.py
+++ b/docs/backends/_utils.py
@@ -26,9 +26,39 @@ def get_callable(obj, name):
         return obj.functions[name]
 
 
+def find_member_with_docstring(member):
+    """Find the first inherited member with a docstring."""
+    if member.docstring is not None:
+        return member
+
+    cls = member.parent
+    for base in cls.resolved_bases:
+        try:
+            parent_member = get_callable(base, member.name)
+        except KeyError:
+            continue
+        else:
+            if parent_member.docstring is not None:
+                return parent_member
+    return member
+
+
 def render_method(*, member, renderer: MdRenderer) -> Iterator[str]:
-    yield f"{'#' * renderer.crnt_header_level} {member.name} {{ #{member.path} }}"
-    yield renderer.render(member)
+    header_level = renderer.crnt_header_level
+    header = "#" * header_level
+    name = member.name
+    try:
+        params = renderer.render(member.parameters)
+    except AttributeError:
+        params = None
+    yield "\n"
+    yield f"{header} {name} {{ #{member.path} }}"
+    yield "\n"
+    if params is not None:
+        yield f"`{name}({params})`"
+    yield "\n"
+
+    yield renderer.render(find_member_with_docstring(member))
 
 
 def render_methods(obj, *methods: str, level: int) -> None:


Test patch:
Repository: ibis-project/ibis

Issue:
feat: clickable hyperlinks in rich repr
### Is your feature request related to a problem?

I have a column of URLs. It would be awesome if they were clickable in the printed table repr from rich.

### Describe the solution you'd like

not sure how to do this.

Call [`.protocol()`](https://ibis-project.org/reference/expression-strings#ibis.expr.types.strings.StringValue.protocol) on all string columns, and if it is one of http,https,[something else?], then surround that string with the [rich [link] tags](https://rich.readthedocs.io/en/stable/markup.html#links)? Should this be done on a per-row basis, or if at least x% of rows match this condition then style all rows like this? Not sure what the performance implications of this would be, or how much we need to worry about it.

### What version of ibis are you running?

main

### What backend(s) are you using, if any?

NA

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:
I don't think we should use ibis methods for this. Not all backends implement `protocol()`, and we shouldn't tie the ability to print a table to a backend's operation support.

We can use `urllib.parse.urlparse` on the materialized results and check the `scheme` field and then add `[link]` tags based on that.

Resolving patch:
diff --git a/ibis/expr/types/pretty.py b/ibis/expr/types/pretty.py
--- a/ibis/expr/types/pretty.py
+++ b/ibis/expr/types/pretty.py
@@ -3,6 +3,7 @@
 import datetime
 from functools import singledispatch
 from math import isfinite
+from urllib.parse import urlparse
 
 import rich
 from rich.align import Align
@@ -138,6 +139,12 @@ def _(dtype, values):
                 v = "".join(
                     f"[dim]{repr(c)[1:-1]}[/]" if not c.isprintable() else c for c in v
                 )
+            elif len(v) <= max_string:
+                url = urlparse(v)
+                # check both scheme and netloc to avoid rendering e.g.,
+                # `https://` as link
+                if url.scheme and url.netloc:
+                    v = f"[link]{v}[/link]"
             text = Text.from_markup(v, style="green")
         else:
             text = Text.styled("~", "dim")


Test patch:
diff --git a/ibis/tests/expr/test_pretty_repr.py b/ibis/tests/expr/test_pretty_repr.py
--- a/ibis/tests/expr/test_pretty_repr.py
+++ b/ibis/tests/expr/test_pretty_repr.py
@@ -9,7 +9,7 @@
 
 import ibis
 import ibis.expr.datatypes as dt
-from ibis.expr.types.pretty import format_column
+from ibis.expr.types.pretty import format_column, format_values
 
 null = "NULL"
 
@@ -178,3 +178,12 @@ def test_non_interactive_column_repr():
 
     result = capture.get()
     assert "Selection" not in result
+
+
+def test_format_link():
+    result = format_values(dt.string, ["https://ibis-project.org"])
+    assert result[0].spans[0].style == "link"
+
+    # not links
+    result = format_values(dt.string, ["https://", "https:", "https"])
+    assert all(not rendered.spans for rendered in result)
Repository: ibis-project/ibis

Issue:
bug: Command drop view IF EXISTS does not exist in Oracle
### What happened?

Oracle queries fail while dropping the view.

IF EXISTS is not supported in Oracle: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/DROP-VIEW.html

### What version of ibis are you using?

7.0.0

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

Oracle

### Relevant log output

```sh
sqlalchemy.exc.DatabaseError: (oracledb.exceptions.DatabaseError) ORA-00933: SQL command not properly ended
[SQL: DROP VIEW IF EXISTS "_ibis_oracle_metadata_d4gbmh4h2fa2jnq5qo3o3rg6sa"]
```


### Code of Conduct

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


Discussion:

Resolving patch:
diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py
--- a/ibis/backends/oracle/__init__.py
+++ b/ibis/backends/oracle/__init__.py
@@ -181,7 +181,7 @@ def _metadata(self, query: str) -> Iterable[tuple[str, dt.DataType]]:
 
         view = sa.table(name)
         create_view = CreateView(view, sa.text(query))
-        drop_view = DropView(view, if_exists=True)
+        drop_view = DropView(view, if_exists=False)
 
         t = sa.table(
             "all_tab_columns",


Test patch:
Repository: ibis-project/ibis

Issue:
bug:  truncating date column by week rounds the week up  instead of down 
### What happened?

When I use truncate on a date column it rounds up (to next monday) instead of down (to last monday)

### What version of ibis are you using?

5.1.0

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

I think SQLite but I'm not 100% sure

### Relevant log output

```sh
outreach_table.outreach_date.truncate('week').execute()
Out[8]: 
0   2023-09-11
1   2023-10-09
2   2023-09-11
3   2023-09-11
Name: DateTruncate(outreach_date), dtype: datetime64[ns]
outreach_table.outreach_date.execute()
Out[9]: 
0   2023-09-05
1   2023-10-03
2   2023-09-11
3   2023-09-10
Name: outreach_date, dtype: datetime64[ns]
```


### Code of Conduct

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


Discussion:

Resolving patch:
diff --git a/ibis/backends/sqlite/registry.py b/ibis/backends/sqlite/registry.py
--- a/ibis/backends/sqlite/registry.py
+++ b/ibis/backends/sqlite/registry.py
@@ -92,14 +92,14 @@ def _extract_quarter(t, op):
 
 
 _truncate_modifiers = {
-    DateUnit.DAY: "start of day",
-    DateUnit.WEEK: "weekday 1",
-    DateUnit.MONTH: "start of month",
-    DateUnit.YEAR: "start of year",
-    IntervalUnit.DAY: "start of day",
-    IntervalUnit.WEEK: "weekday 1",
-    IntervalUnit.MONTH: "start of month",
-    IntervalUnit.YEAR: "start of year",
+    DateUnit.DAY: ("start of day",),
+    DateUnit.WEEK: ("weekday 0", "-6 days"),
+    DateUnit.MONTH: ("start of month",),
+    DateUnit.YEAR: ("start of year",),
+    IntervalUnit.DAY: ("start of day",),
+    IntervalUnit.WEEK: ("weekday 1",),
+    IntervalUnit.MONTH: ("start of month",),
+    IntervalUnit.YEAR: ("start of year",),
 }
 
 
@@ -112,7 +112,7 @@ def translator(t, op):
             raise com.UnsupportedOperationError(
                 f"Unsupported truncate unit {op.unit!r}"
             )
-        return func(sa_arg, modifier)
+        return func(sa_arg, *modifier)
 
     return translator
 


Test patch:
diff --git a/ibis/backends/tests/test_temporal.py b/ibis/backends/tests/test_temporal.py
--- a/ibis/backends/tests/test_temporal.py
+++ b/ibis/backends/tests/test_temporal.py
@@ -537,7 +537,7 @@ def test_timestamp_truncate(backend, alltypes, df, unit):
                     raises=com.UnsupportedOperationError,
                     reason="Unsupported truncate unit W",
                 ),
-                pytest.mark.broken(["impala", "sqlite"], raises=AssertionError),
+                pytest.mark.broken(["impala"], raises=AssertionError),
             ],
         ),
     ],
Repository: ibis-project/ibis

Issue:
bug(oracle): Failing metadata query
### What happened?

Metadata query for Oracle is failing due to filtering the nullable column between SELECT and FROM statements, which is only possible after WHERE.

### What version of ibis are you using?

7.0.0

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

Oracle

### Relevant log output

```sh
sqlalchemy.exc.DatabaseError: (oracledb.exceptions.DatabaseError) ORA-00923: FROM keyword not found where expected
[SQL: SELECT all_tab_columns.column_name, all_tab_columns.data_type, all_tab_columns.data_precision, all_tab_columns.data_scale, all_tab_columns.nullable = :nullable_1 AS nullable
FROM all_tab_columns
WHERE all_tab_columns.table_name = :table_name_1]
[parameters: {'nullable_1': 'Y', 'table_name_1': '_ibis_oracle_metadata_7djjvezdl5bnrmqkf6grsevvjq'}]
```
```


### Code of Conduct

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


Discussion:

Resolving patch:
diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py
--- a/ibis/backends/oracle/__init__.py
+++ b/ibis/backends/oracle/__init__.py
@@ -209,6 +209,7 @@ def list_tables(self, like=None, database=None, schema=None):
         return self._filter_with_like(tables + views, like)
 
     def _metadata(self, query: str) -> Iterable[tuple[str, dt.DataType]]:
+        from sqlalchemy import case
         from sqlalchemy_views import CreateView, DropView
 
         name = util.gen_name("oracle_metadata")
@@ -242,7 +243,7 @@ def _metadata(self, query: str) -> Iterable[tuple[str, dt.DataType]]:
             t.c.data_type,
             t.c.data_precision,
             t.c.data_scale,
-            (t.c.nullable == "Y").label("nullable"),
+            case((t.c.nullable == "Y", True), else_=False).label("nullable"),
         ).where(t.c.table_name == name)
 
         with self.begin() as con:


Test patch:
Repository: ibis-project/ibis

Issue:
feat(oracle): Change NUMBER data type parsing
### Is your feature request related to a problem?

I would like to have a clear distinction how different NUMBER data types from Oracle are handled.

### Describe the solution you'd like

For now, NUMBERs without scale and precision are parsed into Decimals, whereas they are not real Decimals.

### What version of ibis are you running?

7.0.0

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

Oracle

### Code of Conduct

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


Discussion:

Resolving patch:
diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py
--- a/ibis/backends/oracle/__init__.py
+++ b/ibis/backends/oracle/__init__.py
@@ -254,11 +254,34 @@ def _metadata(self, query: str) -> Iterable[tuple[str, dt.DataType]]:
                 con.execute(drop_view)
 
         for name, type_string, precision, scale, nullable in results:
-            if precision is not None and scale is not None and precision != 0:
+            # NUMBER(null, null) --> FLOAT
+            # (null, null) --> from_string()
+            if type_string == "NUMBER" and precision is None and scale is None:
+                typ = dt.Float64(nullable=nullable)
+
+            # (null, 0) --> INT
+            # (null, 3), (null, 6), (null, 9) --> from_string() - TIMESTAMP(3)/(6)/(9)
+            elif precision is None and (scale is not None and scale == 0):
+                typ = dt.Int64(nullable=nullable)
+
+            # NUMBER(*, 0) --> INT
+            # (*, 0) --> from_string() - INTERVAL DAY(3) TO SECOND(0)
+            elif (
+                type_string == "NUMBER"
+                and precision is not None
+                and (scale is not None and scale == 0)
+            ):
+                typ = dt.Int64(nullable=nullable)
+
+            # NUMBER(*, > 0) --> DECIMAL
+            # (*, > 0) --> from_string() - INTERVAL DAY(3) TO SECOND(2)
+            elif (
+                type_string == "NUMBER"
+                and precision is not None
+                and (scale is not None and scale > 0)
+            ):
                 typ = dt.Decimal(precision=precision, scale=scale, nullable=nullable)
-            elif precision == 0:
-                # TODO: how to disambiguate between int and float here without inspecting the value?
-                typ = dt.float
+
             else:
                 typ = OracleType.from_string(type_string, nullable=nullable)
             yield name, typ


Test patch:
Repository: ibis-project/ibis

Issue:
bug(oracle): truly bizarre CI failure with incorrect columns
### What happened?

https://github.com/ibis-project/ibis/actions/runs/7168330883/job/19516290928

This is reproducible but only under a very specific set of conditions:

1. You must run with `pytest -m oracle --randomly-seed=1601193982` (this suggests some kind of test order dependency, possibly created by some underlying state in the backend that isn't cleaned up)
2. The container must be freshly launched. If you run the test two times in a row the first run will fail and the second run will pass.

Looking at the PDB output below the proximate cause is that the column names are out of order.

### What version of ibis are you using?

64d29575f

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

Oracle

### Relevant log output

```sh
(Pdb) df
                nbr_missions name
0    Chang-Diaz, Franklin R.  7.0
1             Ross, Jerry L.  7.0
2          Malenchenko, Yuri  6.0
3          Foale, C. Michael  6.0
4      Brown, Curtis L., Jr.  6.0
..                       ...  ...
559      Dobrovolski, Georgi  1.0
560     Schmitt, Harrison H.  1.0
561        Pogue, William R.  1.0
562            Jahn, Sigmund  1.0
563              Atkov, Oleg  1.0

[564 rows x 2 columns]
```


### Code of Conduct

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


Discussion:

Resolving patch:
diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py
--- a/ibis/backends/oracle/__init__.py
+++ b/ibis/backends/oracle/__init__.py
@@ -237,14 +237,19 @@ def _metadata(self, query: str) -> Iterable[tuple[str, dt.DataType]]:
             sa.column("data_precision"),
             sa.column("data_scale"),
             sa.column("nullable"),
+            sa.column("column_id"),
+        )
+        metadata_query = (
+            sa.select(
+                t.c.column_name,
+                t.c.data_type,
+                t.c.data_precision,
+                t.c.data_scale,
+                case((t.c.nullable == "Y", True), else_=False).label("nullable"),
+            )
+            .where(t.c.table_name == name)
+            .order_by(t.c.column_id)
         )
-        metadata_query = sa.select(
-            t.c.column_name,
-            t.c.data_type,
-            t.c.data_precision,
-            t.c.data_scale,
-            case((t.c.nullable == "Y", True), else_=False).label("nullable"),
-        ).where(t.c.table_name == name)
 
         with self.begin() as con:
             con.execute(create_view)


Test patch:
Repository: ibis-project/ibis

Issue:
feat(geospatial): modify read_geo to read from url (broken on upcoming spatial nightly extension)
At the moment `read_geo` works with a url like `https://.....` but duckdb on the nightly spatial now uses their own filesystem instead of GDAL's so we need to have the `httpfs` extension installed if we want to do a remote query (see https://github.com/duckdb/duckdb_spatial/issues/210#issuecomment-1850927552)

I think to support this we need to add something like:
```python
if source.startswith(("http://", "https://", "s3://")):
    self.load_extensions("httpfs")
```

right after loading the spatial extension in  https://github.com/ibis-project/ibis/blob/2365e10240ec067ea5b04a9517833e56014f7819/ibis/backends/duckdb/__init__.py#L528-L532

In the conftest we have this https://github.com/ibis-project/ibis/blob/2365e10240ec067ea5b04a9517833e56014f7819/ibis/backends/duckdb/tests/conftest.py#L43-L47

I think this is loading the `https` extension so this tests won't fail,
https://github.com/ibis-project/ibis/blob/2365e10240ec067ea5b04a9517833e56014f7819/ibis/backends/duckdb/tests/test_register.py#L95-L108

But when the spatial extension gets updated (following the nightly behavior), we should load `https` when they try to do `read_geo` if reading from url.


Discussion:

Resolving patch:
diff --git a/ibis/backends/duckdb/__init__.py b/ibis/backends/duckdb/__init__.py
--- a/ibis/backends/duckdb/__init__.py
+++ b/ibis/backends/duckdb/__init__.py
@@ -528,8 +528,13 @@ def read_geo(
         # load geospatial extension
         self.load_extension("spatial")
 
+        source = util.normalize_filename(source)
+
+        if source.startswith(("http://", "https://", "s3://")):
+            self._load_extensions(["httpfs"])
+
         source_expr = sa.select(sa.literal_column("*")).select_from(
-            sa.func.st_read(util.normalize_filename(source), _format_kwargs(kwargs))
+            sa.func.st_read(source, _format_kwargs(kwargs))
         )
 
         view = self._compile_temp_view(table_name, source_expr)


Test patch:
diff --git a/ibis/backends/duckdb/tests/test_register.py b/ibis/backends/duckdb/tests/test_register.py
--- a/ibis/backends/duckdb/tests/test_register.py
+++ b/ibis/backends/duckdb/tests/test_register.py
@@ -108,6 +108,20 @@ def test_read_geo_to_geopandas(con, data_dir):
     assert isinstance(gdf, gpd.GeoDataFrame)
 
 
+def test_read_geo_from_url(con, monkeypatch):
+    loaded_exts = []
+    monkeypatch.setattr(con, "_load_extensions", lambda x, **kw: loaded_exts.extend(x))
+
+    with pytest.raises((sa.exc.OperationalError, sa.exc.ProgrammingError)):
+        # The read will fail, either because the URL is bogus (which it is) or
+        # because the current connection doesn't have the spatial extension
+        # installed and so the call to `st_read` will raise a catalog error.
+        con.read_geo("https://...")
+
+    assert "spatial" in loaded_exts
+    assert "httpfs" in loaded_exts
+
+
 @pytest.mark.xfail_version(
     duckdb=["duckdb<0.7.0"], reason="read_json_auto doesn't exist", raises=exc.IbisError
 )
Repository: ibis-project/ibis

Issue:
bug: expressions with deferreds are `True` rather than raising
### What happened?

`max(_.value, 0)` returns always 0, since `bool(0 < _.value)` returns `True`.

Instead both should make clear they are not implemented, ie. `__bool__` of `ibis.common.deferred.Deferred` should raise if it represents an expression.

Probably it should raise `ValueError: The truth value of an Ibis expression is not defined` to be consistent with `bool(df.value > 0)`.
 



### What version of ibis are you using?

7.1.0

### What backend(s) are you using, if any?

DuckDB, but not relevant

### Relevant log output

_No response_

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:

Resolving patch:
diff --git a/ibis/common/deferred.py b/ibis/common/deferred.py
--- a/ibis/common/deferred.py
+++ b/ibis/common/deferred.py
@@ -97,6 +97,11 @@ def __getattr__(self, name):
     def __iter__(self):
         raise TypeError(f"{self.__class__.__name__!r} object is not iterable")
 
+    def __bool__(self):
+        raise TypeError(
+            f"The truth value of {self.__class__.__name__} objects is not defined"
+        )
+
     def __getitem__(self, name):
         return Deferred(Item(self, name))
 


Test patch:
diff --git a/ibis/common/tests/test_deferred.py b/ibis/common/tests/test_deferred.py
--- a/ibis/common/tests/test_deferred.py
+++ b/ibis/common/tests/test_deferred.py
@@ -501,6 +501,14 @@ def test_deferred_is_not_iterable(obj):
         next(obj)
 
 
+@pytest.mark.parametrize("obj", [_, _.a, _.a.b[0]])
+def test_deferred_is_not_truthy(obj):
+    with pytest.raises(
+        TypeError, match="The truth value of Deferred objects is not defined"
+    ):
+        bool(obj)
+
+
 def test_deferrable(table):
     @deferrable
     def f(a, b, c=3):