diff --git a/.travis.yml b/.travis.yml index 7bc822d70..8aaa96ebe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,8 @@ matrix: env: TOXENV=py38 - python: '3.6' env: TOXENV=docs + - python: '3.6' + env: TOXENV=docslint - python: '3.6' env: TOXENV=mypy - python: '3.6' diff --git a/AUTHORS b/AUTHORS index aef4410be..27c51d150 100644 --- a/AUTHORS +++ b/AUTHORS @@ -82,6 +82,7 @@ Other contributors, listed alphabetically, are: * Stephen Finucane -- setup command improvements and documentation * Daniel Pizetta -- inheritance diagram improvements * KINEBUCHI Tomohiko -- typing Sphinx as well as docutils +* Adrián Chaves (Gallaecio) -- coverage builder improvements Many thanks for all contributions! diff --git a/CHANGES b/CHANGES index d2a797046..46af3b707 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,7 @@ Deprecated * ``sphinx.environment.NoUri`` * ``sphinx.ext.apidoc.format_directive()`` * ``sphinx.ext.apidoc.format_heading()`` +* ``sphinx.ext.apidoc.makename()`` * ``sphinx.ext.autodoc.importer.MockFinder`` * ``sphinx.ext.autodoc.importer.MockLoader`` * ``sphinx.ext.autodoc.importer.mock()`` @@ -106,12 +107,17 @@ Features added * #6289: autodoc: :confval:`autodoc_default_options` now supports ``imported-members`` option * #4777: autodoc: Support coroutine +* #744: autodoc: Support abstractmethod +* #6325: autodoc: Support attributes in __slots__. For dict-style __slots__, + autodoc considers values as a docstring of the attribute * #6212 autosummary: Add :confval:`autosummary_imported_members` to display imported members on autosummary * #6271: ``make clean`` is catastrophically broken if building into '.' +* #6363: Support ``%O%`` environment variable in make.bat * #4777: py domain: Add ``:async:`` option to :rst:dir:`py:function` directive * py domain: Add new options to :rst:dir:`py:method` directive + - ``:abstractmethod:`` - ``:async:`` - ``:classmethod:`` - ``:property:`` @@ -120,6 +126,10 @@ Features added * rst domain: Add :rst:dir:`directive:option` directive to describe the option for directive * #6306: html: Add a label to search form for accessability purposes +* #6358: The ``rawsource`` property of ``production`` nodes now contains the + full production rule +* #6373: autosectionlabel: Allow suppression of warnings +* coverage: Support a new ``coverage_ignore_pyobjects`` option Bugs fixed ---------- @@ -129,11 +139,18 @@ Bugs fixed * #6213: ifconfig: contents after headings are not shown * commented term in glossary directive is wrongly recognized * #6299: rst domain: rst:directive directive generates waste space +* #6379: py domain: Module index (py-modindex.html) has duplicate titles * #6331: man: invalid output when doctest follows rubric * #6351: "Hyperlink target is not referenced" message is shown even if referenced * #6165: autodoc: ``tab_width`` setting of docutils has been ignored +* #6311: autosummary: autosummary table gets confused by complex type hints +* #6350: autosummary: confused by an argument having some kind of default value * Generated Makefiles lack a final EOL (refs: #6232) +* #6375: extlinks: Cannot escape angle brackets in link caption +* #6378: linkcheck: Send commonly used User-Agent +* #6387: html search: failed to search document with haiku and scrolls themes +* #6406: Wrong year is returned for ``SOURCE_DATE_EPOCH`` Testing -------- @@ -1598,7 +1615,8 @@ Incompatible changes (refs #3550) * ``Builder.env`` is not filled at instantiation * #3594: LaTeX: single raw directive has been considered as block level element -* #3639: If ``html_experimental_html5_writer`` is available, epub builder use it by default. +* #3639: If ``html_experimental_html5_writer`` is available, epub builder use it + by default. * ``Sphinx.add_source_parser()`` raises an error if duplicated 1.6b2 @@ -1670,8 +1688,9 @@ Features added * #3476: setuptools: Support multiple builders * latex: merged cells in LaTeX tables allow code-blocks, lists, blockquotes... as do normal cells (refs: #3435) -* HTML builder uses experimental HTML5 writer if ``html_experimental_html5_writer`` is True - and docutils 0.13 or later is installed. +* HTML builder uses experimental HTML5 writer if + ``html_experimental_html5_writer`` is True and docutils 0.13 or later is + installed. * LaTeX macros to customize space before and after tables in PDF output (refs #3504) * #3348: Show decorators in literalinclude and viewcode directives * #3108: Show warning if :start-at: and other literalinclude options does not @@ -1710,7 +1729,8 @@ Bugs fixed * #1574: Paragraphs in table cell doesn't work in Latex output * #3288: Table with merged headers not wrapping text * #3491: Inconsistent vertical space around table and longtable in PDF -* #3506: Depart functions for all admonitions in HTML writer now properly pass ``node`` to ``depart_admonition``. +* #3506: Depart functions for all admonitions in HTML writer now properly pass + ``node`` to ``depart_admonition``. * #2693: Sphinx latex style file wrongly inhibits colours for section headings for latex+dvi(ps,pdf,pdfmx) * C++, properly look up ``any`` references. @@ -2036,18 +2056,23 @@ Incompatible changes ``jreport`` and ``jsbook`` as docclass if :confval:`language` is ``ja``. * ``sphinx-quickstart`` now allows a project version is empty -* Fix :download: role on epub/qthelp builder. They ignore the role because they don't support it. -* ``sphinx.ext.viewcode`` doesn't work on epub building by default. ``viewcode_enable_epub`` option +* Fix :download: role on epub/qthelp builder. They ignore the role because they + don't support it. +* ``sphinx.ext.viewcode`` doesn't work on epub building by default. + ``viewcode_enable_epub`` option * ``sphinx.ext.viewcode`` disabled on singlehtml builder. * Use make-mode of ``sphinx-quickstart`` by default. To disable this, use ``-M`` option -* Fix ``genindex.html``, Sphinx's document template, link address to itself to satisfy xhtml standard. +* Fix ``genindex.html``, Sphinx's document template, link address to itself to + satisfy xhtml standard. * Use epub3 builder by default. And the old epub builder is renamed to epub2. -* Fix ``epub`` and ``epub3`` builders that contained links to ``genindex`` even if ``epub_use_index = False``. +* Fix ``epub`` and ``epub3`` builders that contained links to ``genindex`` even + if ``epub_use_index = False``. * ``html_translator_class`` is now deprecated. Use `Sphinx.set_translator()` API instead. * Drop python 2.6 and 3.3 support -* Drop epub3 builder's ``epub3_page_progression_direction`` option (use ``epub3_writing_mode``). +* Drop epub3 builder's ``epub3_page_progression_direction`` option (use + ``epub3_writing_mode``). * #2877: Rename ``latex_elements['footer']`` to ``latex_elements['atendofbody']`` @@ -2301,7 +2326,8 @@ Bugs fixed * #3068: Allow the '=' character in the -D option of sphinx-build.py * #3074: ``add_source_parser()`` crashes in debug mode * #3135: ``sphinx.ext.autodoc`` crashes with plain Callable -* #3150: Fix query word splitter in JavaScript. It behaves as same as Python's regular expression. +* #3150: Fix query word splitter in JavaScript. It behaves as same as Python's + regular expression. * #3093: gettext build broken on substituted images. * #3093: gettext build broken on image node under ``note`` directive. * imgmath: crashes on showing error messages if image generation failed @@ -2329,10 +2355,13 @@ Bugs fixed * #2902: jsdump.loads fails to load search index if keywords starts with underscore * #2900: Fix epub content.opf: add auto generated orphan files to spine. -* #2899: Fix ``hasdoc()`` function in Jinja2 template. It will detect ``genindex``, ``search`` also. -* #2901: Fix epub result: skip creating links from image tags to original image files. +* #2899: Fix ``hasdoc()`` function in Jinja2 template. It will detect + ``genindex``, ``search`` also. +* #2901: Fix epub result: skip creating links from image tags to original image + files. * #2917: inline code is hyphenated on HTML -* #1462: autosummary warns for namedtuple with attribute with trailing underscore +* #1462: autosummary warns for namedtuple with attribute with trailing + underscore * Could not reference equations if ``:nowrap:`` option specified * #2873: code-block overflow in latex (due to commas) * #1060, #2056: sphinx.ext.intersphinx: broken links are generated if relative @@ -2349,29 +2378,35 @@ Release 1.4.6 (released Aug 20, 2016) Incompatible changes -------------------- -* #2867: linkcheck builder crashes with six-1.4. Now Sphinx depends on six-1.5 or - later +* #2867: linkcheck builder crashes with six-1.4. Now Sphinx depends on six-1.5 + or later Bugs fixed ---------- * applehelp: Sphinx crashes if ``hiutil`` or ``codesign`` commands not found -* Fix ``make clean`` abort issue when build dir contains regular files like ``DS_Store``. +* Fix ``make clean`` abort issue when build dir contains regular files like + ``DS_Store``. * Reduce epubcheck warnings/errors: * Fix DOCTYPE to html5 * Change extension from .html to .xhtml. * Disable search page on epub results -* #2778: Fix autodoc crashes if obj.__dict__ is a property method and raises exception +* #2778: Fix autodoc crashes if obj.__dict__ is a property method and raises + exception * Fix duplicated toc in epub3 output. * #2775: Fix failing linkcheck with servers not supporting identity encoding * #2833: Fix formatting instance annotations in ext.autodoc. -* #1911: ``-D`` option of ``sphinx-build`` does not override the ``extensions`` variable -* #2789: `sphinx.ext.intersphinx` generates wrong hyperlinks if the inventory is given -* parsing errors for caption of code-blocks are displayed in document (ref: #2845) +* #1911: ``-D`` option of ``sphinx-build`` does not override the ``extensions`` + variable +* #2789: `sphinx.ext.intersphinx` generates wrong hyperlinks if the inventory is + given +* parsing errors for caption of code-blocks are displayed in document + (ref: #2845) * #2846: ``singlehtml`` builder does not include figure numbers -* #2816: Fix data from builds cluttering the ``Domain.initial_data`` class attributes +* #2816: Fix data from builds cluttering the ``Domain.initial_data`` class + attributes Release 1.4.5 (released Jul 13, 2016) ===================================== @@ -2400,7 +2435,8 @@ Bugs fixed * jsdump fix for python 3: fixes the HTML search on python > 3 * #2676: (latex) Error with verbatim text in captions since Sphinx 1.4.4 -* #2629: memoir class crashes LaTeX. Fixed ``by latex_keep_old_macro_names=False`` (ref 2675) +* #2629: memoir class crashes LaTeX. Fixed by + ``latex_keep_old_macro_names=False`` (ref 2675) * #2684: `sphinx.ext.intersphinx` crashes with six-1.4.1 * #2679: ``float`` package needed for ``'figure_align': 'H'`` latex option * #2671: image directive may lead to inconsistent spacing in pdf @@ -2408,10 +2444,12 @@ Bugs fixed * #2479: `sphinx.ext.viewcode` uses python2 highlighter by default * #2700: HtmlHelp builder has hard coded index.html * latex, since 1.4.4 inline literal text is followed by spurious space -* #2722: C++, fix id generation for var/member declarations to include namespaces. +* #2722: C++, fix id generation for var/member declarations to include + namespaces. * latex, images (from image directive) in lists or quoted blocks did not obey indentation (fixed together with #2671) -* #2733: since Sphinx-1.4.4 ``make latexpdf`` generates lots of hyperref warnings +* #2733: since Sphinx-1.4.4 ``make latexpdf`` generates lots of hyperref + warnings * #2731: `sphinx.ext.autodoc` does not access propertymethods which raises any exceptions * #2666: C++, properly look up nested names involving constructors. @@ -2459,13 +2497,16 @@ Bugs fixed * #2530: got "Counter too large" error on building PDF if large numbered footnotes existed in admonitions -* ``width`` option of figure directive does not work if ``align`` option specified at same time (ref: #2595) +* ``width`` option of figure directive does not work if ``align`` option + specified at same time (ref: #2595) * #2590: The ``inputenc`` package breaks compiling under lualatex and xelatex * #2540: date on latex front page use different font -* Suppress "document isn't included in any toctree" warning if the document is included (ref: #2603) +* Suppress "document isn't included in any toctree" warning if the document is + included (ref: #2603) * #2614: Some tables in PDF output will end up shifted if user sets non zero \parindent in preamble -* #2602: URL redirection breaks the hyperlinks generated by `sphinx.ext.intersphinx` +* #2602: URL redirection breaks the hyperlinks generated by + `sphinx.ext.intersphinx` * #2613: Show warnings if merged extensions are loaded * #2619: make sure amstext LaTeX package always loaded (ref: d657225, 488ee52, 9d82cad and #2615) @@ -2478,7 +2519,8 @@ Release 1.4.2 (released May 29, 2016) Features added -------------- -* Now :confval:`suppress_warnings` accepts following configurations (ref: #2451, #2466): +* Now :confval:`suppress_warnings` accepts following configurations + (ref: #2451, #2466): - ``app.add_node`` - ``app.add_directive`` @@ -2505,14 +2547,17 @@ Bugs fixed * #2370: the equations are slightly misaligned in LaTeX writer * #1817, #2077: suppress pep8 warnings on conf.py generated by sphinx-quickstart * #2407: building docs crash if document includes large data image URIs -* #2436: Sphinx does not check version by :confval:`needs_sphinx` if loading extensions failed +* #2436: Sphinx does not check version by :confval:`needs_sphinx` if loading + extensions failed * #2397: Setup shorthandoff for Turkish documents * #2447: VerbatimBorderColor wrongly used also for captions of PDF -* #2456: C++, fix crash related to document merging (e.g., singlehtml and Latex builders). +* #2456: C++, fix crash related to document merging (e.g., singlehtml and Latex + builders). * #2446: latex(pdf) sets local tables of contents (or more generally topic nodes) in unbreakable boxes, causes overflow at bottom * #2476: Omit MathJax markers if :nowrap: is given -* #2465: latex builder fails in case no caption option is provided to toctree directive +* #2465: latex builder fails in case no caption option is provided to toctree + directive * Sphinx crashes if self referenced toctree found * #2481: spelling mistake for mecab search splitter. Thanks to Naoki Sato. * #2309: Fix could not refer "indirect hyperlink targets" by ref-role @@ -2522,22 +2567,28 @@ Bugs fixed * #1534: Word wrap long lines in Latex verbatim blocks * #2460: too much white space on top of captioned literal blocks in PDF output * Show error reason when multiple math extensions are loaded (ref: #2499) -* #2483: any figure number was not assigned if figure title contains only non text objects +* #2483: any figure number was not assigned if figure title contains only non + text objects * #2501: Unicode subscript numbers are normalized in LaTeX * #2492: Figure directive with :figwidth: generates incorrect Latex-code -* The caption of figure is always put on center even if ``:align:`` was specified +* The caption of figure is always put on center even if ``:align:`` was + specified * #2526: LaTeX writer crashes if the section having only images -* #2522: Sphinx touches mo files under installed directory that caused permission error. -* #2536: C++, fix crash when an immediately nested scope has the same name as the current scope. +* #2522: Sphinx touches mo files under installed directory that caused + permission error. +* #2536: C++, fix crash when an immediately nested scope has the same name as + the current scope. * #2555: Fix crash on any-references with unicode. * #2517: wrong bookmark encoding in PDF if using LuaLaTeX * #2521: generated Makefile causes BSD make crashed if sphinx-build not found * #2470: ``typing`` backport package causes autodoc errors with python 2.7 -* ``sphinx.ext.intersphinx`` crashes if non-string value is used for key of `intersphinx_mapping` +* ``sphinx.ext.intersphinx`` crashes if non-string value is used for key of + `intersphinx_mapping` * #2518: `intersphinx_mapping` disallows non alphanumeric keys * #2558: unpack error on devhelp builder * #2561: Info builder crashes when a footnote contains a link -* #2565: The descriptions of objects generated by ``sphinx.ext.autosummary`` overflow lines at LaTeX writer +* #2565: The descriptions of objects generated by ``sphinx.ext.autosummary`` + overflow lines at LaTeX writer * Extend pdflatex config in sphinx.sty to subparagraphs (ref: #2551) * #2445: `rst_prolog` and `rst_epilog` affect to non reST sources * #2576: ``sphinx.ext.imgmath`` crashes if subprocess raises error @@ -2572,8 +2623,8 @@ Bugs fixed ---------- * C++, added support for ``extern`` and ``thread_local``. -* C++, type declarations are now using the prefixes ``typedef``, ``using``, and ``type``, - depending on the style of declaration. +* C++, type declarations are now using the prefixes ``typedef``, ``using``, and + ``type``, depending on the style of declaration. * #2413: C++, fix crash on duplicate declarations * #2394: Sphinx crashes when html_last_updated_fmt is invalid * #2408: dummy builder not available in Makefile and make.bat @@ -2592,27 +2643,28 @@ Release 1.4 (released Mar 28, 2016) Incompatible changes -------------------- -* Drop ``PorterStemmer`` package support. Use ``PyStemmer`` instead of ``PorterStemmer`` - to accelerate stemming. +* Drop ``PorterStemmer`` package support. Use ``PyStemmer`` instead of + ``PorterStemmer`` to accelerate stemming. * sphinx_rtd_theme has become optional. Please install it manually. Refs #2087, #2086, #1845 and #2097. Thanks to Victor Zverovich. -* #2231: Use DUrole instead of DUspan for custom roles in LaTeX writer. It enables to take - title of roles as an argument of custom macros. -* #2022: 'Thumbs.db' and '.DS_Store' are added to `exclude_patterns` default values in - conf.py that will be provided on sphinx-quickstart. -* #2027, #2208: The ``html_title`` accepts string values only. And The None value cannot be - accepted. +* #2231: Use DUrole instead of DUspan for custom roles in LaTeX writer. It + enables to take title of roles as an argument of custom macros. +* #2022: 'Thumbs.db' and '.DS_Store' are added to `exclude_patterns` default + values in conf.py that will be provided on sphinx-quickstart. +* #2027, #2208: The ``html_title`` accepts string values only. And The None + value cannot be accepted. * ``sphinx.ext.graphviz``: show graph image in inline by default -* #2060, #2224: The ``manpage`` role now generate ``sphinx.addnodes.manpage`` node instead - of ``sphinx.addnodes.literal_emphasis`` node. -* #2022: :confval:`html_extra_path` also copies dotfiles in the extra directory, and - refers to :confval:`exclude_patterns` to exclude extra files and directories. -* #2300: enhance autoclass:: to use the docstring of __new__ if __init__ method's is missing - of empty -* #2251: Previously, under glossary directives, multiple terms for one definition are - converted into single ``term`` node and the each terms in the term node are separated - by ``termsep`` node. In new implementation, each terms are converted into individual - ``term`` nodes and ``termsep`` node is removed. +* #2060, #2224: The ``manpage`` role now generate ``sphinx.addnodes.manpage`` + node instead of ``sphinx.addnodes.literal_emphasis`` node. +* #2022: :confval:`html_extra_path` also copies dotfiles in the extra directory, + and refers to :confval:`exclude_patterns` to exclude extra files and + directories. +* #2300: enhance autoclass:: to use the docstring of __new__ if __init__ + method's is missing of empty +* #2251: Previously, under glossary directives, multiple terms for one + definition are converted into single ``term`` node and the each terms in the + term node are separated by ``termsep`` node. In new implementation, each terms + are converted into individual ``term`` nodes and ``termsep`` node is removed. By this change, output layout of every builders are changed a bit. * The default highlight language is now Python 3. This means that source code is highlighted as Python 3 (which is mostly a superset of Python 2), and no @@ -2620,13 +2672,15 @@ Incompatible changes add ``highlight_language = "python"`` to conf.py. * `Locale Date Markup Language `_ like - ``"MMMM dd, YYYY"`` is default format for `today_fmt` and `html_last_updated_fmt`. - However strftime format like ``"%B %d, %Y"`` is also supported for backward - compatibility until Sphinx-1.5. Later format will be disabled from Sphinx-1.5. + ``"MMMM dd, YYYY"`` is default format for `today_fmt` and + `html_last_updated_fmt`. However strftime format like ``"%B %d, %Y"`` is also + supported for backward compatibility until Sphinx-1.5. Later format will be + disabled from Sphinx-1.5. * #2327: ``latex_use_parts`` is deprecated now. Use `latex_toplevel_sectioning` instead. * #2337: Use ``\url{URL}`` macro instead of ``\href{URL}{URL}`` in LaTeX writer. -* #1498: manpage writer: don't make whole of item in definition list bold if it includes strong node. +* #1498: manpage writer: don't make whole of item in definition list bold if it + includes strong node. * #582: Remove hint message from quick search box for html output. * #2378: Sphinx now bundles newfloat.sty @@ -2637,8 +2691,10 @@ Features added an element is already present (built-in or added by another extension). * #1909: Add "doc" references to Intersphinx inventories. * C++ type alias support (e.g., ``.. type:: T = int``). -* C++ template support for classes, functions, type aliases, and variables (#1729, #1314). -* C++, added new scope management directives ``namespace-push`` and ``namespace-pop``. +* C++ template support for classes, functions, type aliases, and variables + (#1729, #1314). +* C++, added new scope management directives ``namespace-push`` and + ``namespace-pop``. * #1970: Keyboard shortcuts to navigate Next and Previous topics * Intersphinx: Added support for fetching Intersphinx inventories with URLs using HTTP basic auth. @@ -2652,43 +2708,54 @@ Features added * #2170: Support for Chinese language search index. * #2214: Add sphinx.ext.githubpages to publish the docs on GitHub Pages * #1030: Make page reference names for latex_show_pagerefs translatable -* #2162: Add Sphinx.add_source_parser() to add source_suffix and source_parsers from extension +* #2162: Add Sphinx.add_source_parser() to add source_suffix and source_parsers + from extension * #2207: Add sphinx.parsers.Parser class; a base class for new parsers -* #656: Add ``graphviz_dot`` option to graphviz directives to switch the ``dot`` command +* #656: Add ``graphviz_dot`` option to graphviz directives to switch the ``dot`` + command * #1939: Added the ``dummy`` builder: syntax check without output. -* #2230: Add ``math_number_all`` option to number all displayed math in math extensions +* #2230: Add ``math_number_all`` option to number all displayed math in math + extensions * #2235: ``needs_sphinx`` supports micro version comparison * #2282: Add "language" attribute to html tag in the "basic" theme * #1779: Add EPUB 3 builder * #1751: Add :confval:`todo_link_only` to avoid file path and line indication on :rst:dir:`todolist`. Thanks to Francesco Montesano. * #2199: Use ``imagesize`` package to obtain size of images. -* #1099: Add configurable retries to the linkcheck builder. Thanks to Alex Gaynor. - Also don't check anchors starting with ``!``. -* #2300: enhance autoclass:: to use the docstring of __new__ if __init__ method's is missing - of empty -* #1858: Add Sphinx.add_enumerable_node() to add enumerable nodes for numfig feature +* #1099: Add configurable retries to the linkcheck builder. Thanks to Alex + Gaynor. Also don't check anchors starting with ``!``. +* #2300: enhance autoclass:: to use the docstring of __new__ if __init__ + method's is missing of empty +* #1858: Add Sphinx.add_enumerable_node() to add enumerable nodes for numfig + feature * #1286, #2099: Add ``sphinx.ext.autosectionlabel`` extension to allow reference sections using its title. Thanks to Tadhg O'Higgins. * #1854: Allow to choose Janome for Japanese splitter. * #1853: support custom text splitter on html search with ``language='ja'``. -* #2320: classifier of glossary terms can be used for index entries grouping key. - The classifier also be used for translation. See also :ref:`glossary-directive`. -* #2308: Define ``\tablecontinued`` macro to redefine the style of continued label for - longtables. -* Select an image by similarity if multiple images are globbed by ``.. image:: filename.*`` -* #1921: Support figure substitutions by :confval:`language` and :confval:`figure_language_filename` -* #2245: Add ``latex_elements["passoptionstopackages"]`` option to call PassOptionsToPackages - in early stage of preambles. +* #2320: classifier of glossary terms can be used for index entries grouping key + The classifier also be used for translation. See also + :ref:`glossary-directive`. +* #2308: Define ``\tablecontinued`` macro to redefine the style of continued + label for longtables. +* Select an image by similarity if multiple images are globbed by + ``.. image:: filename.*`` +* #1921: Support figure substitutions by :confval:`language` and + :confval:`figure_language_filename` +* #2245: Add ``latex_elements["passoptionstopackages"]`` option to call + PassOptionsToPackages in early stage of preambles. * #2340: Math extension: support alignment of multiple equations for MathJax. -* #2338: Define ``\titleref`` macro to redefine the style of ``title-reference`` roles. -* Define ``\menuselection`` and ``\accelerator`` macros to redefine the style of `menuselection` roles. +* #2338: Define ``\titleref`` macro to redefine the style of ``title-reference`` + roles. +* Define ``\menuselection`` and ``\accelerator`` macros to redefine the style of + `menuselection` roles. * Define ``\crossref`` macro to redefine the style of references * #2301: Texts in the classic html theme should be hyphenated. * #2355: Define ``\termref`` macro to redefine the style of ``term`` roles. -* Add :confval:`suppress_warnings` to suppress arbitrary warning message (experimental) +* Add :confval:`suppress_warnings` to suppress arbitrary warning message + (experimental) * #2229: Fix no warning is given for unknown options -* #2327: Add `latex_toplevel_sectioning` to switch the top level sectioning of LaTeX document. +* #2327: Add `latex_toplevel_sectioning` to switch the top level sectioning of + LaTeX document. Bugs fixed ---------- @@ -2715,14 +2782,16 @@ Bugs fixed * #794: Fix date formatting in latex output is not localized * Remove ``image/gif`` from supported_image_types of LaTeX writer (#2272) * Fix ValueError is raised if LANGUAGE is empty string -* Fix unpack warning is shown when the directives generated from ``Sphinx.add_crossref_type`` is used +* Fix unpack warning is shown when the directives generated from + ``Sphinx.add_crossref_type`` is used * The default highlight language is now ``default``. This means that source code is highlighted as Python 3 (which is mostly a superset of Python 2) if possible. To get the old behavior back, add ``highlight_language = "python"`` to conf.py. * #2329: Refresh environment forcedly if source directory has changed. * #2331: Fix code-blocks are filled by block in dvi; remove ``xcdraw`` option from xcolor package -* Fix the confval type checker emits warnings if unicode is given to confvals which expects string value +* Fix the confval type checker emits warnings if unicode is given to confvals + which expects string value * #2360: Fix numref in LaTeX output is broken * #2361: Fix additional paragraphs inside the "compound" directive are indented * #2364: Fix KeyError 'rootSymbol' on Sphinx upgrade from older version. @@ -2760,13 +2829,16 @@ Bugs fixed * #2265: Fix babel is used in spite of disabling it on ``latex_elements`` * #2295: Avoid mutating dictionary errors while enumerating members in autodoc with Python 3 -* #2291: Fix pdflatex "Counter too large" error from footnotes inside tables of contents +* #2291: Fix pdflatex "Counter too large" error from footnotes inside tables of + contents * #2292: Fix some footnotes disappear from LaTeX output -* #2287: ``sphinx.transforms.Locale`` always uses rst parser. Sphinx i18n feature should - support parsers that specified source_parsers. -* #2290: Fix ``sphinx.ext.mathbase`` use of amsfonts may break user choice of math fonts +* #2287: ``sphinx.transforms.Locale`` always uses rst parser. Sphinx i18n + feature should support parsers that specified source_parsers. +* #2290: Fix ``sphinx.ext.mathbase`` use of amsfonts may break user choice of + math fonts * #2324: Print a hint how to increase the recursion limit when it is hit. -* #1565, #2229: Revert new warning; the new warning will be triggered from version 1.4 on. +* #1565, #2229: Revert new warning; the new warning will be triggered from + version 1.4 on. * #2329: Refresh environment forcedly if source directory has changed. * #2019: Fix the domain objects in search result are not escaped @@ -2808,20 +2880,23 @@ Bugs fixed * #2168: Fix raw directive does not work for text writer * #2171: Fix cannot linkcheck url with unicode * #2182: LaTeX: support image file names with more than 1 dots -* #2189: Fix previous sibling link for first file in subdirectory uses last file, not - intended previous from root toctree +* #2189: Fix previous sibling link for first file in subdirectory uses last + file, not intended previous from root toctree * #2003: Fix decode error under python2 (only) when ``make linkcheck`` is run * #2186: Fix LaTeX output of \mathbb in math * #1480, #2188: LaTeX: Support math in section titles * #2071: Fix same footnote in more than two section titles => LaTeX/PDF Bug -* #2040: Fix UnicodeDecodeError in sphinx-apidoc when author contains non-ascii characters -* #2193: Fix shutil.SameFileError if source directory and destination directory are same -* #2178: Fix unparsable C++ cross-reference when referencing a function with :cpp:any: +* #2040: Fix UnicodeDecodeError in sphinx-apidoc when author contains non-ascii + characters +* #2193: Fix shutil.SameFileError if source directory and destination directory + are same +* #2178: Fix unparsable C++ cross-reference when referencing a function with + :cpp:any: * #2206: Fix Sphinx latex doc build failed due to a footnotes * #2201: Fix wrong table caption for tables with over 30 rows * #2213: Set
in the classic theme to fit with

