diff --git a/AUTHORS b/AUTHORS index f4ce16164..98f005fb7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,6 +18,7 @@ Other co-maintainers: Other contributors, listed alphabetically, are: * Alastair Houghton -- Apple Help builder +* Alexander Todorov -- inheritance_diagram tests and improvements * Andi Albrecht -- agogo theme * Jakob Lykke Andersen -- Rewritten C++ domain * Henrique Bastos -- SVG support for graphviz extension @@ -67,6 +68,7 @@ Other contributors, listed alphabetically, are: * Barry Warsaw -- setup command improvements * Sebastian Wiesner -- image handling, distutils support * Michael Wilson -- Intersphinx HTTP basic auth support +* Matthew Woodcraft -- text output improvements * Joel Wurtz -- cellspanning support in LaTeX * Hong Xu -- svg support in imgmath extension and various bug fixes * Stephen Finucane -- setup command improvements and documentation diff --git a/CHANGES b/CHANGES index d9350d21a..e15890e32 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ Release 1.7 (in development) ============================ +Dependencies +------------ + +* Add ``packaging`` package + Incompatible changes -------------------- @@ -16,6 +21,12 @@ Incompatible changes * #4389: output directory will be created after loading extensions * autodoc does not generate warnings messages to the generated document even if :confval:`keep_warnings` is True. They are only emitted to stderr. +* shebang line is removed from generated conf.py +* #2557: autodoc: :confval:`autodoc_mock_imports` only mocks specified modules + with their descendants. It does not mock their ancestors. If you want to + mock them, please specify the name of ancestors implicitly. +* #3620: html theme: move DOCUMENTATION_OPTIONS to independent JavaScript file + (refs: #4295) Deprecated ---------- @@ -65,6 +76,20 @@ Features added * #947: autodoc now supports ignore-module-all to ignore a module's ``__all__`` * #4332: Let LaTeX obey :confval:`math_numfig` for equation numbering * #4093: sphinx-build creates empty directories for unknown targets/builders +* Add ``top-classes`` option for the ``sphinx.ext.inheritance_diagram`` + extension to limit the scope of inheritance graphs. +* #4183: doctest: ``:pyversion:`` option also follows PEP-440 specification +* #4235: html: Add :confval:`manpages_url` to make manpage roles to hyperlinks +* #3570: autodoc: Do not display 'typing.' module for type hints +* #4354: sphinx-build now emits finish message. Builders can modify it through + ``Builder.epilog`` attribute +* #4245: html themes: Add ``language`` to javascript vars list +* #4079: html: Add ``notranslate`` class to each code-blocks, literals and maths + to let Google Translate know they are not translatable +* #4137: doctest: doctest block is always highlighted as python console (pycon) +* #4137: doctest: testcode block is always highlighted as python +* #3998: text: Assign section numbers by default. You can control it using + :confval:`text_add_secnumbers` and :confval:`text_secnumber_suffix` Features removed ---------------- @@ -95,6 +120,8 @@ Features removed * LaTeX environment ``notice``, use ``sphinxadmonition`` instead * LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily`` * C++, support of function concepts. Thanks to mickk-on-cpp. +* Not used and previously not documented LaTeX macros ``\shortversion`` + and ``\setshortversion`` Bugs fixed @@ -113,11 +140,13 @@ Bugs fixed * #4198: autosummary emits multiple 'autodoc-process-docstring' event. Thanks to Joel Nothman. * #4081: Warnings and errors colored the same when building +* latex: Do not display 'Release' label if :confval:`release` is not set Testing -------- * Add support for docutils 0.14 +* Add tests for the ``sphinx.ext.inheritance_diagram`` extension. Release 1.6.7 (in development) ============================== diff --git a/doc/config.rst b/doc/config.rst index 9bdd283a9..830fb69a0 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -293,6 +293,24 @@ General configuration .. versionadded:: 1.3 +.. confval:: manpages_url + + A URL to cross-reference :rst:role:`manpage` directives. If this is + defined to ``https://manpages.debian.org/{path}``, the + :literal:`:manpage:`man(1)`` role will like to + . The patterns available are: + + * ``page`` - the manual page (``man``) + * ``section`` - the manual section (``1``) + * ``path`` - the original manual page and section specified (``man(1)``) + + This also supports manpages specified as ``man.1``. + + .. note:: This currently affects only HTML writers but could be + expanded in the future. + + .. versionadded:: 1.7 + .. confval:: nitpicky If true, Sphinx will warn about *all* references where the target cannot be @@ -2021,6 +2039,20 @@ These options influence text output. .. versionadded:: 1.1 +.. confval:: text_add_secnumbers + + A boolean that decides whether section numbers are included in text output. + Default is ``True``. + + .. versionadded:: 1.7 + +.. confval:: text_secnumber_suffix + + Suffix for section numbers in text output. Default: ``". "``. Set to ``" "`` + to suppress the final dot on section numbers. + + .. versionadded:: 1.7 + .. _man-options: diff --git a/doc/ext/doctest.rst b/doc/ext/doctest.rst index d1cb3c31d..62221bf04 100644 --- a/doc/ext/doctest.rst +++ b/doc/ext/doctest.rst @@ -80,12 +80,24 @@ a comma-separated list of group names. .. doctest:: :pyversion: > 3.3 - The supported operands are ``<``, ``<=``, ``==``, ``>=``, ``>``, and - comparison is performed by `distutils.version.LooseVersion - `__. + The following operands are supported: + + * ``~=``: Compatible release clause + * ``==``: Version matching clause + * ``!=``: Version exclusion clause + * ``<=``, ``>=``: Inclusive ordered comparison clause + * ``<``, ``>``: Exclusive ordered comparison clause + * ``===``: Arbitrary equality clause. + + ``pyversion`` option is followed `PEP-440: Version Specifiers + `__. .. versionadded:: 1.6 + .. versionchanged:: 1.7 + + Supported PEP-440 operands and notations + Note that like with standard doctests, you have to use ```` to signal a blank line in the expected output. The ```` is removed when building presentation output (HTML, LaTeX etc.). diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst index 231b5fdaa..0062a8afa 100644 --- a/doc/ext/inheritance.rst +++ b/doc/ext/inheritance.rst @@ -42,6 +42,54 @@ It adds this directive: .. versionchanged:: 1.5 Added ``caption`` option + It also supports a ``top-classes`` option which requires one or more class + names separated by comma. If specified inheritance traversal will stop at the + specified class names. Given the following Python module:: + + """ + A + / \ + B C + / \ / \ + E D F + """ + + class A(object): + pass + + class B(A): + pass + + class C(A): + pass + + class D(B, C): + pass + + class E(B): + pass + + class F(C): + pass + + If you have specified a module in the inheritance diagram like this:: + + .. inheritance-diagram:: dummy.test + :top-classes: dummy.test.B, dummy.test.C + + any base classes which are ancestors to ``top-classes`` and are also defined + in the same module will be rendered as stand alone nodes. In this example + class A will be rendered as stand alone node in the graph. This is a known + issue due to how this extension works internally. + + If you don't want class A (or any other ancestors) to be visible then specify + only the classes you would like to generate the diagram for like this:: + + .. inheritance-diagram:: dummy.test.D dummy.test.E dummy.test.F + :top-classes: dummy.test.B, dummy.test.C + + .. versionchanged:: 1.7 + Added ``top-classes`` option to limit the scope of inheritance graphs. New config values are: diff --git a/doc/extdev/builderapi.rst b/doc/extdev/builderapi.rst index 668f46698..b8ff0595b 100644 --- a/doc/extdev/builderapi.rst +++ b/doc/extdev/builderapi.rst @@ -15,6 +15,7 @@ Builder API .. autoattribute:: name .. autoattribute:: format + .. autoattribute:: epilog .. autoattribute:: supported_image_types These methods are predefined and will be called from the application: diff --git a/doc/intro.rst b/doc/intro.rst index d3b191700..a789145fe 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -3,7 +3,7 @@ Introduction This is the documentation for the Sphinx documentation builder. Sphinx is a tool that translates a set of reStructuredText_ source files into various output -formats, automatically producing cross-references, indices etc. That is, if +formats, automatically producing cross-references, indices, etc. That is, if you have a directory containing a bunch of reST-formatted documents (and possibly subdirectories of docs in there as well), Sphinx can generate a nicely-organized arrangement of HTML files (in some other directory) for easy @@ -38,7 +38,7 @@ to reStructuredText/Sphinx from other documentation systems. code to convert Python-doc-style LaTeX markup to Sphinx reST. * Marcin Wojdyr has written a script to convert Docbook to reST with Sphinx - markup; it is at `Google Code `_. + markup; it is at `GitHub `_. * Christophe de Vienne wrote a tool to convert from Open/LibreOffice documents to Sphinx: `odt2sphinx `_. diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index 4d14a653d..c8dfb6ff7 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -355,7 +355,8 @@ in a different style: .. rst:role:: manpage A reference to a Unix manual page including the section, - e.g. ``:manpage:`ls(1)```. + e.g. ``:manpage:`ls(1)```. Creates a hyperlink to an external site + rendering the manpage if :confval:`manpages_url` is defined. .. rst:role:: menuselection diff --git a/doc/markup/misc.rst b/doc/markup/misc.rst index 35ed6375d..51e3a405c 100644 --- a/doc/markup/misc.rst +++ b/doc/markup/misc.rst @@ -323,6 +323,11 @@ following directive exists: Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, ``Y{f}`` and tabulary's columns. + .. note:: + + :rst:dir:`tabularcolumns` conflicts with ``:widths:`` option of table + directives. If both are specified, ``:widths:`` option will be ignored. + Math ---- diff --git a/setup.py b/setup.py index 6b7de9129..f35e5f88d 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ requires = [ 'imagesize', 'requests>=2.0.0', 'setuptools', + 'packaging', 'sphinxcontrib-websupport', ] diff --git a/sphinx/application.py b/sphinx/application.py index e76f101a3..8a22a9e6d 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -338,6 +338,13 @@ class Sphinx(object): (status, self._warncount))) else: logger.info(bold(__('build %s.') % status)) + + if self.statuscode == 0 and self.builder.epilog: + logger.info('') + logger.info(self.builder.epilog % { + 'outdir': path.relpath(self.outdir), + 'project': self.config.project + }) except Exception as err: # delete the saved env to force a fresh build next time envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index a1e360d2f..51578a1d6 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -54,6 +54,11 @@ class Builder(object): name = '' # type: unicode #: The builder's output format, or '' if no document output is produced. format = '' # type: unicode + #: The message emitted upon successful build completion. This can be a + #: printf-style template string with the following keys: ``outdir``, + #: ``project`` + epilog = '' # type: unicode + # default translator class for the builder. This will be overrided by # ``app.set_translator()``. default_translator_class = None # type: nodes.NodeVisitor diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index 52ba2ce5c..0426be331 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -75,6 +75,10 @@ class AppleHelpBuilder(StandaloneHTMLBuilder): on the ``hiutil`` command line tool. """ name = 'applehelp' + epilog = ('The help book is in %(outdir)s.\n' + 'Note that won\'t be able to view it unless you put it in ' + '~/Library/Documentation/Help or install it in your application ' + 'bundle.') # don't copy the reST source copysource = False diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 5309649c6..ff80250a3 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -38,6 +38,7 @@ class ChangesBuilder(Builder): Write a summary with all versionadded/changed directives. """ name = 'changes' + epilog = 'The overview file is in %(outdir)s.' def init(self): # type: () -> None diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index 88a9be219..c5e9eb6ea 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -43,6 +43,10 @@ class DevhelpBuilder(StandaloneHTMLBuilder): Builder that also outputs GNOME Devhelp file. """ name = 'devhelp' + epilog = ('To view the help file:\n' + '$ mkdir -p $HOME/.local/share/devhelp/%(project)s\n' + '$ ln -s %(outdir)s $HOME/.local/share/devhelp/%(project)s\n' + '$ devhelp') # don't copy the reST source copysource = False diff --git a/sphinx/builders/dummy.py b/sphinx/builders/dummy.py index 74a3d4187..08d99a584 100644 --- a/sphinx/builders/dummy.py +++ b/sphinx/builders/dummy.py @@ -21,6 +21,8 @@ if False: class DummyBuilder(Builder): name = 'dummy' + epilog = 'The dummy builder generates no files.' + allow_parallel = True def init(self): diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 92c55c880..c98c4b853 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -63,6 +63,7 @@ class Epub3Builder(_epub_base.EpubBuilder): an epub file. """ name = 'epub' + epilog = 'The ePub file is in %(outdir)s.' supported_remote_images = False template_dir = path.join(package_dir, 'templates', 'epub3') diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index 464d574cc..f7f0d6811 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -214,6 +214,7 @@ class MessageCatalogBuilder(I18nBuilder): Builds gettext-style message catalogs (.pot files). """ name = 'gettext' + epilog = 'The message catalogs are in %(outdir)s.' def init(self): # type: () -> None diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index f9c9420c2..dcbc59280 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -153,6 +153,8 @@ class StandaloneHTMLBuilder(Builder): """ name = 'html' format = 'html' + epilog = 'The HTML pages are in %(outdir)s.' + copysource = True allow_parallel = True out_suffix = '.html' @@ -1066,6 +1068,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): HTML page. """ name = 'singlehtml' + epilog = 'The HTML page is in %(outdir)s.' + copysource = False def get_outdated_docs(self): # type: ignore @@ -1328,12 +1332,14 @@ class PickleHTMLBuilder(SerializingHTMLBuilder): """ A Builder that dumps the generated HTML into pickle files. """ + name = 'pickle' + epilog = 'You can now process the pickle files in %(outdir)s.' + implementation = pickle implementation_dumps_unicode = False additional_dump_args = (pickle.HIGHEST_PROTOCOL,) indexer_format = pickle indexer_dumps_unicode = False - name = 'pickle' out_suffix = '.fpickle' globalcontext_filename = 'globalcontext.pickle' searchindex_filename = 'searchindex.pickle' @@ -1347,11 +1353,13 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): """ A builder that dumps the generated HTML into JSON files. """ + name = 'json' + epilog = 'You can now process the JSON files in %(outdir)s.' + implementation = jsonimpl implementation_dumps_unicode = True indexer_format = jsonimpl indexer_dumps_unicode = True - name = 'json' out_suffix = '.fjson' globalcontext_filename = 'globalcontext.json' searchindex_filename = 'searchindex.json' diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 0b45601e3..63fba05f3 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -174,6 +174,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): index files. Adapted from the original Doc/tools/prechm.py. """ name = 'htmlhelp' + epilog = ('You can now run HTML Help Workshop with the .htp file in ' + '%(outdir)s.') # don't copy the reST source copysource = False diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py index 8fdb2fa49..088f5d9ef 100644 --- a/sphinx/builders/latex.py +++ b/sphinx/builders/latex.py @@ -49,6 +49,12 @@ class LaTeXBuilder(Builder): """ name = 'latex' format = 'latex' + epilog = 'The LaTeX files are in %(outdir)s.' + if os.name == 'posix': + epilog += ("\nRun 'make' in that directory to run these through " + "(pdf)latex\n" + "(use `make latexpdf' here to do that automatically).") + supported_image_types = ['application/pdf', 'image/png', 'image/jpeg'] supported_remote_images = False default_translator_class = LaTeXTranslator diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index ca62b9fe1..c1a47607b 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -90,6 +90,8 @@ class CheckExternalLinksBuilder(Builder): Checks for broken external links. """ name = 'linkcheck' + epilog = ('Look for any errors in the above output or in ' + '%(outdir)s/output.txt') def init(self): # type: () -> None diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index b57a756ee..8f7800846 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -40,6 +40,8 @@ class ManualPageBuilder(Builder): """ name = 'man' format = 'man' + epilog = 'The manual pages are in %(outdir)s.' + default_translator_class = ManualPageTranslator supported_image_types = [] # type: List[unicode] diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 2f56792a9..9d08df2a3 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -108,6 +108,11 @@ class QtHelpBuilder(StandaloneHTMLBuilder): Builder that also outputs Qt help project, contents and index files. """ name = 'qthelp' + epilog = ('You can now run "qcollectiongenerator" with the .qhcp ' + 'project file in %(outdir)s, like this:\n' + '$ qcollectiongenerator %(outdir)s/%(project)s.qhcp\n' + 'To view the help file:\n' + '$ assistant -collectionFile %(outdir)s/%(project)s.qhc') # don't copy the reST source copysource = False diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 82c6f1b9d..39653c117 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -9,6 +9,7 @@ :license: BSD, see LICENSE for details. """ +import os from os import path from docutils import nodes @@ -97,6 +98,12 @@ class TexinfoBuilder(Builder): """ name = 'texinfo' format = 'texinfo' + epilog = 'The Texinfo files are in %(outdir)s.' + if os.name == 'posix': + epilog += ("\nRun 'make' in that directory to run these through " + "makeinfo\n" + "(use 'make info' here to do that automatically).") + supported_image_types = ['image/png', 'image/jpeg', 'image/gif'] default_translator_class = TexinfoTranslator diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index 7b977b1b9..babb6ccee 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -21,7 +21,7 @@ from sphinx.writers.text import TextWriter, TextTranslator if False: # For type annotation - from typing import Any, Dict, Iterator, Set # NOQA + from typing import Any, Dict, Iterator, Set, Tuple # NOQA from docutils import nodes # NOQA from sphinx.application import Sphinx # NOQA @@ -31,6 +31,8 @@ logger = logging.getLogger(__name__) class TextBuilder(Builder): name = 'text' format = 'text' + epilog = 'The text files are in %(outdir)s.' + out_suffix = '.txt' allow_parallel = True default_translator_class = TextTranslator @@ -39,7 +41,8 @@ class TextBuilder(Builder): def init(self): # type: () -> None - pass + # section numbers for headings in the currently visited document + self.secnumbers = {} # type: Dict[unicode, Tuple[int, ...]] def get_outdated_docs(self): # type: () -> Iterator[unicode] @@ -72,6 +75,7 @@ class TextBuilder(Builder): def write_doc(self, docname, doctree): # type: (unicode, nodes.Node) -> None self.current_docname = docname + self.secnumbers = self.env.toc_secnumbers.get(docname, {}) destination = StringOutput(encoding='utf-8') self.writer.write(doctree, destination) outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix) @@ -93,6 +97,8 @@ def setup(app): app.add_config_value('text_sectionchars', '*=-~"+`', 'env') app.add_config_value('text_newlines', 'unix', 'env') + app.add_config_value('text_add_secnumbers', True, 'env') + app.add_config_value('text_secnumber_suffix', '. ', 'env') return { 'version': 'builtin', diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py index 599530ac1..80d7723aa 100644 --- a/sphinx/builders/xml.py +++ b/sphinx/builders/xml.py @@ -35,6 +35,8 @@ class XMLBuilder(Builder): """ name = 'xml' format = 'xml' + epilog = 'The XML files are in %(outdir)s.' + out_suffix = '.xml' allow_parallel = True @@ -108,6 +110,8 @@ class PseudoXMLBuilder(XMLBuilder): """ name = 'pseudoxml' format = 'pseudoxml' + epilog = 'The pseudo-XML files are in %(outdir)s.' + out_suffix = '.pseudoxml' _writer_class = PseudoXMLWriter diff --git a/sphinx/config.py b/sphinx/config.py index c6bf1cc3c..1b3f51a6e 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -125,6 +125,7 @@ class Config(object): primary_domain = ('py', 'env', [NoneType]), needs_sphinx = (None, None, string_classes), needs_extensions = ({}, None), + manpages_url = (None, 'env'), nitpicky = (False, None), nitpick_ignore = ([], None), numfig = (False, 'env'), diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 101cb930f..cea1c12bd 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -23,7 +23,7 @@ from sphinx.util.inspect import isenumclass, safe_getattr if False: # For type annotation - from typing import Any, Callable, Dict, Generator, List, Optional, Set # NOQA + from typing import Any, Callable, Dict, Generator, List, Optional # NOQA logger = logging.getLogger(__name__) @@ -84,13 +84,7 @@ class _MockModule(ModuleType): class _MockImporter(object): def __init__(self, names): # type: (List[str]) -> None - self.base_packages = set() # type: Set[str] - for n in names: - # Convert module names: - # ['a.b.c', 'd.e'] - # to a set of base packages: - # set(['a', 'd']) - self.base_packages.add(n.split('.')[0]) + self.names = names self.mocked_modules = [] # type: List[str] # enable hook by adding itself to meta_path sys.meta_path = sys.meta_path + [self] @@ -106,9 +100,10 @@ class _MockImporter(object): def find_module(self, name, path=None): # type: (str, str) -> Any - base_package = name.split('.')[0] - if base_package in self.base_packages: - return self + # check if name is (or is a descendant of) one of our base_packages + for n in self.names: + if n == name or name.startswith(n + '.'): + return self return None def load_module(self, name): diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 476a0ed46..74d004ad1 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -50,8 +50,12 @@ def compile_regex_list(name, exps): class CoverageBuilder(Builder): - + """ + Evaluates coverage of code in the documentation. + """ name = 'coverage' + epilog = ('Testing of coverage in the sources finished, look at the ' + 'results in %(outdir)s/python.txt.') def init(self): # type: () -> None diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index e0ce050f7..cd35e789a 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -20,7 +20,8 @@ from os import path import doctest from six import itervalues, StringIO, binary_type, text_type, PY2 -from distutils.version import LooseVersion +from packaging.specifiers import SpecifierSet, InvalidSpecifier +from packaging.version import Version from docutils import nodes from docutils.parsers.rst import Directive, directives @@ -57,28 +58,23 @@ else: return text -def compare_version(ver1, ver2, operand): - # type: (unicode, unicode, unicode) -> bool - """Compare `ver1` to `ver2`, relying on `operand`. +def is_allowed_version(spec, version): + # type: (unicode, unicode) -> bool + """Check `spec` satisfies `version` or not. + + This obeys PEP-440 specifiers: + https://www.python.org/dev/peps/pep-0440/#version-specifiers Some examples: - >>> compare_version('3.3', '3.5', '<=') + >>> is_allowed_version('3.3', '<=3.5') True - >>> compare_version('3.3', '3.2', '<=') + >>> is_allowed_version('3.3', '<=3.2') False - >>> compare_version('3.3a0', '3.3', '<=') + >>> is_allowed_version('3.3', '>3.2, <4.0') True """ - if operand not in ('<=', '<', '==', '>=', '>'): - raise ValueError("'%s' is not a valid operand.") - v1 = LooseVersion(ver1) - v2 = LooseVersion(ver2) - return ((operand == '<=' and (v1 <= v2)) or - (operand == '<' and (v1 < v2)) or - (operand == '==' and (v1 == v2)) or - (operand == '>=' and (v1 >= v2)) or - (operand == '>' and (v1 > v2))) + return Version(version) in SpecifierSet(spec) # set up the necessary directives @@ -120,7 +116,11 @@ class TestDirective(Directive): if test is not None: # only save if it differs from code node['test'] = test - if self.name == 'testoutput': + if self.name == 'doctest': + node['language'] = 'pycon' + elif self.name == 'testcode': + node['language'] = 'python' + elif self.name == 'testoutput': # don't try to highlight output node['language'] = 'none' node['options'] = {} @@ -143,16 +143,13 @@ class TestDirective(Directive): node['options'][flag] = (option[0] == '+') if self.name == 'doctest' and 'pyversion' in self.options: try: - option = self.options['pyversion'] - # :pyversion: >= 3.6 --> operand='>=', option_version='3.6' - operand, option_version = [item.strip() for item in option.split()] - running_version = platform.python_version() - if not compare_version(running_version, option_version, operand): + spec = self.options['pyversion'] + if not is_allowed_version(spec, platform.python_version()): flag = doctest.OPTIONFLAGS_BY_NAME['SKIP'] node['options'][flag] = True # Skip the test - except ValueError: + except InvalidSpecifier: self.state.document.reporter.warning( - _("'%s' is not a valid pyversion option") % option, + _("'%s' is not a valid pyversion option") % spec, line=self.lineno) return [node] @@ -278,6 +275,8 @@ class DocTestBuilder(Builder): Runs test snippets in the documentation. """ name = 'doctest' + epilog = ('Testing of doctests in the sources finished, look at the ' + 'results in %(outdir)s/output.txt.') def init(self): # type: () -> None diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 8e01a1b28..d9affb804 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -130,8 +130,8 @@ class InheritanceGraph(object): graphviz dot graph from them. """ def __init__(self, class_names, currmodule, show_builtins=False, - private_bases=False, parts=0, aliases=None): - # type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]]) -> None + private_bases=False, parts=0, aliases=None, top_classes=[]): + # type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]], List[Any]) -> None # NOQA """*class_names* is a list of child classes to show bases from. If *show_builtins* is True, then Python builtins will be shown @@ -140,7 +140,7 @@ class InheritanceGraph(object): self.class_names = class_names classes = self._import_classes(class_names, currmodule) self.class_info = self._class_info(classes, show_builtins, - private_bases, parts, aliases) + private_bases, parts, aliases, top_classes) if not self.class_info: raise InheritanceException('No classes found for ' 'inheritance diagram') @@ -153,13 +153,16 @@ class InheritanceGraph(object): classes.extend(import_classes(name, currmodule)) return classes - def _class_info(self, classes, show_builtins, private_bases, parts, aliases): - # type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA + def _class_info(self, classes, show_builtins, private_bases, parts, aliases, top_classes): + # type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]], List[Any]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA """Return name and bases for all classes that are ancestors of *classes*. *parts* gives the number of dotted name parts that is removed from the displayed node names. + + *top_classes* gives the name(s) of the top most ancestor class to traverse + to. Multiple names can be specified separated by comma. """ all_classes = {} py_builtins = vars(builtins).values() @@ -189,6 +192,10 @@ class InheritanceGraph(object): baselist = [] # type: List[unicode] all_classes[cls] = (nodename, fullname, baselist, tooltip) + + if fullname in top_classes: + return + for base in cls.__bases__: if not show_builtins and base in py_builtins: continue @@ -322,6 +329,7 @@ class InheritanceDiagram(Directive): 'parts': directives.nonnegative_int, 'private-bases': directives.flag, 'caption': directives.unchanged, + 'top-classes': directives.unchanged_required, } def run(self): @@ -334,6 +342,11 @@ class InheritanceDiagram(Directive): # Store the original content for use as a hash node['parts'] = self.options.get('parts', 0) node['content'] = ', '.join(class_names) + node['top-classes'] = [] + for cls in self.options.get('top-classes', '').split(','): + cls = cls.strip() + if cls: + node['top-classes'].append(cls) # Create a graph starting with the list of classes try: @@ -341,7 +354,8 @@ class InheritanceDiagram(Directive): class_names, env.ref_context.get('py:module'), parts=node['parts'], private_bases='private-bases' in self.options, - aliases=env.config.inheritance_alias) + aliases=env.config.inheritance_alias, + top_classes=node['top-classes']) except InheritanceException as err: return [node.document.reporter.warning(err.args[0], line=self.lineno)] diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index a74f0641a..0858e4d5d 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -20,14 +20,14 @@ from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): - self.body.append(self.starttag(node, 'span', '', CLASS='math')) + self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate')) self.body.append(self.encode(node['latex']) + '') raise nodes.SkipNode def html_visit_displaymath(self, node): if node['nowrap']: - self.body.append(self.starttag(node, 'div', CLASS='math')) + self.body.append(self.starttag(node, 'div', CLASS='math notranslate')) self.body.append(self.encode(node['latex'])) self.body.append('') raise nodes.SkipNode @@ -40,7 +40,7 @@ def html_visit_displaymath(self, node): self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') - self.body.append(self.starttag(node, 'div', CLASS='math')) + self.body.append(self.starttag(node, 'div', CLASS='math notranslate')) else: # but only once! self.body.append('
') diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index 8698e2801..bfbd34979 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -21,7 +21,7 @@ from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): - self.body.append(self.starttag(node, 'span', '', CLASS='math')) + self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate')) self.body.append(self.builder.config.mathjax_inline[0] + self.encode(node['latex']) + self.builder.config.mathjax_inline[1] + '') @@ -29,7 +29,7 @@ def html_visit_math(self, node): def html_visit_displaymath(self, node): - self.body.append(self.starttag(node, 'div', CLASS='math')) + self.body.append(self.starttag(node, 'div', CLASS='math notranslate')) if node['nowrap']: self.body.append(self.encode(node['latex'])) self.body.append('
') diff --git a/sphinx/io.py b/sphinx/io.py index 39d653a19..6943a78d0 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -24,7 +24,7 @@ from sphinx.transforms import ( ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, - UnreferencedFootnotesDetector, SphinxSmartQuotes + UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink ) from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.i18n import ( @@ -94,6 +94,7 @@ class SphinxStandaloneReader(SphinxBaseReader): HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, RefOnlyBulletListTransform, UnreferencedFootnotesDetector, SphinxSmartQuotes, + ManpageLink ] # type: List[Transform] def __init__(self, app, *args, **kwargs): @@ -116,7 +117,7 @@ class SphinxI18nReader(SphinxBaseReader): DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, SortIds, RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform, - UnreferencedFootnotesDetector] + UnreferencedFootnotesDetector, ManpageLink] def set_lineno_for_reporter(self, lineno): # type: (int) -> None diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py index 0bc1a797d..4b325160f 100644 --- a/sphinx/make_mode.py +++ b/sphinx/make_mode.py @@ -97,101 +97,6 @@ class Make(object): if not osname or os.name == osname: print(' %s %s' % (blue(bname.ljust(10)), description)) - def build_html(self): - # type: () -> int - if self.run_generic_build('html') > 0: - return 1 - print() - print('Build finished. The HTML pages are in %s.' % self.builddir_join('html')) - return 0 - - def build_dirhtml(self): - # type: () -> int - if self.run_generic_build('dirhtml') > 0: - return 1 - print() - print('Build finished. The HTML pages are in %s.' % - self.builddir_join('dirhtml')) - return 0 - - def build_singlehtml(self): - # type: () -> int - if self.run_generic_build('singlehtml') > 0: - return 1 - print() - print('Build finished. The HTML page is in %s.' % - self.builddir_join('singlehtml')) - return 0 - - def build_pickle(self): - # type: () -> int - if self.run_generic_build('pickle') > 0: - return 1 - print() - print('Build finished; now you can process the pickle files.') - return 0 - - def build_json(self): - # type: () -> int - if self.run_generic_build('json') > 0: - return 1 - print() - print('Build finished; now you can process the JSON files.') - return 0 - - def build_htmlhelp(self): - # type: () -> int - if self.run_generic_build('htmlhelp') > 0: - return 1 - print() - print('Build finished; now you can run HTML Help Workshop with the ' - '.hhp project file in %s.' % self.builddir_join('htmlhelp')) - return 0 - - def build_qthelp(self): - # type: () -> int - if self.run_generic_build('qthelp') > 0: - return 1 - print() - print('Build finished; now you can run "qcollectiongenerator" with the ' - '.qhcp project file in %s, like this:' % self.builddir_join('qthelp')) - print('$ qcollectiongenerator %s.qhcp' % self.builddir_join('qthelp', proj_name)) - print('To view the help file:') - print('$ assistant -collectionFile %s.qhc' % - self.builddir_join('qthelp', proj_name)) - return 0 - - def build_devhelp(self): - # type: () -> int - if self.run_generic_build('devhelp') > 0: - return 1 - print() - print("Build finished.") - print("To view the help file:") - print("$ mkdir -p $HOME/.local/share/devhelp/" + proj_name) - print("$ ln -s %s $HOME/.local/share/devhelp/%s" % - (self.builddir_join('devhelp'), proj_name)) - print("$ devhelp") - return 0 - - def build_epub(self): - # type: () -> int - if self.run_generic_build('epub') > 0: - return 1 - print() - print('Build finished. The ePub file is in %s.' % self.builddir_join('epub')) - return 0 - - def build_latex(self): - # type: () -> int - if self.run_generic_build('latex') > 0: - return 1 - print("Build finished; the LaTeX files are in %s." % self.builddir_join('latex')) - if os.name == 'posix': - print("Run `make' in that directory to run these through (pdf)latex") - print("(use `make latexpdf' here to do that automatically).") - return 0 - def build_latexpdf(self): # type: () -> int if self.run_generic_build('latex') > 0: @@ -206,25 +111,6 @@ class Make(object): with cd(self.builddir_join('latex')): return subprocess.call([self.makecmd, 'all-pdf-ja']) - def build_text(self): - # type: () -> int - if self.run_generic_build('text') > 0: - return 1 - print() - print('Build finished. The text files are in %s.' % self.builddir_join('text')) - return 0 - - def build_texinfo(self): - # type: () -> int - if self.run_generic_build('texinfo') > 0: - return 1 - print("Build finished; the Texinfo files are in %s." % - self.builddir_join('texinfo')) - if os.name == 'posix': - print("Run `make' in that directory to run these through makeinfo") - print("(use `make info' here to do that automatically).") - return 0 - def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: @@ -237,60 +123,6 @@ class Make(object): dtdir = self.builddir_join('gettext', '.doctrees') if self.run_generic_build('gettext', doctreedir=dtdir) > 0: return 1 - print() - print('Build finished. The message catalogs are in %s.' % - self.builddir_join('gettext')) - return 0 - - def build_changes(self): - # type: () -> int - if self.run_generic_build('changes') > 0: - return 1 - print() - print('Build finished. The overview file is in %s.' % - self.builddir_join('changes')) - return 0 - - def build_linkcheck(self): - # type: () -> int - res = self.run_generic_build('linkcheck') - print() - print('Link check complete; look for any errors in the above output ' - 'or in %s.' % self.builddir_join('linkcheck', 'output.txt')) - return res - - def build_doctest(self): - # type: () -> int - res = self.run_generic_build('doctest') - print("Testing of doctests in the sources finished, look at the " - "results in %s." % self.builddir_join('doctest', 'output.txt')) - return res - - def build_coverage(self): - # type: () -> int - if self.run_generic_build('coverage') > 0: - print("Has the coverage extension been enabled?") - return 1 - print() - print("Testing of coverage in the sources finished, look at the " - "results in %s." % self.builddir_join('coverage')) - return 0 - - def build_xml(self): - # type: () -> int - if self.run_generic_build('xml') > 0: - return 1 - print() - print('Build finished. The XML files are in %s.' % self.builddir_join('xml')) - return 0 - - def build_pseudoxml(self): - # type: () -> int - if self.run_generic_build('pseudoxml') > 0: - return 1 - print() - print('Build finished. The pseudo-XML files are in %s.' % - self.builddir_join('pseudoxml')) return 0 def run_generic_build(self, builder, doctreedir=None): diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 2858d9bf7..bf752404e 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -5,14 +5,16 @@ SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build PAPER ?= +SOURCEDIR = {{ rsrcdir }} BUILDDIR = {{ rbuilddir }} # Internal variables. PAPEROPT_a4 = -D latex_elements.papersize=a4 PAPEROPT_letter = -D latex_elements.papersize=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }} +# $(O) is meant as a shortcut for $(SPHINXOPTS) +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR) # the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }} +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR) .PHONY: help help: @@ -49,86 +51,6 @@ help: clean: rm -rf $(BUILDDIR)/* -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/{{ project_fn }}.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/{{ project_fn }}.qhc" - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/{{ project_fn }}" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/{{ project_fn }}" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - .PHONY: latexpdf latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @@ -157,26 +79,6 @@ xelatexpdf: $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex." -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @@ -187,49 +89,9 @@ info: .PHONY: gettext gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." - -.PHONY: dummy -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy - @echo - @echo "Build finished. Dummy builder generates no files." +# Catch-all target: route all unknown targets to Sphinx +.PHONY: Makefile +%: Makefile + $(SPHINXBUILD) -b "$@" $(ALLSPHINXOPTS) "$(BUILDDIR)/$@" diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index c42861c28..2f3f71b1e 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -1,19 +1,12 @@ -{% if PY3 -%} -#!/usr/bin/env python3 -{% endif -%} # -*- coding: utf-8 -*- # -# {{ project }} documentation build configuration file, created by -# sphinx-quickstart on {{ now }}. +# Configuration file for the Sphinx documentation builder. # -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/stable/config + +# -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -33,7 +26,19 @@ sys.path.insert(0, u'{{ module_path }}') {% endif -%} {% endif %} -# -- General configuration ------------------------------------------------ +# -- Project information ----------------------------------------------------- + +project = u'{{ project_str }}' +copyright = u'{{ copyright_str }}' +author = u'{{ author_str }}' + +# The short X.Y version +version = u'{{ version_str }}' +# The full version, including alpha/beta/rc tags +release = u'{{ release_str }}' + + +# -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # @@ -60,20 +65,6 @@ source_suffix = '{{ suffix }}' # The master toctree document. master_doc = '{{ master_str }}' -# General information about the project. -project = u'{{ project_str }}' -copyright = u'{{ copyright_str }}' -author = u'{{ author_str }}' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'{{ version_str }}' -# The full version, including alpha/beta/rc tags. -release = u'{{ release_str }}' - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # @@ -90,7 +81,7 @@ exclude_patterns = [{{ exclude_patterns }}] pygments_style = 'sphinx' -# -- Options for HTML output ---------------------------------------------- +# -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. @@ -119,13 +110,13 @@ html_static_path = ['{{ dot }}static'] # html_sidebars = {} -# -- Options for HTMLHelp output ------------------------------------------ +# -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = '{{ project_fn }}doc' -# -- Options for LaTeX output --------------------------------------------- +# -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). @@ -154,7 +145,7 @@ latex_documents = [ ] -# -- Options for manual page output --------------------------------------- +# -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). @@ -164,7 +155,7 @@ man_pages = [ ] -# -- Options for Texinfo output ------------------------------------------- +# -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, @@ -177,7 +168,7 @@ texinfo_documents = [ {%- if epub %} -# -- Options for Epub output ---------------------------------------------- +# -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project @@ -200,18 +191,18 @@ epub_exclude_files = ['search.html'] {%- if extensions %} -# -- Extension configuration ---------------------------------------------- +# -- Extension configuration ------------------------------------------------- {%- endif %} {%- if 'sphinx.ext.intersphinx' in extensions %} -# -- Options for intersphinx extension ------------------------------------ +# -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} {%- endif %} {%- if 'sphinx.ext.todo' in extensions %} -# -- Options for todo extension ------------------------------------------- +# -- Options for todo extension ---------------------------------------------- # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 230977488..6e8665a49 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -8,8 +8,9 @@ if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR={{ rbuilddir }} -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% {{ rsrcdir }} -set I18NSPHINXOPTS=%SPHINXOPTS% {{ rsrcdir }} +set SOURCEDIR={{ rsrcdir }} +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SOURCEDIR% +set I18NSPHINXOPTS=%SPHINXOPTS% %SOURCEDIR% if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_elements.papersize=%PAPER% %I18NSPHINXOPTS% @@ -50,7 +51,6 @@ if "%1" == "clean" ( goto end ) - REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python @@ -74,92 +74,6 @@ if errorlevel 9009 ( :sphinx_ok - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\{{ project_fn }}.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\{{ project_fn }}.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex @@ -180,96 +94,14 @@ if "%1" == "latexpdfja" ( goto end ) -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -if "%1" == "dummy" ( - %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. Dummy builder generates no files. - goto end -) +%SPHINXBUILD% -b %1 %ALLSPHINXOPTS% %BUILDDIR%/%1 +goto end :end popd diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 2b41673db..075ae408b 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -504,7 +504,7 @@ \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} - \fancyhead[LE,RO]{{\py@HeaderFamily \@title, \py@release}} + \fancyhead[LE,RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}} \renewcommand{\headrulewidth}{0.4pt} \renewcommand{\footrulewidth}{0.4pt} % define chaptermark with \@chappos when \@chappos is available for Japanese @@ -1401,18 +1401,26 @@ % \date{}. This allows the date to reflect the document's date and % release to specify the release that is documented. % -\newcommand{\py@release}{} -\newcommand{\version}{} -\newcommand{\shortversion}{} +\newcommand{\py@release}{\releasename\space\version} +\newcommand{\version}{}% part of \py@release, used by title page and headers +% \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls) \newcommand{\releaseinfo}{} -\newcommand{\releasename}{Release} -\newcommand{\release}[1]{% - \renewcommand{\py@release}{\releasename\space\version}% - \renewcommand{\version}{#1}} -\newcommand{\setshortversion}[1]{% - \renewcommand{\shortversion}{#1}} -\newcommand{\setreleaseinfo}[1]{% - \renewcommand{\releaseinfo}{#1}} +\newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}} +% this is inserted via template and #1=release config variable +\newcommand{\release}[1]{\renewcommand{\version}{#1}} +% this is defined by template to 'releasename' latex_elements key +\newcommand{\releasename}{} +% Fix issue in case release and releasename deliberately left blank +\newcommand{\sphinxheadercomma}{, }% used in fancyhdr header definition +\newcommand{\sphinxifemptyorblank}[1]{% +% test after one expansion of macro #1 if contents is empty or spaces + \if&\expandafter\@firstofone\detokenize\expandafter{#1}&% + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}% +\AtBeginDocument {% + \sphinxifemptyorblank{\releasename} + {\sphinxifemptyorblank{\version}{\let\sphinxheadercomma\empty}{}} + {}% +}% % Allow specification of the author's address separately from the % author's name. This can be used to format them differently, which diff --git a/sphinx/themes/basic/documentation_options.js_t b/sphinx/themes/basic/documentation_options.js_t new file mode 100644 index 000000000..e76f55a4e --- /dev/null +++ b/sphinx/themes/basic/documentation_options.js_t @@ -0,0 +1,9 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: '{{ url_root }}', + VERSION: '{{ release|e }}', + LANGUAGE: '{{ language }}', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}', + HAS_SOURCE: {{ has_source|lower }}, + SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}' +}; diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 75c1ca568..dc05e980d 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -87,16 +87,7 @@ {%- endmacro %} {%- macro script() %} - + {%- for scriptfile in script_files %} {%- endfor %} diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 4e8c6f0bd..a0bc25c25 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -9,6 +9,8 @@ :license: BSD, see LICENSE for details. """ +import re + from docutils import nodes from docutils.transforms import Transform, Transformer from docutils.transforms.parts import ContentsFilter @@ -391,3 +393,21 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform): for txtnode in txtnodes: notsmartquotable = not is_smartquotable(txtnode) yield (texttype[notsmartquotable], txtnode.astext()) + + +class ManpageLink(SphinxTransform): + """Find manpage section numbers and names""" + default_priority = 999 + + def apply(self): + for node in self.document.traverse(addnodes.manpage): + manpage = ' '.join([str(x) for x in node.children + if isinstance(x, nodes.Text)]) + pattern = r'^(?P(?P.+)[\(\.](?P
[1-9]\w*)?\)?)$' # noqa + info = {'path': manpage, + 'page': manpage, + 'section': ''} + r = re.match(pattern, manpage) + if r: + info = r.groupdict() + node.attributes.update(info) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 62cd1a7e9..8c10b7aa5 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -404,10 +404,18 @@ class Signature(object): if annotation == Ellipsis: return '...' if not isinstance(annotation, type): - return repr(annotation) + qualified_name = repr(annotation) + if qualified_name.startswith('typing.'): # for typing.Union + return qualified_name.split('.', 1)[1] + else: + return qualified_name - qualified_name = (annotation.__module__ + '.' + annotation.__qualname__ # type: ignore - if annotation else repr(annotation)) + if not annotation: + qualified_name = repr(annotation) + elif annotation.__module__ == 'typing': + qualified_name = annotation.__qualname__ # type: ignore + else: + qualified_name = (annotation.__module__ + '.' + annotation.__qualname__) # type: ignore # NOQA if annotation.__module__ == 'builtins': return annotation.__qualname__ # type: ignore diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index b3d27e31a..16fc69bea 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -79,6 +79,7 @@ class HTMLTranslator(BaseTranslator): self.highlightopts = builder.config.highlight_options self.highlightlinenothreshold = sys.maxsize self.docnames = [builder.current_docname] # for singlehtml builder + self.manpages_url = builder.config.manpages_url self.protect_literal_text = 0 self.permalink_text = builder.config.html_add_permalinks # support backwards-compatible setting to a bool @@ -443,7 +444,7 @@ class HTMLTranslator(BaseTranslator): location=(self.builder.current_docname, node.line), **highlight_args ) starttag = self.starttag(node, 'div', suffix='', - CLASS='highlight-%s' % lang) + CLASS='highlight-%s notranslate' % lang) self.body.append(starttag + highlighted + '\n') raise nodes.SkipNode @@ -493,10 +494,10 @@ class HTMLTranslator(BaseTranslator): # type: (nodes.Node) -> None if 'kbd' in node['classes']: self.body.append(self.starttag(node, 'kbd', '', - CLASS='docutils literal')) + CLASS='docutils literal notranslate')) else: self.body.append(self.starttag(node, 'code', '', - CLASS='docutils literal')) + CLASS='docutils literal notranslate')) self.protect_literal_text += 1 def depart_literal(self, node): @@ -816,9 +817,14 @@ class HTMLTranslator(BaseTranslator): def visit_manpage(self, node): # type: (nodes.Node) -> None self.visit_literal_emphasis(node) + if self.manpages_url: + node['refuri'] = self.manpages_url.format(**node.attributes) + self.visit_reference(node) def depart_manpage(self, node): # type: (nodes.Node) -> None + if self.manpages_url: + self.depart_reference(node) self.depart_literal_emphasis(node) # overwritten to add even/odd classes diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index a47fee77e..c2810a898 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -49,6 +49,7 @@ class HTML5Translator(BaseTranslator): self.highlightopts = builder.config.highlight_options self.highlightlinenothreshold = sys.maxsize self.docnames = [builder.current_docname] # for singlehtml builder + self.manpages_url = builder.config.manpages_url self.protect_literal_text = 0 self.permalink_text = builder.config.html_add_permalinks # support backwards-compatible setting to a bool @@ -389,7 +390,7 @@ class HTML5Translator(BaseTranslator): location=(self.builder.current_docname, node.line), **highlight_args ) starttag = self.starttag(node, 'div', suffix='', - CLASS='highlight-%s' % lang) + CLASS='highlight-%s notranslate' % lang) self.body.append(starttag + highlighted + '\n') raise nodes.SkipNode @@ -439,10 +440,10 @@ class HTML5Translator(BaseTranslator): # type: (nodes.Node) -> None if 'kbd' in node['classes']: self.body.append(self.starttag(node, 'kbd', '', - CLASS='docutils literal')) + CLASS='docutils literal notranslate')) else: self.body.append(self.starttag(node, 'code', '', - CLASS='docutils literal')) + CLASS='docutils literal notranslate')) self.protect_literal_text += 1 def depart_literal(self, node): @@ -758,9 +759,14 @@ class HTML5Translator(BaseTranslator): def visit_manpage(self, node): # type: (nodes.Node) -> None self.visit_literal_emphasis(node) + if self.manpages_url: + node['refuri'] = self.manpages_url.format(**dict(node)) + self.visit_reference(node) def depart_manpage(self, node): # type: (nodes.Node) -> None + if self.manpages_url: + self.depart_reference(node) self.depart_literal_emphasis(node) # overwritten to add even/odd classes diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index de472b36c..3139a43ad 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -549,7 +549,7 @@ class LaTeXTranslator(nodes.NodeVisitor): 'author': document.settings.author, # treat as a raw LaTeX code 'indexname': _('Index'), }) - if not self.elements['releasename']: + if not self.elements['releasename'] and self.elements['release']: self.elements.update({ 'releasename': _('Release'), }) @@ -1376,6 +1376,9 @@ class LaTeXTranslator(nodes.NodeVisitor): self.table = Table(node) if self.next_table_colspec: self.table.colspec = '{%s}\n' % self.next_table_colspec + if 'colwidths-given' in node.get('classes', []): + logger.info('both tabularcolumns and :widths: option are given. ' + ':widths: is ignored.', location=node) self.next_table_colspec = None def depart_table(self, node): @@ -1853,28 +1856,14 @@ class LaTeXTranslator(nodes.NodeVisitor): (node['align'] == 'right' and 'r' or 'l', length or '0pt')) self.context.append(ids + '\\end{wrapfigure}\n') elif self.in_minipage: - if ('align' not in node.attributes or - node.attributes['align'] == 'center'): - self.body.append('\n\\begin{center}') - self.context.append('\\end{center}\n') - else: - self.body.append('\n\\begin{flush%s}' % node.attributes['align']) - self.context.append('\\end{flush%s}\n' % node.attributes['align']) + self.body.append('\n\\begin{center}') + self.context.append('\\end{center}\n') else: - if ('align' not in node.attributes or - node.attributes['align'] == 'center'): - # centering does not add vertical space like center. - align = '\n\\centering' - align_end = '' - else: - # TODO non vertical space for other alignments. - align = '\\begin{flush%s}' % node.attributes['align'] - align_end = '\\end{flush%s}' % node.attributes['align'] - self.body.append('\n\\begin{figure}[%s]%s\n' % ( - self.elements['figure_align'], align)) + self.body.append('\n\\begin{figure}[%s]\n\\centering\n' % + self.elements['figure_align']) if any(isinstance(child, nodes.caption) for child in node): self.body.append('\\capstart\n') - self.context.append(ids + align_end + '\\end{figure}\n') + self.context.append(ids + '\\end{figure}\n') def depart_figure(self, node): # type: (nodes.Node) -> None diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index b6e3f4cec..dda803025 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -183,6 +183,8 @@ class TextTranslator(nodes.NodeVisitor): else: self.nl = '\n' self.sectionchars = builder.config.text_sectionchars + self.add_secnumbers = builder.config.text_add_secnumbers + self.secnumber_suffix = builder.config.text_secnumber_suffix self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]] self.stateindent = [0] self.list_counter = [] # type: List[int] @@ -307,6 +309,17 @@ class TextTranslator(nodes.NodeVisitor): raise nodes.SkipNode self.new_state(0) + def get_section_number_string(self, node): + # type: (nodes.Node) -> unicode + if isinstance(node.parent, nodes.section): + anchorname = '#' + node.parent['ids'][0] + numbers = self.builder.secnumbers.get(anchorname) + if numbers is None: + numbers = self.builder.secnumbers.get('') + if numbers is not None: + return '.'.join(map(str, numbers)) + self.secnumber_suffix + return '' + def depart_title(self, node): # type: (nodes.Node) -> None if isinstance(node.parent, nodes.section): @@ -315,6 +328,8 @@ class TextTranslator(nodes.NodeVisitor): char = '^' text = None # type: unicode text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore + if self.add_secnumbers: + text = self.get_section_number_string(node) + text self.stateindent.pop() title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode] if len(self.states) == 2 and len(self.states[-1]) == 0: @@ -987,7 +1002,10 @@ class TextTranslator(nodes.NodeVisitor): def visit_reference(self, node): # type: (nodes.Node) -> None - pass + if self.add_secnumbers: + numbers = node.get("secnumber") + if numbers is not None: + self.add_text('.'.join(map(str, numbers)) + self.secnumber_suffix) def depart_reference(self, node): # type: (nodes.Node) -> None diff --git a/tests/roots/test-build-text/contents.txt b/tests/roots/test-build-text/contents.txt index 420d14280..ca9f8dc6c 100644 --- a/tests/roots/test-build-text/contents.txt +++ b/tests/roots/test-build-text/contents.txt @@ -1,5 +1,8 @@ .. toctree:: + :numbered: + doc1 + doc2 maxwidth lineblock nonascii_title diff --git a/tests/roots/test-build-text/doc1.txt b/tests/roots/test-build-text/doc1.txt new file mode 100644 index 000000000..da1909aa8 --- /dev/null +++ b/tests/roots/test-build-text/doc1.txt @@ -0,0 +1,2 @@ +Section A +========= diff --git a/tests/roots/test-build-text/doc2.txt b/tests/roots/test-build-text/doc2.txt new file mode 100644 index 000000000..ebc88e963 --- /dev/null +++ b/tests/roots/test-build-text/doc2.txt @@ -0,0 +1,9 @@ +Section B +========= + +Sub Ba +------ + +Sub Bb +------ + diff --git a/tests/roots/test-inheritance/basic_diagram.rst b/tests/roots/test-inheritance/basic_diagram.rst new file mode 100644 index 000000000..4c3838e65 --- /dev/null +++ b/tests/roots/test-inheritance/basic_diagram.rst @@ -0,0 +1,5 @@ +Basic Diagram +============== + +.. inheritance-diagram:: + dummy.test diff --git a/tests/roots/test-inheritance/conf.py b/tests/roots/test-inheritance/conf.py new file mode 100644 index 000000000..f1ddb4ad6 --- /dev/null +++ b/tests/roots/test-inheritance/conf.py @@ -0,0 +1,6 @@ +import sys, os + +sys.path.insert(0, os.path.abspath('.')) + +extensions = ['sphinx.ext.inheritance_diagram'] +source_suffix = '.rst' diff --git a/tests/roots/test-inheritance/contents.rst b/tests/roots/test-inheritance/contents.rst new file mode 100644 index 000000000..db4fbacb8 --- /dev/null +++ b/tests/roots/test-inheritance/contents.rst @@ -0,0 +1,4 @@ +.. toctree:: + :glob: + + * diff --git a/tests/roots/test-inheritance/diagram_module_w_2_top_classes.rst b/tests/roots/test-inheritance/diagram_module_w_2_top_classes.rst new file mode 100644 index 000000000..cc4365e9c --- /dev/null +++ b/tests/roots/test-inheritance/diagram_module_w_2_top_classes.rst @@ -0,0 +1,6 @@ +Diagram using module with 2 top classes +======================================= + +.. inheritance-diagram:: + dummy.test + :top-classes: dummy.test.B, dummy.test.C diff --git a/tests/roots/test-inheritance/diagram_w_1_top_class.rst b/tests/roots/test-inheritance/diagram_w_1_top_class.rst new file mode 100644 index 000000000..97da82557 --- /dev/null +++ b/tests/roots/test-inheritance/diagram_w_1_top_class.rst @@ -0,0 +1,7 @@ +Diagram using 1 top class +========================= + +.. inheritance-diagram:: + dummy.test + :top-classes: dummy.test.B + diff --git a/tests/roots/test-inheritance/diagram_w_2_top_classes.rst b/tests/roots/test-inheritance/diagram_w_2_top_classes.rst new file mode 100644 index 000000000..8a6ae5865 --- /dev/null +++ b/tests/roots/test-inheritance/diagram_w_2_top_classes.rst @@ -0,0 +1,9 @@ +Diagram using 2 top classes +=========================== + +.. inheritance-diagram:: + dummy.test.F + dummy.test.D + dummy.test.E + :top-classes: dummy.test.B, dummy.test.C + diff --git a/tests/roots/test-inheritance/diagram_w_parts.rst b/tests/roots/test-inheritance/diagram_w_parts.rst new file mode 100644 index 000000000..65a831802 --- /dev/null +++ b/tests/roots/test-inheritance/diagram_w_parts.rst @@ -0,0 +1,7 @@ +Diagram using the parts option +============================== + +.. inheritance-diagram:: + dummy.test + :parts: 1 + diff --git a/tests/roots/test-inheritance/dummy/__init__.py b/tests/roots/test-inheritance/dummy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-inheritance/dummy/test.py b/tests/roots/test-inheritance/dummy/test.py new file mode 100644 index 000000000..cafa07886 --- /dev/null +++ b/tests/roots/test-inheritance/dummy/test.py @@ -0,0 +1,30 @@ +""" + + Test with a class diagram like this:: + + A + / \ + B C + / \ / \ + E D F + +""" + +class A(object): + pass + +class B(A): + pass + +class C(A): + pass + +class D(B, C): + pass + +class E(B): + pass + +class F(C): + pass + diff --git a/tests/roots/test-manpage_url/conf.py b/tests/roots/test-manpage_url/conf.py new file mode 100644 index 000000000..c46e40773 --- /dev/null +++ b/tests/roots/test-manpage_url/conf.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' +html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-manpage_url/index.rst b/tests/roots/test-manpage_url/index.rst new file mode 100644 index 000000000..50d3b042e --- /dev/null +++ b/tests/roots/test-manpage_url/index.rst @@ -0,0 +1,3 @@ + * :manpage:`man(1)` + * :manpage:`ls.1` + * :manpage:`sphinx` diff --git a/tests/roots/test-root/autodoc_missing_imports.py b/tests/roots/test-root/autodoc_missing_imports.py index 0901ce8e2..19d4c6a05 100644 --- a/tests/roots/test-root/autodoc_missing_imports.py +++ b/tests/roots/test-root/autodoc_missing_imports.py @@ -4,6 +4,8 @@ from missing_module import missing_name import missing_package1.missing_module1 from missing_package2 import missing_module2 from missing_package3.missing_module3 import missing_name +import sphinx.missing_module4 +from sphinx.missing_module4 import missing_name2 @missing_name def decoratedFunction(): @@ -16,3 +18,5 @@ class TestAutodoc(object): def decoratedMethod(self): """TestAutodoc::decoratedMethod docstring""" return None + +sphinx.missing_module4.missing_function(len(missing_name2)) diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py index 0753fe19c..04cd87d7b 100644 --- a/tests/roots/test-root/conf.py +++ b/tests/roots/test-root/conf.py @@ -69,9 +69,10 @@ extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '), autodoc_mock_imports = [ 'missing_module', - 'missing_package1.missing_module1', - 'missing_package2.missing_module2', - 'missing_package3.missing_module3', + 'missing_package1', + 'missing_package2', + 'missing_package3', + 'sphinx.missing_module4', ] # modify tags from conf.py diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 8265c8471..2388b06ec 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -163,21 +163,21 @@ def test_html_warnings(app, warning): (".//pre/span", u'"quotes"'), (".//pre/span", u"'included'"), (".//pre/span[@class='s2']", u'üöä'), - (".//div[@class='inc-pyobj1 highlight-text']//pre", + (".//div[@class='inc-pyobj1 highlight-text notranslate']//pre", r'^class Foo:\n pass\n\s*$'), - (".//div[@class='inc-pyobj2 highlight-text']//pre", + (".//div[@class='inc-pyobj2 highlight-text notranslate']//pre", r'^ def baz\(\):\n pass\n\s*$'), - (".//div[@class='inc-lines highlight-text']//pre", + (".//div[@class='inc-lines highlight-text notranslate']//pre", r'^class Foo:\n pass\nclass Bar:\n$'), - (".//div[@class='inc-startend highlight-text']//pre", + (".//div[@class='inc-startend highlight-text notranslate']//pre", u'^foo = "Including Unicode characters: üöä"\\n$'), - (".//div[@class='inc-preappend highlight-text']//pre", + (".//div[@class='inc-preappend highlight-text notranslate']//pre", r'(?m)^START CODE$'), - (".//div[@class='inc-pyobj-dedent highlight-python']//span", + (".//div[@class='inc-pyobj-dedent highlight-python notranslate']//span", r'def'), - (".//div[@class='inc-tab3 highlight-text']//pre", + (".//div[@class='inc-tab3 highlight-text notranslate']//pre", r'-| |-'), - (".//div[@class='inc-tab8 highlight-python']//pre/span", + (".//div[@class='inc-tab8 highlight-python notranslate']//pre/span", r'-| |-'), ], 'autodoc.html': [ @@ -1243,3 +1243,16 @@ def test_html_sidebar(app, status, warning): assert '

