Skip to content

Commit ce62d5e

Browse files
authored
Split sphinx extensions up a little (#4429)
1 parent 2d18034 commit ce62d5e

File tree

4 files changed

+257
-240
lines changed

4 files changed

+257
-240
lines changed

_extensions/apiref.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import re
2+
import string
3+
from docutils import nodes, utils
4+
5+
6+
value_re = re.compile(r"^(.*)\s*<(.*)>$")
7+
DOXYGEN_LOOKUP = {}
8+
for s in string.ascii_lowercase + string.digits:
9+
DOXYGEN_LOOKUP[s] = s
10+
for s in string.ascii_uppercase:
11+
DOXYGEN_LOOKUP[s] = "_{}".format(s.lower())
12+
DOXYGEN_LOOKUP[":"] = "_1"
13+
DOXYGEN_LOOKUP["_"] = "__"
14+
DOXYGEN_LOOKUP["."] = "_8"
15+
16+
17+
def split_text_value(value):
18+
match = value_re.match(value)
19+
if match is None:
20+
return None, value
21+
return match.group(1), match.group(2)
22+
23+
24+
def encode_doxygen(value):
25+
value = value.split("/")[-1]
26+
try:
27+
return "".join(DOXYGEN_LOOKUP[s] for s in value)
28+
except KeyError:
29+
raise ValueError("Unknown character in doxygen string! '{}'".format(value))
30+
31+
32+
def apiref_role(name, rawtext, text, lineno, inliner, options=None, content=None):
33+
text, value = split_text_value(text)
34+
if text is None:
35+
text = "API Reference"
36+
ref = "/api/{}.html".format(encode_doxygen(value))
37+
return [make_link_node(rawtext, text, ref, options)], []
38+
39+
40+
def apiclass_role(name, rawtext, text, lineno, inliner, options=None, content=None):
41+
text, value = split_text_value(text)
42+
if text is None:
43+
text = value
44+
ref = "/api/classesphome_1_1{}.html".format(encode_doxygen(value))
45+
return [make_link_node(rawtext, text, ref, options)], []
46+
47+
48+
def apistruct_role(name, rawtext, text, lineno, inliner, options=None, content=None):
49+
text, value = split_text_value(text)
50+
if text is None:
51+
text = value
52+
ref = "/api/structesphome_1_1{}.html".format(encode_doxygen(value))
53+
return [make_link_node(rawtext, text, ref, options)], []
54+
55+
def make_link_node(rawtext, text, ref, options=None):
56+
options = options or {}
57+
node = nodes.reference(rawtext, utils.unescape(text), refuri=ref, **options)
58+
return node
59+
60+
def setup(app):
61+
app.add_role("apiref", apiref_role)
62+
app.add_role("apiclass", apiclass_role)
63+
app.add_role("apistruct", apistruct_role)
64+
return {"version": "1.0.0", "parallel_read_safe": True, "parallel_write_safe": True}

_extensions/github.py

Lines changed: 1 addition & 239 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import csv
2-
from itertools import zip_longest
1+
32
import os
4-
import re
5-
import string
63

74
from docutils import nodes, utils
8-
from docutils.parsers.rst import directives
9-
from docutils.parsers.rst.directives.tables import Table
105

116

127
def libpr_role(name, rawtext, text, lineno, inliner, options=None, content=None):
@@ -29,56 +24,6 @@ def ghuser_role(name, rawtext, text, lineno, inliner, options=None, content=None
2924
return [make_link_node(rawtext, "@{}".format(text), ref, options)], []
3025

3126

32-
value_re = re.compile(r"^(.*)\s*<(.*)>$")
33-
DOXYGEN_LOOKUP = {}
34-
for s in string.ascii_lowercase + string.digits:
35-
DOXYGEN_LOOKUP[s] = s
36-
for s in string.ascii_uppercase:
37-
DOXYGEN_LOOKUP[s] = "_{}".format(s.lower())
38-
DOXYGEN_LOOKUP[":"] = "_1"
39-
DOXYGEN_LOOKUP["_"] = "__"
40-
DOXYGEN_LOOKUP["."] = "_8"
41-
42-
43-
def split_text_value(value):
44-
match = value_re.match(value)
45-
if match is None:
46-
return None, value
47-
return match.group(1), match.group(2)
48-
49-
50-
def encode_doxygen(value):
51-
value = value.split("/")[-1]
52-
try:
53-
return "".join(DOXYGEN_LOOKUP[s] for s in value)
54-
except KeyError:
55-
raise ValueError("Unknown character in doxygen string! '{}'".format(value))
56-
57-
58-
def apiref_role(name, rawtext, text, lineno, inliner, options=None, content=None):
59-
text, value = split_text_value(text)
60-
if text is None:
61-
text = "API Reference"
62-
ref = "/api/{}.html".format(encode_doxygen(value))
63-
return [make_link_node(rawtext, text, ref, options)], []
64-
65-
66-
def apiclass_role(name, rawtext, text, lineno, inliner, options=None, content=None):
67-
text, value = split_text_value(text)
68-
if text is None:
69-
text = value
70-
ref = "/api/classesphome_1_1{}.html".format(encode_doxygen(value))
71-
return [make_link_node(rawtext, text, ref, options)], []
72-
73-
74-
def apistruct_role(name, rawtext, text, lineno, inliner, options=None, content=None):
75-
text, value = split_text_value(text)
76-
if text is None:
77-
text = value
78-
ref = "/api/structesphome_1_1{}.html".format(encode_doxygen(value))
79-
return [make_link_node(rawtext, text, ref, options)], []
80-
81-
8227
def ghedit_role(name, rawtext, text, lineno, inliner, options=None, content=None):
8328
path = os.path.relpath(
8429
inliner.document.current_source, inliner.document.settings.env.app.srcdir
@@ -93,195 +38,12 @@ def make_link_node(rawtext, text, ref, options=None):
9338
return node
9439

9540

96-
# https://stackoverflow.com/a/3415150/8924614
97-
def grouper(n, iterable, fillvalue=None):
98-
"""Pythonic way to iterate over sequence, 4 items at a time.
99-
100-
grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
101-
"""
102-
args = [iter(iterable)] * n
103-
return zip_longest(fillvalue=fillvalue, *args)
104-
105-
106-
# Based on https://www.slideshare.net/doughellmann/better-documentation-through-automation-creating-docutils-sphinx-extensions
107-
class ImageTableDirective(Table):
108-
109-
option_spec = {
110-
"columns": directives.positive_int,
111-
}
112-
113-
def run(self):
114-
cols = self.options.get("columns", 3)
115-
116-
items = []
117-
118-
data = list(csv.reader(self.content))
119-
for row in data:
120-
if not row:
121-
continue
122-
name, page, image = row[0:3]
123-
link = page.strip()
124-
if link.startswith("http"):
125-
pass
126-
else:
127-
if not link.startswith("/"):
128-
link = "/{}".format(link)
129-
if ".html" not in link:
130-
link += ".html"
131-
category = None
132-
dark_invert = False
133-
if len(row) == 4:
134-
if row[3].strip() == "dark-invert":
135-
dark_invert = True
136-
else:
137-
category = row[3].strip()
138-
if len(row) == 5 and row[4].strip() == "dark-invert":
139-
category = row[3].strip()
140-
dark_invert = True
141-
items.append(
142-
{
143-
"name": name.strip(),
144-
"link": link,
145-
"image": "/images/{}".format(image.strip()),
146-
"category": category,
147-
"dark_invert": dark_invert,
148-
}
149-
)
150-
151-
title, messages = self.make_title()
152-
table = nodes.table()
153-
table["classes"].append("table-center")
154-
table["classes"].append("colwidths-given")
155-
156-
# Set up column specifications based on widths
157-
tgroup = nodes.tgroup(cols=cols)
158-
table += tgroup
159-
tgroup.extend(nodes.colspec(colwidth=1) for _ in range(cols))
160-
161-
tbody = nodes.tbody()
162-
tgroup += tbody
163-
rows = []
164-
for value in grouper(cols, items):
165-
trow = nodes.row()
166-
for cell in value:
167-
entry = nodes.entry()
168-
if cell is None:
169-
entry += nodes.paragraph()
170-
trow += entry
171-
continue
172-
name = cell["name"]
173-
link = cell["link"]
174-
image = cell["image"]
175-
reference_node = nodes.reference(refuri=link)
176-
img = nodes.image(uri=directives.uri(image), alt=name)
177-
img["classes"].append("component-image")
178-
if cell["dark_invert"]:
179-
img["classes"].append("dark-invert")
180-
reference_node += img
181-
para = nodes.paragraph()
182-
para += reference_node
183-
entry += para
184-
trow += entry
185-
rows.append(trow)
186-
187-
trow = nodes.row()
188-
for cell in value:
189-
entry = nodes.entry()
190-
if cell is None:
191-
entry += nodes.paragraph()
192-
trow += entry
193-
continue
194-
name = cell["name"]
195-
link = cell["link"]
196-
ref = nodes.reference(name, name, refuri=link)
197-
para = nodes.paragraph()
198-
para += ref
199-
entry += para
200-
cat_text = cell["category"]
201-
if cat_text:
202-
cat = nodes.paragraph(text=cat_text)
203-
entry += cat
204-
trow += entry
205-
rows.append(trow)
206-
tbody.extend(rows)
207-
208-
self.add_name(table)
209-
if title:
210-
table.insert(0, title)
211-
212-
return [table] + messages
213-
214-
215-
class PinTableDirective(Table):
216-
option_spec = {}
217-
218-
def run(self):
219-
items = []
220-
221-
data = list(csv.reader(self.content))
222-
for row in data:
223-
if not row:
224-
continue
225-
if len(row) == 3:
226-
items.append((row[0], row[1], True))
227-
else:
228-
items.append((row[0], row[1], False))
229-
230-
col_widths = self.get_column_widths(2)
231-
title, messages = self.make_title()
232-
table = nodes.table()
233-
234-
# Set up column specifications based on widths
235-
tgroup = nodes.tgroup(cols=2)
236-
table += tgroup
237-
tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths)
238-
239-
thead = nodes.thead()
240-
tgroup += thead
241-
trow = nodes.row()
242-
thead += trow
243-
trow.extend(
244-
nodes.entry(h, nodes.paragraph(text=h)) for h in ("Pin", "Function")
245-
)
246-
247-
tbody = nodes.tbody()
248-
tgroup += tbody
249-
for name, func, important in items:
250-
trow = nodes.row()
251-
entry = nodes.entry()
252-
para = nodes.paragraph()
253-
para += nodes.literal(text=name)
254-
entry += para
255-
trow += entry
256-
257-
entry = nodes.entry()
258-
if important:
259-
para = nodes.paragraph()
260-
para += nodes.strong(text=func)
261-
else:
262-
para = nodes.paragraph(text=func)
263-
entry += para
264-
trow += entry
265-
tbody += trow
266-
267-
self.add_name(table)
268-
if title:
269-
table.insert(0, title)
270-
271-
return [table] + messages
272-
273-
27441
def setup(app):
27542
app.add_role("libpr", libpr_role)
27643
app.add_role("corepr", libpr_role)
27744
app.add_role("yamlpr", yamlpr_role)
27845
app.add_role("esphomepr", yamlpr_role)
27946
app.add_role("docspr", docspr_role)
28047
app.add_role("ghuser", ghuser_role)
281-
app.add_role("apiref", apiref_role)
282-
app.add_role("apiclass", apiclass_role)
283-
app.add_role("apistruct", apistruct_role)
28448
app.add_role("ghedit", ghedit_role)
285-
app.add_directive("imgtable", ImageTableDirective)
286-
app.add_directive("pintable", PinTableDirective)
28749
return {"version": "1.0.0", "parallel_read_safe": True, "parallel_write_safe": True}

0 commit comments

Comments
 (0)