-* #1815: Fix linkcheck does not raise an exception if warniserror set to true and link is - broken +* #1815: Fix linkcheck does not raise an exception if warniserror set to true + and link is broken * #2197: Fix slightly cryptic error message for missing index.rst file * #1894: Unlisted phony targets in quickstart Makefile * #2125: Fix unifies behavior of collapsed fields (``GroupedField`` and ``TypedField``) @@ -2900,36 +2975,40 @@ Bugs fixed * #1923: Use babel features only if the babel latex element is nonempty. * #1942: Fix a KeyError in websupport. * #1903: Fix strange id generation for glossary terms. -* ``make text`` will crush if a definition list item has more than 1 classifiers as: - ``term : classifier1 : classifier2``. -* #1855: make gettext generates broken po file for definition lists with classifier. -* #1869: Fix problems when dealing with files containing non-ASCII characters. Thanks to - Marvin Schmidt. +* ``make text`` will crush if a definition list item has more than 1 classifiers + as: ``term : classifier1 : classifier2``. +* #1855: make gettext generates broken po file for definition lists with + classifier. +* #1869: Fix problems when dealing with files containing non-ASCII characters. + Thanks to Marvin Schmidt. * #1798: Fix building LaTeX with references in titles. * #1725: On py2 environment, doctest with using non-ASCII characters causes ``'ascii' codec can't decode byte`` exception. * #1540: Fix RuntimeError with circular referenced toctree * #1983: i18n translation feature breaks references which uses section name. * #1990: Use caption of toctree to title of \tableofcontents in LaTeX -* #1987: Fix ampersand is ignored in ``:menuselection:`` and ``:guilabel:`` on LaTeX builder -* #1994: More supporting non-standard parser (like recommonmark parser) for Translation and - WebSupport feature. Now node.rawsource is fall backed to node.astext() during docutils - transforming. -* #1989: "make blahblah" on Windows indicate help messages for sphinx-build every time. - It was caused by wrong make.bat that generated by Sphinx-1.3.0/1.3.1. -* On Py2 environment, conf.py that is generated by sphinx-quickstart should have u prefixed - config value for 'version' and 'release'. +* #1987: Fix ampersand is ignored in ``:menuselection:`` and ``:guilabel:`` + on LaTeX builder +* #1994: More supporting non-standard parser (like recommonmark parser) for + Translation and WebSupport feature. Now node.rawsource is fall backed to + node.astext() during docutils transforming. +* #1989: "make blahblah" on Windows indicate help messages for sphinx-build + every time. It was caused by wrong make.bat that generated by + Sphinx-1.3.0/1.3.1. +* On Py2 environment, conf.py that is generated by sphinx-quickstart should have + u prefixed config value for 'version' and 'release'. * #2102: On Windows + Py3, using ``|today|`` and non-ASCII date format will raise UnicodeEncodeError. -* #1974: UnboundLocalError: local variable 'domain' referenced before assignment when - using `any` role and `sphinx.ext.intersphinx` in same time. -* #2121: multiple words search doesn't find pages when words across on the page title and - the page content. -* #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks to - Suzumizaki. +* #1974: UnboundLocalError: local variable 'domain' referenced before assignment + when using `any` role and `sphinx.ext.intersphinx` in same time. +* #2121: multiple words search doesn't find pages when words across on the page + title and the page content. +* #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks + to Suzumizaki. * #1818: `sphinx.ext.todo` directive generates broken html class attribute as - 'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like - 'ru' or 'ja'. To fix this, now ``todo`` directive can use ``:class:`` option. + 'admonition-' when :confval:`language` is specified with non-ASCII linguistic + area like 'ru' or 'ja'. To fix this, now ``todo`` directive can use + ``:class:`` option. * #2140: Fix footnotes in table has broken in LaTeX * #2127: MecabBinder for html searching feature doesn't work with Python 3. Thanks to Tomoko Uchida. @@ -2993,8 +3072,8 @@ Bugs fixed begin with -, / or +. Thanks to Takayuki Hirai. * #1753: C++, added missing support for more complex declarations. * #1700: Add ``:caption:`` option for :rst:dir:`toctree`. -* #1742: ``:name:`` option is provided for :rst:dir:`toctree`, :rst:dir:`code-block` and - :rst:dir:`literalinclude` directives. +* #1742: ``:name:`` option is provided for :rst:dir:`toctree`, :rst:dir:`code-block` + and :rst:dir:`literalinclude` directives. * #1756: Incorrect section titles in search that was introduced from 1.3b3. * #1746: C++, fixed name lookup procedure, and added missing lookups in declarations. * #1765: C++, fix old id generation to use fully qualified names. diff --git a/doc/develop.rst b/doc/develop.rst index 3828b709d..0612c7113 100644 --- a/doc/develop.rst +++ b/doc/develop.rst @@ -46,7 +46,8 @@ This is the current list of contributed extensions in that repository: - coffeedomain: a domain for (auto)documenting CoffeeScript source code - context: a builder for ConTeXt - disqus: embed Disqus comments in documents -- documentedlist: converts a Python list to a table in the generated documentation +- documentedlist: converts a Python list to a table in the generated + documentation - doxylink: Link to external Doxygen-generated HTML documentation - domaintools_: A tool for easy domain creation - email: obfuscate email addresses @@ -76,7 +77,8 @@ This is the current list of contributed extensions in that repository: - nicovideo: embed videos from nicovideo - nwdiag: embed network diagrams by using nwdiag_ - omegat: support tools to collaborate with OmegaT_ (Sphinx 1.1 needed) -- osaka: convert standard Japanese doc to Osaka dialect (this is a joke extension) +- osaka: convert standard Japanese doc to Osaka dialect (this is a joke + extension) - paverutils: an alternate integration of Sphinx with Paver_ - phpdomain: an extension for PHP support - plantuml: embed UML diagram by using PlantUML_ @@ -96,7 +98,8 @@ This is the current list of contributed extensions in that repository: - sword: an extension inserting Bible verses from Sword_ - tikz: draw pictures with the `TikZ/PGF LaTeX package`_ - traclinks: create TracLinks_ to a Trac_ instance from within Sphinx -- versioning: Sphinx extension that allows building versioned docs for self-hosting +- versioning: Sphinx extension that allows building versioned docs for + self-hosting - whooshindex: whoosh indexer extension - youtube: embed videos from YouTube_ - zopeext: provide an ``autointerface`` directive for using `Zope interfaces`_ diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index 18eea34e7..46540595f 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -145,9 +145,9 @@ Sphinx core events ------------------ These events are known to the core. The arguments shown are given to the -registered event handlers. Use :meth:`.Sphinx.connect` in an extension's ``setup`` -function (note that ``conf.py`` can also have a ``setup`` function) to connect -handlers to the events. Example: +registered event handlers. Use :meth:`.Sphinx.connect` in an extension's +``setup`` function (note that ``conf.py`` can also have a ``setup`` function) to +connect handlers to the events. Example: .. code-block:: python diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index 2ecb1e2e7..38fae288c 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -171,6 +171,11 @@ The following is a list of deprecated interfaces. - 4.0 - N/A + * - ``sphinx.ext.apidoc.makename()`` + - 2.1 + - 4.0 + - ``sphinx.ext.apidoc.module_join()`` + * - ``sphinx.ext.autodoc.importer.MockFinder`` - 2.1 - 4.0 @@ -1066,7 +1071,9 @@ The following is a list of deprecated interfaces. * - ``sphinx.websupport`` - 1.6 - 2.0 - - `sphinxcontrib-websupport `_ + - `sphinxcontrib-websupport`_ + + .. _sphinxcontrib-websupport: https://pypi.org/project/sphinxcontrib-websupport/ * - ``StandaloneHTMLBuilder.css_files`` - 1.6 diff --git a/doc/extdev/logging.rst b/doc/extdev/logging.rst index b66f11dbb..e6c4dc66d 100644 --- a/doc/extdev/logging.rst +++ b/doc/extdev/logging.rst @@ -56,8 +56,8 @@ Logging API :meth:`SphinxLoggerAdapter.warning`. **color** - The color of logs. By default, info and verbose level logs are not colored, - and debug level ones are colored as ``"darkgray"``. + The color of logs. By default, info and verbose level logs are not + colored, and debug level ones are colored as ``"darkgray"``. .. autofunction:: pending_logging() diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index fc25c2327..7a21f8126 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -138,8 +138,8 @@ Both APIs parse the content into a given node. They are used like this:: .. deprecated:: 1.7 - Until Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this purpose. - For now, it is replaced by ``switch_source_input()``. + Until Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this + purpose. For now, it is replaced by ``switch_source_input()``. If you don't need the wrapping node, you can use any concrete node type and return ``node.children`` from the Directive. diff --git a/doc/faq.rst b/doc/faq.rst index cd5eb26c8..a1d9ddd91 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -37,9 +37,6 @@ How do I... You'll still need to mark up classes and such, but the headings and code examples come through cleanly. -... create HTML slides from Sphinx documents? - See the "Hieroglyph" package at https://github.com/nyergler/hieroglyph. - For many more extensions and other contributed stuff, see the sphinx-contrib_ repository. @@ -83,7 +80,8 @@ GitHub Pages Sphinx HTML output properly. MediaWiki - See https://bitbucket.org/kevindunn/sphinx-wiki/wiki/Home, a project by Kevin Dunn. + See https://bitbucket.org/kevindunn/sphinx-wiki/wiki/Home, a project by + Kevin Dunn. Google Analytics You can use a custom ``layout.html`` template, like this: diff --git a/doc/intro.rst b/doc/intro.rst index 622d16b83..f6f6218bd 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -17,10 +17,10 @@ docs have a look at `Epydoc `_, which also understands reST. For a great "introduction" to writing docs in general -- the whys and hows, see -also `Write the docs `_, written by Eric -Holscher. +also `Write the docs`_, written by Eric Holscher. .. _rinohtype: https://github.com/brechtm/rinohtype +.. _Write the docs: http://www.writethedocs.org/guide/writing/beginners-guide-to-docs/ Conversion from other systems ----------------------------- diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index 384374aa9..aef497e0d 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -4,7 +4,8 @@ sphinx-apidoc Synopsis -------- -**sphinx-apidoc** [*OPTIONS*] -o <*OUTPUT_PATH*> <*MODULE_PATH*> [*EXCLUDE_PATTERN*, ...] +**sphinx-apidoc** [*OPTIONS*] -o <*OUTPUT_PATH*> <*MODULE_PATH*> +[*EXCLUDE_PATTERN*, ...] Description ----------- diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 5ec53cf7f..1ef0e07dc 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -302,7 +302,8 @@ variables to customize behavior: .. describe:: SPHINXOPTS - Additional options for :program:`sphinx-build`. + Additional options for :program:`sphinx-build`. These options can + also be set via the shortcut variable **O** (capital 'o'). .. _when-deprecation-warnings-are-displayed: diff --git a/doc/theming.rst b/doc/theming.rst index 4d4af4d90..e2ef1fcf2 100644 --- a/doc/theming.rst +++ b/doc/theming.rst @@ -49,8 +49,9 @@ Python :mod:`ConfigParser` module) and has the following structure: * The **inherit** setting gives the name of a "base theme", or ``none``. The base theme will be used to locate missing templates (most themes will not have to supply most templates if they use ``basic`` as the base theme), its options - will be inherited, and all of its static files will be used as well. If you want - to also inherit the stylesheet, include it via CSS' ``@import`` in your own. + will be inherited, and all of its static files will be used as well. If you + want to also inherit the stylesheet, include it via CSS' ``@import`` in your + own. * The **stylesheet** setting gives the name of a CSS file which will be referenced in the HTML header. If you need more than one CSS file, either diff --git a/doc/usage/advanced/websupport/quickstart.rst b/doc/usage/advanced/websupport/quickstart.rst index de7692231..a55080339 100644 --- a/doc/usage/advanced/websupport/quickstart.rst +++ b/doc/usage/advanced/websupport/quickstart.rst @@ -63,7 +63,7 @@ This dict can then be used as context for templates. The goal is to be easy to integrate with your existing templating system. An example using `Jinja2 `_ is: -.. sourcecode:: html+jinja +.. code-block:: html+jinja {%- extends "layout.html" %} diff --git a/doc/usage/builders/index.rst b/doc/usage/builders/index.rst index 3b74a02e1..db6706944 100644 --- a/doc/usage/builders/index.rst +++ b/doc/usage/builders/index.rst @@ -61,7 +61,7 @@ The builder's "name" must be given to the **-b** command-line option of .. versionadded:: 1.0 -.. module:: sphinx.builders.htmlhelp +.. module:: sphinxcontrib.htmlhelp .. class:: HTMLHelpBuilder This builder produces the same output as the standalone HTML builder, but diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 31a9e0d1c..f411abb1c 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -296,25 +296,26 @@ General configuration Sphinx supports following warning types: - * app.add_node - * app.add_directive - * app.add_role - * app.add_generic_role - * app.add_source_parser - * download.not_readable - * image.not_readable - * ref.term - * ref.ref - * ref.numref - * ref.keyword - * ref.option - * ref.citation - * ref.footnote - * ref.doc - * ref.python - * misc.highlighting_failure - * toc.secnum - * epub.unknown_project_files + * ``app.add_node`` + * ``app.add_directive`` + * ``app.add_role`` + * ``app.add_generic_role`` + * ``app.add_source_parser`` + * ``download.not_readable`` + * ``image.not_readable`` + * ``ref.term`` + * ``ref.ref`` + * ``ref.numref`` + * ``ref.keyword`` + * ``ref.option`` + * ``ref.citation`` + * ``ref.footnote`` + * ``ref.doc`` + * ``ref.python`` + * ``misc.highlighting_failure`` + * ``toc.secnum`` + * ``epub.unknown_project_files`` + * ``autosectionlabel.*`` You can choose from these types. @@ -334,6 +335,10 @@ General configuration Added ``ref.footnote`` + .. versionchanged:: 2.1 + + Added ``autosectionlabel.*`` + .. confval:: needs_sphinx If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst index 0b6061e78..00cca4f0a 100644 --- a/doc/usage/extensions/autodoc.rst +++ b/doc/usage/extensions/autodoc.rst @@ -40,10 +40,8 @@ you can also enable the :mod:`napoleon ` extension. :mod:`napoleon ` is a preprocessor that converts your docstrings to correct reStructuredText before :mod:`autodoc` processes them. -.. _Google: - https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings -.. _NumPy: - https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt +.. _Google: https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings +.. _NumPy: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt Directives diff --git a/doc/usage/extensions/coverage.rst b/doc/usage/extensions/coverage.rst index 1fb9b1850..46d31053c 100644 --- a/doc/usage/extensions/coverage.rst +++ b/doc/usage/extensions/coverage.rst @@ -22,6 +22,16 @@ should check: .. confval:: coverage_ignore_classes +.. confval:: coverage_ignore_pyobjects + + List of `Python regular expressions`_. + + If any of these regular expressions matches any part of the full import path + of a Python object, that Python object is excluded from the documentation + coverage report. + + .. versionadded:: 2.1 + .. confval:: coverage_c_path .. confval:: coverage_c_regexes @@ -40,3 +50,5 @@ should check: ``False`` by default. .. versionadded:: 1.1 + +.. _Python regular expressions: https://docs.python.org/library/re \ No newline at end of file diff --git a/doc/usage/extensions/inheritance.rst b/doc/usage/extensions/inheritance.rst index 8e98b0bc1..78895915b 100644 --- a/doc/usage/extensions/inheritance.rst +++ b/doc/usage/extensions/inheritance.rst @@ -36,8 +36,8 @@ It adds this directive: with ``lib.``, you can give ``:parts: -1`` to remove that prefix from the displayed node names. - The directive also supports a ``private-bases`` flag option; if given, private base - classes (those whose name starts with ``_``) will be included. + The directive also supports a ``private-bases`` flag option; if given, + private base classes (those whose name starts with ``_``) will be included. You can use ``caption`` option to give a caption to the diagram. diff --git a/doc/usage/extensions/todo.rst b/doc/usage/extensions/todo.rst index 982005bd6..bf8b92225 100644 --- a/doc/usage/extensions/todo.rst +++ b/doc/usage/extensions/todo.rst @@ -17,8 +17,9 @@ There are two additional directives when using this extension: ``True``. .. versionadded:: 1.3.2 - This directive supports an ``class`` option that determines the class attribute - for HTML output. If not given, the class defaults to ``admonition-todo``. + This directive supports an ``class`` option that determines the class + attribute for HTML output. If not given, the class defaults to + ``admonition-todo``. .. rst:directive:: todolist @@ -46,8 +47,8 @@ Configuration .. confval:: todo_link_only - If this is ``True``, :rst:dir:`todolist` produce output without file path and line, - The default is ``False``. + If this is ``True``, :rst:dir:`todolist` produce output without file path and + line, The default is ``False``. .. versionadded:: 1.4 @@ -57,5 +58,5 @@ autodoc provides the following an additional event: .. versionadded:: 1.5 - Emitted when a todo is defined. *node* is the defined ``sphinx.ext.todo.todo_node`` - node. + Emitted when a todo is defined. *node* is the defined + ``sphinx.ext.todo.todo_node`` node. diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst index 85ee22ae9..d00979255 100644 --- a/doc/usage/restructuredtext/directives.rst +++ b/doc/usage/restructuredtext/directives.rst @@ -686,8 +686,8 @@ Glossary (When the glossary is sorted, the first term determines the sort order.) - If you want to specify "grouping key" for general index entries, you can put a "key" - as "term : key". For example:: + If you want to specify "grouping key" for general index entries, you can put + a "key" as "term : key". For example:: .. glossary:: @@ -697,12 +697,12 @@ Glossary Note that "key" is used for grouping key as is. The "key" isn't normalized; key "A" and "a" become different groups. - The whole characters in "key" is used instead of a first character; it is used for - "Combining Character Sequence" and "Surrogate Pairs" grouping key. + The whole characters in "key" is used instead of a first character; it is + used for "Combining Character Sequence" and "Surrogate Pairs" grouping key. - In i18n situation, you can specify "localized term : key" even if original text only - have "term" part. In this case, translated "localized term" will be categorized in - "key" group. + In i18n situation, you can specify "localized term : key" even if original + text only have "term" part. In this case, translated "localized term" will be + categorized in "key" group. .. versionadded:: 0.6 You can now give the glossary directive a ``:sorted:`` flag that will @@ -958,16 +958,16 @@ this reason, the following directive exists: .. warning:: Tables with more than 30 rows are rendered using ``longtable``, not - ``tabulary``, in order to allow pagebreaks. The ``L``, ``R``, ... specifiers - do not work for these tables. + ``tabulary``, in order to allow pagebreaks. The ``L``, ``R``, ... + specifiers do not work for these tables. Tables that contain list-like elements such as object descriptions, blockquotes or any kind of lists cannot be set out of the box with - ``tabulary``. They are therefore set with the standard LaTeX ``tabular`` (or - ``longtable``) environment if you don't give a ``tabularcolumns`` directive. - If you do, the table will be set with ``tabulary`` but you must use the - ``p{width}`` construct (or Sphinx's ``\X`` and ``\Y`` specifiers described - below) for the columns containing these elements. + ``tabulary``. They are therefore set with the standard LaTeX ``tabular`` + (or ``longtable``) environment if you don't give a ``tabularcolumns`` + directive. If you do, the table will be set with ``tabulary`` but you + must use the ``p{width}`` construct (or Sphinx's ``\X`` and ``\Y`` + specifiers described below) for the columns containing these elements. Literal blocks do not work with ``tabulary`` at all, so tables containing a literal block are always set with ``tabular``. The verbatim environment @@ -996,10 +996,11 @@ this reason, the following directive exists: .. versionchanged:: 1.6 Merged cells from complex grid tables (either multi-row, multi-column, or - both) now allow blockquotes, lists, literal blocks, ... as do regular cells. + both) now allow blockquotes, lists, literal blocks, ... as do regular + cells. - Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, ``Y{f}`` - and tabulary's columns. + Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, + ``Y{f}`` and tabulary's columns. .. note:: diff --git a/doc/usage/restructuredtext/domains.rst b/doc/usage/restructuredtext/domains.rst index 8b06bf0e0..8c784e158 100644 --- a/doc/usage/restructuredtext/domains.rst +++ b/doc/usage/restructuredtext/domains.rst @@ -128,17 +128,28 @@ declarations: This directive will also cause an entry in the global module index. - The ``platform`` option, if present, is a comma-separated list of the - platforms on which the module is available (if it is available on all - platforms, the option should be omitted). The keys are short identifiers; - examples that are in use include "IRIX", "Mac", "Windows", and "Unix". It is - important to use a key which has already been used when applicable. + .. rubric:: options - The ``synopsis`` option should consist of one sentence describing the - module's purpose -- it is currently only used in the Global Module Index. + .. rst:directive:option:: platform: platforms + :type: comma separated list - The ``deprecated`` option can be given (with no value) to mark a module as - deprecated; it will be designated as such in various locations then. + Indicate platforms which the module is available (if it is available on + all platforms, the option should be omitted). The keys are short + identifiers; examples that are in use include "IRIX", "Mac", "Windows" + and "Unix". It is important to use a key which has already been used when + applicable. + + .. rst:directive:option:: synopsis: purpose + :type: text + + Consist of one sentence describing the module's purpose -- it is currently + only used in the Global Module Index. + + .. rst:directive:option:: deprecated + :type: no argument + + Mark a module as deprecated; it will be designated as such in various + locations then. .. rst:directive:: .. py:currentmodule:: name @@ -169,12 +180,14 @@ The following directives are provided for module and class contents: This information can (in any ``py`` directive) optionally be given in a structured form, see :ref:`info-field-lists`. - The ``async`` option can be given (with no value) to indicate the function is - an async method. + .. rubric:: options - .. versionchanged:: 2.1 + .. rst:directive:option:: async + :type: no value - ``:async:`` option added. + Indicate the function is an async function. + + .. versionadded:: 2.1 .. rst:directive:: .. py:data:: name @@ -223,19 +236,43 @@ The following directives are provided for module and class contents: described for ``function``. See also :ref:`signatures` and :ref:`info-field-lists`. - The ``async`` option can be given (with no value) to indicate the method is - an async method. + .. rubric:: options - The ``classmethod`` option and ``staticmethod`` option can be given (with - no value) to indicate the method is a class method (or a static method). + .. rst:directive:option:: abstractmethod + :type: no value - The ``property`` option can be given (with no value) to indicate the method - is a property. + Indicate the method is an abstract method. - .. versionchanged:: 2.1 + .. versionadded:: 2.1 + + .. rst:directive:option:: async + :type: no value + + Indicate the method is an async method. + + .. versionadded:: 2.1 + + .. rst:directive:option:: classmethod + :type: no value + + Indicate the method is a class method. + + .. versionadded:: 2.1 + + .. rst:directive:option:: property + :type: no value + + Indicate the method is a property. + + .. versionadded:: 2.1 + + .. rst:directive:option:: staticmethod + :type: no value + + Indicate the method is a static method. + + .. versionadded:: 2.1 - ``:async:``, ``:classmethod:``, ``:property:`` and ``:staticmethod:`` - options added. .. rst:directive:: .. py:staticmethod:: name(parameters) @@ -720,7 +757,8 @@ visibility statement (``public``, ``private`` or ``protected``). .. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type - A scoped enum with non-default visibility, and with a specified underlying type. + A scoped enum with non-default visibility, and with a specified + underlying type. .. rst:directive:: .. cpp:enumerator:: name .. cpp:enumerator:: name = constant @@ -760,7 +798,8 @@ visibility statement (``public``, ``private`` or ``protected``). **Valid Expressions** - :cpp:expr:`*r`, when :cpp:expr:`r` is dereferenceable. - - :cpp:expr:`++r`, with return type :cpp:expr:`It&`, when :cpp:expr:`r` is incrementable. + - :cpp:expr:`++r`, with return type :cpp:expr:`It&`, when + :cpp:expr:`r` is incrementable. This will render as follows: @@ -799,11 +838,12 @@ Anonymous Entities ~~~~~~~~~~~~~~~~~~ C++ supports anonymous namespaces, classes, enums, and unions. -For the sake of documentation they must be given some name that starts with ``@``, -e.g., ``@42`` or ``@data``. +For the sake of documentation they must be given some name that starts with +``@``, e.g., ``@42`` or ``@data``. These names can also be used in cross-references and (type) expressions, though nested symbols will be found even when omitted. -The ``@...`` name will always be rendered as **[anonymous]** (possibly as a link). +The ``@...`` name will always be rendered as **[anonymous]** (possibly as a +link). Example:: @@ -835,8 +875,8 @@ Explicit ref: :cpp:var:`Data::@data::a`. Short-hand ref: :cpp:var:`Data::a`. Aliasing Declarations ~~~~~~~~~~~~~~~~~~~~~ -Sometimes it may be helpful list declarations elsewhere than their main documentation, -e.g., when creating a synopsis of a class interface. +Sometimes it may be helpful list declarations elsewhere than their main +documentation, e.g., when creating a synopsis of a class interface. The following directive can be used for this purpose. .. rst:directive:: .. cpp:alias:: name or function signature @@ -1079,7 +1119,8 @@ These roles link to the given declaration types: be properly qualified relative to the position of the link. .. versionadded:: 2.0 - The :rst:role:`cpp:struct` role as alias for the :rst:role:`cpp:class` role. + The :rst:role:`cpp:struct` role as alias for the :rst:role:`cpp:class` + role. .. admonition:: Note on References with Templates Parameters/Arguments @@ -1126,7 +1167,8 @@ References using the :rst:role:`cpp:func` role: - Specific overload: ``void C::f()``, :cpp:func:`void C::f()` - Specific overload: ``void C::f(int)``, :cpp:func:`void C::f(int)` - Specific overload: ``void C::f(double)``, :cpp:func:`void C::f(double)` -- Specific overload: ``void C::f(double) const``, :cpp:func:`void C::f(double) const` +- Specific overload: ``void C::f(double) const``, + :cpp:func:`void C::f(double) const` Note that the :confval:`add_function_parentheses` configuration variable does not influence specific overload references. @@ -1155,8 +1197,8 @@ and template arguments for the prefix of qualified names. For example: - ``template\ template\ Wrapper::Outer::Inner`` (:cpp:class:`template\ template\ Wrapper::Outer::Inner`) -Currently the lookup only succeed if the template parameter identifiers are equal strings. -That is, ``template\ Wrapper::Outer`` will not work. +Currently the lookup only succeed if the template parameter identifiers are equal +strings. That is, ``template\ Wrapper::Outer`` will not work. As a shorthand notation, if a template parameter list is omitted, then the lookup will assume either a primary template or a non-template, @@ -1447,8 +1489,8 @@ The reStructuredText domain (name **rst**) provides the following directives: .. rubric:: options - .. rst:directive:option:: type - :type: description for the option of directive + .. rst:directive:option:: type: description of argument + :type: text Describe the type of option value. @@ -1459,7 +1501,7 @@ The reStructuredText domain (name **rst**) provides the following directives: .. rst:directive:option:: maxdepth :type: integer or no value - .. versionadded:: 2.1 + .. versionadded:: 2.1 .. rst:directive:: .. rst:role:: name diff --git a/sphinx/application.py b/sphinx/application.py index e9b950c83..411fa42d8 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -343,9 +343,16 @@ class Sphinx: status = (self.statuscode == 0 and __('succeeded') or __('finished with problems')) if self._warncount: - logger.info(bold(__('build %s, %s warning.', - 'build %s, %s warnings.', self._warncount) % - (status, self._warncount))) + if self.warningiserror: + msg = __('build %s, %s warning (with warnings treated as errors).', + 'build %s, %s warnings (with warnings treated as errors).', + self._warncount) + else: + msg = __('build %s, %s warning.', + 'build %s, %s warnings.', + self._warncount) + + logger.info(bold(msg % (status, self._warncount))) else: logger.info(bold(__('build %s.') % status)) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 84a69436a..164f1e6b7 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -108,7 +108,8 @@ class CheckExternalLinksBuilder(Builder): kwargs = { 'allow_redirects': True, 'headers': { - 'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8' + 'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8', + 'User-Agent': requests.useragent_header[0][1], }, } if self.app.config.linkcheck_timeout: diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 4bfaaf848..f5bb3000c 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -576,6 +576,7 @@ class PyMethod(PyObject): option_spec = PyObject.option_spec.copy() option_spec.update({ + 'abstractmethod': directives.flag, 'async': directives.flag, 'classmethod': directives.flag, 'property': directives.flag, @@ -592,6 +593,8 @@ class PyMethod(PyObject): def get_signature_prefix(self, sig): # type: (str) -> str prefix = [] + if 'abstractmethod' in self.options: + prefix.append('abstract') if 'async' in self.options: prefix.append('async') if 'classmethod' in self.options: @@ -849,7 +852,6 @@ class PythonModuleIndex(Index): last = entries[-1] entries[-1] = IndexEntry(last[0], 1, last[2], last[3], last[4], last[5], last[6]) - entries.append(IndexEntry(stripped + package, 1, '', '', '', '', '')) elif not prev_modname.startswith(package): # submodule without parent in list, add dummy entry entries.append(IndexEntry(stripped + package, 1, '', '', '', '', '')) diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index f054abf28..349043294 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -139,6 +139,7 @@ class ReSTDirectiveOption(ReSTMarkup): def add_target_and_index(self, name, sig, signode): # type: (str, str, addnodes.desc_signature) -> None + directive_name = self.current_directive targetname = '-'.join([self.objtype, self.current_directive, name]) if targetname not in self.state.document.ids: signode['names'].append(targetname) @@ -146,12 +147,13 @@ class ReSTDirectiveOption(ReSTMarkup): signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) + objname = ':'.join(filter(None, [directive_name, name])) domain = cast(ReSTDomain, self.env.get_domain('rst')) - domain.note_object(self.objtype, name, location=(self.env.docname, self.lineno)) + domain.note_object(self.objtype, objname, location=(self.env.docname, self.lineno)) - if self.current_directive: + if directive_name: key = name[0].upper() - pair = [_('%s (directive)') % self.current_directive, + pair = [_('%s (directive)') % directive_name, _(':%s: (directive option)') % name] self.indexnode['entries'].append(('pair', '; '.join(pair), targetname, '', key)) else: diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index b42925f89..35f86809e 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -442,7 +442,7 @@ class ProductionList(SphinxDirective): name, tokens = rule.split(':', 1) except ValueError: break - subnode = addnodes.production() + subnode = addnodes.production(rule) subnode['tokenname'] = name.strip() if subnode['tokenname']: idname = nodes.make_id('grammar-token-%s' % subnode['tokenname']) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 2243e0644..2ec337d4c 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -56,6 +56,8 @@ template_dir = path.join(package_dir, 'templates', 'apidoc') def makename(package, module): # type: (str, str) -> str """Join package and module with a dot.""" + warnings.warn('makename() is deprecated.', + RemovedInSphinx40Warning) # Both package and module can be None/empty. if package: name = package @@ -66,6 +68,12 @@ def makename(package, module): return name +def module_join(*modnames): + # type: (*str) -> str + """Join module names with dots.""" + return '.'.join(filter(None, modnames)) + + def write_file(name, text, opts): # type: (str, str, Any) -> None """Write the output file for module/package .""" @@ -97,7 +105,7 @@ def format_directive(module, package=None): """Create the automodule directive and add the options.""" warnings.warn('format_directive() is deprecated.', RemovedInSphinx40Warning) - directive = '.. automodule:: %s\n' % makename(package, module) + directive = '.. automodule:: %s\n' % module_join(package, module) for option in OPTIONS: directive += ' :%s:\n' % option return directive @@ -106,7 +114,7 @@ def format_directive(module, package=None): def create_module_file(package, basename, opts): # type: (str, str, Any) -> None """Build the text of the file and write the file.""" - qualname = makename(package, basename) + qualname = module_join(package, basename) context = { 'show_headings': not opts.noheadings, 'basename': basename, @@ -123,17 +131,18 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_ # build a list of sub packages (directories containing an INITPY file) subpackages = [sub for sub in subs if not shall_skip(path.join(root, sub, INITPY), opts, excludes)] - subpackages = [makename(makename(master_package, subroot), pkgname) + subpackages = [module_join(master_package, subroot, pkgname) for pkgname in subpackages] # build a list of sub modules submodules = [path.splitext(sub)[0] for sub in py_files if not shall_skip(path.join(root, sub), opts, excludes) and sub != INITPY] - submodules = [makename(master_package, makename(subroot, modname)) + submodules = [module_join(master_package, subroot, modname) for modname in submodules] + pkgname = module_join(master_package, subroot) context = { - 'pkgname': makename(master_package, subroot), + 'pkgname': pkgname, 'subpackages': subpackages, 'submodules': submodules, 'is_namespace': is_namespace, @@ -143,7 +152,7 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_ 'show_headings': not opts.noheadings, } text = ReSTRenderer(template_dir).render('package.rst', context) - write_file(makename(master_package, subroot), text, opts) + write_file(pkgname, text, opts) if submodules and opts.separatemodules: for submodule in submodules: @@ -250,7 +259,7 @@ def recurse_tree(rootpath, excludes, opts): if not is_namespace or len(py_files) > 0: create_package_file(root, root_package, subpackage, py_files, opts, subs, is_namespace, excludes) - toplevels.append(makename(root_package, subpackage)) + toplevels.append(module_join(root_package, subpackage)) else: # if we are at the root level, we don't require it to be a package assert root == rootpath and root_package is None diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index b3c04e464..8d53c113a 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -65,6 +65,7 @@ def identity(x): ALL = object() INSTANCEATTR = object() +SLOTSATTR = object() def members_option(arg): @@ -363,8 +364,8 @@ class Documenter: return False return True - def format_args(self): - # type: () -> str + def format_args(self, **kwargs): + # type: (Any) -> str """Format the argument signature of *self.object*. Should return None if the object does not have a signature. @@ -383,8 +384,8 @@ class Documenter: # directives of course) return '.'.join(self.objpath) or self.modname - def format_signature(self): - # type: () -> str + def format_signature(self, **kwargs): + # type: (Any) -> str """Format the signature (arguments and return annotation) of the object. Let the user process it via the ``autodoc-process-signature`` event. @@ -395,7 +396,11 @@ class Documenter: else: # try to introspect the signature try: - args = self.format_args() + try: + args = self.format_args(**kwargs) + except TypeError: + # retry without arguments for old documenters + args = self.format_args() except Exception as err: logger.warning(__('error while formatting arguments for %s: %s') % (self.fullname, err), type='autodoc') @@ -954,15 +959,15 @@ class DocstringSignatureMixin: return lines return super().get_doc(None, ignore) # type: ignore - def format_signature(self): - # type: () -> str + def format_signature(self, **kwargs): + # type: (Any) -> str if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() if result is not None: self.args, self.retann = result - return super().format_signature() # type: ignore + return super().format_signature(**kwargs) # type: ignore class DocstringStripSignatureMixin(DocstringSignatureMixin): @@ -970,8 +975,8 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin): Mixin for AttributeDocumenter to provide the feature of stripping any function signature from the docstring. """ - def format_signature(self): - # type: () -> str + def format_signature(self, **kwargs): + # type: (Any) -> str if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore # only act if a signature is not explicitly given already, and if # the feature is enabled @@ -981,7 +986,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin): # DocstringSignatureMixin.format_signature. # Documenter.format_signature use self.args value to format. _args, self.retann = result - return super().format_signature() + return super().format_signature(**kwargs) class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore @@ -998,8 +1003,8 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ return (inspect.isfunction(member) or inspect.isbuiltin(member) or (inspect.isroutine(member) and isinstance(parent, ModuleDocumenter))) - def format_args(self): - # type: () -> str + def format_args(self, **kwargs): + # type: (Any) -> str if inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object): # cannot introspect arguments of a C function or method return None @@ -1009,9 +1014,9 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ not inspect.isbuiltin(self.object) and not inspect.isclass(self.object) and hasattr(self.object, '__call__')): - args = Signature(self.object.__call__).format_args() + args = Signature(self.object.__call__).format_args(**kwargs) else: - args = Signature(self.object).format_args() + args = Signature(self.object).format_args(**kwargs) except TypeError: if (inspect.is_builtin_class_method(self.object, '__new__') and inspect.is_builtin_class_method(self.object, '__init__')): @@ -1022,10 +1027,10 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ # signature without the first argument. try: sig = Signature(self.object.__new__, bound_method=True, has_retval=False) - args = sig.format_args() + args = sig.format_args(**kwargs) except TypeError: sig = Signature(self.object.__init__, bound_method=True, has_retval=False) - args = sig.format_args() + args = sig.format_args(**kwargs) # escape backslashes for reST args = args.replace('\\', '\\\\') @@ -1053,8 +1058,8 @@ class DecoratorDocumenter(FunctionDocumenter): # must be lower than FunctionDocumenter priority = -1 - def format_args(self): - args = super().format_args() + def format_args(self, **kwargs): + args = super().format_args(**kwargs) if ',' in args: return args else: @@ -1097,8 +1102,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: self.doc_as_attr = True return ret - def format_args(self): - # type: () -> str + def format_args(self, **kwargs): + # type: (Any) -> str # for classes, the relevant signature is the __init__ method's initmeth = self.get_attr(self.object, '__init__', None) # classes without __init__ method, default __init__ or @@ -1108,18 +1113,19 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)): return None try: - return Signature(initmeth, bound_method=True, has_retval=False).format_args() + sig = Signature(initmeth, bound_method=True, has_retval=False) + return sig.format_args(**kwargs) except TypeError: # still not possible: happens e.g. for old-style classes # with __init__ in C return None - def format_signature(self): - # type: () -> str + def format_signature(self, **kwargs): + # type: (Any) -> str if self.doc_as_attr: return '' - return super().format_signature() + return super().format_signature(**kwargs) def add_directive_header(self, sig): # type: (str) -> None @@ -1310,15 +1316,15 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return ret - def format_args(self): - # type: () -> str + def format_args(self, **kwargs): + # type: (Any) -> str if inspect.isbuiltin(self.object) or inspect.ismethoddescriptor(self.object): # can never get arguments of a C function or method return None if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): - args = Signature(self.object, bound_method=False).format_args() + args = Signature(self.object, bound_method=False).format_args(**kwargs) else: - args = Signature(self.object, bound_method=True).format_args() + args = Signature(self.object, bound_method=True).format_args(**kwargs) # escape backslashes for reST args = args.replace('\\', '\\\\') return args @@ -1329,6 +1335,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: sourcename = self.get_sourcename() obj = self.parent.__dict__.get(self.object_name, self.object) + if inspect.isabstractmethod(obj): + self.add_line(' :abstractmethod:', sourcename) if inspect.iscoroutinefunction(obj): self.add_line(' :async:', sourcename) if inspect.isclassmethod(obj): @@ -1446,7 +1454,10 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # def add_directive_header(self, sig): # type: (str) -> None super().add_directive_header(sig) - self.add_line(' :property:', self.get_sourcename()) + sourcename = self.get_sourcename() + if inspect.isabstractmethod(self.object): + self.add_line(' :abstractmethod:', sourcename) + self.add_line(' :property:', sourcename) class InstanceAttributeDocumenter(AttributeDocumenter): @@ -1481,6 +1492,55 @@ class InstanceAttributeDocumenter(AttributeDocumenter): super().add_content(more_content, no_docstring=True) +class SlotsAttributeDocumenter(AttributeDocumenter): + """ + Specialized Documenter subclass for attributes that cannot be imported + because they are attributes in __slots__. + """ + objtype = 'slotsattribute' + directivetype = 'attribute' + member_order = 60 + + # must be higher than AttributeDocumenter + priority = 11 + + @classmethod + def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, str, bool, Any) -> bool + """This documents only SLOTSATTR members.""" + return member is SLOTSATTR + + def import_object(self): + # type: () -> bool + """Never import anything.""" + # disguise as an attribute + self.objtype = 'attribute' + self._datadescriptor = True + + with mock(self.env.config.autodoc_mock_imports): + try: + ret = import_object(self.modname, self.objpath[:-1], 'class', + attrgetter=self.get_attr, + warningiserror=self.env.config.autodoc_warningiserror) + self.module, _, _, self.parent = ret + return True + except ImportError as exc: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False + + def get_doc(self, encoding=None, ignore=1): + # type: (str, int) -> List[List[str]] + """Decode and return lines of the docstring(s) for the object.""" + name = self.objpath[-1] + __slots__ = safe_getattr(self.parent, '__slots__', []) + if isinstance(__slots__, dict) and isinstance(__slots__.get(name), str): + docstring = prepare_docstring(__slots__[name]) + return [docstring] + else: + return [] + + def get_documenters(app): # type: (Sphinx) -> Dict[str, Type[Documenter]] """Returns registered Documenter classes""" @@ -1509,6 +1569,7 @@ def setup(app): app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) app.add_autodocumenter(InstanceAttributeDocumenter) + app.add_autodocumenter(SlotsAttributeDocumenter) app.add_config_value('autoclass_content', 'class', True) app.add_config_value('autodoc_member_order', 'alphabetic', True) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 557461fd4..18c6fc8f1 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -15,7 +15,7 @@ from collections import namedtuple from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.util import logging -from sphinx.util.inspect import isenumclass, safe_getattr +from sphinx.util.inspect import isclass, isenumclass, safe_getattr if False: # For type annotation @@ -127,6 +127,13 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None): if name not in superclass.__dict__: members[name] = Attribute(name, True, value) + # members in __slots__ + if isclass(subject) and hasattr(subject, '__slots__'): + from sphinx.ext.autodoc import SLOTSATTR + + for name in subject.__slots__: + members[name] = Attribute(name, True, SLOTSATTR) + # other members for name in dir(subject): try: diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index de46cec52..3d55ad749 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -55,7 +55,7 @@ def register_sections_as_label(app, document): if name in labels: logger.warning(__('duplicate label %s, other instance in %s'), name, app.env.doc2path(labels[name][0]), - location=node) + location=node, type='autosectionlabel', subtype=docname) anonlabels[name] = docname, labelid labels[name] = docname, labelid, sectname diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 5840f0ccd..262b36cea 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -63,7 +63,7 @@ from typing import List, cast from docutils import nodes from docutils.parsers.rst import directives -from docutils.parsers.rst.states import RSTStateMachine, state_classes +from docutils.parsers.rst.states import RSTStateMachine, Struct, state_classes from docutils.statemachine import StringList import sphinx @@ -175,7 +175,10 @@ _app = None # type: Sphinx class FakeDirective(DocumenterBridge): def __init__(self): # type: () -> None - super().__init__({}, None, Options(), 0, None) # type: ignore + settings = Struct(tab_width=8) + document = Struct(settings=settings) + state = Struct(document=document) + super().__init__({}, None, Options(), 0, state) # type: ignore def get_documenter(app, obj, parent): @@ -329,7 +332,12 @@ class Autosummary(SphinxDirective): # -- Grab the signature - sig = documenter.format_signature() + try: + sig = documenter.format_signature(show_annotation=False) + except TypeError: + # the documenter does not support ``show_annotation`` option + sig = documenter.format_signature() + if not sig: sig = '' else: @@ -436,16 +444,26 @@ def mangle_signature(sig, max_chars=30): # Remove parenthesis s = re.sub(r"^\((.*)\)$", r"\1", s).strip() - # Strip strings (which can contain things that confuse the code below) - s = re.sub(r"\\\\", "", s) - s = re.sub(r"\\'", "", s) - s = re.sub(r"'[^']*'", "", s) + # Strip literals (which can contain things that confuse the code below) + s = re.sub(r"\\\\", "", s) # escaped backslash (maybe inside string) + s = re.sub(r"\\'", "", s) # escaped single quote + s = re.sub(r'\\"', "", s) # escaped double quote + s = re.sub(r"'[^']*'", "", s) # string literal (w/ single quote) + s = re.sub(r'"[^"]*"', "", s) # string literal (w/ double quote) + + # Strip complex objects (maybe default value of arguments) + while re.search(r'\([^)]*\)', s): # contents of parenthesis (ex. NamedTuple(attr=...)) + s = re.sub(r'\([^)]*\)', '', s) + while re.search(r'<[^>]*>', s): # contents of angle brackets (ex. ) + s = re.sub(r'<[^>]*>', '', s) + while re.search(r'{[^}]*}', s): # contents of curly brackets (ex. dict) + s = re.sub(r'{[^}]*}', '', s) # Parse the signature to arguments + options args = [] # type: List[str] opts = [] # type: List[str] - opt_re = re.compile(r"^(.*, |)([a-zA-Z0-9_*]+)=") + opt_re = re.compile(r"^(.*, |)([a-zA-Z0-9_*]+)\s*=\s*") while s: m = opt_re.search(s) if not m: diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index eac25697a..a8bda3811 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -24,7 +24,7 @@ import pydoc import re import sys -from jinja2 import FileSystemLoader, TemplateNotFound +from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound from jinja2.sandbox import SandboxedEnvironment import sphinx.locale @@ -34,9 +34,9 @@ from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.locale import __ from sphinx.registry import SphinxComponentRegistry +from sphinx.util import rst from sphinx.util.inspect import safe_getattr from sphinx.util.osutil import ensuredir -from sphinx.util.rst import escape as rst_escape if False: # For type annotation @@ -86,6 +86,42 @@ def _underline(title, line='='): return title + '\n' + line * len(title) +class AutosummaryRenderer: + """A helper class for rendering.""" + + def __init__(self, builder, template_dir): + # type: (Builder, str) -> None + loader = None # type: BaseLoader + template_dirs = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')] + if builder is None: + if template_dir: + template_dirs.insert(0, template_dir) + loader = FileSystemLoader(template_dirs) + else: + # allow the user to override the templates + loader = BuiltinTemplateLoader() + loader.init(builder, dirs=template_dirs) + + self.env = SandboxedEnvironment(loader=loader) + self.env.filters['escape'] = rst.escape + self.env.filters['e'] = rst.escape + self.env.filters['underline'] = _underline + + def exists(self, template_name): + # type: (str) -> bool + """Check if template file exists.""" + try: + self.env.get_template(template_name) + return True + except TemplateNotFound: + return False + + def render(self, template_name, context): + # type: (str, Dict) -> str + """Render a template file.""" + return self.env.get_template(template_name).render(context) + + # -- Generating output --------------------------------------------------------- def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', @@ -106,26 +142,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', if base_path is not None: sources = [os.path.join(base_path, filename) for filename in sources] - # create our own templating environment - template_dirs = None # type: List[str] - template_dirs = [os.path.join(package_dir, 'ext', - 'autosummary', 'templates')] - - template_loader = None # type: Union[BuiltinTemplateLoader, FileSystemLoader] - if builder is not None: - # allow the user to override the templates - template_loader = BuiltinTemplateLoader() - template_loader.init(builder, dirs=template_dirs) - else: - if template_dir: - template_dirs.insert(0, template_dir) - template_loader = FileSystemLoader(template_dirs) - template_env = SandboxedEnvironment(loader=template_loader) - template_env.filters['underline'] = _underline - - # replace the builtin html filters - template_env.filters['escape'] = rst_escape - template_env.filters['e'] = rst_escape + template = AutosummaryRenderer(builder, template_dir) # read items = find_autosummary_in_files(sources) @@ -160,14 +177,10 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', with open(fn, 'w') as f: doc = get_documenter(app, obj, parent) - if template_name is not None: - template = template_env.get_template(template_name) - else: - try: - template = template_env.get_template('autosummary/%s.rst' - % doc.objtype) - except TemplateNotFound: - template = template_env.get_template('autosummary/base.rst') + if template_name is None: + template_name = 'autosummary/%s.rst' % doc.objtype + if not template.exists(template_name): + template_name = 'autosummary/base.rst' def get_members(obj, types, include_public=[], imported=True): # type: (Any, Set[str], List[str], bool) -> Tuple[List[str], List[str]] # NOQA @@ -222,7 +235,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', ns['objtype'] = doc.objtype ns['underline'] = len(name) * '=' - rendered = template.render(**ns) + rendered = template.render(template_name, ns) f.write(rendered) # descend recursively to new files diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 63beecd61..6c9489046 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -79,6 +79,8 @@ class CoverageBuilder(Builder): self.config.coverage_ignore_classes) self.fun_ignorexps = compile_regex_list('coverage_ignore_functions', self.config.coverage_ignore_functions) + self.py_ignorexps = compile_regex_list('coverage_ignore_pyobjects', + self.config.coverage_ignore_pyobjects) def get_outdated_docs(self): # type: () -> str @@ -130,6 +132,12 @@ class CoverageBuilder(Builder): op.write(' * %-50s [%9s]\n' % (name, typ)) op.write('\n') + def ignore_pyobj(self, full_name): + for exp in self.py_ignorexps: + if exp.search(full_name): + return True + return False + def build_py_coverage(self): # type: () -> None objects = self.env.domaindata['py']['objects'] @@ -143,7 +151,7 @@ class CoverageBuilder(Builder): if exp.match(mod_name): ignore = True break - if ignore: + if ignore or self.ignore_pyobj(mod_name): continue try: @@ -169,6 +177,8 @@ class CoverageBuilder(Builder): continue full_name = '%s.%s' % (mod_name, name) + if self.ignore_pyobj(full_name): + continue if inspect.isfunction(obj): if full_name not in objects: @@ -209,11 +219,11 @@ class CoverageBuilder(Builder): if skip_undoc and not attr.__doc__: # skip methods without docstring if wished continue - full_attr_name = '%s.%s' % (full_name, attr_name) + if self.ignore_pyobj(full_attr_name): + continue if full_attr_name not in objects: attrs.append(attr_name) - if attrs: # some attributes are undocumented classes[name] = attrs @@ -270,6 +280,7 @@ def setup(app): app.add_config_value('coverage_ignore_modules', [], False) app.add_config_value('coverage_ignore_functions', [], False) app.add_config_value('coverage_ignore_classes', [], False) + app.add_config_value('coverage_ignore_pyobjects', [], False) app.add_config_value('coverage_c_path', [], False) app.add_config_value('coverage_c_regexes', {}, False) app.add_config_value('coverage_ignore_c_items', {}, False) diff --git a/sphinx/templates/quickstart/make.bat.new_t b/sphinx/templates/quickstart/make.bat.new_t index 50a12e7af..1bb2f3489 100644 --- a/sphinx/templates/quickstart/make.bat.new_t +++ b/sphinx/templates/quickstart/make.bat.new_t @@ -25,11 +25,11 @@ if errorlevel 9009 ( exit /b 1 ) -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 004f1f912..774585566 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -9,7 +9,7 @@ if "%SPHINXBUILD%" == "" ( ) set BUILDDIR={{ rbuilddir }} set SOURCEDIR={{ rsrcdir }} -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SOURCEDIR% +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %O% %SOURCEDIR% set I18NSPHINXOPTS=%SPHINXOPTS% %SOURCEDIR% if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER%paper %ALLSPHINXOPTS% diff --git a/sphinx/themes/haiku/layout.html b/sphinx/themes/haiku/layout.html index 9dbae6d0a..2f1a0b4a0 100644 --- a/sphinx/themes/haiku/layout.html +++ b/sphinx/themes/haiku/layout.html @@ -51,7 +51,7 @@ -
+
{#{%- if display_toc %}

{{ _('Table of Contents') }}

diff --git a/sphinx/themes/scrolls/layout.html b/sphinx/themes/scrolls/layout.html index 852ac967f..08f8970fc 100644 --- a/sphinx/themes/scrolls/layout.html +++ b/sphinx/themes/scrolls/layout.html @@ -42,7 +42,9 @@ {{ toc }}
{%- endif %} +
{% block body %}{% endblock %} +
{% endblock %} diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 89534f5ae..0caee3af6 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -244,7 +244,7 @@ date_format_mappings = { '%x': 'medium', # Locale’s appropriate date representation. '%X': 'medium', # Locale’s appropriate time representation. '%y': 'YY', # Year without century as a zero-padded decimal number. - '%Y': 'YYYY', # Year with century as a decimal number. + '%Y': 'yyyy', # Year with century as a decimal number. '%Z': 'zzzz', # Time zone name (no characters if no time zone exists). '%%': '%', } diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index caf333493..34709d250 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -170,6 +170,12 @@ def isdescriptor(x): return False +def isabstractmethod(obj): + # type: (Any) -> bool + """Check if the object is an abstractmethod.""" + return safe_getattr(obj, '__isabstractmethod__', False) is True + + def isattributedescriptor(obj): # type: (Any) -> bool """Check if the object is an attribute like descriptor.""" @@ -229,7 +235,7 @@ def isproperty(obj): def safe_getattr(obj, name, *defargs): - # type: (Any, str, str) -> object + # type: (Any, str, Any) -> Any """A getattr() that turns all exceptions into AttributeErrors.""" try: return getattr(obj, name, *defargs) @@ -317,9 +323,9 @@ def is_builtin_class_method(obj, attr_name): classes = [c for c in inspect.getmro(obj) if attr_name in c.__dict__] cls = classes[0] if classes else object - if not hasattr(builtins, safe_getattr(cls, '__name__', '')): # type: ignore + if not hasattr(builtins, safe_getattr(cls, '__name__', '')): return False - return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls # type: ignore + return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls class Signature: @@ -391,8 +397,8 @@ class Signature: else: return None - def format_args(self): - # type: () -> str + def format_args(self, show_annotation=True): + # type: (bool) -> str args = [] last_kind = None for i, param in enumerate(self.parameters.values()): @@ -413,7 +419,7 @@ class Signature: param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY): arg.write(param.name) - if param.annotation is not param.empty: + if show_annotation and param.annotation is not param.empty: if isinstance(param.annotation, str) and param.name in self.annotations: arg.write(': ') arg.write(self.format_annotation(self.annotations[param.name])) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 60e0144b0..58c6a6698 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) # \x00 means the "<" was backslash-escaped -explicit_title_re = re.compile(r'^(.+?)\s*(?$', re.DOTALL) +explicit_title_re = re.compile(r'^(.+?)\s*(?$', re.DOTALL) caption_ref_re = explicit_title_re # b/w compat alias diff --git a/tests/roots/test-ext-autodoc/target/abstractmethods.py b/tests/roots/test-ext-autodoc/target/abstractmethods.py new file mode 100644 index 000000000..a4396d5c9 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/abstractmethods.py @@ -0,0 +1,29 @@ +from abc import abstractmethod + + +class Base(): + def meth(self): + pass + + @abstractmethod + def abstractmeth(self): + pass + + @staticmethod + @abstractmethod + def staticmeth(): + pass + + @classmethod + @abstractmethod + def classmeth(cls): + pass + + @property + @abstractmethod + def prop(self): + pass + + @abstractmethod + async def coroutinemeth(self): + pass diff --git a/tests/roots/test-ext-autodoc/target/slots.py b/tests/roots/test-ext-autodoc/target/slots.py new file mode 100644 index 000000000..44e750320 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/slots.py @@ -0,0 +1,11 @@ +class Foo: + __slots__ = ['attr'] + + +class Bar: + __slots__ = {'attr1': 'docstring of attr1', + 'attr2': 'docstring of attr2', + 'attr3': None} + + def __init__(self): + self.attr2 = None #: docstring of instance attr2 diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index 5506d0bc9..02e6c0e7d 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -1,4 +1,5 @@ from os import * # NOQA +from typing import Union class Foo: @@ -11,3 +12,7 @@ class Foo: @property def baz(self): pass + + +def bar(x: Union[int, str], y: int = 1): + pass diff --git a/tests/roots/test-ext-autosummary/index.rst b/tests/roots/test-ext-autosummary/index.rst index fc84927bb..c52e96ed9 100644 --- a/tests/roots/test-ext-autosummary/index.rst +++ b/tests/roots/test-ext-autosummary/index.rst @@ -8,4 +8,5 @@ autosummary_dummy_module autosummary_dummy_module.Foo + autosummary_dummy_module.bar autosummary_importfail diff --git a/tests/roots/test-ext-coverage/conf.py b/tests/roots/test-ext-coverage/conf.py new file mode 100644 index 000000000..d3ec6e87f --- /dev/null +++ b/tests/roots/test-ext-coverage/conf.py @@ -0,0 +1,12 @@ +import os +import sys + +sys.path.insert(0, os.path.abspath('.')) + +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage'] + +coverage_ignore_pyobjects = [ + r'^coverage_ignored(\..*)?$', + r'\.Ignored$', + r'\.Documented\.ignored\d$', +] diff --git a/tests/roots/test-ext-coverage/coverage_ignored.py b/tests/roots/test-ext-coverage/coverage_ignored.py new file mode 100644 index 000000000..b76295501 --- /dev/null +++ b/tests/roots/test-ext-coverage/coverage_ignored.py @@ -0,0 +1,22 @@ +class Documented: + """Documented""" + + def ignored1(self): + pass + + def ignored2(self): + pass + + def not_ignored1(self): + pass + + def not_ignored2(self): + pass + + +class Ignored: + pass + + +class NotIgnored: + pass diff --git a/tests/roots/test-ext-coverage/coverage_not_ignored.py b/tests/roots/test-ext-coverage/coverage_not_ignored.py new file mode 100644 index 000000000..b76295501 --- /dev/null +++ b/tests/roots/test-ext-coverage/coverage_not_ignored.py @@ -0,0 +1,22 @@ +class Documented: + """Documented""" + + def ignored1(self): + pass + + def ignored2(self): + pass + + def not_ignored1(self): + pass + + def not_ignored2(self): + pass + + +class Ignored: + pass + + +class NotIgnored: + pass diff --git a/tests/roots/test-ext-coverage/index.rst b/tests/roots/test-ext-coverage/index.rst new file mode 100644 index 000000000..b8468987e --- /dev/null +++ b/tests/roots/test-ext-coverage/index.rst @@ -0,0 +1,6 @@ +.. automodule:: coverage_ignored + :members: + + +.. automodule:: coverage_not_ignored + :members: diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 0c3de1fae..5a49a59ac 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1317,6 +1317,46 @@ def test_instance_attributes(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_slots(app): + options = {"members": None, + "undoc-members": True} + actual = do_autodoc(app, 'module', 'target.slots', options) + assert list(actual) == [ + '', + '.. py:module:: target.slots', + '', + '', + '.. py:class:: Bar()', + ' :module: target.slots', + '', + ' ', + ' .. py:attribute:: Bar.attr1', + ' :module: target.slots', + ' ', + ' docstring of attr1', + ' ', + ' ', + ' .. py:attribute:: Bar.attr2', + ' :module: target.slots', + ' ', + ' docstring of instance attr2', + ' ', + ' ', + ' .. py:attribute:: Bar.attr3', + ' :module: target.slots', + ' ', + '', + '.. py:class:: Foo', + ' :module: target.slots', + '', + ' ', + ' .. py:attribute:: Foo.attr', + ' :module: target.slots', + ' ', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_enum_class(app): options = {"members": None, @@ -1482,6 +1522,55 @@ def test_mocked_module_imports(app, warning): assert warning.getvalue() == '' +@pytest.mark.usefixtures('setup_test') +def test_abstractmethods(): + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.abstractmethods', options) + assert list(actual) == [ + '', + '.. py:module:: target.abstractmethods', + '', + '', + '.. py:class:: Base', + ' :module: target.abstractmethods', + '', + ' ', + ' .. py:method:: Base.abstractmeth()', + ' :module: target.abstractmethods', + ' :abstractmethod:', + ' ', + ' ', + ' .. py:method:: Base.classmeth()', + ' :module: target.abstractmethods', + ' :abstractmethod:', + ' :classmethod:', + ' ', + ' ', + ' .. py:method:: Base.coroutinemeth()', + ' :module: target.abstractmethods', + ' :abstractmethod:', + ' :async:', + ' ', + ' ', + ' .. py:method:: Base.meth()', + ' :module: target.abstractmethods', + ' ', + ' ', + ' .. py:method:: Base.prop', + ' :module: target.abstractmethods', + ' :abstractmethod:', + ' :property:', + ' ', + ' ', + ' .. py:method:: Base.staticmeth()', + ' :module: target.abstractmethods', + ' :abstractmethod:', + ' :staticmethod:', + ' ' + ] + + @pytest.mark.usefixtures('setup_test') def test_partialfunction(): options = {"members": None} diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index fac8a838f..d438543bd 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -18,7 +18,10 @@ from sphinx.addnodes import ( desc, desc_addname, desc_annotation, desc_content, desc_name, desc_optional, desc_parameter, desc_parameterlist, desc_returns, desc_signature ) -from sphinx.domains.python import py_sig_re, _pseudo_parse_arglist, PythonDomain +from sphinx.domains import IndexEntry +from sphinx.domains.python import ( + py_sig_re, _pseudo_parse_arglist, PythonDomain, PythonModuleIndex +) from sphinx.testing import restructuredtext from sphinx.testing.util import assert_node @@ -335,7 +338,9 @@ def test_pymethod_options(app): " .. py:method:: meth4\n" " :async:\n" " .. py:method:: meth5\n" - " :property:\n") + " :property:\n" + " .. py:method:: meth6\n" + " :abstractmethod:\n") domain = app.env.get_domain('py') doctree = restructuredtext.parse(app, text) assert_node(doctree, (addnodes.index, @@ -350,6 +355,8 @@ def test_pymethod_options(app): addnodes.index, desc, addnodes.index, + desc, + addnodes.index, desc)])])) # method @@ -400,6 +407,16 @@ def test_pymethod_options(app): assert 'Class.meth5' in domain.objects assert domain.objects['Class.meth5'] == ('index', 'method') + # :abstractmethod: + assert_node(doctree[1][1][10], addnodes.index, + entries=[('single', 'meth6() (Class method)', 'Class.meth6', '', None)]) + assert_node(doctree[1][1][11], ([desc_signature, ([desc_annotation, "abstract "], + [desc_name, "meth6"], + [desc_parameterlist, ()])], + [desc_content, ()])) + assert 'Class.meth6' in domain.objects + assert domain.objects['Class.meth6'] == ('index', 'method') + def test_pyclassmethod(app): text = (".. py:class:: Class\n" @@ -460,3 +477,49 @@ def test_pyattribute(app): [desc_content, ()])) assert 'Class.attr' in domain.objects assert domain.objects['Class.attr'] == ('index', 'attribute') + + +@pytest.mark.sphinx(freshenv=True) +def test_module_index(app): + text = (".. py:module:: docutils\n" + ".. py:module:: sphinx\n" + ".. py:module:: sphinx.config\n" + ".. py:module:: sphinx.builders\n" + ".. py:module:: sphinx.builders.html\n" + ".. py:module:: sphinx_intl\n") + restructuredtext.parse(app, text) + index = PythonModuleIndex(app.env.get_domain('py')) + assert index.generate() == ( + [('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]), + ('s', [IndexEntry('sphinx', 1, 'index', 'module-sphinx', '', '', ''), + IndexEntry('sphinx.builders', 2, 'index', 'module-sphinx.builders', '', '', ''), # NOQA + IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx.builders.html', '', '', ''), # NOQA + IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', ''), + IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx_intl', '', '', '')])], + False + ) + + +@pytest.mark.sphinx(freshenv=True) +def test_module_index_submodule(app): + text = ".. py:module:: sphinx.config\n" + restructuredtext.parse(app, text) + index = PythonModuleIndex(app.env.get_domain('py')) + assert index.generate() == ( + [('s', [IndexEntry('sphinx', 1, '', '', '', '', ''), + IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', '')])], + False + ) + + +@pytest.mark.sphinx(freshenv=True) +def test_module_index_not_collapsed(app): + text = (".. py:module:: docutils\n" + ".. py:module:: sphinx\n") + restructuredtext.parse(app, text) + index = PythonModuleIndex(app.env.get_domain('py')) + assert index.generate() == ( + [('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]), + ('s', [IndexEntry('sphinx', 0, 'index', 'module-sphinx', '', '', '')])], + True + ) diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 2ccfd9342..04af9ed85 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -13,9 +13,13 @@ from io import StringIO from unittest.mock import Mock import pytest +from docutils import nodes -from sphinx.ext.autosummary import mangle_signature, import_by_name, extract_summary -from sphinx.testing.util import etree_parse +from sphinx import addnodes +from sphinx.ext.autosummary import ( + autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary +) +from sphinx.testing.util import assert_node, etree_parse from sphinx.util.docutils import new_document html_warnfile = StringIO() @@ -43,11 +47,13 @@ def test_mangle_signature(): (a, b[, c]) :: (a, b[, c]) (a, b[, cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]) :: (a, b[, ...) (a, b='c=d, e=f, g=h', c=3) :: (a[, b, c]) + (a, b="c=d, e=f, g=h", c=3) :: (a[, b, c]) (a, b='c=d, \\'e=f,\\' g=h', c=3) :: (a[, b, c]) (a, b='c=d, ', e='\\\\' g=h, c=3) :: (a[, b, e, c]) (a, b={'c=d, ': 3, '\\\\': 3}) :: (a[, b]) (a=1, b=2, c=3) :: ([a, b, c]) (a=1, b=, c=3) :: ([a, b, c]) + (a=1, b=T(a=1, b=2), c=3) :: ([a, b, c]) (a: int, b: int) -> str :: (a, b) """ @@ -179,6 +185,24 @@ def test_escaping(app, status, warning): def test_autosummary_generate(app, status, warning): app.builder.build_all() + doctree = app.env.get_doctree('index') + assert_node(doctree, (nodes.paragraph, + nodes.paragraph, + addnodes.tabular_col_spec, + autosummary_table, + autosummary_toc)) + assert_node(doctree[3], + [autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec, + nodes.colspec, + [nodes.tbody, (nodes.row, + nodes.row, + nodes.row, + nodes.row)])]) + assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n' + assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n' + assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' + assert doctree[3][0][0][2][3].astext() == 'autosummary_importfail\n\n' + module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').text() assert (' .. autosummary::\n' ' \n' diff --git a/tests/test_ext_coverage.py b/tests/test_ext_coverage.py index 73181909d..8209820a0 100644 --- a/tests/test_ext_coverage.py +++ b/tests/test_ext_coverage.py @@ -45,3 +45,22 @@ def test_build(app, status, warning): assert 'classes' in undoc_py['autodoc_target'] assert 'Class' in undoc_py['autodoc_target']['classes'] assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class'] + + +@pytest.mark.sphinx('coverage', testroot='ext-coverage') +def test_coverage_ignore_pyobjects(app, status, warning): + app.builder.build_all() + actual = (app.outdir / 'python.txt').text() + expected = '''Undocumented Python objects +=========================== +coverage_not_ignored +-------------------- +Classes: + * Documented -- missing methods: + + - not_ignored1 + - not_ignored2 + * NotIgnored + +''' + assert actual == expected diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index c83fda36f..1a2ded447 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -17,7 +17,7 @@ from docutils.parsers import rst from docutils.utils import new_document from sphinx.transforms import ApplySourceWorkaround -from sphinx.util.nodes import NodeMatcher, extract_messages, clean_astext +from sphinx.util.nodes import NodeMatcher, extract_messages, clean_astext, split_explicit_title def _transform(doctree): @@ -178,3 +178,18 @@ def test_clean_astext(): node = nodes.paragraph(text='hello world') node += nodes.raw('', 'raw text', format='html') assert 'hello world' == clean_astext(node) + + +@pytest.mark.parametrize( + 'title, expected', + [ + # implicit + ('hello', (False, 'hello', 'hello')), + # explicit + ('hello ', (True, 'hello', 'world')), + # explicit (title having angle brackets) + ('hello ', (True, 'hello ', 'sphinx')), + ] +) +def test_split_explicit_target(title, expected): + assert expected == split_explicit_title(title) diff --git a/utils/doclinter.py b/utils/doclinter.py index 3f711bfa5..01b043ab8 100644 --- a/utils/doclinter.py +++ b/utils/doclinter.py @@ -14,7 +14,10 @@ import sys from typing import List -MAX_LINE_LENGTH = 100 +MAX_LINE_LENGTH = 90 +LONG_INTERPRETED_TEXT = re.compile(r'^\s*\W*(:(\w+:)+)?`.*`\W*$') +CODE_BLOCK_DIRECTIVE = re.compile(r'^(\s*)\.\. code-block::') +LEADING_SPACES = re.compile(r'^(\s*)') def lint(path: str) -> int: @@ -22,13 +25,28 @@ def lint(path: str) -> int: document = f.readlines() errors = 0 + in_code_block = False + code_block_depth = 0 for i, line in enumerate(document): if line.endswith(' '): print('%s:%d: the line ends with whitespace.' % (path, i + 1)) errors += 1 - if len(line) > MAX_LINE_LENGTH: + matched = CODE_BLOCK_DIRECTIVE.match(line) + if matched: + in_code_block = True + code_block_depth = len(matched.group(1)) + elif in_code_block: + if line.strip() == '': + pass + else: + spaces = LEADING_SPACES.match(line).group(1) + if len(spaces) < code_block_depth: + in_code_block = False + elif LONG_INTERPRETED_TEXT.match(line): + pass + elif len(line) > MAX_LINE_LENGTH: if re.match(r'^\s*\.\. ', line): # ignore directives and hyperlink targets pass @@ -42,12 +60,15 @@ def lint(path: str) -> int: def main(args: List[str]) -> int: errors = 0 - for directory in args: - for root, dirs, files in os.walk(directory): - for filename in files: - if filename.endswith('.rst'): - path = os.path.join(root, filename) - errors += lint(path) + for path in args: + if os.path.isfile(path): + errors += lint(path) + elif os.path.isdir(path): + for root, dirs, files in os.walk(path): + for filename in files: + if filename.endswith('.rst'): + path = os.path.join(root, filename) + errors += lint(path) if errors: return 1