Related Topics

' not in result assert '

This Page

' not in result assert '

Quick search

' not in result + + +@pytest.mark.parametrize('fname,expect', flat_dict({ + 'index.html': [(".//em/a[@href='https://example.com/man.1']", "", True), + (".//em/a[@href='https://example.com/ls.1']", "", True), + (".//em/a[@href='https://example.com/sphinx.']", "", True)] + })) +@pytest.mark.sphinx('html', testroot='manpage_url', confoverrides={ + 'manpages_url': 'https://example.com/{page}.{section}'}) +@pytest.mark.test_params(shared_result='test_build_html_manpage_url') +def test_html_manpage(app, cached_etree_parse, fname, expect): + app.build() + check_xpath(cached_etree_parse(app.outdir / fname), fname, *expect) diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py index 4ac70be51..168e516cf 100644 --- a/tests/test_build_html5.py +++ b/tests/test_build_html5.py @@ -72,21 +72,21 @@ def cached_etree_parse(): (".//pre/span", u'"quotes"'), (".//pre/span", u"'included'"), (".//pre/span[@class='s2']", u'üöä'), - (".//div[@class='inc-pyobj1 highlight-text']//pre", + (".//div[@class='inc-pyobj1 highlight-text notranslate']//pre", r'^class Foo:\n pass\n\s*$'), - (".//div[@class='inc-pyobj2 highlight-text']//pre", + (".//div[@class='inc-pyobj2 highlight-text notranslate']//pre", r'^ def baz\(\):\n pass\n\s*$'), - (".//div[@class='inc-lines highlight-text']//pre", + (".//div[@class='inc-lines highlight-text notranslate']//pre", r'^class Foo:\n pass\nclass Bar:\n$'), - (".//div[@class='inc-startend highlight-text']//pre", + (".//div[@class='inc-startend highlight-text notranslate']//pre", u'^foo = "Including Unicode characters: üöä"\\n$'), - (".//div[@class='inc-preappend highlight-text']//pre", + (".//div[@class='inc-preappend highlight-text notranslate']//pre", r'(?m)^START CODE$'), - (".//div[@class='inc-pyobj-dedent highlight-python']//span", + (".//div[@class='inc-pyobj-dedent highlight-python notranslate']//span", r'def'), - (".//div[@class='inc-tab3 highlight-text']//pre", + (".//div[@class='inc-tab3 highlight-text notranslate']//pre", r'-| |-'), - (".//div[@class='inc-tab8 highlight-python']//pre/span", + (".//div[@class='inc-tab8 highlight-python notranslate']//pre/span", r'-| |-'), ], 'autodoc.html': [ diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index ab91d7a48..e7b61ad0c 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -165,13 +165,15 @@ def test_latex_warnings(app, status, warning): @pytest.mark.sphinx('latex', testroot='basic') -def test_latex_title(app, status, warning): +def test_latex_basic(app, status, warning): app.builder.build_all() result = (app.outdir / 'test.tex').text(encoding='utf8') print(result) print(status.getvalue()) print(warning.getvalue()) - assert '\\title{The basic Sphinx documentation for testing}' in result + assert r'\title{The basic Sphinx documentation for testing}' in result + assert r'\release{}' in result + assert r'\renewcommand{\releasename}{}' in result @pytest.mark.sphinx('latex', testroot='latex-title') @@ -184,6 +186,18 @@ def test_latex_title_after_admonitions(app, status, warning): assert '\\title{test-latex-title}' in result +@pytest.mark.sphinx('latex', testroot='basic', + confoverrides={'release': '1.0'}) +def test_latex_release(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'test.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert r'\release{1.0}' in result + assert r'\renewcommand{\releasename}{Release}' in result + + @pytest.mark.sphinx('latex', testroot='numfig', confoverrides={'numfig': True}) def test_numref(app, status, warning): diff --git a/tests/test_build_text.py b/tests/test_build_text.py index 9bfbe1206..85b518007 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -63,7 +63,7 @@ def test_lineblock(app, status, warning): def test_nonascii_title_line(app, status, warning): app.builder.build_update() result = (app.outdir / 'nonascii_title.txt').text(encoding='utf-8') - expect_underline = '******' + expect_underline = '*********' result_underline = result.splitlines()[1].strip() assert expect_underline == result_underline @@ -110,3 +110,83 @@ def test_list_items_in_admonition(app, status, warning): assert lines[2] == " * item 1" assert lines[3] == "" assert lines[4] == " * item 2" + + +@with_text_app() +def test_secnums(app, status, warning): + app.builder.build_all() + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + lines = contents.splitlines() + assert lines[0] == "* 1. Section A" + assert lines[1] == "" + assert lines[2] == "* 2. Section B" + assert lines[3] == "" + assert lines[4] == " * 2.1. Sub Ba" + assert lines[5] == "" + assert lines[6] == " * 2.2. Sub Bb" + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') + expect = ( + "2. Section B\n" + "************\n" + "\n" + "\n" + "2.1. Sub Ba\n" + "===========\n" + "\n" + "\n" + "2.2. Sub Bb\n" + "===========\n" + ) + assert doc2 == expect + + app.config.text_secnumber_suffix = " " + app.builder.build_all() + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + lines = contents.splitlines() + assert lines[0] == "* 1 Section A" + assert lines[1] == "" + assert lines[2] == "* 2 Section B" + assert lines[3] == "" + assert lines[4] == " * 2.1 Sub Ba" + assert lines[5] == "" + assert lines[6] == " * 2.2 Sub Bb" + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') + expect = ( + "2 Section B\n" + "***********\n" + "\n" + "\n" + "2.1 Sub Ba\n" + "==========\n" + "\n" + "\n" + "2.2 Sub Bb\n" + "==========\n" + ) + assert doc2 == expect + + app.config.text_add_secnumbers = False + app.builder.build_all() + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + lines = contents.splitlines() + assert lines[0] == "* Section A" + assert lines[1] == "" + assert lines[2] == "* Section B" + assert lines[3] == "" + assert lines[4] == " * Sub Ba" + assert lines[5] == "" + assert lines[6] == " * Sub Bb" + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') + expect = ( + "Section B\n" + "*********\n" + "\n" + "\n" + "Sub Ba\n" + "======\n" + "\n" + "\n" + "Sub Bb\n" + "======\n" + ) + assert doc2 == expect diff --git a/tests/test_ext_doctest.py b/tests/test_ext_doctest.py index 020357879..7d907d086 100644 --- a/tests/test_ext_doctest.py +++ b/tests/test_ext_doctest.py @@ -9,7 +9,9 @@ :license: BSD, see LICENSE for details. """ import pytest -from sphinx.ext.doctest import compare_version +from sphinx.ext.doctest import is_allowed_version +from packaging.version import InvalidVersion +from packaging.specifiers import InvalidSpecifier cleanup_called = 0 @@ -26,19 +28,28 @@ def test_build(app, status, warning): assert cleanup_called == 3, 'testcleanup did not get executed enough times' -def test_compare_version(): - assert compare_version('3.3', '3.4', '<') is True - assert compare_version('3.3', '3.2', '<') is False - assert compare_version('3.3', '3.4', '<=') is True - assert compare_version('3.3', '3.2', '<=') is False - assert compare_version('3.3', '3.3', '==') is True - assert compare_version('3.3', '3.4', '==') is False - assert compare_version('3.3', '3.2', '>=') is True - assert compare_version('3.3', '3.4', '>=') is False - assert compare_version('3.3', '3.2', '>') is True - assert compare_version('3.3', '3.4', '>') is False - with pytest.raises(ValueError): - compare_version('3.3', '3.4', '+') +def test_is_allowed_version(): + assert is_allowed_version('<3.4', '3.3') is True + assert is_allowed_version('<3.4', '3.3') is True + assert is_allowed_version('<3.2', '3.3') is False + assert is_allowed_version('<=3.4', '3.3') is True + assert is_allowed_version('<=3.2', '3.3') is False + assert is_allowed_version('==3.3', '3.3') is True + assert is_allowed_version('==3.4', '3.3') is False + assert is_allowed_version('>=3.2', '3.3') is True + assert is_allowed_version('>=3.4', '3.3') is False + assert is_allowed_version('>3.2', '3.3') is True + assert is_allowed_version('>3.4', '3.3') is False + assert is_allowed_version('~=3.4', '3.4.5') is True + assert is_allowed_version('~=3.4', '3.5.0') is True + + # invalid spec + with pytest.raises(InvalidSpecifier): + is_allowed_version('&3.4', '3.5') + + # invalid version + with pytest.raises(InvalidVersion): + is_allowed_version('>3.4', 'Sphinx') def cleanup_call(): diff --git a/tests/test_ext_inheritance.py b/tests/test_ext_inheritance.py new file mode 100644 index 000000000..fcf313a30 --- /dev/null +++ b/tests/test_ext_inheritance.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +""" + test_inheritance + ~~~~~~~~~~~~~~~~ + + Tests for :mod:`sphinx.ext.inheritance_diagram` module. + + :copyright: Copyright 2015 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import os +import pytest +from sphinx.ext.inheritance_diagram import InheritanceDiagram + + +@pytest.mark.sphinx(buildername="html", testroot="inheritance") +@pytest.mark.usefixtures('if_graphviz_found') +def test_inheritance_diagram(app, status, warning): + # monkey-patch InheritaceDiagram.run() so we can get access to its + # results. + orig_run = InheritanceDiagram.run + graphs = {} + + def new_run(self): + result = orig_run(self) + node = result[0] + source = os.path.basename(node.document.current_source).replace(".rst", "") + graphs[source] = node['graph'] + return result + + InheritanceDiagram.run = new_run + + try: + app.builder.build_all() + finally: + InheritanceDiagram.run = orig_run + + assert app.statuscode == 0 + + html_warnings = warning.getvalue() + assert html_warnings == "" + + # note: it is better to split these asserts into separate test functions + # but I can't figure out how to build only a specific .rst file + + # basic inheritance diagram showing all classes + for cls in graphs['basic_diagram'].class_info: + # use in b/c traversing order is different sometimes + assert cls in [ + ('dummy.test.A', 'dummy.test.A', [], None), + ('dummy.test.F', 'dummy.test.F', ['dummy.test.C'], None), + ('dummy.test.C', 'dummy.test.C', ['dummy.test.A'], None), + ('dummy.test.E', 'dummy.test.E', ['dummy.test.B'], None), + ('dummy.test.D', 'dummy.test.D', + ['dummy.test.B', 'dummy.test.C'], None), + ('dummy.test.B', 'dummy.test.B', ['dummy.test.A'], None) + ] + + # inheritance diagram using :parts: 1 option + for cls in graphs['diagram_w_parts'].class_info: + assert cls in [ + ('A', 'dummy.test.A', [], None), + ('F', 'dummy.test.F', ['C'], None), + ('C', 'dummy.test.C', ['A'], None), + ('E', 'dummy.test.E', ['B'], None), + ('D', 'dummy.test.D', ['B', 'C'], None), + ('B', 'dummy.test.B', ['A'], None) + ] + + # inheritance diagram with 1 top class + # :top-classes: dummy.test.B + # rendering should be + # A + # \ + # B C + # / \ / \ + # E D F + # + for cls in graphs['diagram_w_1_top_class'].class_info: + assert cls in [ + ('dummy.test.A', 'dummy.test.A', [], None), + ('dummy.test.F', 'dummy.test.F', ['dummy.test.C'], None), + ('dummy.test.C', 'dummy.test.C', ['dummy.test.A'], None), + ('dummy.test.E', 'dummy.test.E', ['dummy.test.B'], None), + ('dummy.test.D', 'dummy.test.D', + ['dummy.test.B', 'dummy.test.C'], None), + ('dummy.test.B', 'dummy.test.B', [], None) + ] + + + # inheritance diagram with 2 top classes + # :top-classes: dummy.test.B, dummy.test.C + # Note: we're specifying separate classes, not the entire module here + # rendering should be + # + # B C + # / \ / \ + # E D F + # + for cls in graphs['diagram_w_2_top_classes'].class_info: + assert cls in [ + ('dummy.test.F', 'dummy.test.F', ['dummy.test.C'], None), + ('dummy.test.C', 'dummy.test.C', [], None), + ('dummy.test.E', 'dummy.test.E', ['dummy.test.B'], None), + ('dummy.test.D', 'dummy.test.D', + ['dummy.test.B', 'dummy.test.C'], None), + ('dummy.test.B', 'dummy.test.B', [], None) + ] + + # inheritance diagram with 2 top classes and specifiying the entire module + # rendering should be + # + # A + # B C + # / \ / \ + # E D F + # + # Note: dummy.test.A is included in the graph before its descendants are even processed + # b/c we've specified to load the entire module. The way InheritanceGraph works it is very + # hard to exclude parent classes once after they have been included in the graph. + # If you'd like to not show class A in the graph don't specify the entire module. + # this is a known issue. + for cls in graphs['diagram_module_w_2_top_classes'].class_info: + assert cls in [ + ('dummy.test.F', 'dummy.test.F', ['dummy.test.C'], None), + ('dummy.test.C', 'dummy.test.C', [], None), + ('dummy.test.E', 'dummy.test.E', ['dummy.test.B'], None), + ('dummy.test.D', 'dummy.test.D', + ['dummy.test.B', 'dummy.test.C'], None), + ('dummy.test.B', 'dummy.test.B', [], None), + ('dummy.test.A', 'dummy.test.A', [], None), + ] diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 19f8613c6..aef495d30 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -236,7 +236,8 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): html = (app.outdir / 'index.html').text() assert ('' + ' title="(in foo v2.0)">' + '' 'Bar' in html) assert ('\na^2 + b^2 = c^2' in content - assert '
\n\\begin{split}a + 1 < b\\end{split}
' in content + assert '
\na^2 + b^2 = c^2
' in content + assert '
\n\\begin{split}a + 1 < b\\end{split}
' in content assert (u'(1)
\xb6' - u'
\ne^{i\\pi} = 1
' in content) + u'
\ne^{i\\pi} = 1
' in content) assert (u'(2)\xb6' - u'
\n' + u'
\n' u'e^{ix} = \\cos x + i\\sin x
' in content) - assert '
\nn \\in \\mathbb N
' in content - assert '
\na + 1 < b
' in content + assert '
\nn \\in \\mathbb N
' in content + assert '
\na + 1 < b
' in content @pytest.mark.skipif(not has_binary('dvipng'), @@ -89,7 +89,7 @@ def test_mathjax_align(app, status, warning): app.builder.build_all() content = (app.outdir / 'index.html').text() - html = (r'
\s*' + html = (r'
\s*' r'\\\[ \\begin\{align\}\\begin\{aligned\}S \&= \\pi r\^2\\\\' r'V \&= \\frac\{4\}\{3\} \\pi r\^3\\end\{aligned\}\\end\{align\} \\\]
') assert re.search(html, content, re.S) @@ -102,7 +102,7 @@ def test_math_number_all_mathjax(app, status, warning): app.builder.build_all() content = (app.outdir / 'index.html').text() - html = (r'
\s*' + html = (r'
\s*' r'\(1\)\xb6\\\[a\^2\+b\^2=c\^2\\\]
') assert re.search(html, content, re.S) @@ -167,7 +167,7 @@ def test_mathjax_numfig_html(app, status, warning): app.builder.build_all() content = (app.outdir / 'math.html').text() - html = ('
\n' + html = ('
\n' '(1.2)') assert html in content html = ('

