We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
docs: infinite build when using `mkdocs serve`
It appears that when using `mkdocs serve` the docs are repeatedly rebuilt to no end.

I suspect there's a file that we're generating (maybe the operation matrix?) that is being considered new and triggering a rebuild.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gen_matrix.py`
Content:
```
1 from pathlib import Path
2 
3 import pandas as pd
4 import tomli
5 
6 import ibis
7 import ibis.expr.operations as ops
8 
9 
10 def get_backends():
11     pyproject = tomli.loads(Path("pyproject.toml").read_text())
12     backends = pyproject["tool"]["poetry"]["plugins"]["ibis.backends"]
13     del backends["spark"]
14     return [(backend, getattr(ibis, backend)) for backend in sorted(backends.keys())]
15 
16 
17 def get_leaf_classes(op):
18     for child_class in op.__subclasses__():
19         if not child_class.__subclasses__():
20             yield child_class
21         else:
22             yield from get_leaf_classes(child_class)
23 
24 
25 EXCLUDED_OPS = {
26     # Never translates into anything
27     ops.UnresolvedExistsSubquery,
28     ops.UnresolvedNotExistsSubquery,
29     ops.ScalarParameter,
30 }
31 
32 INCLUDED_OPS = {
33     # Parent class of MultiQuantile so it's ignored by `get_backends()`
34     ops.Quantile,
35 }
36 
37 
38 ICONS = {
39     True: ":material-check-decagram:{ .verified }",
40     False: ":material-cancel:{ .cancel }",
41 }
42 
43 
44 def main():
45     possible_ops = (
46         frozenset(get_leaf_classes(ops.Value)) | INCLUDED_OPS
47     ) - EXCLUDED_OPS
48 
49     support = {"operation": [f"`{op.__name__}`" for op in possible_ops]}
50     support.update(
51         (name, list(map(backend.has_operation, possible_ops)))
52         for name, backend in get_backends()
53     )
54 
55     df = pd.DataFrame(support).set_index("operation").sort_index()
56 
57     counts = df.sum().sort_values(ascending=False)
58     num_ops = len(possible_ops)
59     coverage = (
60         counts.map(lambda n: f"_{n} ({round(100 * n / num_ops)}%)_")
61         .to_frame(name="**API Coverage**")
62         .T
63     )
64 
65     ops_table = df.loc[:, counts.index].replace(ICONS)
66     table = pd.concat([coverage, ops_table])
67     dst = Path(__file__).parent.joinpath(
68         "docs",
69         "backends",
70         "support_matrix.csv",
71     )
72     table.to_csv(dst, index_label="Backends")
73 
74 
75 main()
76
```
--- 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/gen_matrix.py b/gen_matrix.py
--- a/gen_matrix.py
+++ b/gen_matrix.py
@@ -69,7 +69,15 @@
         "backends",
         "support_matrix.csv",
     )
-    table.to_csv(dst, index_label="Backends")
+
+    if dst.exists():
+        old = pd.read_csv(dst, index_col="Backends")
+        should_write = not old.equals(table)
+    else:
+        should_write = True
+
+    if should_write:
+        table.to_csv(dst, index_label="Backends")
 
 
 main()

{"golden_diff": "diff --git a/gen_matrix.py b/gen_matrix.py\n--- a/gen_matrix.py\n+++ b/gen_matrix.py\n@@ -69,7 +69,15 @@\n         \"backends\",\n         \"support_matrix.csv\",\n     )\n-    table.to_csv(dst, index_label=\"Backends\")\n+\n+    if dst.exists():\n+        old = pd.read_csv(dst, index_col=\"Backends\")\n+        should_write = not old.equals(table)\n+    else:\n+        should_write = True\n+\n+    if should_write:\n+        table.to_csv(dst, index_label=\"Backends\")\n \n \n main()\n", "issue": "docs: infinite build when using `mkdocs serve`\nIt appears that when using `mkdocs serve` the docs are repeatedly rebuilt to no end.\r\n\r\nI suspect there's a file that we're generating (maybe the operation matrix?) that is being considered new and triggering a rebuild.\n", "before_files": [{"content": "from pathlib import Path\n\nimport pandas as pd\nimport tomli\n\nimport ibis\nimport ibis.expr.operations as ops\n\n\ndef get_backends():\n    pyproject = tomli.loads(Path(\"pyproject.toml\").read_text())\n    backends = pyproject[\"tool\"][\"poetry\"][\"plugins\"][\"ibis.backends\"]\n    del backends[\"spark\"]\n    return [(backend, getattr(ibis, backend)) for backend in sorted(backends.keys())]\n\n\ndef get_leaf_classes(op):\n    for child_class in op.__subclasses__():\n        if not child_class.__subclasses__():\n            yield child_class\n        else:\n            yield from get_leaf_classes(child_class)\n\n\nEXCLUDED_OPS = {\n    # Never translates into anything\n    ops.UnresolvedExistsSubquery,\n    ops.UnresolvedNotExistsSubquery,\n    ops.ScalarParameter,\n}\n\nINCLUDED_OPS = {\n    # Parent class of MultiQuantile so it's ignored by `get_backends()`\n    ops.Quantile,\n}\n\n\nICONS = {\n    True: \":material-check-decagram:{ .verified }\",\n    False: \":material-cancel:{ .cancel }\",\n}\n\n\ndef main():\n    possible_ops = (\n        frozenset(get_leaf_classes(ops.Value)) | INCLUDED_OPS\n    ) - EXCLUDED_OPS\n\n    support = {\"operation\": [f\"`{op.__name__}`\" for op in possible_ops]}\n    support.update(\n        (name, list(map(backend.has_operation, possible_ops)))\n        for name, backend in get_backends()\n    )\n\n    df = pd.DataFrame(support).set_index(\"operation\").sort_index()\n\n    counts = df.sum().sort_values(ascending=False)\n    num_ops = len(possible_ops)\n    coverage = (\n        counts.map(lambda n: f\"_{n} ({round(100 * n / num_ops)}%)_\")\n        .to_frame(name=\"**API Coverage**\")\n        .T\n    )\n\n    ops_table = df.loc[:, counts.index].replace(ICONS)\n    table = pd.concat([coverage, ops_table])\n    dst = Path(__file__).parent.joinpath(\n        \"docs\",\n        \"backends\",\n        \"support_matrix.csv\",\n    )\n    table.to_csv(dst, index_label=\"Backends\")\n\n\nmain()\n", "path": "gen_matrix.py"}], "after_files": [{"content": "from pathlib import Path\n\nimport pandas as pd\nimport tomli\n\nimport ibis\nimport ibis.expr.operations as ops\n\n\ndef get_backends():\n    pyproject = tomli.loads(Path(\"pyproject.toml\").read_text())\n    backends = pyproject[\"tool\"][\"poetry\"][\"plugins\"][\"ibis.backends\"]\n    del backends[\"spark\"]\n    return [(backend, getattr(ibis, backend)) for backend in sorted(backends.keys())]\n\n\ndef get_leaf_classes(op):\n    for child_class in op.__subclasses__():\n        if not child_class.__subclasses__():\n            yield child_class\n        else:\n            yield from get_leaf_classes(child_class)\n\n\nEXCLUDED_OPS = {\n    # Never translates into anything\n    ops.UnresolvedExistsSubquery,\n    ops.UnresolvedNotExistsSubquery,\n    ops.ScalarParameter,\n}\n\nINCLUDED_OPS = {\n    # Parent class of MultiQuantile so it's ignored by `get_backends()`\n    ops.Quantile,\n}\n\n\nICONS = {\n    True: \":material-check-decagram:{ .verified }\",\n    False: \":material-cancel:{ .cancel }\",\n}\n\n\ndef main():\n    possible_ops = (\n        frozenset(get_leaf_classes(ops.Value)) | INCLUDED_OPS\n    ) - EXCLUDED_OPS\n\n    support = {\"operation\": [f\"`{op.__name__}`\" for op in possible_ops]}\n    support.update(\n        (name, list(map(backend.has_operation, possible_ops)))\n        for name, backend in get_backends()\n    )\n\n    df = pd.DataFrame(support).set_index(\"operation\").sort_index()\n\n    counts = df.sum().sort_values(ascending=False)\n    num_ops = len(possible_ops)\n    coverage = (\n        counts.map(lambda n: f\"_{n} ({round(100 * n / num_ops)}%)_\")\n        .to_frame(name=\"**API Coverage**\")\n        .T\n    )\n\n    ops_table = df.loc[:, counts.index].replace(ICONS)\n    table = pd.concat([coverage, ops_table])\n    dst = Path(__file__).parent.joinpath(\n        \"docs\",\n        \"backends\",\n        \"support_matrix.csv\",\n    )\n\n    if dst.exists():\n        old = pd.read_csv(dst, index_col=\"Backends\")\n        should_write = not old.equals(table)\n    else:\n        should_write = True\n\n    if should_write:\n        table.to_csv(dst, index_label=\"Backends\")\n\n\nmain()\n", "path": "gen_matrix.py"}]}