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

Issue:
bug(testing): importorskip swallows valid import errors
Intentionally making an import error:

```diff
diff --git a/ibis/backends/base/sql/compiler/select_builder.py b/ibis/backends/base/sql/compiler/select_builder.py
index 86bfedc6..b5a6e970 100644
--- a/ibis/backends/base/sql/compiler/select_builder.py
+++ b/ibis/backends/base/sql/compiler/select_builder.py
@@ -5,7 +5,7 @@ import ibis.expr.analysis as L
 import ibis.expr.datatypes as dt
 import ibis.expr.operations as ops
 import ibis.expr.types as ir
-import ibis.util as util
+import ibis.common.util as util

 from .extract_subqueries import ExtractSubqueries
```

Causes to skip the builds instead of raising an `ImportError`

```
$ pytest -sv -m sqlite ibis/backends/tests/test_numeric.py
ibis/backends/tests/test_numeric.py::test_floating_mod[sqlite] SKIPPED (could not import 'ibis.backends.sqlite.tests.conftest': No module named 'ibis.common.util')
ibis/backends/tests/test_numeric.py::test_math_functions_literals[sqlite-round-digits] SKIPPED (could not import 'ibis.backends.sqlite.tests.conftest': No module named 'ibis.common.util')
ibis/backends/tests/test_numeric.py::test_complex_math_functions_columns[sqlite-log2] SKIPPED (could not import 'ibis.backends.sqlite.tests.conftest': No module named 'ibis.common.util')
...
```

I assume this is caused by `pytest.importorskip` in `_get_backend_conf()`.

cc @cpcloud 


Discussion:
Yep, definitely a problem.
Wait, I didn't realize that this isn't actually happening right now.

Thoughts on how to go about making sure this doesn't happen in the future?
Ideally we can leave the bug prefix and label for things that are active problems.
> Wait, I didn't realize that this isn't actually happening right now.

We may have import errors not surfacing on the CI.

> Thoughts on how to go about making sure this doesn't happen in the future?

Making it mandatory to import `backend.TestConf`?


> > Wait, I didn't realize that this isn't actually happening right now.
> 
> We may have import errors not surfacing on the CI.

Ah, yeah you're right.

> 
> > Thoughts on how to go about making sure this doesn't happen in the future?
> 
> Making it mandatory to import `backend.TestConf`?

Yep, I'll look into it.

Resolving patch:
diff --git a/ibis/backends/conftest.py b/ibis/backends/conftest.py
--- a/ibis/backends/conftest.py
+++ b/ibis/backends/conftest.py
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import importlib
 import os
 from functools import lru_cache
 from pathlib import Path
@@ -63,7 +64,7 @@ def _get_backend_names() -> frozenset[str]:
 
 def _get_backend_conf(backend_str: str):
     """Convert a backend string to the test class for the backend."""
