We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Missing documentation for SquaredExponential kernel
# Documentation

*Is there anything missing in the docs?*

Documentation of gpflow.kernels.stationaries.SquaredExponential went missing sometime after 2.4.0

It is there in [2.4.0](https://gpflow.github.io/GPflow/2.4.0/api/gpflow/kernels/index.html#gpflow-kernels-squaredexponential).

In [2.5.0](https://gpflow.github.io/GPflow/2.5.0/api/gpflow/kernels/index.html#gpflow-kernels-rbf) (and [currently](https://gpflow.github.io/GPflow/develop/api/gpflow/kernels/index.html#gpflow-kernels-rbf)), the entry was replaced by the RBF "as an alias of `gpflow.kernels.stationaries.SquaredExponential`", but there is no `SquaredExponential` entry.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `doc/generate_module_rst.py`
Content:
```
1 # Copyright 2019 GPflow Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Script to autogenerate .rst files for autodocumentation of classes and modules in GPflow.
15 To be run by the CI system to update docs.
16 """
17 import inspect
18 from dataclasses import dataclass
19 from pathlib import Path
20 from types import ModuleType
21 from typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Type, Union
22 
23 from gpflow.utilities import Dispatcher
24 
25 RST_LEVEL_SYMBOLS = ["=", "-", "~", '"', "'", "^"]
26 
27 IGNORE_MODULES = {
28     "gpflow.covariances.dispatch",
29     "gpflow.conditionals.dispatch",
30     "gpflow.expectations.dispatch",
31     "gpflow.kullback_leiblers.dispatch",
32     "gpflow.versions",
33 }
34 
35 
36 def _header(header: str, level: int) -> str:
37     return f"{header}\n{RST_LEVEL_SYMBOLS[level] * len(header)}"
38 
39 
40 @dataclass
41 class DocumentableDispatcher:
42 
43     name: str
44     obj: Dispatcher
45 
46     def implementations(self) -> Mapping[Callable[..., Any], List[Type[Any]]]:
47         implementations: Dict[Callable[..., Any], List[Type[Any]]] = {}
48         for args, impl in self.obj.funcs.items():
49             implementations.setdefault(impl, []).append(args)
50         return implementations
51 
52     def write(self, out: TextIO) -> None:
53         out.write(
54             f"""
55 {_header(self.name, 2)}
56 
57 This function uses multiple dispatch, which will depend on the type of argument passed in:
58 """
59         )
60         for impl, argss in self.implementations().items():
61             impl_name = f"{impl.__module__}.{impl.__name__}"
62 
63             out.write(
64                 """
65 .. code-block:: python
66 
67 """
68             )
69             for args in argss:
70                 arg_names = ", ".join([a.__name__ for a in args])
71                 out.write(f"    {self.name}( {arg_names} )\n")
72             out.write(f"    # dispatch to -> {impl_name}(...)\n")
73             out.write(
74                 f"""
75 .. autofunction:: {impl_name}
76 """
77             )
78 
79 
80 @dataclass
81 class DocumentableClass:
82 
83     name: str
84     obj: Type[Any]
85 
86     def write(self, out: TextIO) -> None:
87         out.write(
88             f"""
89 {_header(self.name, 2)}
90 
91 .. autoclass:: {self.name}
92    :show-inheritance:
93    :members:
94 """
95         )
96 
97 
98 @dataclass
99 class DocumentableFunction:
100 
101     name: str
102     obj: Callable[..., Any]
103 
104     def write(self, out: TextIO) -> None:
105         out.write(
106             f"""
107 {_header(self.name, 2)}
108 
109 .. autofunction:: {self.name}
110 """
111         )
112 
113 
114 @dataclass
115 class DocumentableModule:
116 
117     name: str
118     obj: ModuleType
119     modules: List["DocumentableModule"]
120     classes: List[DocumentableClass]
121     functions: List[Union[DocumentableDispatcher, DocumentableFunction]]
122 
123     @staticmethod
124     def collect(
125         root: ModuleType,
126     ) -> "DocumentableModule":
127         root_name = root.__name__
128         exported_names = set(getattr(root, "__all__", []))
129 
130         modules: List["DocumentableModule"] = []
131         classes: List[DocumentableClass] = []
132         functions: List[Union[DocumentableDispatcher, DocumentableFunction]] = []
133 
134         for key in dir(root):
135             if key.startswith("_"):
136                 continue
137 
138             child = getattr(root, key)
139             child_name = root_name + "." + key
140             if child_name in IGNORE_MODULES:
141                 continue
142 
143             # pylint: disable=cell-var-from-loop
144             def _should_ignore(child: Union[Callable[..., Any], Type[Any]]) -> bool:
145                 declared_in_root = child.__module__ == root_name
146                 explicitly_exported = key in exported_names
147                 return not (declared_in_root or explicitly_exported)
148 
149             # pylint: enable=cell-var-from-loop
150 
151             if isinstance(child, Dispatcher):
152                 functions.append(DocumentableDispatcher(child_name, child))
153             elif inspect.ismodule(child):
154                 if child.__name__ != child_name:  # Ignore imports of modules.
155                     continue
156                 modules.append(DocumentableModule.collect(child))
157             elif inspect.isclass(child):
158                 if _should_ignore(child):
159                     continue
160                 classes.append(DocumentableClass(child_name, child))
161             elif inspect.isfunction(child):
162                 if _should_ignore(child):
163                     continue
164                 functions.append(DocumentableFunction(child_name, child))
165 
166         return DocumentableModule(root_name, root, modules, classes, functions)
167 
168     def seen_in_dispatchers(self, seen: Set[int]) -> None:
169         for module in self.modules:
170             module.seen_in_dispatchers(seen)
171         for function in self.functions:
172             if isinstance(function, DocumentableDispatcher):
173                 impls = function.obj.funcs.values()
174                 for impl in impls:
175                     seen.add(id(impl))
176 
177     def prune_duplicates(self) -> None:
178         seen: Set[int] = set()
179         self.seen_in_dispatchers(seen)
180 
181         # Breadth-first search so that we prefer objects with shorter names.
182         todo = Deque([self])
183         while todo:
184             module = todo.popleft()
185 
186             new_classes = []
187             for c in module.classes:
188                 if id(c.obj) not in seen:
189                     seen.add(id(c.obj))
190                     new_classes.append(c)
191             module.classes = new_classes
192 
193             new_functions = []
194             for f in module.functions:
195                 if id(f.obj) not in seen:
196                     seen.add(id(f.obj))
197                     new_functions.append(f)
198             module.functions = new_functions
199 
200             todo.extend(module.modules)
201 
202     def prune_empty_modules(self) -> None:
203         new_modules = []
204         for m in self.modules:
205             m.prune_empty_modules()
206 
207             if m.modules or m.classes or m.functions:
208                 new_modules.append(m)
209         self.modules = new_modules
210 
211     def prune(self) -> None:
212         self.prune_duplicates()
213         self.prune_empty_modules()
214 
215     def write_modules(self, out: TextIO) -> None:
216         if not self.modules:
217             return
218 
219         out.write(
220             f"""
221 {_header('Modules', 1)}
222 
223 .. toctree::
224    :maxdepth: 1
225 
226 """
227         )
228         for module in self.modules:
229             out.write(f"   {module.name} <{module.name.split('.')[-1]}/index>\n")
230 
231     def write_classes(self, out: TextIO) -> None:
232         if not self.classes:
233             return
234 
235         out.write(
236             f"""
237 {_header('Classes', 1)}
238 """
239         )
240         for cls in self.classes:
241             cls.write(out)
242 
243     def write_functions(self, out: TextIO) -> None:
244         if not self.functions:
245             return
246 
247         out.write(
248             f"""
249 {_header('Functions', 1)}
250 """
251         )
252         for function in self.functions:
253             function.write(out)
254 
255     def write(self, path: Path) -> None:
256         dir_path = path / f"{self.name.replace('.', '/')}"
257         dir_path.mkdir(parents=True, exist_ok=True)
258         index_path = dir_path / "index.rst"
259         with index_path.open("wt") as out:
260             print("Writing", index_path)
261             out.write(
262                 f"""{_header(self.name, 0)}
263 
264 .. THIS IS AN AUTOGENERATED RST FILE
265 
266 .. automodule:: {self.name}
267 """
268             )
269             self.write_modules(out)
270             self.write_classes(out)
271             self.write_functions(out)
272 
273         for module in self.modules:
274             module.write(path)
275 
276     def str_into(self, indent: int, lines: List[str]) -> None:
277         lines.append(2 * indent * " " + "Module: " + self.name)
278         for module in self.modules:
279             module.str_into(indent + 1, lines)
280         for cls in self.classes:
281             lines.append(2 * (indent + 1) * " " + "Class: " + cls.name)
282         for function in self.functions:
283             lines.append(2 * (indent + 1) * " " + "Function: " + function.name)
284 
285     def __str__(self) -> str:
286         lines: List[str] = []
287         self.str_into(0, lines)
288         return "\n".join(lines)
289 
290 
291 def generate_module_rst(module: ModuleType, dest: Path) -> None:
292     """
293     Traverses the given `module` and generates `.rst` files for Sphinx.
294     """
295     docs = DocumentableModule.collect(module)
296     docs.prune()
297     docs.write(dest)
298
```
--- 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/doc/generate_module_rst.py b/doc/generate_module_rst.py
--- a/doc/generate_module_rst.py
+++ b/doc/generate_module_rst.py
@@ -18,7 +18,7 @@
 from dataclasses import dataclass
 from pathlib import Path
 from types import ModuleType
-from typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Type, Union
+from typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Tuple, Type, Union
 
 from gpflow.utilities import Dispatcher
 
@@ -165,17 +165,19 @@
 
         return DocumentableModule(root_name, root, modules, classes, functions)
 
-    def seen_in_dispatchers(self, seen: Set[int]) -> None:
+    def seen_in_dispatchers(self, seen: Set[Tuple[str, int]]) -> None:
         for module in self.modules:
             module.seen_in_dispatchers(seen)
         for function in self.functions:
             if isinstance(function, DocumentableDispatcher):
                 impls = function.obj.funcs.values()
                 for impl in impls:
-                    seen.add(id(impl))
+                    # See comment below (for classes) about aliases.
+                    key = (impl.__name__, id(impl))
+                    seen.add(key)
 
     def prune_duplicates(self) -> None:
-        seen: Set[int] = set()
+        seen: Set[Tuple[str, int]] = set()
         self.seen_in_dispatchers(seen)
 
         # Breadth-first search so that we prefer objects with shorter names.
@@ -185,15 +187,20 @@
 
             new_classes = []
             for c in module.classes:
-                if id(c.obj) not in seen:
-                    seen.add(id(c.obj))
+                # Account for objects to have aliases, hence include the object name in the key.
+                # We want to generate documentation for both the alias and the original object.
+                key = (c.name[c.name.rfind(".") + 1 :], id(c.obj))
+                if key not in seen:
+                    seen.add(key)
                     new_classes.append(c)
             module.classes = new_classes
 
             new_functions = []
             for f in module.functions:
-                if id(f.obj) not in seen:
-                    seen.add(id(f.obj))
+                # See comment above (for classes) about aliases.
+                key = (f.name[f.name.rfind(".") + 1 :], id(f.obj))
+                if key not in seen:
+                    seen.add(key)
                     new_functions.append(f)
             module.functions = new_functions

{"golden_diff": "diff --git a/doc/generate_module_rst.py b/doc/generate_module_rst.py\n--- a/doc/generate_module_rst.py\n+++ b/doc/generate_module_rst.py\n@@ -18,7 +18,7 @@\n from dataclasses import dataclass\n from pathlib import Path\n from types import ModuleType\n-from typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Type, Union\n+from typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Tuple, Type, Union\n \n from gpflow.utilities import Dispatcher\n \n@@ -165,17 +165,19 @@\n \n         return DocumentableModule(root_name, root, modules, classes, functions)\n \n-    def seen_in_dispatchers(self, seen: Set[int]) -> None:\n+    def seen_in_dispatchers(self, seen: Set[Tuple[str, int]]) -> None:\n         for module in self.modules:\n             module.seen_in_dispatchers(seen)\n         for function in self.functions:\n             if isinstance(function, DocumentableDispatcher):\n                 impls = function.obj.funcs.values()\n                 for impl in impls:\n-                    seen.add(id(impl))\n+                    # See comment below (for classes) about aliases.\n+                    key = (impl.__name__, id(impl))\n+                    seen.add(key)\n \n     def prune_duplicates(self) -> None:\n-        seen: Set[int] = set()\n+        seen: Set[Tuple[str, int]] = set()\n         self.seen_in_dispatchers(seen)\n \n         # Breadth-first search so that we prefer objects with shorter names.\n@@ -185,15 +187,20 @@\n \n             new_classes = []\n             for c in module.classes:\n-                if id(c.obj) not in seen:\n-                    seen.add(id(c.obj))\n+                # Account for objects to have aliases, hence include the object name in the key.\n+                # We want to generate documentation for both the alias and the original object.\n+                key = (c.name[c.name.rfind(\".\") + 1 :], id(c.obj))\n+                if key not in seen:\n+                    seen.add(key)\n                     new_classes.append(c)\n             module.classes = new_classes\n \n             new_functions = []\n             for f in module.functions:\n-                if id(f.obj) not in seen:\n-                    seen.add(id(f.obj))\n+                # See comment above (for classes) about aliases.\n+                key = (f.name[f.name.rfind(\".\") + 1 :], id(f.obj))\n+                if key not in seen:\n+                    seen.add(key)\n                     new_functions.append(f)\n             module.functions = new_functions\n", "issue": "Missing documentation for SquaredExponential kernel\n# Documentation\r\n\r\n*Is there anything missing in the docs?*\r\n\r\nDocumentation of gpflow.kernels.stationaries.SquaredExponential went missing sometime after 2.4.0\r\n\r\nIt is there in [2.4.0](https://gpflow.github.io/GPflow/2.4.0/api/gpflow/kernels/index.html#gpflow-kernels-squaredexponential).\r\n\r\nIn [2.5.0](https://gpflow.github.io/GPflow/2.5.0/api/gpflow/kernels/index.html#gpflow-kernels-rbf) (and [currently](https://gpflow.github.io/GPflow/develop/api/gpflow/kernels/index.html#gpflow-kernels-rbf)), the entry was replaced by the RBF \"as an alias of `gpflow.kernels.stationaries.SquaredExponential`\", but there is no `SquaredExponential` entry.\r\n\n", "before_files": [{"content": "# Copyright 2019 GPflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Script to autogenerate .rst files for autodocumentation of classes and modules in GPflow.\nTo be run by the CI system to update docs.\n\"\"\"\nimport inspect\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom types import ModuleType\nfrom typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Type, Union\n\nfrom gpflow.utilities import Dispatcher\n\nRST_LEVEL_SYMBOLS = [\"=\", \"-\", \"~\", '\"', \"'\", \"^\"]\n\nIGNORE_MODULES = {\n    \"gpflow.covariances.dispatch\",\n    \"gpflow.conditionals.dispatch\",\n    \"gpflow.expectations.dispatch\",\n    \"gpflow.kullback_leiblers.dispatch\",\n    \"gpflow.versions\",\n}\n\n\ndef _header(header: str, level: int) -> str:\n    return f\"{header}\\n{RST_LEVEL_SYMBOLS[level] * len(header)}\"\n\n\n@dataclass\nclass DocumentableDispatcher:\n\n    name: str\n    obj: Dispatcher\n\n    def implementations(self) -> Mapping[Callable[..., Any], List[Type[Any]]]:\n        implementations: Dict[Callable[..., Any], List[Type[Any]]] = {}\n        for args, impl in self.obj.funcs.items():\n            implementations.setdefault(impl, []).append(args)\n        return implementations\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\nThis function uses multiple dispatch, which will depend on the type of argument passed in:\n\"\"\"\n        )\n        for impl, argss in self.implementations().items():\n            impl_name = f\"{impl.__module__}.{impl.__name__}\"\n\n            out.write(\n                \"\"\"\n.. code-block:: python\n\n\"\"\"\n            )\n            for args in argss:\n                arg_names = \", \".join([a.__name__ for a in args])\n                out.write(f\"    {self.name}( {arg_names} )\\n\")\n            out.write(f\"    # dispatch to -> {impl_name}(...)\\n\")\n            out.write(\n                f\"\"\"\n.. autofunction:: {impl_name}\n\"\"\"\n            )\n\n\n@dataclass\nclass DocumentableClass:\n\n    name: str\n    obj: Type[Any]\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\n.. autoclass:: {self.name}\n   :show-inheritance:\n   :members:\n\"\"\"\n        )\n\n\n@dataclass\nclass DocumentableFunction:\n\n    name: str\n    obj: Callable[..., Any]\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\n.. autofunction:: {self.name}\n\"\"\"\n        )\n\n\n@dataclass\nclass DocumentableModule:\n\n    name: str\n    obj: ModuleType\n    modules: List[\"DocumentableModule\"]\n    classes: List[DocumentableClass]\n    functions: List[Union[DocumentableDispatcher, DocumentableFunction]]\n\n    @staticmethod\n    def collect(\n        root: ModuleType,\n    ) -> \"DocumentableModule\":\n        root_name = root.__name__\n        exported_names = set(getattr(root, \"__all__\", []))\n\n        modules: List[\"DocumentableModule\"] = []\n        classes: List[DocumentableClass] = []\n        functions: List[Union[DocumentableDispatcher, DocumentableFunction]] = []\n\n        for key in dir(root):\n            if key.startswith(\"_\"):\n                continue\n\n            child = getattr(root, key)\n            child_name = root_name + \".\" + key\n            if child_name in IGNORE_MODULES:\n                continue\n\n            # pylint: disable=cell-var-from-loop\n            def _should_ignore(child: Union[Callable[..., Any], Type[Any]]) -> bool:\n                declared_in_root = child.__module__ == root_name\n                explicitly_exported = key in exported_names\n                return not (declared_in_root or explicitly_exported)\n\n            # pylint: enable=cell-var-from-loop\n\n            if isinstance(child, Dispatcher):\n                functions.append(DocumentableDispatcher(child_name, child))\n            elif inspect.ismodule(child):\n                if child.__name__ != child_name:  # Ignore imports of modules.\n                    continue\n                modules.append(DocumentableModule.collect(child))\n            elif inspect.isclass(child):\n                if _should_ignore(child):\n                    continue\n                classes.append(DocumentableClass(child_name, child))\n            elif inspect.isfunction(child):\n                if _should_ignore(child):\n                    continue\n                functions.append(DocumentableFunction(child_name, child))\n\n        return DocumentableModule(root_name, root, modules, classes, functions)\n\n    def seen_in_dispatchers(self, seen: Set[int]) -> None:\n        for module in self.modules:\n            module.seen_in_dispatchers(seen)\n        for function in self.functions:\n            if isinstance(function, DocumentableDispatcher):\n                impls = function.obj.funcs.values()\n                for impl in impls:\n                    seen.add(id(impl))\n\n    def prune_duplicates(self) -> None:\n        seen: Set[int] = set()\n        self.seen_in_dispatchers(seen)\n\n        # Breadth-first search so that we prefer objects with shorter names.\n        todo = Deque([self])\n        while todo:\n            module = todo.popleft()\n\n            new_classes = []\n            for c in module.classes:\n                if id(c.obj) not in seen:\n                    seen.add(id(c.obj))\n                    new_classes.append(c)\n            module.classes = new_classes\n\n            new_functions = []\n            for f in module.functions:\n                if id(f.obj) not in seen:\n                    seen.add(id(f.obj))\n                    new_functions.append(f)\n            module.functions = new_functions\n\n            todo.extend(module.modules)\n\n    def prune_empty_modules(self) -> None:\n        new_modules = []\n        for m in self.modules:\n            m.prune_empty_modules()\n\n            if m.modules or m.classes or m.functions:\n                new_modules.append(m)\n        self.modules = new_modules\n\n    def prune(self) -> None:\n        self.prune_duplicates()\n        self.prune_empty_modules()\n\n    def write_modules(self, out: TextIO) -> None:\n        if not self.modules:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Modules', 1)}\n\n.. toctree::\n   :maxdepth: 1\n\n\"\"\"\n        )\n        for module in self.modules:\n            out.write(f\"   {module.name} <{module.name.split('.')[-1]}/index>\\n\")\n\n    def write_classes(self, out: TextIO) -> None:\n        if not self.classes:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Classes', 1)}\n\"\"\"\n        )\n        for cls in self.classes:\n            cls.write(out)\n\n    def write_functions(self, out: TextIO) -> None:\n        if not self.functions:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Functions', 1)}\n\"\"\"\n        )\n        for function in self.functions:\n            function.write(out)\n\n    def write(self, path: Path) -> None:\n        dir_path = path / f\"{self.name.replace('.', '/')}\"\n        dir_path.mkdir(parents=True, exist_ok=True)\n        index_path = dir_path / \"index.rst\"\n        with index_path.open(\"wt\") as out:\n            print(\"Writing\", index_path)\n            out.write(\n                f\"\"\"{_header(self.name, 0)}\n\n.. THIS IS AN AUTOGENERATED RST FILE\n\n.. automodule:: {self.name}\n\"\"\"\n            )\n            self.write_modules(out)\n            self.write_classes(out)\n            self.write_functions(out)\n\n        for module in self.modules:\n            module.write(path)\n\n    def str_into(self, indent: int, lines: List[str]) -> None:\n        lines.append(2 * indent * \" \" + \"Module: \" + self.name)\n        for module in self.modules:\n            module.str_into(indent + 1, lines)\n        for cls in self.classes:\n            lines.append(2 * (indent + 1) * \" \" + \"Class: \" + cls.name)\n        for function in self.functions:\n            lines.append(2 * (indent + 1) * \" \" + \"Function: \" + function.name)\n\n    def __str__(self) -> str:\n        lines: List[str] = []\n        self.str_into(0, lines)\n        return \"\\n\".join(lines)\n\n\ndef generate_module_rst(module: ModuleType, dest: Path) -> None:\n    \"\"\"\n    Traverses the given `module` and generates `.rst` files for Sphinx.\n    \"\"\"\n    docs = DocumentableModule.collect(module)\n    docs.prune()\n    docs.write(dest)\n", "path": "doc/generate_module_rst.py"}], "after_files": [{"content": "# Copyright 2019 GPflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Script to autogenerate .rst files for autodocumentation of classes and modules in GPflow.\nTo be run by the CI system to update docs.\n\"\"\"\nimport inspect\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom types import ModuleType\nfrom typing import Any, Callable, Deque, Dict, List, Mapping, Set, TextIO, Tuple, Type, Union\n\nfrom gpflow.utilities import Dispatcher\n\nRST_LEVEL_SYMBOLS = [\"=\", \"-\", \"~\", '\"', \"'\", \"^\"]\n\nIGNORE_MODULES = {\n    \"gpflow.covariances.dispatch\",\n    \"gpflow.conditionals.dispatch\",\n    \"gpflow.expectations.dispatch\",\n    \"gpflow.kullback_leiblers.dispatch\",\n    \"gpflow.versions\",\n}\n\n\ndef _header(header: str, level: int) -> str:\n    return f\"{header}\\n{RST_LEVEL_SYMBOLS[level] * len(header)}\"\n\n\n@dataclass\nclass DocumentableDispatcher:\n\n    name: str\n    obj: Dispatcher\n\n    def implementations(self) -> Mapping[Callable[..., Any], List[Type[Any]]]:\n        implementations: Dict[Callable[..., Any], List[Type[Any]]] = {}\n        for args, impl in self.obj.funcs.items():\n            implementations.setdefault(impl, []).append(args)\n        return implementations\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\nThis function uses multiple dispatch, which will depend on the type of argument passed in:\n\"\"\"\n        )\n        for impl, argss in self.implementations().items():\n            impl_name = f\"{impl.__module__}.{impl.__name__}\"\n\n            out.write(\n                \"\"\"\n.. code-block:: python\n\n\"\"\"\n            )\n            for args in argss:\n                arg_names = \", \".join([a.__name__ for a in args])\n                out.write(f\"    {self.name}( {arg_names} )\\n\")\n            out.write(f\"    # dispatch to -> {impl_name}(...)\\n\")\n            out.write(\n                f\"\"\"\n.. autofunction:: {impl_name}\n\"\"\"\n            )\n\n\n@dataclass\nclass DocumentableClass:\n\n    name: str\n    obj: Type[Any]\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\n.. autoclass:: {self.name}\n   :show-inheritance:\n   :members:\n\"\"\"\n        )\n\n\n@dataclass\nclass DocumentableFunction:\n\n    name: str\n    obj: Callable[..., Any]\n\n    def write(self, out: TextIO) -> None:\n        out.write(\n            f\"\"\"\n{_header(self.name, 2)}\n\n.. autofunction:: {self.name}\n\"\"\"\n        )\n\n\n@dataclass\nclass DocumentableModule:\n\n    name: str\n    obj: ModuleType\n    modules: List[\"DocumentableModule\"]\n    classes: List[DocumentableClass]\n    functions: List[Union[DocumentableDispatcher, DocumentableFunction]]\n\n    @staticmethod\n    def collect(\n        root: ModuleType,\n    ) -> \"DocumentableModule\":\n        root_name = root.__name__\n        exported_names = set(getattr(root, \"__all__\", []))\n\n        modules: List[\"DocumentableModule\"] = []\n        classes: List[DocumentableClass] = []\n        functions: List[Union[DocumentableDispatcher, DocumentableFunction]] = []\n\n        for key in dir(root):\n            if key.startswith(\"_\"):\n                continue\n\n            child = getattr(root, key)\n            child_name = root_name + \".\" + key\n            if child_name in IGNORE_MODULES:\n                continue\n\n            # pylint: disable=cell-var-from-loop\n            def _should_ignore(child: Union[Callable[..., Any], Type[Any]]) -> bool:\n                declared_in_root = child.__module__ == root_name\n                explicitly_exported = key in exported_names\n                return not (declared_in_root or explicitly_exported)\n\n            # pylint: enable=cell-var-from-loop\n\n            if isinstance(child, Dispatcher):\n                functions.append(DocumentableDispatcher(child_name, child))\n            elif inspect.ismodule(child):\n                if child.__name__ != child_name:  # Ignore imports of modules.\n                    continue\n                modules.append(DocumentableModule.collect(child))\n            elif inspect.isclass(child):\n                if _should_ignore(child):\n                    continue\n                classes.append(DocumentableClass(child_name, child))\n            elif inspect.isfunction(child):\n                if _should_ignore(child):\n                    continue\n                functions.append(DocumentableFunction(child_name, child))\n\n        return DocumentableModule(root_name, root, modules, classes, functions)\n\n    def seen_in_dispatchers(self, seen: Set[Tuple[str, int]]) -> None:\n        for module in self.modules:\n            module.seen_in_dispatchers(seen)\n        for function in self.functions:\n            if isinstance(function, DocumentableDispatcher):\n                impls = function.obj.funcs.values()\n                for impl in impls:\n                    # See comment below (for classes) about aliases.\n                    key = (impl.__name__, id(impl))\n                    seen.add(key)\n\n    def prune_duplicates(self) -> None:\n        seen: Set[Tuple[str, int]] = set()\n        self.seen_in_dispatchers(seen)\n\n        # Breadth-first search so that we prefer objects with shorter names.\n        todo = Deque([self])\n        while todo:\n            module = todo.popleft()\n\n            new_classes = []\n            for c in module.classes:\n                # Account for objects to have aliases, hence include the object name in the key.\n                # We want to generate documentation for both the alias and the original object.\n                key = (c.name[c.name.rfind(\".\") + 1 :], id(c.obj))\n                if key not in seen:\n                    seen.add(key)\n                    new_classes.append(c)\n            module.classes = new_classes\n\n            new_functions = []\n            for f in module.functions:\n                # See comment above (for classes) about aliases.\n                key = (f.name[f.name.rfind(\".\") + 1 :], id(f.obj))\n                if key not in seen:\n                    seen.add(key)\n                    new_functions.append(f)\n            module.functions = new_functions\n\n            todo.extend(module.modules)\n\n    def prune_empty_modules(self) -> None:\n        new_modules = []\n        for m in self.modules:\n            m.prune_empty_modules()\n\n            if m.modules or m.classes or m.functions:\n                new_modules.append(m)\n        self.modules = new_modules\n\n    def prune(self) -> None:\n        self.prune_duplicates()\n        self.prune_empty_modules()\n\n    def write_modules(self, out: TextIO) -> None:\n        if not self.modules:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Modules', 1)}\n\n.. toctree::\n   :maxdepth: 1\n\n\"\"\"\n        )\n        for module in self.modules:\n            out.write(f\"   {module.name} <{module.name.split('.')[-1]}/index>\\n\")\n\n    def write_classes(self, out: TextIO) -> None:\n        if not self.classes:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Classes', 1)}\n\"\"\"\n        )\n        for cls in self.classes:\n            cls.write(out)\n\n    def write_functions(self, out: TextIO) -> None:\n        if not self.functions:\n            return\n\n        out.write(\n            f\"\"\"\n{_header('Functions', 1)}\n\"\"\"\n        )\n        for function in self.functions:\n            function.write(out)\n\n    def write(self, path: Path) -> None:\n        dir_path = path / f\"{self.name.replace('.', '/')}\"\n        dir_path.mkdir(parents=True, exist_ok=True)\n        index_path = dir_path / \"index.rst\"\n        with index_path.open(\"wt\") as out:\n            print(\"Writing\", index_path)\n            out.write(\n                f\"\"\"{_header(self.name, 0)}\n\n.. THIS IS AN AUTOGENERATED RST FILE\n\n.. automodule:: {self.name}\n\"\"\"\n            )\n            self.write_modules(out)\n            self.write_classes(out)\n            self.write_functions(out)\n\n        for module in self.modules:\n            module.write(path)\n\n    def str_into(self, indent: int, lines: List[str]) -> None:\n        lines.append(2 * indent * \" \" + \"Module: \" + self.name)\n        for module in self.modules:\n            module.str_into(indent + 1, lines)\n        for cls in self.classes:\n            lines.append(2 * (indent + 1) * \" \" + \"Class: \" + cls.name)\n        for function in self.functions:\n            lines.append(2 * (indent + 1) * \" \" + \"Function: \" + function.name)\n\n    def __str__(self) -> str:\n        lines: List[str] = []\n        self.str_into(0, lines)\n        return \"\\n\".join(lines)\n\n\ndef generate_module_rst(module: ModuleType, dest: Path) -> None:\n    \"\"\"\n    Traverses the given `module` and generates `.rst` files for Sphinx.\n    \"\"\"\n    docs = DocumentableModule.collect(module)\n    docs.prune()\n    docs.write(dest)\n", "path": "doc/generate_module_rst.py"}]}