We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
docs: add blurb about the datafusion backend
After #2918 lands, we need to mention it in the docs.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ibis/backends/datafusion/__init__.py`
Content:
```
1 from __future__ import annotations
2 
3 import re
4 from typing import Mapping
5 
6 import datafusion as df
7 import pyarrow as pa
8 
9 import ibis.common.exceptions as com
10 import ibis.expr.schema as sch
11 import ibis.expr.types as ir
12 from ibis.backends.base import BaseBackend
13 
14 from .compiler import translate
15 
16 
17 def _to_pyarrow_table(frame):
18     batches = frame.collect()
19     if batches:
20         return pa.Table.from_batches(batches)
21     else:
22         # TODO(kszucs): file a bug to datafusion because the fields'
23         # nullability from frame.schema() is not always consistent
24         # with the first record batch's schema
25         return pa.Table.from_batches(batches, schema=frame.schema())
26 
27 
28 class Backend(BaseBackend):
29     name = 'datafusion'
30     builder = None
31 
32     @property
33     def version(self):
34         try:
35             import importlib.metadata as importlib_metadata
36         except ImportError:
37             # TODO: remove this when Python 3.7 support is dropped
38             import importlib_metadata
39         return importlib_metadata.version("datafusion")
40 
41     def do_connect(self, config):
42         """
43         Create a DataFusionClient for use with Ibis
44 
45         Parameters
46         ----------
47         config : DataFusionContext or dict
48 
49         Returns
50         -------
51         DataFusionClient
52         """
53         if isinstance(config, df.ExecutionContext):
54             self._context = config
55         else:
56             self._context = df.ExecutionContext()
57 
58         for name, path in config.items():
59             strpath = str(path)
60             if strpath.endswith('.csv'):
61                 self.register_csv(name, path)
62             elif strpath.endswith('.parquet'):
63                 self.register_parquet(name, path)
64             else:
65                 raise ValueError(
66                     "Currently the DataFusion backend only supports CSV "
67                     "files with the extension .csv and Parquet files with "
68                     "the .parquet extension."
69                 )
70 
71     def current_database(self):
72         raise NotImplementedError()
73 
74     def list_databases(self, like: str = None) -> list[str]:
75         raise NotImplementedError()
76 
77     def list_tables(self, like: str = None, database: str = None) -> list[str]:
78         """List the available tables."""
79         tables = list(self._context.tables())
80         if like is not None:
81             pattern = re.compile(like)
82             return list(filter(lambda t: pattern.findall(t), tables))
83         return tables
84 
85     def table(self, name, schema=None):
86         catalog = self._context.catalog()
87         database = catalog.database('public')
88         table = database.table(name)
89         schema = sch.infer(table.schema)
90         return self.table_class(name, schema, self).to_expr()
91 
92     def register_csv(self, name, path, schema=None):
93         self._context.register_csv(name, path, schema=schema)
94 
95     def register_parquet(self, name, path, schema=None):
96         self._context.register_parquet(name, path, schema=schema)
97 
98     def execute(
99         self,
100         expr: ir.Expr,
101         params: Mapping[ir.Expr, object] = None,
102         limit: str = 'default',
103         **kwargs,
104     ):
105         if isinstance(expr, ir.TableExpr):
106             frame = self.compile(expr, params, **kwargs)
107             table = _to_pyarrow_table(frame)
108             return table.to_pandas()
109         elif isinstance(expr, ir.ColumnExpr):
110             # expression must be named for the projection
111             expr = expr.name('tmp').to_projection()
112             frame = self.compile(expr, params, **kwargs)
113             table = _to_pyarrow_table(frame)
114             return table['tmp'].to_pandas()
115         elif isinstance(expr, ir.ScalarExpr):
116             if expr.op().root_tables():
117                 # there are associated datafusion tables so convert the expr
118                 # to a selection which we can directly convert to a datafusion
119                 # plan
120                 expr = expr.name('tmp').to_projection()
121                 frame = self.compile(expr, params, **kwargs)
122             else:
123                 # doesn't have any tables associated so create a plan from a
124                 # dummy datafusion table
125                 compiled = self.compile(expr, params, **kwargs)
126                 frame = self._context.empty_table().select(compiled)
127             table = _to_pyarrow_table(frame)
128             return table[0][0].as_py()
129         else:
130             raise com.IbisError(
131                 f"Cannot execute expression of type: {type(expr)}"
132             )
133 
134     def compile(
135         self, expr: ir.Expr, params: Mapping[ir.Expr, object] = None, **kwargs
136     ):
137         return translate(expr)
138
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ibis/backends/datafusion/__init__.py b/ibis/backends/datafusion/__init__.py
--- a/ibis/backends/datafusion/__init__.py
+++ b/ibis/backends/datafusion/__init__.py
@@ -83,6 +83,20 @@
         return tables
 
     def table(self, name, schema=None):
+        """Get an ibis expression representing a DataFusion table.
+
+        Parameters
+        ---------
+        name
+            The name of the table to retreive
+        schema
+            An optional schema
+
+        Returns
+        -------
+        ibis.expr.types.TableExpr
+            A table expression
+        """
         catalog = self._context.catalog()
         database = catalog.database('public')
         table = database.table(name)
@@ -90,9 +104,31 @@
         return self.table_class(name, schema, self).to_expr()
 
     def register_csv(self, name, path, schema=None):
+        """Register a CSV file with with `name` located at `path`.
+
+        Parameters
+        ----------
+        name
+            The name of the table
+        path
+            The path to the CSV file
+        schema
+            An optional schema
+        """
         self._context.register_csv(name, path, schema=schema)
 
     def register_parquet(self, name, path, schema=None):
+        """Register a parquet file with with `name` located at `path`.
+
+        Parameters
+        ----------
+        name
+            The name of the table
+        path
+            The path to the parquet file
+        schema
+            An optional schema
+        """
         self._context.register_parquet(name, path, schema=schema)
 
     def execute(

{"golden_diff": "diff --git a/ibis/backends/datafusion/__init__.py b/ibis/backends/datafusion/__init__.py\n--- a/ibis/backends/datafusion/__init__.py\n+++ b/ibis/backends/datafusion/__init__.py\n@@ -83,6 +83,20 @@\n         return tables\n \n     def table(self, name, schema=None):\n+        \"\"\"Get an ibis expression representing a DataFusion table.\n+\n+        Parameters\n+        ---------\n+        name\n+            The name of the table to retreive\n+        schema\n+            An optional schema\n+\n+        Returns\n+        -------\n+        ibis.expr.types.TableExpr\n+            A table expression\n+        \"\"\"\n         catalog = self._context.catalog()\n         database = catalog.database('public')\n         table = database.table(name)\n@@ -90,9 +104,31 @@\n         return self.table_class(name, schema, self).to_expr()\n \n     def register_csv(self, name, path, schema=None):\n+        \"\"\"Register a CSV file with with `name` located at `path`.\n+\n+        Parameters\n+        ----------\n+        name\n+            The name of the table\n+        path\n+            The path to the CSV file\n+        schema\n+            An optional schema\n+        \"\"\"\n         self._context.register_csv(name, path, schema=schema)\n \n     def register_parquet(self, name, path, schema=None):\n+        \"\"\"Register a parquet file with with `name` located at `path`.\n+\n+        Parameters\n+        ----------\n+        name\n+            The name of the table\n+        path\n+            The path to the parquet file\n+        schema\n+            An optional schema\n+        \"\"\"\n         self._context.register_parquet(name, path, schema=schema)\n \n     def execute(\n", "issue": "docs: add blurb about the datafusion backend\nAfter #2918 lands, we need to mention it in the docs.\n", "before_files": [{"content": "from __future__ import annotations\n\nimport re\nfrom typing import Mapping\n\nimport datafusion as df\nimport pyarrow as pa\n\nimport ibis.common.exceptions as com\nimport ibis.expr.schema as sch\nimport ibis.expr.types as ir\nfrom ibis.backends.base import BaseBackend\n\nfrom .compiler import translate\n\n\ndef _to_pyarrow_table(frame):\n    batches = frame.collect()\n    if batches:\n        return pa.Table.from_batches(batches)\n    else:\n        # TODO(kszucs): file a bug to datafusion because the fields'\n        # nullability from frame.schema() is not always consistent\n        # with the first record batch's schema\n        return pa.Table.from_batches(batches, schema=frame.schema())\n\n\nclass Backend(BaseBackend):\n    name = 'datafusion'\n    builder = None\n\n    @property\n    def version(self):\n        try:\n            import importlib.metadata as importlib_metadata\n        except ImportError:\n            # TODO: remove this when Python 3.7 support is dropped\n            import importlib_metadata\n        return importlib_metadata.version(\"datafusion\")\n\n    def do_connect(self, config):\n        \"\"\"\n        Create a DataFusionClient for use with Ibis\n\n        Parameters\n        ----------\n        config : DataFusionContext or dict\n\n        Returns\n        -------\n        DataFusionClient\n        \"\"\"\n        if isinstance(config, df.ExecutionContext):\n            self._context = config\n        else:\n            self._context = df.ExecutionContext()\n\n        for name, path in config.items():\n            strpath = str(path)\n            if strpath.endswith('.csv'):\n                self.register_csv(name, path)\n            elif strpath.endswith('.parquet'):\n                self.register_parquet(name, path)\n            else:\n                raise ValueError(\n                    \"Currently the DataFusion backend only supports CSV \"\n                    \"files with the extension .csv and Parquet files with \"\n                    \"the .parquet extension.\"\n                )\n\n    def current_database(self):\n        raise NotImplementedError()\n\n    def list_databases(self, like: str = None) -> list[str]:\n        raise NotImplementedError()\n\n    def list_tables(self, like: str = None, database: str = None) -> list[str]:\n        \"\"\"List the available tables.\"\"\"\n        tables = list(self._context.tables())\n        if like is not None:\n            pattern = re.compile(like)\n            return list(filter(lambda t: pattern.findall(t), tables))\n        return tables\n\n    def table(self, name, schema=None):\n        catalog = self._context.catalog()\n        database = catalog.database('public')\n        table = database.table(name)\n        schema = sch.infer(table.schema)\n        return self.table_class(name, schema, self).to_expr()\n\n    def register_csv(self, name, path, schema=None):\n        self._context.register_csv(name, path, schema=schema)\n\n    def register_parquet(self, name, path, schema=None):\n        self._context.register_parquet(name, path, schema=schema)\n\n    def execute(\n        self,\n        expr: ir.Expr,\n        params: Mapping[ir.Expr, object] = None,\n        limit: str = 'default',\n        **kwargs,\n    ):\n        if isinstance(expr, ir.TableExpr):\n            frame = self.compile(expr, params, **kwargs)\n            table = _to_pyarrow_table(frame)\n            return table.to_pandas()\n        elif isinstance(expr, ir.ColumnExpr):\n            # expression must be named for the projection\n            expr = expr.name('tmp').to_projection()\n            frame = self.compile(expr, params, **kwargs)\n            table = _to_pyarrow_table(frame)\n            return table['tmp'].to_pandas()\n        elif isinstance(expr, ir.ScalarExpr):\n            if expr.op().root_tables():\n                # there are associated datafusion tables so convert the expr\n                # to a selection which we can directly convert to a datafusion\n                # plan\n                expr = expr.name('tmp').to_projection()\n                frame = self.compile(expr, params, **kwargs)\n            else:\n                # doesn't have any tables associated so create a plan from a\n                # dummy datafusion table\n                compiled = self.compile(expr, params, **kwargs)\n                frame = self._context.empty_table().select(compiled)\n            table = _to_pyarrow_table(frame)\n            return table[0][0].as_py()\n        else:\n            raise com.IbisError(\n                f\"Cannot execute expression of type: {type(expr)}\"\n            )\n\n    def compile(\n        self, expr: ir.Expr, params: Mapping[ir.Expr, object] = None, **kwargs\n    ):\n        return translate(expr)\n", "path": "ibis/backends/datafusion/__init__.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport re\nfrom typing import Mapping\n\nimport datafusion as df\nimport pyarrow as pa\n\nimport ibis.common.exceptions as com\nimport ibis.expr.schema as sch\nimport ibis.expr.types as ir\nfrom ibis.backends.base import BaseBackend\n\nfrom .compiler import translate\n\n\ndef _to_pyarrow_table(frame):\n    batches = frame.collect()\n    if batches:\n        return pa.Table.from_batches(batches)\n    else:\n        # TODO(kszucs): file a bug to datafusion because the fields'\n        # nullability from frame.schema() is not always consistent\n        # with the first record batch's schema\n        return pa.Table.from_batches(batches, schema=frame.schema())\n\n\nclass Backend(BaseBackend):\n    name = 'datafusion'\n    builder = None\n\n    @property\n    def version(self):\n        try:\n            import importlib.metadata as importlib_metadata\n        except ImportError:\n            # TODO: remove this when Python 3.7 support is dropped\n            import importlib_metadata\n        return importlib_metadata.version(\"datafusion\")\n\n    def do_connect(self, config):\n        \"\"\"\n        Create a DataFusionClient for use with Ibis\n\n        Parameters\n        ----------\n        config : DataFusionContext or dict\n\n        Returns\n        -------\n        DataFusionClient\n        \"\"\"\n        if isinstance(config, df.ExecutionContext):\n            self._context = config\n        else:\n            self._context = df.ExecutionContext()\n\n        for name, path in config.items():\n            strpath = str(path)\n            if strpath.endswith('.csv'):\n                self.register_csv(name, path)\n            elif strpath.endswith('.parquet'):\n                self.register_parquet(name, path)\n            else:\n                raise ValueError(\n                    \"Currently the DataFusion backend only supports CSV \"\n                    \"files with the extension .csv and Parquet files with \"\n                    \"the .parquet extension.\"\n                )\n\n    def current_database(self):\n        raise NotImplementedError()\n\n    def list_databases(self, like: str = None) -> list[str]:\n        raise NotImplementedError()\n\n    def list_tables(self, like: str = None, database: str = None) -> list[str]:\n        \"\"\"List the available tables.\"\"\"\n        tables = list(self._context.tables())\n        if like is not None:\n            pattern = re.compile(like)\n            return list(filter(lambda t: pattern.findall(t), tables))\n        return tables\n\n    def table(self, name, schema=None):\n        \"\"\"Get an ibis expression representing a DataFusion table.\n\n        Parameters\n        ---------\n        name\n            The name of the table to retreive\n        schema\n            An optional schema\n\n        Returns\n        -------\n        ibis.expr.types.TableExpr\n            A table expression\n        \"\"\"\n        catalog = self._context.catalog()\n        database = catalog.database('public')\n        table = database.table(name)\n        schema = sch.infer(table.schema)\n        return self.table_class(name, schema, self).to_expr()\n\n    def register_csv(self, name, path, schema=None):\n        \"\"\"Register a CSV file with with `name` located at `path`.\n\n        Parameters\n        ----------\n        name\n            The name of the table\n        path\n            The path to the CSV file\n        schema\n            An optional schema\n        \"\"\"\n        self._context.register_csv(name, path, schema=schema)\n\n    def register_parquet(self, name, path, schema=None):\n        \"\"\"Register a parquet file with with `name` located at `path`.\n\n        Parameters\n        ----------\n        name\n            The name of the table\n        path\n            The path to the parquet file\n        schema\n            An optional schema\n        \"\"\"\n        self._context.register_parquet(name, path, schema=schema)\n\n    def execute(\n        self,\n        expr: ir.Expr,\n        params: Mapping[ir.Expr, object] = None,\n        limit: str = 'default',\n        **kwargs,\n    ):\n        if isinstance(expr, ir.TableExpr):\n            frame = self.compile(expr, params, **kwargs)\n            table = _to_pyarrow_table(frame)\n            return table.to_pandas()\n        elif isinstance(expr, ir.ColumnExpr):\n            # expression must be named for the projection\n            expr = expr.name('tmp').to_projection()\n            frame = self.compile(expr, params, **kwargs)\n            table = _to_pyarrow_table(frame)\n            return table['tmp'].to_pandas()\n        elif isinstance(expr, ir.ScalarExpr):\n            if expr.op().root_tables():\n                # there are associated datafusion tables so convert the expr\n                # to a selection which we can directly convert to a datafusion\n                # plan\n                expr = expr.name('tmp').to_projection()\n                frame = self.compile(expr, params, **kwargs)\n            else:\n                # doesn't have any tables associated so create a plan from a\n                # dummy datafusion table\n                compiled = self.compile(expr, params, **kwargs)\n                frame = self._context.empty_table().select(compiled)\n            table = _to_pyarrow_table(frame)\n            return table[0][0].as_py()\n        else:\n            raise com.IbisError(\n                f\"Cannot execute expression of type: {type(expr)}\"\n            )\n\n    def compile(\n        self, expr: ir.Expr, params: Mapping[ir.Expr, object] = None, **kwargs\n    ):\n        return translate(expr)\n", "path": "ibis/backends/datafusion/__init__.py"}]}