Referencing equation >``<' + ('

' 'code   sample

'), r'\\sphinxcode{\\sphinxupquote{code sample}}', ), @@ -141,7 +141,7 @@ def get_verifier(verify, verify_re): # correct interpretation of code with whitespace 'verify_re', ':samp:`code sample`', - ('

' + ('

' 'code   sample

'), r'\\sphinxcode{\\sphinxupquote{code sample}}', ), @@ -149,7 +149,8 @@ def get_verifier(verify, verify_re): # interpolation of braces in samp and file roles (HTML only) 'verify', ':samp:`a{b}c`', - ('

a' + ('

' + 'a' 'b' 'c

'), '\\sphinxcode{\\sphinxupquote{a\\sphinxstyleemphasis{b}c}}', @@ -173,7 +174,7 @@ def get_verifier(verify, verify_re): # non-interpolation of dashes in option role 'verify_re', ':option:`--with-option`', - ('

' + ('

' '--with-option

$'), r'\\sphinxcode{\\sphinxupquote{-{-}with-option}}$', ), @@ -188,7 +189,7 @@ def get_verifier(verify, verify_re): # ... but not in literal text 'verify', '``"John"``', - ('

' + ('

' '"John"

'), '\\sphinxcode{\\sphinxupquote{"John"}}', ), diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index f0188cafa..b5d50ed71 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -211,15 +211,15 @@ def test_Signature_annotations(): # Generic types with concrete parameters sig = inspect.Signature(f1).format_args() - assert sig == '(x: typing.List[int]) -> typing.List[int]' + assert sig == '(x: List[int]) -> List[int]' # TypeVars and generic types with TypeVars sig = inspect.Signature(f2).format_args() - assert sig == '(x: typing.List[T], y: typing.List[T_co], z: T) -> typing.List[T_contra]' + assert sig == '(x: List[T], y: List[T_co], z: T) -> List[T_contra]' # Union types sig = inspect.Signature(f3).format_args() - assert sig == '(x: typing.Union[str, numbers.Integral]) -> None' + assert sig == '(x: Union[str, numbers.Integral]) -> None' # Quoted annotations sig = inspect.Signature(f4).format_args() @@ -239,14 +239,14 @@ def test_Signature_annotations(): # Callable types sig = inspect.Signature(f8).format_args() - assert sig == '(x: typing.Callable[[int, str], int]) -> None' + assert sig == '(x: Callable[[int, str], int]) -> None' sig = inspect.Signature(f9).format_args() - assert sig == '(x: typing.Callable) -> None' + assert sig == '(x: Callable) -> None' # Tuple types sig = inspect.Signature(f10).format_args() - assert sig == '(x: typing.Tuple[int, str], y: typing.Tuple[int, ...]) -> None' + assert sig == '(x: Tuple[int, str], y: Tuple[int, ...]) -> None' # Instance annotations sig = inspect.Signature(f11).format_args()