-    conftest = pytest.importorskip(
+    conftest = importlib.import_module(
         f"ibis.backends.{backend_str}.tests.conftest"
     )
     return conftest.TestConf


Test patch:
Repository: ibis-project/ibis

Issue:
feat: expose APIs for constructing SortExprs using asc/desc functions and methods
This will enable sort expr specifications without having to pass an `ascending` argument or have a function like `to_sort_expr` which makes assumptions about the meaning of its second argument.

Moreover, it becomes a lot less cumbersome to specify multiple sort exprs in a function like `array_agg` that, in some backends supports an `ORDER BY` clause.


Discussion:
I think we just need an `asc` function/method to round out `desc`.

Resolving patch:
diff --git a/ibis/expr/api.py b/ibis/expr/api.py
--- a/ibis/expr/api.py
+++ b/ibis/expr/api.py
@@ -118,6 +118,7 @@
     'cumulative_window',
     'date',
     'desc',
+    'asc',
     'Expr',
     'geo_area',
     'geo_as_binary',
@@ -347,6 +348,31 @@ def desc(expr: ir.ColumnExpr | str) -> ir.SortExpr | ops.DeferredSortKey:
         return ops.SortKey(expr, ascending=False).to_expr()
 
 
+def asc(expr: ir.ColumnExpr | str) -> ir.SortExpr | ops.DeferredSortKey:
+    """Create a ascending sort key from `asc` or column name.
+
+    Parameters
+    ----------
+    expr
+        The expression or column name to use for sorting
+
+    Examples
+    --------
+    >>> import ibis
+    >>> t = ibis.table([('g', 'string')])
+    >>> result = t.group_by('g').size('count').sort_by(ibis.asc('count'))
+
+    Returns
+    -------
+    ops.DeferredSortKey
+        A deferred sort key
+    """
+    if not isinstance(expr, Expr):
+        return ops.DeferredSortKey(expr)
+    else:
+        return ops.SortKey(expr).to_expr()
+
+
 def timestamp(
     value: str | numbers.Integral,
     timezone: str | None = None,


Test patch:
diff --git a/ibis/tests/expr/test_table.py b/ibis/tests/expr/test_table.py
--- a/ibis/tests/expr/test_table.py
+++ b/ibis/tests/expr/test_table.py
@@ -386,6 +386,17 @@ def test_sort_by_desc_deferred_sort_key(table):
     assert_equal(result, expected2)
 
 
+def test_sort_by_asc_deferred_sort_key(table):
+    result = table.group_by('g').size().sort_by(ibis.asc('count'))
+
+    tmp = table.group_by('g').size()
+    expected = tmp.sort_by(tmp['count'])
+    expected2 = tmp.sort_by(ibis.asc(tmp['count']))
+
+    assert_equal(result, expected)
+    assert_equal(result, expected2)
+
+
 def test_slice_convenience(table):
     expr = table[:5]
     expr2 = table[:5:1]
@@ -1219,6 +1230,10 @@ def test_sort_by2(table):
     expected = m.sort_by(ibis.desc('foo'))
     assert_equal(result, expected)
 
+    result = m.sort_by(ibis.asc(lambda x: x.foo))
+    expected = m.sort_by('foo')
+    assert_equal(result, expected)
+
 
 def test_projection2(table):
     m = table.mutate(foo=table.f * 2)
Repository: ibis-project/ibis

Issue:
SettingWithCopyWarning on table select using pandas backend
```
import ibis
import pandas as pd

ibis.options.interactive = True

conn = ibis.pandas.connect({'foo': pd.read_csv('foo.csv', dtype=str)})

foo_table = conn.table('foo')

foo_table.select('col')
```

Yields a SettingWithCopyWarning warning:

```
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  result[new_col] = result.loc[:, from_col]
/home/patrick/dev/repos/ibis/ibis/backends/pandas/execution/selection.py:336: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  result[new_col] = result.loc[:, from_col]
```

This warning is also blasted when selecting one column in a list:

```
foo_table.select(['col'])
```

This warning, however, is not blasted when selecting by multiple columns in a list:

```
foo_table.select(['col', 'col1'])
```


Discussion:
Thanks for reporting @p-a-a-a-trick !  Fix incoming

Resolving patch:
diff --git a/ibis/backends/pandas/execution/selection.py b/ibis/backends/pandas/execution/selection.py
--- a/ibis/backends/pandas/execution/selection.py
+++ b/ibis/backends/pandas/execution/selection.py
@@ -333,7 +333,8 @@ def build_df_from_selection(
             renamed_cols[from_col] = to_cols[0]
         else:
             for new_col in to_cols:
-                result[new_col] = result.loc[:, from_col]
+                if from_col != new_col:
+                    result[new_col] = result[from_col]
 
     if renamed_cols:
         result = result.rename(columns=renamed_cols)


Test patch:
Repository: ibis-project/ibis

Issue:
bug: repr for interval literals doesn't show unit information
`interval` literal values don't show any information about their units, so all values show up looking the same:

```
In [4]: import ibis

In [5]: ibis.interval(1, unit="s")
Out[5]: 1

In [6]: ibis.interval(1, unit="h")
Out[6]: 1
```


Discussion:

Resolving patch:
diff --git a/ibis/expr/format.py b/ibis/expr/format.py
--- a/ibis/expr/format.py
+++ b/ibis/expr/format.py
@@ -534,6 +534,8 @@ def _fmt_value_negate(op: ops.Negate, *, aliases: Aliases) -> str:
 
 @fmt_value.register
 def _fmt_value_literal(op: ops.Literal, **_: Any) -> str:
+    if isinstance(op.dtype, dt.Interval):
+        return f"{op.value} {op.dtype.unit}"
     return repr(op.value)
 
 


Test patch:
Repository: ibis-project/ibis

Issue:
bug: loss of decimal precision in aggregate in 3.x
With ibis 2.1.1:

```
In [1]: import ibis.expr.datatypes as dt

In [2]: import ibis

In [3]: t = ibis.table(
   ...:     [
   ...:         ("l_quantity", dt.Decimal(15, 2)),
   ...:     ],
   ...:     name="t",
   ...: )

In [4]: lquantsum = t.aggregate(sum_qty=lambda t: t.l_quantity.sum())

In [5]: lquantsum._get_type("sum_qty")
Out[5]: Decimal(precision=38, scale=2, nullable=True)
```

On 3.x.x
```
In [1]: import ibis.expr.datatypes as dt

In [2]: import ibis

In [3]: t = ibis.table(
   ...:     [
   ...:         ("l_quantity", dt.Decimal(15, 2)),
   ...:     ],
   ...:     name="t",
   ...: )

In [4]: lquantsum = t.aggregate(sum_qty=lambda t: t.l_quantity.sum())

In [5]: lquantsum._get_type("sum_qty")
Out[5]: Decimal(precision=None, scale=None, nullable=True)
```

This is causing some understandable issues when serializing to substrait


Discussion:
Darn.

This is a fun area to work in because of the maximum decimal precision being a backend-dependent type.

We can probably bring back the max precision of `38` without breaking support for arbitrary precision decimal types.
I think I've got a semi-reasonable solution -- defaulting to `None` for `precision` and `scale` on the call to `largest` if `scale` and `precision` are `None`, but if they've been set to a non-`None` value, default to `38` and `2`.  Probably missing some edge cases

Resolving patch:
diff --git a/ibis/expr/datatypes/core.py b/ibis/expr/datatypes/core.py
--- a/ibis/expr/datatypes/core.py
+++ b/ibis/expr/datatypes/core.py
@@ -440,7 +440,10 @@ def __init__(
     @property
     def largest(self):
         """Return the largest type of decimal."""
-        return self.__class__(precision=None, scale=None)
+        return self.__class__(
+            precision=38 if self.precision is not None else None,
+            scale=2 if self.scale is not None else None,
+        )
 
     @property
     def _pretty_piece(self) -> str:


Test patch:
diff --git a/ibis/tests/expr/test_decimal.py b/ibis/tests/expr/test_decimal.py
--- a/ibis/tests/expr/test_decimal.py
+++ b/ibis/tests/expr/test_decimal.py
@@ -2,6 +2,7 @@
 
 import pytest
 
+import ibis
 import ibis.expr.api as api
 import ibis.expr.datatypes as dt
 import ibis.expr.operations as ops
@@ -27,6 +28,14 @@ def test_decimal_sum_type(lineitem):
     col = lineitem.l_extendedprice
     result = col.sum()
     assert isinstance(result, ir.DecimalScalar)
+    assert result.type() == dt.Decimal(38, 2)
+
+
+def test_decimal_sum_type_unbounded_precision():
+    t = ibis.table([("l_extendedprice", dt.Decimal(None, None))], name="t")
+    col = t.l_extendedprice
+    result = col.sum()
+    assert isinstance(result, ir.DecimalScalar)
     assert result.type() == dt.decimal
Repository: ibis-project/ibis

Issue:
feat(sqlalchemy): allow non-primitive arrays
SQLAlchemy type inference fails on arrays where the value type is not a primitive or string prevent use cases like `array<array<int>>` from working.


Discussion:

Resolving patch:
diff --git a/ibis/backends/base/sql/alchemy/datatypes.py b/ibis/backends/base/sql/alchemy/datatypes.py
--- a/ibis/backends/base/sql/alchemy/datatypes.py
+++ b/ibis/backends/base/sql/alchemy/datatypes.py
@@ -96,8 +96,6 @@ def _(itype, **kwargs):
 @to_sqla_type.register(dt.Array)
 def _(itype, **kwargs):
     ibis_type = itype.value_type
-    if not isinstance(ibis_type, (dt.Primitive, dt.String)):
-        raise TypeError(f'Type {ibis_type} is not a primitive or string type')
     return sa.ARRAY(to_sqla_type(ibis_type, **kwargs))
 
 


Test patch:
diff --git a/ibis/tests/sql/test_sqlalchemy.py b/ibis/tests/sql/test_sqlalchemy.py
--- a/ibis/tests/sql/test_sqlalchemy.py
+++ b/ibis/tests/sql/test_sqlalchemy.py
@@ -25,6 +25,7 @@
     AlchemyCompiler,
     AlchemyContext,
     schema_from_table,
+    to_sqla_type,
 )
 from ibis.tests.expr.mocks import MockAlchemyBackend
 from ibis.tests.util import assert_equal
@@ -1131,3 +1132,13 @@ def test_tpc_h11(h11):
 
     ex = sa.select(t0.c.ps_partkey, t0.c.value).order_by(t0.c.value.desc())
     _check(h11, ex)
+
+
+def test_to_sqla_type_array_of_non_primitive():
+    result = to_sqla_type(dt.Array(dt.Struct.from_dict(dict(a="int"))))
+    [(result_name, result_type)] = result.item_type.pairs
+    expected_name = "a"
+    expected_type = sa.BigInteger()
+    assert result_name == expected_name
+    assert type(result_type) == type(expected_type)
+    assert isinstance(result, sa.ARRAY)
Repository: ibis-project/ibis

Issue:
bug: ibis datatype parser doesn't parse "null" string
I noticed that the following no longer parses correctly:

```
schema = [('a', 'null'), ('b', 'null')]
ibis.schema(schema)
```
Because we're missing a null definition here: https://github.com/ibis-project/ibis/blob/master/ibis/expr/datatypes/core.py#L1060. 

Is that intentional?


Discussion:
This looks like a regression. Fix incoming.
@gerrymanoim Can you comment on your use case here a bit? Would love to know how `null` is useful to y'all.
Found it while bumping ibis internally and running through broken tests. Let me come back with what the underlying use case for these types is. 
Sounds good. Just curious whether there's a use case we haven't thought of!
@gerrymanoim Any updates here?

Resolving patch:
diff --git a/ibis/expr/datatypes/core.py b/ibis/expr/datatypes/core.py
--- a/ibis/expr/datatypes/core.py
+++ b/ibis/expr/datatypes/core.py
@@ -1084,6 +1084,7 @@ def parser():
         | spaceless_string("category").result(category)
         | spaceless_string("geometry").result(GeoSpatial(geotype='geometry'))
         | spaceless_string("geography").result(GeoSpatial(geotype='geography'))
+        | spaceless_string("null").result(null)
         | geotype_parser("linestring", LineString)
         | geotype_parser("polygon", Polygon)
         | geotype_parser("point", Point)


Test patch:
diff --git a/ibis/tests/expr/test_datatypes.py b/ibis/tests/expr/test_datatypes.py
--- a/ibis/tests/expr/test_datatypes.py
+++ b/ibis/tests/expr/test_datatypes.py
@@ -507,3 +507,7 @@ class MyStruct(dt.Struct):
 def test_parse_type_warns():
     with pytest.warns(FutureWarning):
         dt.parse_type("int64")
+
+
+def test_parse_null():
+    assert dt.parse("null") == dt.null
Repository: ibis-project/ibis

Issue:
feat: add `__getattr__` to `StructValue`
`StructValue` expressions allow access to fields using `__getitem__`, we should add dot attribute access with `__getattr__`.


Discussion:

Resolving patch:
diff --git a/ibis/expr/types/structs.py b/ibis/expr/types/structs.py
--- a/ibis/expr/types/structs.py
+++ b/ibis/expr/types/structs.py
@@ -80,6 +80,15 @@ def __getitem__(self, name: str) -> ir.Value:
 
         return ops.StructField(self, name).to_expr().name(name)
 
+    def __setstate__(self, instance_dictionary):
+        self.__dict__ = instance_dictionary
+
+    def __getattr__(self, name: str) -> ir.Value:
+        """Extract the `name` field from this struct."""
+        if name in self.names:
+            return self.__getitem__(name)
+        raise AttributeError(name)
+
     @cached_property
     def names(self) -> Sequence[str]:
         """Return the field names of the struct."""


Test patch:
diff --git a/ibis/tests/expr/test_struct.py b/ibis/tests/expr/test_struct.py
--- a/ibis/tests/expr/test_struct.py
+++ b/ibis/tests/expr/test_struct.py
@@ -1,5 +1,7 @@
 from collections import OrderedDict
 
+import pytest
+
 import ibis
 import ibis.expr.operations as ops
 import ibis.expr.types as ir
@@ -20,6 +22,14 @@ def test_struct_operations():
     assert isinstance(expr['a'].op(), ops.StructField)
 
 
+def test_struct_getattr():
+    expr = ibis.struct({"a": 1, "b": 2})
+    assert isinstance(expr.a, ir.IntegerValue)
+    assert expr.a.get_name() == "a"
+    with pytest.raises(AttributeError, match="bad"):
+        expr.bad
+
+
 def test_struct_field_dir():
     t = ibis.table([('struct_col', 'struct<my_field: string>')])
     assert 'struct_col' in dir(t)
Repository: ibis-project/ibis

Issue:
bug(impala) A delimited table should be explicitly stored as textfile
https://github.com/ibis-project/ibis/blob/88ffe3367cb6a34936e578f6a9b68dc30d559507/ibis/backends/impala/ddl.py#L67
when the cluster's default format is set as parquet, this will cause an exception. It should be explicitly stored as textfile. such as

```python
        if self.lineterminator is not None:
            yield f"LINES TERMINATED BY '{self.lineterminator}'"

        yield 'STORED AS TEXTFILE'
        yield f"LOCATION '{self.path}'"
```


Discussion:
@yi-you Thanks for the issue. Would you mind submitting a pull request for this? Looks like you've already done most of the work!

Resolving patch:
diff --git a/ibis/backends/impala/ddl.py b/ibis/backends/impala/ddl.py
--- a/ibis/backends/impala/ddl.py
+++ b/ibis/backends/impala/ddl.py
@@ -91,6 +91,7 @@ def to_ddl(self):
         if self.lineterminator is not None:
             yield f"LINES TERMINATED BY '{self.lineterminator}'"
 
+        yield 'STORED AS TEXTFILE'
         yield f"LOCATION '{self.path}'"
 
         if self.na_rep is not None:


Test patch:
diff --git a/ibis/backends/impala/tests/test_ddl_compilation.py b/ibis/backends/impala/tests/test_ddl_compilation.py
--- a/ibis/backends/impala/tests/test_ddl_compilation.py
+++ b/ibis/backends/impala/tests/test_ddl_compilation.py
@@ -407,6 +407,7 @@ def test_create_table_delimited():
 FIELDS TERMINATED BY '|'
 ESCAPED BY '\\'
 LINES TERMINATED BY '\0'
+STORED AS TEXTFILE
 LOCATION '{}'""".format(
         path
     )
Repository: ibis-project/ibis

Issue:
bug(pandas): pandas backend does not support aggregation with list-based where condition
Pandas backend throws a `NotImplementedError` when evaluating an ibis expression that contains a `groupby()` with an `aggregate()` that depends on a list-based `where` condition using `isin()`.

MWE

```
import ibis
import pandas as pd

test_df = pd.DataFrame({
    'id': ['1', '1', '2', '3', '4', '4'],
    'value': ['a', 'a', 'b', 'c', 'd', 'a']
})

conn = ibis.pandas.connect({'sample_df': test_df})
table = conn.table('sample_df')

expr1 = table.groupby("id").aggregate([
    table.id.count(table.value == "a")
])

expr2 = table.groupby("id").aggregate([
    table.id.count(table.value.isin(["a", "b"]))
])

#this works
print(expr1.execute())

#this fails
print(expr2.execute())
```

The specific error yielded is `NotImplementedError: Could not find signature for execute_node: <Contains, SeriesGroupBy, list>`


Discussion:
@brendanbikes Thanks for the MWE!

Looks like this functionality just isn't implemented.

Resolving patch:
diff --git a/ibis/backends/pandas/execution/generic.py b/ibis/backends/pandas/execution/generic.py
--- a/ibis/backends/pandas/execution/generic.py
+++ b/ibis/backends/pandas/execution/generic.py
@@ -982,6 +982,17 @@ def execute_node_contains_series_sequence(op, data, elements, **kwargs):
     return data.isin(elements)
 
 
+@execute_node.register(
+    ops.Contains,
+    SeriesGroupBy,
+    (collections.abc.Sequence, collections.abc.Set, pd.Series),
+)
+def execute_node_contains_series_group_by_sequence(
+    op, data, elements, **kwargs
+):
+    return data.obj.isin(elements).groupby(data.grouper.groupings)
+
+
 @execute_node.register(
     ops.NotContains,
     pd.Series,
diff --git a/ibis/backends/pandas/execution/strings.py b/ibis/backends/pandas/execution/strings.py
--- a/ibis/backends/pandas/execution/strings.py
+++ b/ibis/backends/pandas/execution/strings.py
@@ -237,6 +237,8 @@ def execute_group_concat_series_gb_mask(
     op, data, sep, mask, aggcontext=None, **kwargs
 ):
     def method(series, sep=sep):
+        if series.empty:
+            return pd.NA
         return sep.join(series.values.astype(str))
 
     return aggcontext.agg(


Test patch:
diff --git a/ibis/backends/tests/test_aggregation.py b/ibis/backends/tests/test_aggregation.py
--- a/ibis/backends/tests/test_aggregation.py
+++ b/ibis/backends/tests/test_aggregation.py
@@ -506,7 +506,7 @@ def test_approx_median(alltypes):
         param(
             lambda t: t.string_col.isin(['1', '7']),
             lambda t: t.string_col.isin(['1', '7']),
-            marks=mark.notimpl(["dask", "pandas"]),
+            marks=mark.notimpl(["dask"]),
             id='is_in',
         ),
     ],
Repository: ibis-project/ibis

Issue:
feat(ux): use `sqlglot` for pretty printing SQL
[`sqlglot`](https://github.com/tobymao/sqlglot) does a better job than [`sqlparse`](https://github.com/andialbrecht/sqlparse) of pretty printing SQL in my opinion:

Given this SQL string:

```
SELECT r_name,
       count(?) AS count
FROM customer AS t0
JOIN nation AS t1 ON t0.c_nationkey = t1.n_nationkey
JOIN (
      VALUES (?,
              ?), (?,
                   ?), (?,
                        ?), (?,
                             ?), (?,
                                  ?)) AS t2 (r_regionkey, r_name) ON t1.n_regionkey = t2.r_regionkey
GROUP BY r_name
```

sqlglot:

```
SELECT
  r_name,
  COUNT(?) AS count
FROM customer AS t0
JOIN nation AS t1
  ON t0.c_nationkey = t1.n_nationkey
JOIN (
  VALUES
    (?, ?),
    (?, ?),
    (?, ?),
    (?, ?),
    (?, ?)
) AS t2(r_regionkey, r_name)
  ON t1.n_regionkey = t2.r_regionkey
GROUP BY
  r_name
```

sqlparse:

```
SELECT r_name,
       count(?) AS count
FROM customer AS t0
JOIN nation AS t1 ON t0.c_nationkey = t1.n_nationkey
JOIN (
      VALUES (?,
              ?), (?,
                   ?), (?,
                        ?), (?,
                             ?), (?,
                                  ?)) AS t2 (r_regionkey, r_name) ON t1.n_regionkey = t2.r_regionkey
GROUP BY r_name
```

Let's use `sqlglot` instead.


Discussion:
The main place this is used is in `ibis.util.psql`.

Resolving patch:
diff --git a/ibis/util.py b/ibis/util.py
--- a/ibis/util.py
+++ b/ibis/util.py
@@ -530,15 +530,15 @@ def psql(
     expr
         Expression whose SQL will be printed
     reindent
-        Tell `sqlparse` to reindent the SQL string
+        Tell `sqlglot` to reindent the SQL string
     file
         File to write output to
     kwargs
-        `sqlparse.format` options
+        `sqlglot.transpile` options
     """
-    import sqlparse as sp
+    import sqlglot
 
     print(
-        sp.format(str(expr.compile()), reindent=reindent, **kwargs),
+        sqlglot.transpile(str(expr.compile()), pretty=reindent, **kwargs)[0],
         file=file,
     )


Test patch: