m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
11 KiB

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