Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/humanfriendly/sphinx.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 # Human friendly input/output in Python. | |
2 # | |
3 # Author: Peter Odding <peter@peterodding.com> | |
4 # Last Change: March 1, 2020 | |
5 # URL: https://humanfriendly.readthedocs.io | |
6 | |
7 """ | |
8 Customizations for and integration with the Sphinx_ documentation generator. | |
9 | |
10 The :mod:`humanfriendly.sphinx` module uses the `Sphinx extension API`_ to | |
11 customize the process of generating Sphinx based Python documentation. To | |
12 explore the functionality this module offers its best to start reading | |
13 from the :func:`setup()` function. | |
14 | |
15 .. _Sphinx: http://www.sphinx-doc.org/ | |
16 .. _Sphinx extension API: http://sphinx-doc.org/extdev/appapi.html | |
17 """ | |
18 | |
19 # Standard library modules. | |
20 import logging | |
21 import types | |
22 | |
23 # External dependencies (if Sphinx is installed docutils will be installed). | |
24 import docutils.nodes | |
25 import docutils.utils | |
26 | |
27 # Modules included in our package. | |
28 from humanfriendly.deprecation import get_aliases | |
29 from humanfriendly.text import compact, dedent, format | |
30 from humanfriendly.usage import USAGE_MARKER, render_usage | |
31 | |
32 # Public identifiers that require documentation. | |
33 __all__ = ( | |
34 "deprecation_note_callback", | |
35 "enable_deprecation_notes", | |
36 "enable_man_role", | |
37 "enable_pypi_role", | |
38 "enable_special_methods", | |
39 "enable_usage_formatting", | |
40 "logger", | |
41 "man_role", | |
42 "pypi_role", | |
43 "setup", | |
44 "special_methods_callback", | |
45 "usage_message_callback", | |
46 ) | |
47 | |
48 # Initialize a logger for this module. | |
49 logger = logging.getLogger(__name__) | |
50 | |
51 | |
52 def deprecation_note_callback(app, what, name, obj, options, lines): | |
53 """ | |
54 Automatically document aliases defined using :func:`~humanfriendly.deprecation.define_aliases()`. | |
55 | |
56 Refer to :func:`enable_deprecation_notes()` to enable the use of this | |
57 function (you probably don't want to call :func:`deprecation_note_callback()` | |
58 directly). | |
59 | |
60 This function implements a callback for ``autodoc-process-docstring`` that | |
61 reformats module docstrings to append an overview of aliases defined by the | |
62 module. | |
63 | |
64 The parameters expected by this function are those defined for Sphinx event | |
65 callback functions (i.e. I'm not going to document them here :-). | |
66 """ | |
67 if isinstance(obj, types.ModuleType) and lines: | |
68 aliases = get_aliases(obj.__name__) | |
69 if aliases: | |
70 # Convert the existing docstring to a string and remove leading | |
71 # indentation from that string, otherwise our generated content | |
72 # would have to match the existing indentation in order not to | |
73 # break docstring parsing (because indentation is significant | |
74 # in the reStructuredText format). | |
75 blocks = [dedent("\n".join(lines))] | |
76 # Use an admonition to group the deprecated aliases together and | |
77 # to distinguish them from the autodoc entries that follow. | |
78 blocks.append(".. note:: Deprecated names") | |
79 indent = " " * 3 | |
80 if len(aliases) == 1: | |
81 explanation = """ | |
82 The following alias exists to preserve backwards compatibility, | |
83 however a :exc:`~exceptions.DeprecationWarning` is triggered | |
84 when it is accessed, because this alias will be removed | |
85 in a future release. | |
86 """ | |
87 else: | |
88 explanation = """ | |
89 The following aliases exist to preserve backwards compatibility, | |
90 however a :exc:`~exceptions.DeprecationWarning` is triggered | |
91 when they are accessed, because these aliases will be | |
92 removed in a future release. | |
93 """ | |
94 blocks.append(indent + compact(explanation)) | |
95 for name, target in aliases.items(): | |
96 blocks.append(format("%s.. data:: %s", indent, name)) | |
97 blocks.append(format("%sAlias for :obj:`%s`.", indent * 2, target)) | |
98 update_lines(lines, "\n\n".join(blocks)) | |
99 | |
100 | |
101 def enable_deprecation_notes(app): | |
102 """ | |
103 Enable documenting backwards compatibility aliases using the autodoc_ extension. | |
104 | |
105 :param app: The Sphinx application object. | |
106 | |
107 This function connects the :func:`deprecation_note_callback()` function to | |
108 ``autodoc-process-docstring`` events. | |
109 | |
110 .. _autodoc: http://www.sphinx-doc.org/en/stable/ext/autodoc.html | |
111 """ | |
112 app.connect("autodoc-process-docstring", deprecation_note_callback) | |
113 | |
114 | |
115 def enable_man_role(app): | |
116 """ | |
117 Enable the ``:man:`` role for linking to Debian Linux manual pages. | |
118 | |
119 :param app: The Sphinx application object. | |
120 | |
121 This function registers the :func:`man_role()` function to handle the | |
122 ``:man:`` role. | |
123 """ | |
124 app.add_role("man", man_role) | |
125 | |
126 | |
127 def enable_pypi_role(app): | |
128 """ | |
129 Enable the ``:pypi:`` role for linking to the Python Package Index. | |
130 | |
131 :param app: The Sphinx application object. | |
132 | |
133 This function registers the :func:`pypi_role()` function to handle the | |
134 ``:pypi:`` role. | |
135 """ | |
136 app.add_role("pypi", pypi_role) | |
137 | |
138 | |
139 def enable_special_methods(app): | |
140 """ | |
141 Enable documenting "special methods" using the autodoc_ extension. | |
142 | |
143 :param app: The Sphinx application object. | |
144 | |
145 This function connects the :func:`special_methods_callback()` function to | |
146 ``autodoc-skip-member`` events. | |
147 | |
148 .. _autodoc: http://www.sphinx-doc.org/en/stable/ext/autodoc.html | |
149 """ | |
150 app.connect("autodoc-skip-member", special_methods_callback) | |
151 | |
152 | |
153 def enable_usage_formatting(app): | |
154 """ | |
155 Reformat human friendly usage messages to reStructuredText_. | |
156 | |
157 :param app: The Sphinx application object (as given to ``setup()``). | |
158 | |
159 This function connects the :func:`usage_message_callback()` function to | |
160 ``autodoc-process-docstring`` events. | |
161 | |
162 .. _reStructuredText: https://en.wikipedia.org/wiki/ReStructuredText | |
163 """ | |
164 app.connect("autodoc-process-docstring", usage_message_callback) | |
165 | |
166 | |
167 def man_role(role, rawtext, text, lineno, inliner, options={}, content=[]): | |
168 """ | |
169 Convert a Linux manual topic to a hyperlink. | |
170 | |
171 Using the ``:man:`` role is very simple, here's an example: | |
172 | |
173 .. code-block:: rst | |
174 | |
175 See the :man:`python` documentation. | |
176 | |
177 This results in the following: | |
178 | |
179 See the :man:`python` documentation. | |
180 | |
181 As the example shows you can use the role inline, embedded in sentences of | |
182 text. In the generated documentation the ``:man:`` text is omitted and a | |
183 hyperlink pointing to the Debian Linux manual pages is emitted. | |
184 """ | |
185 man_url = "https://manpages.debian.org/%s" % text | |
186 reference = docutils.nodes.reference(rawtext, docutils.utils.unescape(text), refuri=man_url, **options) | |
187 return [reference], [] | |
188 | |
189 | |
190 def pypi_role(role, rawtext, text, lineno, inliner, options={}, content=[]): | |
191 """ | |
192 Generate hyperlinks to the Python Package Index. | |
193 | |
194 Using the ``:pypi:`` role is very simple, here's an example: | |
195 | |
196 .. code-block:: rst | |
197 | |
198 See the :pypi:`humanfriendly` package. | |
199 | |
200 This results in the following: | |
201 | |
202 See the :pypi:`humanfriendly` package. | |
203 | |
204 As the example shows you can use the role inline, embedded in sentences of | |
205 text. In the generated documentation the ``:pypi:`` text is omitted and a | |
206 hyperlink pointing to the Python Package Index is emitted. | |
207 """ | |
208 pypi_url = "https://pypi.org/project/%s/" % text | |
209 reference = docutils.nodes.reference(rawtext, docutils.utils.unescape(text), refuri=pypi_url, **options) | |
210 return [reference], [] | |
211 | |
212 | |
213 def setup(app): | |
214 """ | |
215 Enable all of the provided Sphinx_ customizations. | |
216 | |
217 :param app: The Sphinx application object. | |
218 | |
219 The :func:`setup()` function makes it easy to enable all of the Sphinx | |
220 customizations provided by the :mod:`humanfriendly.sphinx` module with the | |
221 least amount of code. All you need to do is to add the module name to the | |
222 ``extensions`` variable in your ``conf.py`` file: | |
223 | |
224 .. code-block:: python | |
225 | |
226 # Sphinx extension module names. | |
227 extensions = [ | |
228 'sphinx.ext.autodoc', | |
229 'sphinx.ext.doctest', | |
230 'sphinx.ext.intersphinx', | |
231 'humanfriendly.sphinx', | |
232 ] | |
233 | |
234 When Sphinx sees the :mod:`humanfriendly.sphinx` name it will import the | |
235 module and call its :func:`setup()` function. This function will then call | |
236 the following: | |
237 | |
238 - :func:`enable_deprecation_notes()` | |
239 - :func:`enable_man_role()` | |
240 - :func:`enable_pypi_role()` | |
241 - :func:`enable_special_methods()` | |
242 - :func:`enable_usage_formatting()` | |
243 | |
244 Of course more functionality may be added at a later stage. If you don't | |
245 like that idea you may be better of calling the individual functions from | |
246 your own ``setup()`` function. | |
247 """ | |
248 enable_deprecation_notes(app) | |
249 enable_man_role(app) | |
250 enable_pypi_role(app) | |
251 enable_special_methods(app) | |
252 enable_usage_formatting(app) | |
253 | |
254 | |
255 def special_methods_callback(app, what, name, obj, skip, options): | |
256 """ | |
257 Enable documenting "special methods" using the autodoc_ extension. | |
258 | |
259 Refer to :func:`enable_special_methods()` to enable the use of this | |
260 function (you probably don't want to call | |
261 :func:`special_methods_callback()` directly). | |
262 | |
263 This function implements a callback for ``autodoc-skip-member`` events to | |
264 include documented "special methods" (method names with two leading and two | |
265 trailing underscores) in your documentation. The result is similar to the | |
266 use of the ``special-members`` flag with one big difference: Special | |
267 methods are included but other types of members are ignored. This means | |
268 that attributes like ``__weakref__`` will always be ignored (this was my | |
269 main annoyance with the ``special-members`` flag). | |
270 | |
271 The parameters expected by this function are those defined for Sphinx event | |
272 callback functions (i.e. I'm not going to document them here :-). | |
273 """ | |
274 if getattr(obj, "__doc__", None) and isinstance(obj, (types.FunctionType, types.MethodType)): | |
275 return False | |
276 else: | |
277 return skip | |
278 | |
279 | |
280 def update_lines(lines, text): | |
281 """Private helper for ``autodoc-process-docstring`` callbacks.""" | |
282 while lines: | |
283 lines.pop() | |
284 lines.extend(text.splitlines()) | |
285 | |
286 | |
287 def usage_message_callback(app, what, name, obj, options, lines): | |
288 """ | |
289 Reformat human friendly usage messages to reStructuredText_. | |
290 | |
291 Refer to :func:`enable_usage_formatting()` to enable the use of this | |
292 function (you probably don't want to call :func:`usage_message_callback()` | |
293 directly). | |
294 | |
295 This function implements a callback for ``autodoc-process-docstring`` that | |
296 reformats module docstrings using :func:`.render_usage()` so that Sphinx | |
297 doesn't mangle usage messages that were written to be human readable | |
298 instead of machine readable. Only module docstrings whose first line starts | |
299 with :data:`.USAGE_MARKER` are reformatted. | |
300 | |
301 The parameters expected by this function are those defined for Sphinx event | |
302 callback functions (i.e. I'm not going to document them here :-). | |
303 """ | |
304 # Make sure we only modify the docstrings of modules. | |
305 if isinstance(obj, types.ModuleType) and lines: | |
306 # Make sure we only modify docstrings containing a usage message. | |
307 if lines[0].startswith(USAGE_MARKER): | |
308 # Convert the usage message to reStructuredText. | |
309 text = render_usage("\n".join(lines)) | |
310 # Fill up the buffer with our modified docstring. | |
311 update_lines(lines, text) |