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) |
