-
Notifications
You must be signed in to change notification settings - Fork 795
/
Copy pathgenerate_api_docs.py
203 lines (146 loc) · 4.93 KB
/
generate_api_docs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""Fills the contents of doc/user_guide/api.rst based on the updated Altair schema."""
from __future__ import annotations
import types
from pathlib import Path
from types import ModuleType
from typing import TYPE_CHECKING, Final
import altair as alt
if TYPE_CHECKING:
from collections.abc import Iterator
API_FILENAME: Final = str(Path.cwd() / "doc" / "user_guide" / "api.rst")
API_TEMPLATE: Final = """\
.. _api:
API Reference
=============
This is the class and function reference of Altair, and the following content
is generated automatically from the code documentation strings.
Please refer to the `full user guide <http://altair-viz.github.io>`_ for
further details, as this low-level documentation may not be enough to give
full guidelines on their use.
.. _api-toplevel:
Top-Level Objects
-----------------
.. currentmodule:: altair
.. autosummary::
:toctree: generated/toplevel/
:nosignatures:
{toplevel_charts}
.. _api-channels:
Encoding Channels
-----------------
.. currentmodule:: altair
.. autosummary::
:toctree: generated/channels/
:nosignatures:
{encoding_wrappers}
.. _api-functions:
API Functions
-------------
.. currentmodule:: altair
.. autosummary::
:toctree: generated/api/
:nosignatures:
{api_functions}
.. _api-theme:
Theme
-----
.. currentmodule:: altair.theme
.. autosummary::
:toctree: generated/theme/
:nosignatures:
{theme_objects}
.. _api-core:
Low-Level Schema Wrappers
-------------------------
.. currentmodule:: altair
.. autosummary::
:toctree: generated/core/
:nosignatures:
{lowlevel_wrappers}
.. _api-cls:
API Utility Classes
-------------------
.. currentmodule:: altair
.. autosummary::
:toctree: generated/api-cls/
:nosignatures:
{api_classes}
.. _api-typing:
Typing
------
.. currentmodule:: altair.typing
.. autosummary::
:toctree: generated/typing/
:nosignatures:
{typing_objects}
.. _Generic:
https://typing.readthedocs.io/en/latest/spec/generics.html#generics
"""
def iter_objects(
mod: ModuleType,
ignore_private: bool = True,
restrict_to_type: type | None = None,
restrict_to_subclass: type | None = None,
) -> Iterator[str]:
for name in dir(mod):
obj = getattr(mod, name)
if ignore_private and name.startswith("_"):
continue
if restrict_to_type is not None and not isinstance(obj, restrict_to_type):
continue
if restrict_to_subclass is not None and (
not (isinstance(obj, type) and issubclass(obj, restrict_to_subclass))
):
continue
if hasattr(obj, "__deprecated__"):
continue
yield name
def toplevel_charts() -> list[str]:
return sorted(iter_objects(alt.api, restrict_to_subclass=alt.TopLevelMixin))
def encoding_wrappers() -> list[str]:
return sorted(iter_objects(alt.channels, restrict_to_subclass=alt.SchemaBase))
def api_functions() -> list[str]:
# Exclude `typing` functions/SpecialForm(s)
KEEP = set(alt.api.__all__) - set(alt.typing.__all__)
return sorted(
name
for name in iter_objects(alt.api, restrict_to_type=types.FunctionType)
if name in KEEP
)
def api_classes() -> list[str]:
# Part of the Public API, but are not inherited from `vega-lite`.
return ["expr", "When", "Then", "ChainedWhen"]
def type_hints() -> list[str]:
return sorted(s for s in iter_objects(alt.typing) if s in alt.typing.__all__)
def theme() -> list[str]:
sort_1 = sorted(s for s in iter_objects(alt.theme) if s in alt.theme.__all__)
# Display functions before `TypedDict`, but show `ThemeConfig` before `Kwds`
sort_2 = sorted(sort_1, key=lambda s: s.endswith("Kwds"))
sort_3 = sorted(sort_2, key=lambda s: not s.islower())
return sort_3
def lowlevel_wrappers() -> list[str]:
objects = sorted(iter_objects(alt.schema.core, restrict_to_subclass=alt.SchemaBase))
# The names of these two classes are also used for classes in alt.channels. Due to
# how imports are set up, these channel classes overwrite the two low-level classes
# in the top-level Altair namespace. Therefore, they cannot be imported as e.g.
# altair.Color (which gives you the Channel class) and therefore Sphinx won't
# be able to produce a documentation page.
objects = [o for o in objects if o not in {"Color", "Text"}]
return objects
def write_api_file() -> None:
print(f"Updating API docs\n ->{API_FILENAME}")
sep = "\n "
Path(API_FILENAME).write_text(
API_TEMPLATE.format(
toplevel_charts=sep.join(toplevel_charts()),
api_functions=sep.join(api_functions()),
encoding_wrappers=sep.join(encoding_wrappers()),
lowlevel_wrappers=sep.join(lowlevel_wrappers()),
api_classes=sep.join(api_classes()),
typing_objects=sep.join(type_hints()),
theme_objects=sep.join(theme()),
),
encoding="utf-8",
)
if __name__ == "__main__":
write_api_file()