From de356149cda6076555fbff768590aa1ab483fec1 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Fri, 5 Feb 2016 17:15:27 +0100 Subject: [PATCH 0001/1814] Test for bug #2298: automodule fails to document a class attribute This test case demonstrates a bug, where automodule:: with option :members: fails to document a class attribute of a class, that was imported into the documented module. This commit extends test_ext_viewcode, instead of creating a separate test module, because the development guide recommends it for performance reasons. --- tests/roots/test-ext-viewcode/index.rst | 5 +++++ tests/roots/test-ext-viewcode/spam/mod1.py | 7 +++++++ tests/roots/test-ext-viewcode/spam/mod3.py | 2 ++ tests/test_ext_viewcode.py | 6 ++++++ 4 files changed, 20 insertions(+) create mode 100644 tests/roots/test-ext-viewcode/spam/mod3.py diff --git a/tests/roots/test-ext-viewcode/index.rst b/tests/roots/test-ext-viewcode/index.rst index b5776cfa7..e7956e723 100644 --- a/tests/roots/test-ext-viewcode/index.rst +++ b/tests/roots/test-ext-viewcode/index.rst @@ -28,6 +28,11 @@ viewcode :language: python :pyobject: func1 +.. autoclass:: spam.mod3.Class3 + :members: + +.. automodule:: spam.mod3 + :members: .. toctree:: diff --git a/tests/roots/test-ext-viewcode/spam/mod1.py b/tests/roots/test-ext-viewcode/spam/mod1.py index 7133fc829..226f0c8a2 100644 --- a/tests/roots/test-ext-viewcode/spam/mod1.py +++ b/tests/roots/test-ext-viewcode/spam/mod1.py @@ -13,3 +13,10 @@ class Class1(object): """ this is Class1 """ + +class Class3(object): + """ + this is Class3 + """ + class_attr = 42 + """this is the class attribute class_attr""" diff --git a/tests/roots/test-ext-viewcode/spam/mod3.py b/tests/roots/test-ext-viewcode/spam/mod3.py new file mode 100644 index 000000000..f7b6afbe0 --- /dev/null +++ b/tests/roots/test-ext-viewcode/spam/mod3.py @@ -0,0 +1,2 @@ +from spam.mod1 import Class3 +__all__ = ('Class3',) diff --git a/tests/test_ext_viewcode.py b/tests/test_ext_viewcode.py index 93e681a5d..eaa7a736d 100644 --- a/tests/test_ext_viewcode.py +++ b/tests/test_ext_viewcode.py @@ -31,6 +31,12 @@ def test_viewcode(app, status, warning): assert result.count('href="_modules/spam/mod1.html#Class1"') == 2 assert result.count('href="_modules/spam/mod2.html#Class2"') == 2 + # test that the class attribute is correctly documented + assert result.count('this is Class3') == 2 + assert 'this is the class attribute class_attr' in result + # the next assert fails, until the autodoc bug gets fixed + assert result.count('this is the class attribute class_attr') == 2 + @with_app(testroot='ext-viewcode', tags=['test_linkcode']) def test_linkcode(app, status, warning): From c44608234d5eb8821f7b3c204b52fdcce0823cd2 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Fri, 5 Feb 2016 17:56:25 +0100 Subject: [PATCH 0002/1814] Fix #2298 automodule fails to document a class attribute. This commit adds the method ClassDocumenter.generate. This method calls the implementation from the super class without passing the optional argument real_modname. This causes Documenter.generate() to use the module of the imported class. Why is this change save: if the class can't be imported in Documenter.generate(), Documenter.generate() returns early and the module name is not used. If Documenter.generate() can import the class, Documenter.get_real_modname() always returns a module name. --- sphinx/ext/autodoc.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index f906d9666..095dea93b 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -1193,6 +1193,17 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): return ModuleLevelDocumenter.document_members(self, all_members) + def generate(self, more_content=None, real_modname=None, + check_module=False, all_members=False): + # Do not pass real_modname and use the name from the __module__ + # attribute of the class. + # If a class gets imported into the module real_modname + # the analyzer won't find the source of the class, if + # it looks in real_modname. + return super(ClassDocumenter, self).generate(more_content=more_content, + check_module=check_module, + all_members=all_members) + class ExceptionDocumenter(ClassDocumenter): """ From 72e70b1b361a649f1e81ed4ed29cbb8a31024563 Mon Sep 17 00:00:00 2001 From: "Mr. Senko" Date: Thu, 21 Jan 2016 11:13:29 +0200 Subject: [PATCH 0003/1814] Add tests for sphinx.ext.inheritance_diagram --- AUTHORS | 1 + CHANGES | 1 + .../roots/test-inheritance/basic_diagram.rst | 5 ++ tests/roots/test-inheritance/conf.py | 6 ++ tests/roots/test-inheritance/contents.rst | 4 ++ .../test-inheritance/diagram_w_parts.rst | 7 ++ .../roots/test-inheritance/dummy/__init__.py | 0 tests/roots/test-inheritance/dummy/test.py | 30 +++++++++ tests/test_ext_inheritance.py | 67 +++++++++++++++++++ 9 files changed, 121 insertions(+) create mode 100644 tests/roots/test-inheritance/basic_diagram.rst create mode 100644 tests/roots/test-inheritance/conf.py create mode 100644 tests/roots/test-inheritance/contents.rst create mode 100644 tests/roots/test-inheritance/diagram_w_parts.rst create mode 100644 tests/roots/test-inheritance/dummy/__init__.py create mode 100644 tests/roots/test-inheritance/dummy/test.py create mode 100644 tests/test_ext_inheritance.py diff --git a/AUTHORS b/AUTHORS index 580feeb32..bafe242e8 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 diff --git a/CHANGES b/CHANGES index 85b660775..30d6a5aae 100644 --- a/CHANGES +++ b/CHANGES @@ -52,6 +52,7 @@ Bugs fixed Testing -------- +* Add tests for the ``sphinx.ext.inheritance_diagram`` extension. Release 1.6.3 (in development) ============================== 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_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/test_ext_inheritance.py b/tests/test_ext_inheritance.py new file mode 100644 index 000000000..ce4b50a56 --- /dev/null +++ b/tests/test_ext_inheritance.py @@ -0,0 +1,67 @@ +# -*- 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) + ] From 9486f0d8f78c5683ed4df2015fd42b24ab147ab8 Mon Sep 17 00:00:00 2001 From: "Mr. Senko" Date: Thu, 21 Jan 2016 11:11:06 +0200 Subject: [PATCH 0004/1814] Add top-classes option to sphinx.ext.inheritance_diagram This will limit the scope of inheritance traversal --- CHANGES | 4 ++ doc/ext/inheritance.rst | 52 ++++++++++++++ sphinx/ext/inheritance_diagram.py | 26 +++++-- .../diagram_module_w_2_top_classes.rst | 6 ++ .../diagram_w_1_top_class.rst | 7 ++ .../diagram_w_2_top_classes.rst | 9 +++ tests/test_ext_inheritance.py | 68 ++++++++++++++++++- 7 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 tests/roots/test-inheritance/diagram_module_w_2_top_classes.rst create mode 100644 tests/roots/test-inheritance/diagram_w_1_top_class.rst create mode 100644 tests/roots/test-inheritance/diagram_w_2_top_classes.rst diff --git a/CHANGES b/CHANGES index 30d6a5aae..67db95381 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,8 @@ Features added * C++, add a ``cpp:expr`` role for inserting inline C++ expressions or types. * #3638: Allow to change a label of reference to equation using ``math_eqref_format`` +* Add ``top-classes`` option for the ``sphinx.ext.inheritance_diagram`` + extension to limit the scope of inheritance graphs. Features removed ---------------- @@ -52,8 +54,10 @@ Bugs fixed Testing -------- + * Add tests for the ``sphinx.ext.inheritance_diagram`` extension. + Release 1.6.3 (in development) ============================== diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst index bd287aa49..4a8a3c0f1 100644 --- a/doc/ext/inheritance.rst +++ b/doc/ext/inheritance.rst @@ -42,6 +42,58 @@ 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/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index f5b0228a5..7ba972f9f 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -133,8 +133,8 @@ class InheritanceGraph(object): graphviz dot graph from them. """ def __init__(self, class_names, currmodule, show_builtins=False, - private_bases=False, parts=0): - # type: (unicode, str, bool, bool, int) -> None + private_bases=False, parts=0, top_classes=[]): + # type: (unicode, str, bool, bool, int, List[Any]) -> None """*class_names* is a list of child classes to show bases from. If *show_builtins* is True, then Python builtins will be shown @@ -143,7 +143,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) + private_bases, parts, top_classes) if not self.class_info: raise InheritanceException('No classes found for ' 'inheritance diagram') @@ -156,13 +156,16 @@ class InheritanceGraph(object): classes.extend(import_classes(name, currmodule)) return classes - def _class_info(self, classes, show_builtins, private_bases, parts): - # type: (List[Any], bool, bool, int) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA + def _class_info(self, classes, show_builtins, private_bases, parts, top_classes): + # type: (List[Any], bool, bool, int, 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() @@ -192,6 +195,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 @@ -321,6 +328,7 @@ class InheritanceDiagram(Directive): 'parts': directives.nonnegative_int, 'private-bases': directives.flag, 'caption': directives.unchanged, + 'top-classes': directives.unchanged_required, } def run(self): @@ -333,13 +341,19 @@ 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: graph = InheritanceGraph( class_names, env.ref_context.get('py:module'), parts=node['parts'], - private_bases='private-bases' in self.options) + private_bases='private-bases' in self.options, + top_classes=node['top-classes']) except InheritanceException as err: return [node.document.reporter.warning(err.args[0], line=self.lineno)] 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/test_ext_inheritance.py b/tests/test_ext_inheritance.py index ce4b50a56..fcf313a30 100644 --- a/tests/test_ext_inheritance.py +++ b/tests/test_ext_inheritance.py @@ -13,6 +13,7 @@ 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): @@ -51,7 +52,8 @@ def test_inheritance_diagram(app, status, warning): ('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.D', 'dummy.test.D', + ['dummy.test.B', 'dummy.test.C'], None), ('dummy.test.B', 'dummy.test.B', ['dummy.test.A'], None) ] @@ -65,3 +67,67 @@ def test_inheritance_diagram(app, status, warning): ('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), + ] From db88166a3f5fa9335def587d6da0407a92a29475 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 17 Jun 2017 10:47:35 +0900 Subject: [PATCH 0005/1814] Fix #3866: Suppress a new warning type: python refs --- CHANGES | 4 ++++ doc/config.rst | 1 + sphinx/domains/python.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 6e1c01609..f72412c83 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,10 @@ Deprecated Features added -------------- +* Now :confval:`suppress_warnings` accepts following configurations: + + - ``ref.python`` (ref: #3866) + Bugs fixed ---------- diff --git a/doc/config.rst b/doc/config.rst index 74943c904..88b7f11fc 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -239,6 +239,7 @@ General configuration * ref.citation * ref.footnote * ref.doc + * ref.python * misc.highlighting_failure * toc.secnum * epub.unknown_project_files diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index eb6fe76cb..bc8423968 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -833,7 +833,7 @@ class PythonDomain(Domain): elif len(matches) > 1: logger.warning('more than one target found for cross-reference %r: %s', target, ', '.join(match[0] for match in matches), - location=node) + type='ref', subtype='python', location=node) name, obj = matches[0] if obj[1] == 'module': From 28226b59c531974535d1fac2e437f96d40df4c5c Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 16 Jun 2017 14:24:40 +0200 Subject: [PATCH 0006/1814] latex: better fix to French lists issue (refs: 66fdb34) --- sphinx/texinputs/sphinx.sty | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 5295cfe48..e3e286859 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -684,10 +684,17 @@ \newcommand*\sphinxVerbatimTitle {} % This box to typeset the caption before framed.sty multiple passes for framing. \newbox\spx@Verbatim@TitleBox +% This is a workaround to a "feature" of French lists, which shows when non- +% paragraph material immediately follows a list. A priori usable generally +% as it does only \par for normal situations. +\newcommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} % Holder macro for labels of literal blocks. Set-up by LaTeX writer. \newcommand*\sphinxLiteralBlockLabel {} \newcommand*\sphinxSetupCaptionForVerbatim [1] {% + \sphinxvspacefixafterfrenchlists \needspace{\sphinxliteralblockneedspace}% % insert a \label via \sphinxLiteralBlockLabel % reset to normal the color for the literal block caption @@ -839,13 +846,10 @@ % Sphinx <1.5 optional argument was in fact mandatory. It is now really % optional and handled by original Verbatim. \newenvironment{sphinxVerbatim}{% - % quit horizontal mode if we are still in a paragraph - \par - % list starts new par, but we don't want it to be set apart vertically - \parskip\z@skip % first, let's check if there is a caption \ifx\sphinxVerbatimTitle\empty - \addvspace\z@% counteract possible previous negative skip (French lists!) + \sphinxvspacefixafterfrenchlists + \parskip\z@skip \smallskip % there was no caption. Check if nevertheless a label was set. \ifx\sphinxLiteralBlockLabel\empty\else @@ -856,6 +860,7 @@ \fi \let\spx@Verbatim@Title\@empty \else + \parskip\z@skip % non-empty \sphinxVerbatimTitle has label inside it (in case there is one) \setbox\spx@Verbatim@TitleBox \hbox{\begin{minipage}{\linewidth}% @@ -1110,10 +1115,9 @@ {\parskip\z@skip\noindent}% } {% - \par % counteract previous possible negative skip (French lists!): % (we can't cancel that any earlier \vskip introduced a potential pagebreak) - \ifdim\lastskip<\z@\vskip-\lastskip\fi + \sphinxvspacefixafterfrenchlists \nobreak\vbox{\noindent\kern\@totalleftmargin {\color{spx@notice@bordercolor}% \rule[\dimexpr.4\baselineskip-\spx@notice@border\relax] From 5e6d37292968015f6deeb0fae8f0e653f4f38d35 Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 16 Jun 2017 16:46:32 +0200 Subject: [PATCH 0007/1814] Move latex macros for easier maintenance --- sphinx/texinputs/sphinx.sty | 68 +++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index e3e286859..fa2be7d93 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -656,10 +656,6 @@ \let\OriginalVerbatim \Verbatim \let\endOriginalVerbatim\endVerbatim -% if the available space on page is less than \literalblockneedspace, insert pagebreak -\newcommand{\sphinxliteralblockneedspace}{5\baselineskip} -\newcommand{\sphinxliteralblockwithoutcaptionneedspace}{1.5\baselineskip} - % for captions of literal blocks % also define `\theH...` macros for hyperref \newcounter{literalblock} @@ -679,38 +675,6 @@ % analogous to \listoffigures, but for the code listings (foo = chosen title.) \newcommand*{\ext@literalblock}{lol} -% The title (caption) is specified from outside as macro \sphinxVerbatimTitle. -% \sphinxVerbatimTitle is reset to empty after each use of Verbatim. -\newcommand*\sphinxVerbatimTitle {} -% This box to typeset the caption before framed.sty multiple passes for framing. -\newbox\spx@Verbatim@TitleBox -% This is a workaround to a "feature" of French lists, which shows when non- -% paragraph material immediately follows a list. A priori usable generally -% as it does only \par for normal situations. -\newcommand*\sphinxvspacefixafterfrenchlists{% - \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi -} -% Holder macro for labels of literal blocks. Set-up by LaTeX writer. -\newcommand*\sphinxLiteralBlockLabel {} -\newcommand*\sphinxSetupCaptionForVerbatim [1] -{% - \sphinxvspacefixafterfrenchlists - \needspace{\sphinxliteralblockneedspace}% -% insert a \label via \sphinxLiteralBlockLabel -% reset to normal the color for the literal block caption -% the caption inserts \abovecaptionskip whitespace above itself (usually 10pt) -% there is also \belowcaptionskip but it is usually zero, hence the \smallskip - \def\sphinxVerbatimTitle - {\py@NormalColor - \captionof{literalblock}{\sphinxLiteralBlockLabel #1}\smallskip }% -} -\newcommand*\sphinxSetupCodeBlockInFootnote {% - \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption - \sphinxverbatimwithminipagetrue % reduces vertical spaces - % we counteract float.sty's \caption which does \@normalsize - \let\normalsize\footnotesize\let\@parboxrestore\relax - \abovecaptionskip \smallskipamount \belowcaptionskip \z@skip} - \newif\ifspx@inframed % flag set if we are already in a framed environment % if forced use of minipage encapsulation is needed (e.g. table cells) \newif\ifsphinxverbatimwithminipage \sphinxverbatimwithminipagefalse @@ -841,6 +805,38 @@ {\kern\fontdimen2\font}% }% +% if the available space on page is less than \literalblockneedspace, insert pagebreak +\newcommand{\sphinxliteralblockneedspace}{5\baselineskip} +\newcommand{\sphinxliteralblockwithoutcaptionneedspace}{1.5\baselineskip} +% The title (caption) is specified from outside as macro \sphinxVerbatimTitle. +% \sphinxVerbatimTitle is reset to empty after each use of Verbatim. +\newcommand*\sphinxVerbatimTitle {} +% This box to typeset the caption before framed.sty multiple passes for framing. +\newbox\sphinxVerbatim@TitleBox +% This is a workaround to a "feature" of French lists, when literal block +% follows immediately; usable generally (does only \par then), a priori... +\newcommand*\sphinxvspacefixafterfrenchlists{% + \ifvmode\ifdim\lastskip<\z@ \vskip\parskip\fi\else\par\fi +} +% Holder macro for labels of literal blocks. Set-up by LaTeX writer. +\newcommand*\sphinxLiteralBlockLabel {} +\newcommand*\sphinxSetupCaptionForVerbatim [1] +{% + \sphinxvspacefixafterfrenchlists + \needspace{\sphinxliteralblockneedspace}% +% insert a \label via \sphinxLiteralBlockLabel +% reset to normal the color for the literal block caption + \def\sphinxVerbatimTitle + {\py@NormalColor\sphinxcaption{\sphinxLiteralBlockLabel #1}}% +} +\newcommand*\sphinxSetupCodeBlockInFootnote {% + \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption + \sphinxverbatimwithminipagetrue % reduces vertical spaces + % we counteract \caption issueing \@normalsize + % this all happens in a group + \let\normalsize\footnotesize\let\@parboxrestore\relax + \abovecaptionskip \smallskipamount \belowcaptionskip \z@skip +} % needed to create wrapper environments of fancyvrb's Verbatim \newcommand*{\sphinxVerbatimEnvironment}{\gdef\FV@EnvironName{sphinxVerbatim}} % Sphinx <1.5 optional argument was in fact mandatory. It is now really From 634d76faf195c6783d6e9f803e6c6d3e91454a2f Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 16 Jun 2017 14:24:40 +0200 Subject: [PATCH 0008/1814] latex: add option to put literal block captions before or after According to ``literalblockcappos`` setting in ``'sphinxsetup'``, (t)op or (b)ottom, the caption will be typeset before or after the literal block. If typeset above, its distance to frame is now identical to the setting used for captions of tables (one half of the baseline). Further keys ``verbatimcontinuedalign`` and ``verbatimcontinuesalign`` allow to horizontally align the continuation hints relative to the literal block contents: either (l)eft, (c)enter, or (r)ight. --- doc/latex.rst | 26 ++++-- sphinx/texinputs/sphinx.sty | 167 ++++++++++++++++++++++-------------- sphinx/writers/latex.py | 4 - tests/test_build_latex.py | 3 +- 4 files changed, 121 insertions(+), 79 deletions(-) diff --git a/doc/latex.rst b/doc/latex.rst index 3965afee2..ff79cc574 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -189,14 +189,25 @@ The available styling options default ``true``. Tells whether long lines in :rst:dir:`code-block`\ 's contents should wrap. +``literalblockcappos`` + default ``t`` for "top". Decides the caption position. Alternative is + ``b`` ("bottom"). + + .. versionadded:: 1.7 + ``verbatimhintsturnover`` - default ``false``. If ``true``, code-blocks display "continued on next + default ``true``. If ``true``, code-blocks display "continued on next page", "continued from previous page" hints in case of pagebreaks. .. versionadded:: 1.6.3 - the default will change to ``true`` at 1.7 and horizontal positioning - of continuation hints (currently right aligned only) will be - customizable. + .. versionchanged:: 1.7 + the default changed from ``false`` to ``true``. + +``verbatimcontinuedalign``, ``verbatimcontinuesalign`` + default ``c``. Horizontal position relative to the framed contents: + either ``l`` (left aligned), ``r`` (right aligned) or ``c`` (centered). + + .. versionadded:: 1.7 ``parsedliteralwraps`` default ``true``. Tells whether long lines in :dudir:`parsed-literal`\ 's @@ -356,10 +367,9 @@ Macros with LaTeX packages. - more text styling: ``\sphinxstyle`` with ```` one of ``indexentry``, ``indexextra``, ``indexpageref``, ``topictitle``, - ``sidebartitle``, ``othertitle``, ``sidebarsubtitle``, - ``theadfamily``, ``emphasis``, ``literalemphasis``, ``strong``, - ``literalstrong``, ``abbreviation``, ``literalintitle``, ``codecontinued``, - ``codecontinues``. + ``sidebartitle``, ``othertitle``, ``sidebarsubtitle``, ``theadfamily``, + ``emphasis``, ``literalemphasis``, ``strong``, ``literalstrong``, + ``abbreviation``, ``literalintitle``, ``codecontinued``, ``codecontinues`` .. versionadded:: 1.5 these macros were formerly hard-coded as non customizable ``\texttt``, diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index fa2be7d93..c8d6103bb 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -114,19 +114,25 @@ % move back vertically to compensate space inserted by next paragraph \vskip-\baselineskip\vskip-\parskip }% +% use \LTcapwidth (default is 4in) to wrap caption (if line width is bigger) \newcommand\sphinxcaption[2][\LTcapwidth]{% \noindent\hb@xt@\linewidth{\hss \vtop{\@tempdima\dimexpr#1\relax % don't exceed linewidth for the caption width \ifdim\@tempdima>\linewidth\hsize\linewidth\else\hsize\@tempdima\fi -% longtable ignores \abovecaptionskip/\belowcaptionskip, so do the same here - \abovecaptionskip\z@skip - \belowcaptionskip\z@skip +% longtable ignores \abovecaptionskip/\belowcaptionskip, so add hooks here +% to uniformize control of caption distance to tables + \abovecaptionskip\sphinxabovecaptionskip + \belowcaptionskip\sphinxbelowcaptionskip \caption[{#2}]% {\strut\ignorespaces#2\ifhmode\unskip\@finalstrut\strutbox\fi}% }\hss}% \par\prevdepth\dp\strutbox }% +\def\spx@abovecaptionskip{\abovecaptionskip} +\newcommand*\sphinxabovecaptionskip{\z@skip} +\newcommand*\sphinxbelowcaptionskip{\z@skip} + \newcommand\sphinxaftercaption {% this default definition serves with a caption *above* a table, to make sure % its last baseline is \sphinxbelowcaptionspace above table top @@ -256,8 +262,11 @@ % verbatim \DeclareBoolOption[true]{verbatimwithframe} \DeclareBoolOption[true]{verbatimwrapslines} -\DeclareBoolOption[false]{verbatimhintsturnover} +\DeclareBoolOption[true]{verbatimhintsturnover} \DeclareBoolOption[true]{inlineliteralwraps} +\DeclareStringOption[t]{literalblockcappos} +\DeclareStringOption[r]{verbatimcontinuedalign} +\DeclareStringOption[r]{verbatimcontinuesalign} % parsed literal \DeclareBoolOption[true]{parsedliteralwraps} % \textvisiblespace for compatibility with fontspec+XeTeX/LuaTeX @@ -678,22 +687,27 @@ \newif\ifspx@inframed % flag set if we are already in a framed environment % if forced use of minipage encapsulation is needed (e.g. table cells) \newif\ifsphinxverbatimwithminipage \sphinxverbatimwithminipagefalse -\long\def\spx@colorbox #1#2#3{% -% let the framing obey the current indentation (adapted from framed.sty's code). + +% Framing macro for use with framed.sty's \FrameCommand +% - it obeys current indentation, +% - frame is \fboxsep separated from the contents, +% - the contents use the full available text width, +% - #1 = color of frame, #2 = color of background, +% - #3 = above frame, #4 = below frame, #5 = within frame, +% - #3 and #4 must be already typeset boxes; they must issue \normalcolor +% or similar, else, they are under scope of color #1 +\long\def\spx@fcolorbox #1#2#3#4#5{% \hskip\@totalleftmargin \hskip-\fboxsep\hskip-\fboxrule - \spx@fcolorbox{VerbatimBorderColor}{VerbatimColor}{#1}{#2}{#3}% + % use of \color@b@x here is compatible with both xcolor.sty and color.sty + \color@b@x {\color{#1}\spx@CustomFBox{#3}{#4}}{\color{#2}}{#5}% \hskip-\fboxsep\hskip-\fboxrule \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth -} -% use of \color@b@x here is compatible with both xcolor.sty and color.sty -\long\def\spx@fcolorbox #1#2#3#4% - {\color@b@x {\color{#1}\spx@VerbatimFBox{#3}{#4}}{\color{#2}}}% -% Frame drawing macro -% #1 = used by default for title above frame, may contain "continued" hint -% #2 = for material underneath frame, used for "continues on next page" hint -% #3 = actual contents with background color -\long\def\spx@VerbatimFBox#1#2#3{% +}% +% #1 = for material above frame, such as a caption or a "continued" hint +% #2 = for material below frame, such as a caption or "continues on next page" +% #3 = actual contents, which will be typeset with a background color +\long\def\spx@CustomFBox#1#2#3{% \leavevmode \begingroup \setbox\@tempboxa\hbox{{#3}}% inner braces to avoid color leaks @@ -717,37 +731,40 @@ }% }% \endgroup -} - -% Customize framed.sty \MakeFramed to glue caption to literal block -% and add optional hint "continued on next page" -\def\spx@Verbatim@FrameCommand - {\spx@colorbox\spx@Verbatim@Title{}}% -% Macros for a frame with page breaks: -\def\spx@Verbatim@FirstFrameCommand - {\spx@colorbox\spx@Verbatim@Title\spx@Verbatim@Continues}% -\def\spx@Verbatim@MidFrameCommand - {\spx@colorbox\spx@Verbatim@Continued\spx@Verbatim@Continues}% -\def\spx@Verbatim@LastFrameCommand - {\spx@colorbox\spx@Verbatim@Continued{}}% - -\def\spx@Verbatim@Title{% hide width from framed.sty measuring - \moveright\dimexpr\fboxrule+.5\wd\@tempboxa - \hb@xt@\z@{\hss\unhcopy\spx@Verbatim@TitleBox\hss}% }% -\def\spx@Verbatim@Continued{% - \moveright\dimexpr\fboxrule+\wd\@tempboxa-\fboxsep - \hb@xt@\z@{\hss - {\normalcolor\sphinxstylecodecontinued\literalblockcontinuedname}}% +\def\spx@fcolorbox@put@c#1{% hide width from framed.sty measuring + \moveright\dimexpr\fboxrule+.5\wd\@tempboxa\hb@xt@\z@{\hss#1\hss}% }% -\def\spx@Verbatim@Continues{% - \moveright\dimexpr\fboxrule+\wd\@tempboxa-\fboxsep - \hb@xt@\z@{\hss - {\normalcolor\sphinxstylecodecontinues\literalblockcontinuesname}}% +\def\spx@fcolorbox@put@r#1{% right align with contents, width hidden + \moveright\dimexpr\fboxrule+\wd\@tempboxa-\fboxsep\hb@xt@\z@{\hss#1}% }% +\def\spx@fcolorbox@put@l#1{% left align with contents, width hidden + \moveright\dimexpr\fboxrule+\fboxsep\hb@xt@\z@{#1\hss}% +}% +% +\def\sphinxVerbatim@Continued + {\csname spx@fcolorbox@put@\spx@opt@verbatimcontinuedalign\endcsname + {\normalcolor\sphinxstylecodecontinued\literalblockcontinuedname}}% +\def\sphinxVerbatim@Continues + {\csname spx@fcolorbox@put@\spx@opt@verbatimcontinuesalign\endcsname + {\normalcolor\sphinxstylecodecontinues\literalblockcontinuesname}}% +\def\sphinxVerbatim@Title + {\spx@fcolorbox@put@c{\unhcopy\sphinxVerbatim@TitleBox}}% +\let\sphinxVerbatim@Before\@empty +\let\sphinxVerbatim@After\@empty % Defaults are redefined in document preamble according to language \newcommand*\literalblockcontinuedname{continued from previous page}% \newcommand*\literalblockcontinuesname{continues on next page}% +% +\def\spx@verbatimfcolorbox{\spx@fcolorbox{VerbatimBorderColor}{VerbatimColor}}% +\def\sphinxVerbatim@FrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Before\sphinxVerbatim@After}% +\def\sphinxVerbatim@FirstFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Before\sphinxVerbatim@Continues}% +\def\sphinxVerbatim@MidFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Continued\sphinxVerbatim@Continues}% +\def\sphinxVerbatim@LastFrameCommand + {\spx@verbatimfcolorbox\sphinxVerbatim@Continued\sphinxVerbatim@After}% % For linebreaks inside Verbatim environment from package fancyvrb. \newbox\sphinxcontinuationbox @@ -832,21 +849,19 @@ \newcommand*\sphinxSetupCodeBlockInFootnote {% \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption \sphinxverbatimwithminipagetrue % reduces vertical spaces - % we counteract \caption issueing \@normalsize - % this all happens in a group + % we counteract (this is in a group) the \@normalsize from \caption \let\normalsize\footnotesize\let\@parboxrestore\relax - \abovecaptionskip \smallskipamount \belowcaptionskip \z@skip + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% } % needed to create wrapper environments of fancyvrb's Verbatim \newcommand*{\sphinxVerbatimEnvironment}{\gdef\FV@EnvironName{sphinxVerbatim}} -% Sphinx <1.5 optional argument was in fact mandatory. It is now really -% optional and handled by original Verbatim. +\newcommand*{\sphinxverbatimsmallskipamount}{\smallskipamount} \newenvironment{sphinxVerbatim}{% % first, let's check if there is a caption \ifx\sphinxVerbatimTitle\empty \sphinxvspacefixafterfrenchlists \parskip\z@skip - \smallskip + \vskip\sphinxverbatimsmallskipamount % there was no caption. Check if nevertheless a label was set. \ifx\sphinxLiteralBlockLabel\empty\else % we require some space to be sure hyperlink target from \phantomsection @@ -854,25 +869,37 @@ \needspace{\sphinxliteralblockwithoutcaptionneedspace}% \phantomsection\sphinxLiteralBlockLabel \fi - \let\spx@Verbatim@Title\@empty \else \parskip\z@skip - % non-empty \sphinxVerbatimTitle has label inside it (in case there is one) - \setbox\spx@Verbatim@TitleBox + \if t\spx@opt@literalblockcappos + \vskip\spx@abovecaptionskip + \def\sphinxVerbatim@Before + {\sphinxVerbatim@Title\nointerlineskip + \kern\dimexpr-\dp\strutbox+\sphinxbelowcaptionspace\relax}% + \else + \vskip\sphinxverbatimsmallskipamount + \def\sphinxVerbatim@After + {\nointerlineskip\kern\dp\strutbox\sphinxVerbatim@Title}% + \fi + \def\@captype{literalblock}% + \capstart + % \sphinxVerbatimTitle must reset color + \setbox\sphinxVerbatim@TitleBox \hbox{\begin{minipage}{\linewidth}% \sphinxVerbatimTitle \end{minipage}}% \fi + \global\let\sphinxLiteralBlockLabel\empty + \global\let\sphinxVerbatimTitle\empty \fboxsep\sphinxverbatimsep \fboxrule\sphinxverbatimborder - % setting borderwidth to zero is simplest for no-frame effect with same pagebreaks \ifspx@opt@verbatimwithframe\else\fboxrule\z@\fi - \let\FrameCommand \spx@Verbatim@FrameCommand - \let\FirstFrameCommand\spx@Verbatim@FirstFrameCommand - \let\MidFrameCommand \spx@Verbatim@MidFrameCommand - \let\LastFrameCommand \spx@Verbatim@LastFrameCommand + \let\FrameCommand \sphinxVerbatim@FrameCommand + \let\FirstFrameCommand\sphinxVerbatim@FirstFrameCommand + \let\MidFrameCommand \sphinxVerbatim@MidFrameCommand + \let\LastFrameCommand \sphinxVerbatim@LastFrameCommand \ifspx@opt@verbatimhintsturnover\else - \let\spx@Verbatim@Continued\@empty - \let\spx@Verbatim@Continues\@empty + \let\sphinxVerbatim@Continued\@empty + \let\sphinxVerbatim@Continues\@empty \fi \ifspx@opt@verbatimwrapslines % fancyvrb's Verbatim puts each input line in (unbreakable) horizontal boxes. @@ -903,13 +930,21 @@ \def\@toodeep {\advance\@listdepth\@ne}% % The list environment is needed to control perfectly the vertical space. % Note: \OuterFrameSep used by framed.sty is later set to \topsep hence 0pt. - % - if caption: vertical space above caption = (\abovecaptionskip + D) with - % D = \baselineskip-\FrameHeightAdjust, and then \smallskip above frame. - % - if no caption: (\smallskip + D) above frame. By default D=6pt. - % Use trivlist rather than list to avoid possible "too deeply nested" error. + % - if caption: distance from last text baseline to caption baseline is + % A+(B-F)+\ht\strutbox, A = \abovecaptionskip (default 10pt), B = + % \baselineskip, F is the framed.sty \FrameHeightAdjust macro, default 6pt. + % Formula valid for F < 10pt. + % - distance of baseline of caption to top of frame is like for tables: + % \sphinxbelowcaptionspace (=0.5\baselineskip) + % - if no caption: distance of last text baseline to code frame is S+(B-F), + % with S = \sphinxverbatimtopskip (=\smallskip) + % - and distance from bottom of frame to next text baseline is + % \baselineskip+\parskip. + % The \trivlist is used to avoid possible "too deeply nested" error. \itemsep \z@skip \topsep \z@skip - \partopsep \z@skip% trivlist will set \parsep to \parskip = zero (see above) + \partopsep \z@skip + % trivlist will set \parsep to \parskip = zero % \leftmargin will be set to zero by trivlist \rightmargin\z@ \parindent \z@% becomes \itemindent. Default zero, but perhaps overwritten. @@ -945,10 +980,12 @@ {% don't use a frame if in a table cell \spx@opt@verbatimwithframefalse \sphinxverbatimwithminipagetrue - % counteract longtable redefinition of caption + % the literal block caption uses \sphinxcaption which is wrapper of \caption, + % but \caption must be modified because longtable redefines it to work only + % for the own table caption, and tabulary has multiple passes \let\caption\sphinxfigcaption - % reduce above caption space if in a table cell - \abovecaptionskip\smallskipamount + % reduce above caption skip + \def\spx@abovecaptionskip{\sphinxverbatimsmallskipamount}% \def\sphinxVerbatimEnvironment{\gdef\FV@EnvironName{sphinxVerbatimintable}}% \begin{sphinxVerbatim}} {\end{sphinxVerbatim}} diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 8d0b7759b..0f06b385a 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2284,8 +2284,6 @@ class LaTeXTranslator(nodes.NodeVisitor): else: hlcode += '\\end{sphinxVerbatim}' self.body.append('\n' + hlcode + '\n') - if ids: - self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n') raise nodes.SkipNode def depart_literal_block(self, node): @@ -2488,8 +2486,6 @@ class LaTeXTranslator(nodes.NodeVisitor): # type: (nodes.Node) -> None if node.get('literal_block'): self.in_container_literal_block -= 1 - self.body.append('\\let\\sphinxVerbatimTitle\\empty\n') - self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n') def visit_decoration(self, node): # type: (nodes.Node) -> None diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 441f12d0d..d32c4f4da 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -542,8 +542,7 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning): assert ('&\nThis is one more footnote with some code in it %\n' '\\begin{footnote}[10]\\sphinxAtStartFootnote\n' 'Third footnote in longtable\n') in result - assert ('\\end{sphinxVerbatim}\n\\let\\sphinxVerbatimTitle\\empty\n' - '\\let\\sphinxLiteralBlockLabel\\empty\n%\n\\end{footnote}.\n') in result + assert ('\\end{sphinxVerbatim}\n%\n\\end{footnote}.\n') in result assert '\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]' in result From 6f8d7627475db899e219ac0ae517df76e73d1b51 Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 16 Jun 2017 19:24:06 +0200 Subject: [PATCH 0009/1814] Trim unneeded TeX macros --- sphinx/texinputs/sphinx.sty | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index c8d6103bb..768a4f448 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -708,12 +708,9 @@ % #2 = for material below frame, such as a caption or "continues on next page" % #3 = actual contents, which will be typeset with a background color \long\def\spx@CustomFBox#1#2#3{% - \leavevmode \begingroup \setbox\@tempboxa\hbox{{#3}}% inner braces to avoid color leaks - \hbox - {\lower\dimexpr\fboxrule+\dp\@tempboxa\hbox{% - \vbox{#1% above frame + \vbox{#1% above frame % draw frame border _latest_ to avoid pdf viewer issue \kern\fboxrule \hbox{\kern\fboxrule @@ -726,10 +723,8 @@ \hrule\@height\fboxrule \kern\dimexpr\ht\@tempboxa+\dp\@tempboxa\relax \hrule\@height\fboxrule - #2% below frame - }% - }% - }% + #2% below frame + }% \endgroup }% \def\spx@fcolorbox@put@c#1{% hide width from framed.sty measuring From 798eead678f0f7dcfc007b5cf26a0051c4bf2efe Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 19 Jun 2017 01:28:31 +0900 Subject: [PATCH 0010/1814] Fix mypy violation --- sphinx/environment/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index dfbf448e3..de02d453c 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -300,7 +300,7 @@ class BuildEnvironment(object): be emitted instantly, but collected for emitting all warnings after the update of the environment. """ - self.app.warn(msg, location=(docname, lineno), **kwargs) + self.app.warn(msg, location=(docname, lineno), **kwargs) # type: ignore def warn_node(self, msg, node, **kwargs): # type: (unicode, nodes.Node, Any) -> None From 5ebfd516722f2e049748386f2091f042e1599a22 Mon Sep 17 00:00:00 2001 From: Andy Neebel Date: Wed, 21 Jun 2017 17:37:34 -0500 Subject: [PATCH 0011/1814] Improve cpp intersphinx support Now types called out in function declarations will be searched for in the intersphinx inventory as well --- sphinx/domains/cpp.py | 10 +++++----- tests/roots/test-ext-intersphinx-cppdomain/index.rst | 2 ++ tests/test_ext_intersphinx.py | 6 ++++++ tests/test_util_inventory.py | 2 ++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index b1e83a041..ac9978640 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4816,12 +4816,12 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(l_('class'), 'class'), - 'function': ObjType(l_('function'), 'func'), + 'class': ObjType(l_('class'), 'class', 'typeOrConcept'), + 'function': ObjType(l_('function'), 'func', 'typeOrConcept'), 'member': ObjType(l_('member'), 'member'), - 'type': ObjType(l_('type'), 'type'), - 'concept': ObjType(l_('concept'), 'concept'), - 'enum': ObjType(l_('enum'), 'enum'), + 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), + 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), + 'enum': ObjType(l_('enum'), 'enum', 'typeOrConcept'), 'enumerator': ObjType(l_('enumerator'), 'enumerator') } diff --git a/tests/roots/test-ext-intersphinx-cppdomain/index.rst b/tests/roots/test-ext-intersphinx-cppdomain/index.rst index b5397f856..06c954b99 100644 --- a/tests/roots/test-ext-intersphinx-cppdomain/index.rst +++ b/tests/roots/test-ext-intersphinx-cppdomain/index.rst @@ -4,3 +4,5 @@ test-ext-intersphinx-cppdomain .. cpp:namespace:: foo :cpp:class:`Bar` + +.. cpp:function:: std::uint8_t FooBarBaz() diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 4965108ef..96210dc6c 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -232,6 +232,12 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): ' href="https://docs.python.org/index.html#cpp_foo_bar"' ' title="(in foo v2.0)">' 'Bar' in html) + assert ('std' in html) + assert ('uint8_t' in html) def test_missing_reference_jsdomain(tempdir, app, status, warning): diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py index ecd2be1a6..1a5be431b 100644 --- a/tests/test_util_inventory.py +++ b/tests/test_util_inventory.py @@ -34,6 +34,8 @@ module1 py:module 0 foo.html#module-module1 Long Module desc module2 py:module 0 foo.html#module-$ - module1.func py:function 1 sub/foo.html#$ - CFunc c:function 2 cfunc.html#CFunc - +std cpp:type 1 index.html#std - +std::uint8_t cpp:type 1 index.html#std_uint8_t - foo::Bar cpp:class 1 index.html#cpp_foo_bar - foo::Bar::baz cpp:function 1 index.html#cpp_foo_bar_baz - a term std:term -1 glossary.html#term-a-term - From 60574eae3bb435e9e8263b0a534f72ddf68dee43 Mon Sep 17 00:00:00 2001 From: Andy Neebel Date: Thu, 22 Jun 2017 09:33:28 -0500 Subject: [PATCH 0012/1814] Clean up if tree, use the objtypes list --- sphinx/domains/cpp.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index ac9978640..957b2bd5b 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4816,13 +4816,13 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(l_('class'), 'class', 'typeOrConcept'), - 'function': ObjType(l_('function'), 'func', 'typeOrConcept'), - 'member': ObjType(l_('member'), 'member'), - 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), - 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), - 'enum': ObjType(l_('enum'), 'enum', 'typeOrConcept'), - 'enumerator': ObjType(l_('enumerator'), 'enumerator') + 'class': ObjType(l_('class'), 'class', 'type', 'typeOrConcept'), + 'function': ObjType(l_('function'), 'func', 'function', 'type', 'typeOrConcept'), + 'member': ObjType(l_('member'), 'member', 'var'), + 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), + 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), + 'enum': ObjType(l_('enum'), 'enum', 'type', 'typeOrConcept'), + 'enumerator': ObjType(l_('enumerator'), 'enumerator') } directives = { @@ -4955,16 +4955,10 @@ class CPPDomain(Domain): return True if declTyp == 'templateParam': return True - if typ == 'var' or typ == 'member': - return declTyp in ['var', 'member'] - if typ in ['enum', 'enumerator', 'function', 'class', 'concept']: - return declTyp == typ - validForType = ['enum', 'class', 'function', 'type'] - if typ == 'typeOrConcept': - return declTyp == 'concept' or declTyp in validForType - if typ == 'type': - return declTyp in validForType - print("Type is %s" % typ) + objtypes = self.objtypes_for_role(typ) + if objtypes and declTyp in objtypes: + return True + print("Type is %s, declType is %s" % (typ, declTyp)) assert False if not checkType(): warner.warn("cpp:%s targets a %s (%s)." From a6123001a3d44c63481d942bfa899ba50d400a2b Mon Sep 17 00:00:00 2001 From: Andy Neebel Date: Wed, 28 Jun 2017 10:02:50 -0500 Subject: [PATCH 0013/1814] Lines were too long, clean up spacing to fit --- sphinx/domains/cpp.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 957b2bd5b..6f1ce09ce 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4816,13 +4816,13 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(l_('class'), 'class', 'type', 'typeOrConcept'), - 'function': ObjType(l_('function'), 'func', 'function', 'type', 'typeOrConcept'), - 'member': ObjType(l_('member'), 'member', 'var'), - 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), - 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), - 'enum': ObjType(l_('enum'), 'enum', 'type', 'typeOrConcept'), - 'enumerator': ObjType(l_('enumerator'), 'enumerator') + 'class': ObjType(l_('class'), 'class', 'type', 'typeOrConcept'), + 'function': ObjType(l_('function'), 'function', 'func', 'type', 'typeOrConcept'), + 'member': ObjType(l_('member'), 'member', 'var' ), + 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), + 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), + 'enum': ObjType(l_('enum'), 'enum', 'type', 'typeOrConcept'), + 'enumerator': ObjType(l_('enumerator'), 'enumerator' ) } directives = { From 009afbd11f38a5cbcd60f652dbe9498c2da773d8 Mon Sep 17 00:00:00 2001 From: Andy Neebel Date: Wed, 28 Jun 2017 10:18:31 -0500 Subject: [PATCH 0014/1814] Whitespace isn't allowed before ) --- sphinx/domains/cpp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 6f1ce09ce..ece1eba3a 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4818,11 +4818,11 @@ class CPPDomain(Domain): object_types = { 'class': ObjType(l_('class'), 'class', 'type', 'typeOrConcept'), 'function': ObjType(l_('function'), 'function', 'func', 'type', 'typeOrConcept'), - 'member': ObjType(l_('member'), 'member', 'var' ), + 'member': ObjType(l_('member'), 'member', 'var'), 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), 'enum': ObjType(l_('enum'), 'enum', 'type', 'typeOrConcept'), - 'enumerator': ObjType(l_('enumerator'), 'enumerator' ) + 'enumerator': ObjType(l_('enumerator'), 'enumerator') } directives = { From 328e57949e6f11e0c6a587da4c919471e2eb382e Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 2 Jul 2017 15:19:47 +0200 Subject: [PATCH 0015/1814] #1236 add note: omit underscore in internal ref --- doc/markup/inline.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index a59585bab..32360baf7 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -145,10 +145,15 @@ Cross-referencing arbitrary locations The same works for tables that are given an explicit caption using the :dudir:`table` directive. - * Labels that aren't placed before a section title can still be referenced - to, but you must give the link an explicit title, using this syntax: + * Labels that aren't placed before a section title can still be referenced, + but you must give the link an explicit title, using this syntax: ``:ref:`Link title ```. + .. note:: + + Reference labels must start with an underscore. When referencing a + label, the underscore must be omitted (see examples above). + Using :rst:role:`ref` is advised over standard reStructuredText links to sections (like ```Section title`_``) because it works across files, when section headings are changed, and for all builders that support From 75154196b1008bbc0fea0b1018184bcb4a581591 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 10 Jul 2017 14:17:22 +0100 Subject: [PATCH 0016/1814] .gitignore: Ignore '.venv' directories This is a commonly used name for virtualenv directories and should be ignored. Signed-off-by: Stephen Finucane --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4472af150..d8a75381c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ TAGS .tags .tox +.venv .DS_Store sphinx/pycode/Grammar*pickle distribute-* From c244a7c9a94fc3451024f5488ffd631827072e81 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 3 May 2017 16:33:26 +0100 Subject: [PATCH 0017/1814] doc: Update sphinx-apidoc man page This man page wasn't making full use of Sphinx's own features. Update it to do so, and remove the duplicated information from 'invocation'. Signed-off-by: Stephen Finucane --- doc/invocation.rst | 123 +------------------------------------- doc/man/sphinx-apidoc.rst | 123 ++++++++++++++++++++++++++++---------- 2 files changed, 93 insertions(+), 153 deletions(-) diff --git a/doc/invocation.rst b/doc/invocation.rst index d0dedbd8b..80616d0c9 100644 --- a/doc/invocation.rst +++ b/doc/invocation.rst @@ -442,125 +442,4 @@ variable to your environment. For example: Invocation of sphinx-apidoc =========================== -The :program:`sphinx-apidoc` generates completely automatic API documentation -for a Python package. It is called like this: - -.. code-block:: console - - $ sphinx-apidoc [options] -o outputdir packagedir [pathnames] - -where *packagedir* is the path to the package to document, and *outputdir* is -the directory where the generated sources are placed. Any *pathnames* given -are paths to be excluded ignored during generation. - -.. warning:: - - ``sphinx-apidoc`` generates reST files that use :mod:`sphinx.ext.autodoc` to - document all found modules. If any modules have side effects on import, - these will be executed by ``autodoc`` when ``sphinx-build`` is run. - - If you document scripts (as opposed to library modules), make sure their main - routine is protected by a ``if __name__ == '__main__'`` condition. - - -The :program:`sphinx-apidoc` script has several options: - -.. program:: sphinx-apidoc - -.. option:: -o outputdir - - Gives the directory in which to place the generated output. - -.. option:: -f, --force - - Normally, sphinx-apidoc does not overwrite any files. Use this option to - force the overwrite of all files that it generates. - -.. option:: -n, --dry-run - - With this option given, no files will be written at all. - -.. option:: -e, --separate - - Put documentation for each module on its own page. - - .. versionadded:: 1.2 - -.. option:: -P, --private - - Include "_private" modules. - - .. versionadded:: 1.2 - -.. option:: -s suffix - - This option selects the file name suffix of output files. By default, this - is ``rst``. - -.. option:: -d maxdepth - - This sets the maximum depth of the table of contents, if one is generated. - -.. option:: -l, --follow-links - - This option makes sphinx-apidoc follow symbolic links when recursing the - filesystem to discover packages and modules. You may need it if you want - to generate documentation from a source directory managed by - `collective.recipe.omelette - `_. - By default, symbolic links are skipped. - - .. versionadded:: 1.2 - -.. option:: -T, --no-toc - - This prevents the generation of a table-of-contents file ``modules.rst``. - This has no effect when :option:`--full` is given. - -.. option:: -E, --no-headings - - Don't create headings for the module/package packages (e.g. when the - docstrings already contain them). - - .. versionadded:: 1.2 - -.. option:: -F, --full - - This option makes sphinx-apidoc create a full Sphinx project, using the same - mechanism as :program:`sphinx-quickstart`. Most configuration values are set - to default values, but you can influence the most important ones using the - following options. - -.. option:: --implicit-namespaces - - By default sphinx-apidoc processes sys.path searching for modules only. - Python 3.3 introduced :pep:`420` implicit namespaces that allow module path - structures such as ``foo/bar/module.py`` or ``foo/bar/baz/__init__.py`` - (notice that ``bar`` and ``foo`` are namespaces, not modules). - - Specifying this option interprets paths recursively according to PEP-0420. - -.. option:: -M - - This option makes sphinx-apidoc put module documentation before submodule - documentation. - -.. option:: -a - - Append module_path to sys.path. - -.. option:: -H project - - Sets the project name to put in generated files (see :confval:`project`). - -.. option:: -A author - - Sets the author name(s) to put in generated files (see :confval:`copyright`). - -.. option:: -V version - - Sets the project version to put in generated files (see :confval:`version`). - -.. option:: -R release - - Sets the project release to put in generated files (see :confval:`release`). +Refer to the :doc:`sphinx-apidoc man page `. diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index be0c3d3a3..4586d43f5 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -1,23 +1,21 @@ -:orphan: - -sphinx-apidoc manual page -========================= +sphinx-apidoc +============= Synopsis -------- **sphinx-apidoc** [*options*] -o <*outputdir*> <*sourcedir*> [*pathnames* ...] - Description ----------- :program:`sphinx-apidoc` is a tool for automatic generation of Sphinx sources -that, using the autodoc extension, document a whole package in the style of -other automatic API documentation tools. +that, using the :rst:dir:`autodoc` extension, document a whole package in the +style of other automatic API documentation tools. -*sourcedir* must point to a Python package. Any *pathnames* given are paths to -be excluded from the generation. +*sourcedir* is the path to a Python package to document, and *outputdir* is the +directory where the generated sources are placed. Any *pathnames* given are +paths to be excluded from the generation. .. warning:: @@ -28,40 +26,103 @@ be excluded from the generation. If you document scripts (as opposed to library modules), make sure their main routine is protected by a ``if __name__ == '__main__'`` condition. - Options ------- --o Directory to place the output files. If it does not exist, - it is created. --f, --force Usually, apidoc does not overwrite files, unless this option - is given. --l, --follow-links Follow symbolic links. --n, --dry-run If given, apidoc does not create any files. --s Suffix for the source files generated, default is ``rst``. --d Maximum depth for the generated table of contents file. --T, --no-toc Do not create a table of contents file. --F, --full If given, a full Sphinx project is generated (``conf.py``, - ``Makefile`` etc.) using sphinx-quickstart. --e, --separate Put each module file in its own page. --E, --no-headings Don't create headings for the modules/packages --P, --private Include "_private" modules +.. program:: sphinx-apidoc -These options are used with ``-F``: +.. option:: -o --a Append module_path to sys.path. --H Project name to put into the configuration. --A Author name(s) to put into the configuration. --V Project version. --R Project release. + Directory to place the output files. If it does not exist, it is created. +.. option:: -f, --force + + Force overwritting of any existing generated files. + +.. option:: -l, --follow-links + + Follow symbolic links. + +.. option:: -n, --dry-run + + Do not create any files. + +.. option:: -s + + Suffix for the source files generated. Defaults to ``rst``. + +.. option:: -d + + Maximum depth for the generated table of contents file. + +.. option:: -T, --no-toc + + Do not create a table of contents file. Ignored when :option:`--full` is + provided. + +.. option:: -F, --full + + Generate a full Sphinx project (``conf.py``, ``Makefile`` etc.) using + the same mechanism as :program:`sphinx-quickstart`. + +.. option:: -e, --separate + + Put documentation for each module on its own page. + + .. versionadded:: 1.2 + +.. option:: -E, --no-headings + + Do not create headings for the modules/packages. This is useful, for + example, when docstrings already contain headings. + +.. option:: -P, --private + + Include "_private" modules. + + .. versionadded:: 1.2 + +.. option:: --implicit-namespaces + + By default sphinx-apidoc processes sys.path searching for modules only. + Python 3.3 introduced :pep:`420` implicit namespaces that allow module path + structures such as ``foo/bar/module.py`` or ``foo/bar/baz/__init__.py`` + (notice that ``bar`` and ``foo`` are namespaces, not modules). + + Interpret paths recursively according to PEP-0420. + +.. option:: -M + + Put module documentation before submodule documentation. + +These options are used when :option:`--full` is specified: + +.. option:: -a + + Append module_path to sys.path. + +.. option:: -H + + Sets the project name to put in generated files (see :confval:`project`). + +.. option:: -A + + Sets the author name(s) to put in generated files (see + :confval:`copyright`). + +.. option:: -V + + Sets the project version to put in generated files (see :confval:`version`). + +.. option:: -R + + Sets the project release to put in generated files (see :confval:`release`). See also -------- :manpage:`sphinx-build(1)` - Author ------ From 2cfa2bc67371a229b8b1fa05fc69eb5e82efc61f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 4 Jul 2017 20:03:05 +0100 Subject: [PATCH 0018/1814] doc: Update sphinx-quickstart man page This man page wasn't making full use of Sphinx's own features. Update it to do so, and remove the duplicated information from 'invocation'. Signed-off-by: Stephen Finucane --- doc/invocation.rst | 169 +--------------------------------- doc/man/sphinx-quickstart.rst | 152 ++++++++++++++++++++++++++++-- doc/tutorial.rst | 2 +- 3 files changed, 148 insertions(+), 175 deletions(-) diff --git a/doc/invocation.rst b/doc/invocation.rst index 80616d0c9..2b0ae8bb7 100644 --- a/doc/invocation.rst +++ b/doc/invocation.rst @@ -5,172 +5,7 @@ Invocation of sphinx-quickstart =============================== -The :program:`sphinx-quickstart` script generates a Sphinx documentation set. -It is called like this: - -.. code-block:: console - - $ sphinx-quickstart [options] [projectdir] - -where *projectdir* is the Sphinx documentation set directory in which you want -to place. If you omit *projectdir*, files are generated into current directory -by default. - -The :program:`sphinx-quickstart` script has several options: - -.. program:: sphinx-quickstart - -.. option:: -q, --quiet - - Quiet mode that will skips interactive wizard to specify options. - This option requires `-p`, `-a` and `-v` options. - -.. option:: -h, --help, --version - - Display usage summary or Sphinx version. - - -Structure options ------------------ - -.. option:: --sep - - If specified, separate source and build directories. - -.. option:: --dot=DOT - - Inside the root directory, two more directories will be created; - "_templates" for custom HTML templates and "_static" for custom stylesheets - and other static files. You can enter another prefix (such as ".") to - replace the underscore. - -Project basic options ---------------------- - -.. option:: -p PROJECT, --project=PROJECT - - Project name will be set. (see :confval:`project`). - -.. option:: -a AUTHOR, --author=AUTHOR - - Author names. (see :confval:`copyright`). - -.. option:: -v VERSION - - Version of project. (see :confval:`version`). - -.. option:: -r RELEASE, --release=RELEASE - - Release of project. (see :confval:`release`). - -.. option:: -l LANGUAGE, --language=LANGUAGE - - Document language. (see :confval:`language`). - -.. option:: --suffix=SUFFIX - - Source file suffix. (see :confval:`source_suffix`). - -.. option:: --master=MASTER - - Master document name. (see :confval:`master_doc`). - -.. option:: --epub - - Use epub. - -Extension options ------------------ - -.. option:: --ext-autodoc - - Enable `sphinx.ext.autodoc` extension. - -.. option:: --ext-doctest - - Enable `sphinx.ext.doctest` extension. - -.. option:: --ext-intersphinx - - Enable `sphinx.ext.intersphinx` extension. - -.. option:: --ext-todo - - Enable `sphinx.ext.todo` extension. - -.. option:: --ext-coverage - - Enable `sphinx.ext.coverage` extension. - -.. option:: --ext-imgmath - - Enable `sphinx.ext.imgmath` extension. - -.. option:: --ext-mathjax - - Enable `sphinx.ext.mathjax` extension. - -.. option:: --ext-ifconfig - - Enable `sphinx.ext.ifconfig` extension. - -.. option:: --ext-viewcode - - Enable `sphinx.ext.viewcode` extension. - -.. option:: --extensions=EXTENSIONS - - Enable arbitary extensions. - - -Makefile and Batchfile creation options ---------------------------------------- - -.. option:: --use-make-mode, --no-use-make-mode - - Makefile/make.bat uses (or not use) make-mode. Default is use. - - .. versionchanged:: 1.5 - make-mode is default. - -.. option:: --makefile, --no-makefile - - Create (or not create) makefile. - -.. option:: --batchfile, --no-batchfile - - Create (or not create) batchfile - - -.. versionadded:: 1.3 - Add various options for sphinx-quickstart invocation. - -Project templating ------------------- - -.. option:: -t, --templatedir=TEMPLATEDIR - - Template directory for template files. You can modify the templates of - sphinx project files generated by quickstart. Following Jinja2 template - files are allowed: - - * master_doc.rst_t - * conf.py_t - * Makefile_t - * Makefile.new_t - * make.bat_t - * make.bat.new_t - - In detail, please refer the system template files Sphinx provides. - (sphinx/templates/quickstart) - -.. option:: -d NAME=VALUE - - Define a template variable - -.. versionadded:: 1.5 - Project templating options for sphinx-quickstart - +Refer to the :doc:`sphinx-quickstart man page `. Invocation of sphinx-build ========================== @@ -437,8 +272,6 @@ variable to your environment. For example: * modify your Makefile/make.bat and set the environment variable -.. _invocation-apidoc: - Invocation of sphinx-apidoc =========================== diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index 172772610..7437dca06 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -1,14 +1,11 @@ -:orphan: - -sphinx-quickstart manual page -============================= +sphinx-quickstart +================= Synopsis -------- **sphinx-quickstart** - Description ----------- @@ -16,13 +13,156 @@ Description about your project and then generates a complete documentation directory and sample Makefile to be used with :manpage:`sphinx-build(1)`. +Options +------- + +.. program:: sphinx-quickstart + +.. option:: -q, --quiet + + Quiet mode that will skips interactive wizard to specify options. + This option requires `-p`, `-a` and `-v` options. + +.. option:: -h, --help, --version + + Display usage summary or Sphinx version. + +.. rubric:: Structure Options + +.. option:: --sep + + If specified, separate source and build directories. + +.. option:: --dot=DOT + + Inside the root directory, two more directories will be created; + "_templates" for custom HTML templates and "_static" for custom stylesheets + and other static files. You can enter another prefix (such as ".") to + replace the underscore. + +.. rubric:: Project Basic Options + +.. option:: -p PROJECT, --project=PROJECT + + Project name will be set. (see :confval:`project`). + +.. option:: -a AUTHOR, --author=AUTHOR + + Author names. (see :confval:`copyright`). + +.. option:: -v VERSION + + Version of project. (see :confval:`version`). + +.. option:: -r RELEASE, --release=RELEASE + + Release of project. (see :confval:`release`). + +.. option:: -l LANGUAGE, --language=LANGUAGE + + Document language. (see :confval:`language`). + +.. option:: --suffix=SUFFIX + + Source file suffix. (see :confval:`source_suffix`). + +.. option:: --master=MASTER + + Master document name. (see :confval:`master_doc`). + +.. option:: --epub + + Use epub. + +.. rubric:: Extension Options + +.. option:: --ext-autodoc + + Enable `sphinx.ext.autodoc` extension. + +.. option:: --ext-doctest + + Enable `sphinx.ext.doctest` extension. + +.. option:: --ext-intersphinx + + Enable `sphinx.ext.intersphinx` extension. + +.. option:: --ext-todo + + Enable `sphinx.ext.todo` extension. + +.. option:: --ext-coverage + + Enable `sphinx.ext.coverage` extension. + +.. option:: --ext-imgmath + + Enable `sphinx.ext.imgmath` extension. + +.. option:: --ext-mathjax + + Enable `sphinx.ext.mathjax` extension. + +.. option:: --ext-ifconfig + + Enable `sphinx.ext.ifconfig` extension. + +.. option:: --ext-viewcode + + Enable `sphinx.ext.viewcode` extension. + +.. option:: --extensions=EXTENSIONS + + Enable arbitary extensions. + +.. rubric:: Makefile and Batchfile Creation Options + +.. option:: --use-make-mode, --no-use-make-mode + + Makefile/make.bat uses (or not use) make-mode. Default is use. + + .. versionchanged:: 1.5 + make-mode is default. + +.. option:: --makefile, --no-makefile + + Create (or not create) makefile. + +.. option:: --batchfile, --no-batchfile + + Create (or not create) batchfile + +.. rubric:: Project templating + +.. versionadded:: 1.5 + Project templating options for sphinx-quickstart + +.. option:: -t, --templatedir=TEMPLATEDIR + + Template directory for template files. You can modify the templates of + sphinx project files generated by quickstart. Following Jinja2 template + files are allowed: + + * ``master_doc.rst_t`` + * ``conf.py_t`` + * ``Makefile_t`` + * ``Makefile.new_t`` + * ``make.bat_t`` + * ``make.bat.new_t`` + + In detail, please refer the system template files Sphinx provides. + (``sphinx/templates/quickstart``) + +.. option:: -d NAME=VALUE + + Define a template variable See also -------- :manpage:`sphinx-build(1)` - Author ------ diff --git a/doc/tutorial.rst b/doc/tutorial.rst index ffabbd93e..20c5590e2 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -36,7 +36,7 @@ configuration values from a few questions it asks you. Just run :: and answer its questions. (Be sure to say yes to the "autodoc" extension.) There is also an automatic "API documentation" generator called -:program:`sphinx-apidoc`; see :ref:`invocation-apidoc` for details. +:program:`sphinx-apidoc`; see :doc:`/man/sphinx-apidoc` for details. Defining document structure From 12e190f35f122e41a1bc36254ea522b99014d34f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 4 Jul 2017 20:13:36 +0100 Subject: [PATCH 0019/1814] doc: Update sphinx-build man page This man page wasn't making full use of Sphinx's own features. Update it to do so, and remove the duplicated information from 'invocation'. Signed-off-by: Stephen Finucane --- doc/invocation.rst | 262 +---------------------------- doc/man/sphinx-build.rst | 353 ++++++++++++++++++++++++++++----------- 2 files changed, 257 insertions(+), 358 deletions(-) diff --git a/doc/invocation.rst b/doc/invocation.rst index 2b0ae8bb7..4387b066e 100644 --- a/doc/invocation.rst +++ b/doc/invocation.rst @@ -10,267 +10,7 @@ Refer to the :doc:`sphinx-quickstart man page `. Invocation of sphinx-build ========================== -The :program:`sphinx-build` script builds a Sphinx documentation set. It is -called like this: - -.. code-block:: console - - $ sphinx-build [options] sourcedir builddir [filenames] - -where *sourcedir* is the :term:`source directory`, and *builddir* is the -directory in which you want to place the built documentation. Most of the time, -you don't need to specify any *filenames*. - -The :program:`sphinx-build` script has several options: - -.. program:: sphinx-build - -.. option:: -b buildername - - The most important option: it selects a builder. The most common builders - are: - - **html** - Build HTML pages. This is the default builder. - - **dirhtml** - Build HTML pages, but with a single directory per document. Makes for - prettier URLs (no ``.html``) if served from a webserver. - - **singlehtml** - Build a single HTML with the whole content. - - **htmlhelp**, **qthelp**, **devhelp**, **epub** - Build HTML files with additional information for building a documentation - collection in one of these formats. - - **applehelp** - Build an Apple Help Book. Requires :program:`hiutil` and - :program:`codesign`, which are not Open Source and presently only - available on Mac OS X 10.6 and higher. - - **latex** - Build LaTeX sources that can be compiled to a PDF document using - :program:`pdflatex`. - - **man** - Build manual pages in groff format for UNIX systems. - - **texinfo** - Build Texinfo files that can be processed into Info files using - :program:`makeinfo`. - - **text** - Build plain text files. - - **gettext** - Build gettext-style message catalogs (``.pot`` files). - - **doctest** - Run all doctests in the documentation, if the :mod:`~sphinx.ext.doctest` - extension is enabled. - - **linkcheck** - Check the integrity of all external links. - - **xml** - Build Docutils-native XML files. - - **pseudoxml** - Build compact pretty-printed "pseudo-XML" files displaying the - internal structure of the intermediate document trees. - - See :ref:`builders` for a list of all builders shipped with Sphinx. - Extensions can add their own builders. - -.. option:: -a - - If given, always write all output files. The default is to only write output - files for new and changed source files. (This may not apply to all - builders.) - -.. option:: -E - - Don't use a saved :term:`environment` (the structure caching all - cross-references), but rebuild it completely. The default is to only read - and parse source files that are new or have changed since the last run. - -.. option:: -t tag - - Define the tag *tag*. This is relevant for :rst:dir:`only` directives that - only include their content if this tag is set. - - .. versionadded:: 0.6 - -.. option:: -d path - - Since Sphinx has to read and parse all source files before it can write an - output file, the parsed source files are cached as "doctree pickles". - Normally, these files are put in a directory called :file:`.doctrees` under - the build directory; with this option you can select a different cache - directory (the doctrees can be shared between all builders). - -.. option:: -j N - - Distribute the build over *N* processes in parallel, to make building on - multiprocessor machines more effective. Note that not all parts and not all - builders of Sphinx can be parallelized. - - .. versionadded:: 1.2 - This option should be considered *experimental*. - -.. option:: -c path - - Don't look for the :file:`conf.py` in the source directory, but use the given - configuration directory instead. Note that various other files and paths - given by configuration values are expected to be relative to the - configuration directory, so they will have to be present at this location - too. - - .. versionadded:: 0.3 - -.. option:: -C - - Don't look for a configuration file; only take options via the ``-D`` option. - - .. versionadded:: 0.5 - -.. option:: -D setting=value - - Override a configuration value set in the :file:`conf.py` file. The value - must be a number, string, list or dictionary value. - - For lists, you can separate elements with a comma like this: ``-D - html_theme_path=path1,path2``. - - For dictionary values, supply the setting name and key like this: - ``-D latex_elements.docclass=scrartcl``. - - For boolean values, use ``0`` or ``1`` as the value. - - .. versionchanged:: 0.6 - The value can now be a dictionary value. - - .. versionchanged:: 1.3 - The value can now also be a list value. - -.. option:: -A name=value - - Make the *name* assigned to *value* in the HTML templates. - - .. versionadded:: 0.5 - -.. option:: -n - - Run in nit-picky mode. Currently, this generates warnings for all missing - references. See the config value :confval:`nitpick_ignore` for a way to - exclude some references as "known missing". - -.. option:: -N - - Do not emit colored output. - -.. option:: -v - - Increase verbosity (loglevel). This option can be given up to three times - to get more debug logging output. It implies :option:`-T`. - - .. versionadded:: 1.2 - -.. option:: -q - - Do not output anything on standard output, only write warnings and errors to - standard error. - -.. option:: -Q - - Do not output anything on standard output, also suppress warnings. Only - errors are written to standard error. - -.. option:: -w file - - Write warnings (and errors) to the given file, in addition to standard error. - -.. option:: -W - - Turn warnings into errors. This means that the build stops at the first - warning and ``sphinx-build`` exits with exit status 1. - -.. option:: -T - - Display the full traceback when an unhandled exception occurs. Otherwise, - only a summary is displayed and the traceback information is saved to a file - for further analysis. - - .. versionadded:: 1.2 - -.. option:: -P - - (Useful for debugging only.) Run the Python debugger, :mod:`pdb`, if an - unhandled exception occurs while building. - -.. option:: -h, --help, --version - - Display usage summary or Sphinx version. - - .. versionadded:: 1.2 - -You can also give one or more filenames on the command line after the source and -build directories. Sphinx will then try to build only these output files (and -their dependencies). - -Environment variables ---------------------- - -The :program:`sphinx-build` refers following environment variables: - -.. describe:: MAKE - - A path to make command. A command name is also allowed. - :program:`sphinx-build` uses it to invoke sub-build process on make-mode. - -Makefile options ----------------- - -The :file:`Makefile` and :file:`make.bat` files created by -:program:`sphinx-quickstart` usually run :program:`sphinx-build` only with the -:option:`-b` and :option:`-d` options. However, they support the following -variables to customize behavior: - -.. describe:: PAPER - - The value for '"papersize"` key of :confval:`latex_elements`. - -.. describe:: SPHINXBUILD - - The command to use instead of ``sphinx-build``. - -.. describe:: BUILDDIR - - The build directory to use instead of the one chosen in - :program:`sphinx-quickstart`. - -.. describe:: SPHINXOPTS - - Additional options for :program:`sphinx-build`. - -.. _when-deprecation-warnings-are-displayed: - -Deprecation Warnings --------------------- - -If any deprecation warning like ``RemovedInSphinxXXXWarning`` are displayed -when building a user's document, some Sphinx extension is using deprecated -features. In that case, please report it to author of the extension. - -To disable the deprecation warnings, please set ``PYTHONWARNINGS=`` environment -variable to your environment. For example: - -* ``PYTHONWARNINGS= make html`` (Linux/Mac) -* ``export PYTHONWARNINGS=`` and do ``make html`` (Linux/Mac) -* ``set PYTHONWARNINGS=`` and do ``make html`` (Windows) -* modify your Makefile/make.bat and set the environment variable - +Refer to the :doc:`sphinx-build man page `. Invocation of sphinx-apidoc =========================== diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 13564ff4d..29bd27e23 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -1,121 +1,280 @@ -:orphan: - -sphinx-build manual page -======================== +sphinx-build +============ Synopsis -------- -**sphinx-build** [*options*] <*sourcedir*> <*outdir*> [*filenames* ...] - +**sphinx-build** [*options*] <*sourcedir*> <*outputdir*> [*filenames* ...] Description ----------- :program:`sphinx-build` generates documentation from the files in -```` and places it in the ````. +```` and places it in the ````. :program:`sphinx-build` looks for ``/conf.py`` for the configuration settings. :manpage:`sphinx-quickstart(1)` may be used to generate template files, including ``conf.py``. -:program:`sphinx-build` can create documentation in different formats. A format -is selected by specifying the builder name on the command line; it defaults to -HTML. Builders can also perform other tasks related to documentation -processing. +:program:`sphinx-build` can create documentation in different formats. A +format is selected by specifying the builder name on the command line; it +defaults to HTML. Builders can also perform other tasks related to +documentation processing. By default, everything that is outdated is built. Output only for selected files can be built by specifying individual filenames. -List of available builders: - -html - HTML file generation. This is the default builder. - -dirhtml - HTML file generation with every HTML file named "index.html" in a separate - directory. - -singlehtml - HTML file generation with all content in a single HTML file. - -htmlhelp - Generates files for CHM (compiled help files) generation. - -qthelp - Generates files for Qt help collection generation. - -devhelp - Generates files for the GNOME Devhelp help viewer. - -latex - Generates LaTeX output that can be compiled to a PDF document. - -man - Generates manual pages. - -texinfo - Generates Texinfo output that can be processed by :program:`makeinfo` to - generate an Info document. - -epub - Generates an ePub e-book version of the HTML output. - -text - Generates a plain-text version of the documentation. - -gettext - Generates Gettext message catalogs for content translation. - -changes - Generates HTML files listing changed/added/deprecated items for - the current version of the documented project. - -linkcheck - Checks the integrity of all external links in the source. - -pickle / json - Generates serialized HTML files for use in web applications. - -xml - Generates Docutils-native XML files. - -pseudoxml - Generates compact pretty-printed "pseudo-XML" files displaying the - internal structure of the intermediate document trees. - +For a list of available options, refer to :option:`sphinx-build -b`. Options ------- --b Builder to use; defaults to html. See the full list - of builders above. --a Generate output for all files; without this option only - output for new and changed files is generated. --E Ignore cached files, forces to re-read all source files - from disk. --d Path to cached files; defaults to /.doctrees. --j Build in parallel with N processes where possible. --c Locate the conf.py file in the specified path instead of - . --C Specify that no conf.py file at all is to be used. - Configuration can only be set with the -D option. --D Override a setting from the configuration file. --t Define *tag* for use in "only" blocks. --A Pass a value into the HTML templates (only for HTML - builders). --n Run in nit-picky mode, warn about all missing references. --v Increase verbosity (can be repeated). --N Prevent colored output. --q Quiet operation, just print warnings and errors on stderr. --Q Very quiet operation, don't print anything except for - errors. --w Write warnings and errors into the given file, in addition - to stderr. --W Turn warnings into errors. --T Show full traceback on exception. --P Run Pdb on exception. +.. program:: sphinx-build +.. option:: -b buildername + + The most important option: it selects a builder. The most common builders + are: + + **html** + Build HTML pages. This is the default builder. + + **dirhtml** + Build HTML pages, but with a single directory per document. Makes for + prettier URLs (no ``.html``) if served from a webserver. + + **singlehtml** + Build a single HTML with the whole content. + + **htmlhelp**, **qthelp**, **devhelp**, **epub** + Build HTML files with additional information for building a documentation + collection in one of these formats. + + **applehelp** + Build an Apple Help Book. Requires :program:`hiutil` and + :program:`codesign`, which are not Open Source and presently only + available on Mac OS X 10.6 and higher. + + **latex** + Build LaTeX sources that can be compiled to a PDF document using + :program:`pdflatex`. + + **man** + Build manual pages in groff format for UNIX systems. + + **texinfo** + Build Texinfo files that can be processed into Info files using + :program:`makeinfo`. + + **text** + Build plain text files. + + **gettext** + Build gettext-style message catalogs (``.pot`` files). + + **doctest** + Run all doctests in the documentation, if the :mod:`~sphinx.ext.doctest` + extension is enabled. + + **linkcheck** + Check the integrity of all external links. + + **xml** + Build Docutils-native XML files. + + **pseudoxml** + Build compact pretty-printed "pseudo-XML" files displaying the + internal structure of the intermediate document trees. + + See :ref:`builders` for a list of all builders shipped with Sphinx. + Extensions can add their own builders. + +.. option:: -a + + If given, always write all output files. The default is to only write output + files for new and changed source files. (This may not apply to all + builders.) + +.. option:: -E + + Don't use a saved :term:`environment` (the structure caching all + cross-references), but rebuild it completely. The default is to only read + and parse source files that are new or have changed since the last run. + +.. option:: -t tag + + Define the tag *tag*. This is relevant for :rst:dir:`only` directives that + only include their content if this tag is set. + + .. versionadded:: 0.6 + +.. option:: -d path + + Since Sphinx has to read and parse all source files before it can write an + output file, the parsed source files are cached as "doctree pickles". + Normally, these files are put in a directory called :file:`.doctrees` under + the build directory; with this option you can select a different cache + directory (the doctrees can be shared between all builders). + +.. option:: -j N + + Distribute the build over *N* processes in parallel, to make building on + multiprocessor machines more effective. Note that not all parts and not all + builders of Sphinx can be parallelized. + + .. versionadded:: 1.2 + This option should be considered *experimental*. + +.. option:: -c path + + Don't look for the :file:`conf.py` in the source directory, but use the given + configuration directory instead. Note that various other files and paths + given by configuration values are expected to be relative to the + configuration directory, so they will have to be present at this location + too. + + .. versionadded:: 0.3 + +.. option:: -C + + Don't look for a configuration file; only take options via the ``-D`` option. + + .. versionadded:: 0.5 + +.. option:: -D setting=value + + Override a configuration value set in the :file:`conf.py` file. The value + must be a number, string, list or dictionary value. + + For lists, you can separate elements with a comma like this: ``-D + html_theme_path=path1,path2``. + + For dictionary values, supply the setting name and key like this: + ``-D latex_elements.docclass=scrartcl``. + + For boolean values, use ``0`` or ``1`` as the value. + + .. versionchanged:: 0.6 + The value can now be a dictionary value. + + .. versionchanged:: 1.3 + The value can now also be a list value. + +.. option:: -A name=value + + Make the *name* assigned to *value* in the HTML templates. + + .. versionadded:: 0.5 + +.. option:: -n + + Run in nit-picky mode. Currently, this generates warnings for all missing + references. See the config value :confval:`nitpick_ignore` for a way to + exclude some references as "known missing". + +.. option:: -N + + Do not emit colored output. + +.. option:: -v + + Increase verbosity (loglevel). This option can be given up to three times + to get more debug logging output. It implies :option:`-T`. + + .. versionadded:: 1.2 + +.. option:: -q + + Do not output anything on standard output, only write warnings and errors to + standard error. + +.. option:: -Q + + Do not output anything on standard output, also suppress warnings. Only + errors are written to standard error. + +.. option:: -w file + + Write warnings (and errors) to the given file, in addition to standard error. + +.. option:: -W + + Turn warnings into errors. This means that the build stops at the first + warning and ``sphinx-build`` exits with exit status 1. + +.. option:: -T + + Display the full traceback when an unhandled exception occurs. Otherwise, + only a summary is displayed and the traceback information is saved to a file + for further analysis. + + .. versionadded:: 1.2 + +.. option:: -P + + (Useful for debugging only.) Run the Python debugger, :mod:`pdb`, if an + unhandled exception occurs while building. + +.. option:: -h, --help, --version + + Display usage summary or Sphinx version. + + .. versionadded:: 1.2 + +You can also give one or more filenames on the command line after the source +and build directories. Sphinx will then try to build only these output files +(and their dependencies). + +Environment Variables +--------------------- + +The :program:`sphinx-build` refers following environment variables: + +.. describe:: MAKE + + A path to make command. A command name is also allowed. + :program:`sphinx-build` uses it to invoke sub-build process on make-mode. + +.. rubric:: Makefile Options + +The :file:`Makefile` and :file:`make.bat` files created by +:program:`sphinx-quickstart` usually run :program:`sphinx-build` only with the +:option:`-b` and :option:`-d` options. However, they support the following +variables to customize behavior: + +.. describe:: PAPER + + The value for '"papersize"` key of :confval:`latex_elements`. + +.. describe:: SPHINXBUILD + + The command to use instead of ``sphinx-build``. + +.. describe:: BUILDDIR + + The build directory to use instead of the one chosen in + :program:`sphinx-quickstart`. + +.. describe:: SPHINXOPTS + + Additional options for :program:`sphinx-build`. + +.. _when-deprecation-warnings-are-displayed: + +Deprecation Warnings +-------------------- + +If any deprecation warning like ``RemovedInSphinxXXXWarning`` are displayed +when building a user's document, some Sphinx extension is using deprecated +features. In that case, please report it to author of the extension. + +To disable the deprecation warnings, please set ``PYTHONWARNINGS=`` environment +variable to your environment. For example: + +* ``PYTHONWARNINGS= make html`` (Linux/Mac) +* ``export PYTHONWARNINGS=`` and do ``make html`` (Linux/Mac) +* ``set PYTHONWARNINGS=`` and do ``make html`` (Windows) +* modify your Makefile/make.bat and set the environment variable See also -------- @@ -125,8 +284,8 @@ See also Author ------ -Georg Brandl , Armin Ronacher et -al. +Georg Brandl , Armin Ronacher +et al. This manual page was initially written by Mikhail Gusarov , for the Debian project. From 9b7525d47df40c1e5d63ec4ee2fdbc51d35bf1ea Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 4 Jul 2017 20:32:36 +0100 Subject: [PATCH 0020/1814] doc: Remove 'invocation' document This contains no useful information at this point. Better to simply drop it. Signed-off-by: Stephen Finucane --- doc/contents.rst | 2 +- doc/invocation.rst | 18 ------------------ doc/man/index.rst | 21 +++++++++++++++++++++ doc/tutorial.rst | 8 ++++---- 4 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 doc/invocation.rst create mode 100644 doc/man/index.rst diff --git a/doc/contents.rst b/doc/contents.rst index 36eed649e..ab8d09eb0 100644 --- a/doc/contents.rst +++ b/doc/contents.rst @@ -9,7 +9,7 @@ Sphinx documentation contents intro tutorial - invocation + man/index rest markup/index domains diff --git a/doc/invocation.rst b/doc/invocation.rst deleted file mode 100644 index 4387b066e..000000000 --- a/doc/invocation.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. default-role:: any - -.. _invocation: - -Invocation of sphinx-quickstart -=============================== - -Refer to the :doc:`sphinx-quickstart man page `. - -Invocation of sphinx-build -========================== - -Refer to the :doc:`sphinx-build man page `. - -Invocation of sphinx-apidoc -=========================== - -Refer to the :doc:`sphinx-apidoc man page `. diff --git a/doc/man/index.rst b/doc/man/index.rst new file mode 100644 index 000000000..5d0e2c035 --- /dev/null +++ b/doc/man/index.rst @@ -0,0 +1,21 @@ +Man Pages +========= + +These are the applications provided as part of Sphinx. + +Core Applications +----------------- + +.. toctree:: + :maxdepth: 3 + + sphinx-quickstart + sphinx-build + +Additional Applications +----------------------- + +.. toctree:: + :maxdepth: 3 + + sphinx-apidoc diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 20c5590e2..148e8cdad 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -126,8 +126,8 @@ directory in which you want to place the built documentation. The :option:`-b ` option selects a builder; in this example Sphinx will build HTML files. -|more| See :ref:`invocation` for all options that :program:`sphinx-build` -supports. +|more| Refer to the :program:`sphinx-build man page ` for all +options that :program:`sphinx-build` supports. However, :program:`sphinx-quickstart` script creates a :file:`Makefile` and a :file:`make.bat` which make life even easier for you: with them you only need @@ -317,8 +317,8 @@ More topics to be covered .. rubric:: Footnotes .. [#] This is the usual layout. However, :file:`conf.py` can also live in - another directory, the :term:`configuration directory`. See - :ref:`invocation`. + another directory, the :term:`configuration directory`. Refer to the + :program:`sphinx-build man page ` for more information. .. |more| image:: more.png :align: middle From 65a81e205622fd3fc788a8861ace3bdef2c5891a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 11 Jul 2017 15:58:20 +0100 Subject: [PATCH 0021/1814] doc: Add sphinx-autogen man page This wasn't documented in depth anywhere, so do just that. Signed-off-by: Stephen Finucane --- doc/conf.py | 2 + doc/ext/autosummary.rst | 3 ++ doc/man/index.rst | 1 + doc/man/sphinx-apidoc.rst | 2 +- doc/man/sphinx-autogen.rst | 93 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 doc/man/sphinx-autogen.rst diff --git a/doc/conf.py b/doc/conf.py index 62c5c13d5..db2846186 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -84,6 +84,8 @@ man_pages = [ 'template generator', '', 1), ('man/sphinx-apidoc', 'sphinx-apidoc', 'Sphinx API doc generator tool', '', 1), + ('man/sphinx-autogen', 'sphinx-autogen', 'Generate autodoc stub pages', + '', 1), ] texinfo_documents = [ diff --git a/doc/ext/autosummary.rst b/doc/ext/autosummary.rst index d2e94e7da..7adf65c53 100644 --- a/doc/ext/autosummary.rst +++ b/doc/ext/autosummary.rst @@ -125,6 +125,9 @@ text of the form:: If the ``-o`` option is not given, the script will place the output files in the directories specified in the ``:toctree:`` options. +For more information, refer to the :doc:`sphinx-autogen documentation +` + Generating stub pages automatically ----------------------------------- diff --git a/doc/man/index.rst b/doc/man/index.rst index 5d0e2c035..c2ca3f065 100644 --- a/doc/man/index.rst +++ b/doc/man/index.rst @@ -19,3 +19,4 @@ Additional Applications :maxdepth: 3 sphinx-apidoc + sphinx-autogen diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index 4586d43f5..145c53648 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -121,7 +121,7 @@ These options are used when :option:`--full` is specified: See also -------- -:manpage:`sphinx-build(1)` +:manpage:`sphinx-build(1)`, :manpage:`sphinx-autogen(1)` Author ------ diff --git a/doc/man/sphinx-autogen.rst b/doc/man/sphinx-autogen.rst new file mode 100644 index 000000000..dcab68d76 --- /dev/null +++ b/doc/man/sphinx-autogen.rst @@ -0,0 +1,93 @@ +sphinx-autogen +============== + +Synopsis +-------- + +**sphinx-autogen** [*options*] ... + +Description +----------- + +:program:`sphinx-autogen` is a tool for automatic generation of Sphinx sources +that, using the :rst:dir:`autodoc` extension, document items included in +:rst:dir:`autosummary` listing(s). + +*sourcefile* is the path to one or more reStructuredText documents containing +:rst:dir:`autosummary` entries with the ``:toctree::`` option set. *sourcefile* +can be an :py:module:`fnmatch`-style pattern. + +Options +------- + +.. program:: sphinx-autogen + +.. option:: -o + + Directory to place the output file. If it does not exist, it is created. + Defaults to the value passed to the ``:toctree:`` option. + +.. option:: -s , --suffix + + Default suffix to use for generated files. Defaults to ``rst``. + +.. option:: -t , --templates + + Custom template directory. Defaults to ``None``. + +.. option:: -i, --imported-members + + Document imported members. + +Example +------- + +Given the following directory structure:: + + docs + ├── index.rst + └── ... + foobar + ├── foo + │ └── __init__.py + └── bar + ├── __init__.py + └── baz + └── __init__.py + +and assuming ``docs/index.rst`` contained the following: + +.. code-block:: rst + + Modules + ======= + + .. autosummary:: + :toctree: modules + + foobar.foo + foobar.bar + foobar.bar.baz + +If you run the following: + +.. code-block:: bash + + $ sphinx-autodoc doc/index.rst + +then the following stub files will be created in ``docs``:: + + docs + ├── index.rst + └── modules + ├── foobar.bar.rst + ├── foobar.bar.baz.rst + └── foobar.foo.rst + +and each of those files will contain a :rst:dir:`autodoc` directive and some +other information. + +See also +-------- + +:manpage:`sphinx-build(1)`, :manpage:`sphinx-apidoc(1)` From 348bf2a421d3d8ce5fa483e32bc1d5fd2e76aa06 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 11 Jul 2017 16:05:07 +0100 Subject: [PATCH 0022/1814] doc: Remove 'Author' section from man pages Per the closest thing we have to official man page guidelines [1]: Use of an AUTHORS section is strongly discouraged. Generally, it is better not to clutter every page with a list of (over time potentially numerous) authors; if you write or significantly amend a page, add a copyright notice as a comment in the source file. We already do a good job of tracking authors in the AUTHORS file, so we can remove this. [1] https://linux.die.net/man/7/man-pages Signed-off-by: Stephen Finucane --- doc/man/sphinx-apidoc.rst | 6 ------ doc/man/sphinx-build.rst | 9 --------- doc/man/sphinx-quickstart.rst | 9 --------- 3 files changed, 24 deletions(-) diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index 145c53648..803466040 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -122,9 +122,3 @@ See also -------- :manpage:`sphinx-build(1)`, :manpage:`sphinx-autogen(1)` - -Author ------- - -Etienne Desautels, , Georg Brandl - et al. diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 29bd27e23..0f969b732 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -280,12 +280,3 @@ See also -------- :manpage:`sphinx-quickstart(1)` - -Author ------- - -Georg Brandl , Armin Ronacher -et al. - -This manual page was initially written by Mikhail Gusarov -, for the Debian project. diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index 7437dca06..db552ef2f 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -162,12 +162,3 @@ See also -------- :manpage:`sphinx-build(1)` - -Author ------- - -Georg Brandl , Armin Ronacher et -al. - -This manual page was initially written by Mikhail Gusarov -, for the Debian project. From 7046d17631a89b569b095f8a4b379cab0b639635 Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Wed, 12 Jul 2017 21:49:10 -0700 Subject: [PATCH 0023/1814] Python parameter/variable types should match classes, not all objects Parameter and variable types in the Python domain have the counter-intuitive behavior of matching instance methods (or likely any other objects) rather than classes, e.g.: ```python class Foo(object): def list(self): """List some things.""" def bar(x): """ :param x: x :type x: list """ ``` `bar()` will link to `Foo.list()` rather than the standard library `list` type. --- sphinx/domains/python.py | 4 ++-- tests/test_domain_py.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index eb6fe76cb..a65cf76bb 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -177,11 +177,11 @@ class PyObject(ObjectDescription): PyTypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument', 'keyword', 'kwarg', 'kwparam'), - typerolename='obj', typenames=('paramtype', 'type'), + typerolename='class', typenames=('paramtype', 'type'), can_collapse=True), PyTypedField('variable', label=l_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), - typerolename='obj', typenames=('vartype',), + typerolename='class', typenames=('vartype',), can_collapse=True), PyGroupedField('exceptions', label=l_('Raises'), rolename='exc', names=('raises', 'raise', 'exception', 'except'), diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 28743f9e1..b95b85bc2 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -109,10 +109,10 @@ def test_domain_py_xrefs(app, status, warning): 'ModTopLevel', 'class') assert_refnode(refnodes[6], 'module_b.submodule', 'ModTopLevel', 'ModNoModule', 'class') - assert_refnode(refnodes[7], False, False, 'int', 'obj') - assert_refnode(refnodes[8], False, False, 'tuple', 'obj') - assert_refnode(refnodes[9], False, False, 'str', 'obj') - assert_refnode(refnodes[10], False, False, 'float', 'obj') + assert_refnode(refnodes[7], False, False, 'int', 'class') + assert_refnode(refnodes[8], False, False, 'tuple', 'class') + assert_refnode(refnodes[9], False, False, 'str', 'class') + assert_refnode(refnodes[10], False, False, 'float', 'class') assert len(refnodes) == 11 From 38b39c008ddf16dd4055fa5eff55290bb15a1592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vedran=20Mileti=C4=87?= Date: Fri, 14 Jul 2017 01:46:09 +0200 Subject: [PATCH 0024/1814] Clean up and update EXAMPLES --- EXAMPLES | 323 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 162 insertions(+), 161 deletions(-) diff --git a/EXAMPLES b/EXAMPLES index 805f0edba..8a4cee2d6 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -12,235 +12,236 @@ interesting examples. Documentation using the alabaster theme --------------------------------------- +* Blinker: https://pythonhosted.org/blinker/ +* Calibre: https://manual.calibre-ebook.com/ * CodePy: https://documen.tician.de/codepy/ +* Fityk: http://fityk.nieto.pl/ +* Flask: http://flask.pocoo.org/docs/ +* Flask-OpenID: https://pythonhosted.org/Flask-OpenID/ +* Jinja: http://jinja.pocoo.org/docs/ +* Lino: http://www.lino-framework.org/ (customized) * MeshPy: https://documen.tician.de/meshpy/ -* PyCuda: https://documen.tician.de/pycuda/ +* PyCUDA: https://documen.tician.de/pycuda/ +* PyOpenCL: https://documen.tician.de/pyopencl/ * PyLangAcq: http://pylangacq.org/ +* python-apt: https://apt.alioth.debian.org/python-apt-doc/ +* PyVisfile: https://documen.tician.de/pyvisfile/ +* Tablib: http://docs.python-tablib.org/ +* Werkzeug: http://werkzeug.pocoo.org/docs/ (customized) Documentation using the classic theme ------------------------------------- +* Advanced Generic Widgets: http://xoomer.virgilio.it/infinity77/AGW_Docs/ (customized) * APSW: https://rogerbinns.github.io/apsw/ -* Calibre: http://manual.calibre-ebook.com/ -* Cython: http://docs.cython.org/ +* Arb: http://arblib.org/ +* Bazaar: http://doc.bazaar.canonical.com/ (customized) +* Blender: https://docs.blender.org/api/current/ +* Chaco: http://docs.enthought.com/chaco/ (customized) * Cormoran: http://cormoran.nhopkg.org/docs/ -* Director: http://pythonhosted.org/director/ +* DEAP: https://deap.readthedocs.io/ (customized) +* Director: https://pythonhosted.org/director/ +* EZ-Draw: https://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html (customized) * F2py: http://f2py.sourceforge.net/docs/ -* Genomedata: - http://noble.gs.washington.edu/proj/genomedata/doc/1.2.2/genomedata.html +* Genomedata: https://noble.gs.washington.edu/proj/genomedata/doc/1.3.3/ +* GetFEM++: http://getfem.org/ (customized) +* Glasgow Haskell Compiler: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ (customized) +* Grok: http://grok.zope.org/doc/current/ (customized) +* GROMACS: http://manual.gromacs.org/documentation/ * GSL Shell: http://www.nongnu.org/gsl-shell/ -* Hands-on Python Tutorial: - http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/ -* Hedge: https://documen.tician.de/hedge/ +* Hands-on Python Tutorial: http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/ +* Kaa: http://api.freevo.org/kaa-base/ (customized) * Leo: http://leoeditor.com/ -* Lino: http://www.lino-framework.org/ +* LEPL: http://www.acooke.org/lepl/ (customized) +* Mayavi: http://docs.enthought.com/mayavi/mayavi/ (customized) * mpmath: http://mpmath.org/doc/current/ +* OpenCV: http://docs.opencv.org/ (customized) * OpenEXR: http://excamera.com/articles/26/doc/index.html * OpenGDA: http://www.opengda.org/gdadoc/html/ -* openWNS: http://docs.openwns.org/ -* Pioneers and Prominent Men of Utah: http://pioneers.rstebbing.com/ -* PyCantonese: http://pycantonese.org/ +* Peach^3: https://peach3.nl/doc/latest/userdoc/ (customized) +* PyEMD: https://pyemd.readthedocs.io/ * Pyevolve: http://pyevolve.sourceforge.net/ -* PyMQI: http://pythonhosted.org/pymqi/ -* pySPACE: http://pyspace.github.io/pyspace/ -* Python: https://docs.python.org/3/ -* python-apt: http://apt.alioth.debian.org/python-apt-doc/ -* PyUblas: https://documen.tician.de/pyublas/ -* Ring programming language: http://ring-lang.sourceforge.net/doc/index.html -* Scapy: http://www.secdev.org/projects/scapy/doc/ +* Pygame: https://www.pygame.org/docs/ (customized) +* PyMQI: https://pythonhosted.org/pymqi/ +* Python 2: https://docs.python.org/2/ +* Python 3: https://docs.python.org/3/ (customized) +* Ring programming language: http://ring-lang.sourceforge.net/doc/ (customized) +* SageMath: https://doc.sagemath.org/ (customized) * Segway: http://noble.gs.washington.edu/proj/segway/doc/1.1.0/segway.html +* simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html (customized) +* Sprox: http://sprox.org/ (customized) * SymPy: http://docs.sympy.org/ -* WTForms: http://wtforms.simplecodes.com/docs/ +* TurboGears: https://turbogears.readthedocs.org/ (customized) +* tvtk: http://docs.enthought.com/mayavi/tvtk/ +* Varnish: https://www.varnish-cache.org/docs/ (customized, alabaster for index) +* Waf: https://waf.io/apidocs/ +* wxPython Phoenix: https://wxpython.org/Phoenix/docs/html/main.html (customized) * z3c: http://www.ibiblio.org/paulcarduner/z3ctutorial/ - - -Documentation using a customized version of the classic theme -------------------------------------------------------------- - -* Advanced Generic Widgets: - http://xoomer.virgilio.it/infinity77/AGW_Docs/index.html -* Arb: http://fredrikj.net/arb/ -* Bazaar: http://doc.bazaar.canonical.com/en/ -* CakePHP: http://book.cakephp.org/2.0/en/index.html -* Chaco: http://docs.enthought.com/chaco/ -* Chef: https://docs.chef.io/index.html -* Djagios: http://djagios.org/ -* EZ-Draw: http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html -* GetFEM++: http://home.gna.org/getfem/ -* Google or-tools: - https://or-tools.googlecode.com/svn/trunk/documentation/user_manual/index.html -* GPAW: https://wiki.fysik.dtu.dk/gpaw/ -* Grok: http://grok.zope.org/doc/current/ -* Kaa: http://api.freevo.org/kaa-base/ -* LEPL: http://www.acooke.org/lepl/ -* Mayavi: http://docs.enthought.com/mayavi/mayavi/ -* NICOS: http://trac.frm2.tum.de/nicos/doc/nicos-master/index.html -* NOC: http://redmine.nocproject.org/projects/noc -* NumPy: http://docs.scipy.org/doc/numpy/reference/ -* OpenCV: http://docs.opencv.org/ -* Peach^3: http://peach3.nl/doc/latest/userdoc/ -* Pygame: http://www.pygame.org/docs/ -* Sage: http://www.sagemath.org/doc/ -* SciPy: http://docs.scipy.org/doc/scipy/reference/ -* simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html -* Sprox: http://sprox.org/ -* TurboGears: http://turbogears.readthedocs.org/en/latest/ -* Varnish: https://www.varnish-cache.org/docs/ -* Zentyal: http://doc.zentyal.org/ -* Zope: http://docs.zope.org/zope2/index.html -* zc.async: http://pythonhosted.org/zc.async/1.5.0/ - +* zc.async: https://pythonhosted.org/zc.async/ (customized) +* Zope: https://docs.zope.org/zope2/ (customized) Documentation using the sphinxdoc theme --------------------------------------- -* Fityk: http://fityk.nieto.pl/ -* MapServer: http://mapserver.org/ -* Matplotlib: http://matplotlib.org/ -* Music21: http://web.mit.edu/music21/doc/index.html -* NetworkX: http://networkx.github.io/ -* Pweave: http://mpastell.com/pweave/ +* Matplotlib: https://matplotlib.org/ +* NetworkX: https://networkx.github.io/ +* PyCantonese: http://pycantonese.org/ * Pyre: http://docs.danse.us/pyre/sphinx/ +* pySPACE: https://pyspace.github.io/pyspace/ * Pysparse: http://pysparse.sourceforge.net/ * PyTango: - http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/pytango/latest/index.html -* Python Wild Magic: http://vmlaker.github.io/pythonwildmagic/ -* Reteisi: http://www.reteisi.org/contents.html -* Sqlkit: http://sqlkit.argolinux.org/ + http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/pytango/latest/ +* Python Wild Magic: https://vmlaker.github.io/pythonwildmagic/ (customized) +* Reteisi: http://www.reteisi.org/contents.html (customized) +* Sqlkit: http://sqlkit.argolinux.org/ (customized) * Turbulenz: http://docs.turbulenz.com/ -* WebFaction: https://docs.webfaction.com/ +Documentation using the nature theme +------------------------------------ + +* Cython: http://docs.cython.org/ +* jsFiddle: http://doc.jsfiddle.net/ +* libLAS: https://www.liblas.org/ (customized) +* MapServer: http://mapserver.org/ (customized) +* Setuptools: https://setuptools.readthedocs.io/ +* Spring Python: https://docs.spring.io/spring-python/1.2.x/sphinx/html/ +* Sylli: http://sylli.sourceforge.net/ Documentation using another builtin theme ----------------------------------------- -* ASE: https://wiki.fysik.dtu.dk/ase/ (sphinx_rtd_theme) -* C/C++ Development with Eclipse: http://eclipsebook.in/ (agogo) -* ESWP3 (http://eswp3.org) (sphinx_rtd_theme) -* Jinja: http://jinja.pocoo.org/ (scrolls) -* jsFiddle: http://doc.jsfiddle.net/ (nature) -* libLAS: http://www.liblas.org/ (nature) -* Linguistica: http://linguistica-uchicago.github.io/lxa5/ (sphinx_rtd_theme) -* MoinMoin: https://moin-20.readthedocs.io/en/latest/ (sphinx_rtd_theme) -* MPipe: http://vmlaker.github.io/mpipe/ (sphinx13) -* Paver: http://paver.readthedocs.io/en/latest/ -* pip: https://pip.pypa.io/en/latest/ (sphinx_rtd_theme) +* MPipe: https://vmlaker.github.io/mpipe/ (sphinx13) * Programmieren mit PyGTK und Glade (German): - http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo) -* PyPubSub: http://pypubsub.readthedocs.io/ (bizstyle) + http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo, customized) +* PyPubSub: https://pypubsub.readthedocs.io/ (bizstyle) +* Pylons: http://docs.pylonsproject.org/projects/pylons-webframework/ (pyramid) * Pyramid web framework: - http://docs.pylonsproject.org/projects/pyramid/en/latest/ (pyramid) -* Quex: http://quex.sourceforge.net/doc/html/main.html -* Satchmo: http://docs.satchmoproject.com/en/latest/ (sphinx_rtd_theme) -* Setuptools: http://pythonhosted.org/setuptools/ (nature) -* SimPy: http://simpy.readthedocs.org/en/latest/ -* Spring Python: http://docs.spring.io/spring-python/1.2.x/sphinx/html/ (nature) -* sqlparse: http://python-sqlparse.googlecode.com/svn/docs/api/index.html - (agogo) -* Sylli: http://sylli.sourceforge.net/ (nature) -* Tuleap Open ALM: https://tuleap.net/doc/en/ (nature) + https://docs.pylonsproject.org/projects/pyramid/ (pyramid) * Valence: http://docs.valence.desire2learn.com/ (haiku) +Documentation using sphinx_rtd_theme +------------------------------------ -Documentation using a custom theme/integrated in a site -------------------------------------------------------- +* ASE: https://wiki.fysik.dtu.dk/ase/ +* Elemental: http://libelemental.org/documentation/dev/ +* ESWP3: https://eswp3.readthedocs.io/ +* GPAW: https://wiki.fysik.dtu.dk/gpaw/ (customized) +* Linguistica: https://linguistica-uchicago.github.io/lxa5/ +* MathJax: https://docs.mathjax.org/ +* MoinMoin: https://moin-20.readthedocs.io/ +* MyHDL: http://docs.myhdl.org/ +* NICOS: https://forge.frm2.tum.de/nicos/doc/nicos-master/ (customized) +* pip: https://pip.pypa.io/ +* Paver: https://paver.readthedocs.io/ +* Pweave: http://mpastell.com/pweave/ +* python-sqlparse: https://sqlparse.readthedocs.io/ +* Free your information from their silos (French): + http://redaction-technique.org/ (customized) +* Quex: http://quex.sourceforge.net/doc/html/main.html +* Satchmo: http://docs.satchmoproject.com/ +* Scapy: https://scapy.readthedocs.io/ +* SimPy: http://simpy.readthedocs.io/ +* Tango Controls: https://tango-controls.readthedocs.io/ (customized) +* Tuleap: https://tuleap.net/doc/en/ -* Blender: https://www.blender.org/api/250PythonDoc/ -* Blinker: http://discorporate.us/projects/Blinker/docs/ +Documentation using sphinx_bootstrap_theme +------------------------------------------ + +* C/C++ Software Development with Eclipse: http://eclipsebook.in/ +* e-cidadania: http://e-cidadania.readthedocs.org/ +* Hedge: https://documen.tician.de/hedge/ +* Open Dylan: https://opendylan.org/documentation/ +* PyUblas: https://documen.tician.de/pyublas/ + +Documentation using a custom theme or integrated in a website +------------------------------------------------------------- + +* CakePHP: https://book.cakephp.org/ * Ceph: http://docs.ceph.com/docs/master/ -* Classy: http://www.pocoo.org/projects/classy/ -* DEAP: http://deap.gel.ulaval.ca/doc/0.8/index.html +* Chef: https://docs.chef.io/ * Django: https://docs.djangoproject.com/ -* Elemental: http://libelemental.org/documentation/dev/index.html * Enterprise Toolkit for Acrobat products: - http://www.adobe.com/devnet-docs/acrobatetk/ -* e-cidadania: http://e-cidadania.readthedocs.org/en/latest/ -* Flask: http://flask.pocoo.org/docs/ -* Flask-OpenID: http://pythonhosted.org/Flask-OpenID/ + https://www.adobe.com/devnet-docs/acrobatetk/ * Gameduino: http://excamera.com/sphinx/gameduino/ * GeoServer: http://docs.geoserver.org/ * gevent: http://www.gevent.org/ -* GHC - Glasgow Haskell Compiler: http://downloads.haskell.org/~ghc/master/users-guide/ -* Glashammer: http://glashammer.org/ -* Istihza (Turkish Python documentation project): http://belgeler.istihza.com/py2/ +* Guzzle: http://docs.guzzlephp.org/en/stable/ +* Istihza (Turkish Python documentation project): https://belgeler.yazbel.com/python-istihza/ * Lasso: http://lassoguide.com/ -* Manage documentation such as source code (fr): http://redaction-technique.org/ -* MathJax: http://docs.mathjax.org/en/latest/ * MirrorBrain: http://mirrorbrain.org/docs/ -* MyHDL: http://docs.myhdl.org/en/latest/ -* nose: http://nose.readthedocs.org/en/latest/ -* NoTex: https://www.notex.ch/overview/ +* Music21: http://web.mit.edu/music21/doc/ +* nose: https://nose.readthedocs.io/ +* NumPy: https://docs.scipy.org/doc/numpy/reference/ * ObjectListView: http://objectlistview.sourceforge.net/python/ -* Open ERP: https://doc.odoo.com/ +* OpenERP: https://doc.odoo.com/ * OpenCV: http://docs.opencv.org/ -* Open Dylan: http://opendylan.org/documentation/ * OpenLayers: http://docs.openlayers.org/ * PyEphem: http://rhodesmill.org/pyephem/ -* German Plone user manual: http://www.hasecke.com/plone-benutzerhandbuch/ +* Pygments: http://pygments.org/docs/ +* Plone User Manual (German): https://www.hasecke.com/plone-benutzerhandbuch/4.0/ * PSI4: http://www.psicode.org/psi4manual/master/index.html -* Pylons: http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/ * PyMOTW: https://pymotw.com/2/ -* python-aspectlib: http://python-aspectlib.readthedocs.org/en/latest/ - (`sphinx-py3doc-enhanced-theme`_) -* QGIS: http://qgis.org/en/docs/index.html -* qooxdoo: http://manual.qooxdoo.org/current/ +* python-aspectlib: https://python-aspectlib.readthedocs.io/ + (`sphinx_py3doc_enhanced_theme `__) +* QGIS: https://qgis.org/en/docs/index.html +* qooxdoo: http://www.qooxdoo.org/current/ * Roundup: http://www.roundup-tracker.org/ -* Seaborn: https://stanford.edu/~mwaskom/software/seaborn/ +* scikit-learn: http://scikit-learn.org/stable/ +* SciPy: https://docs.scipy.org/doc/scipy/refrence/ +* Seaborn: https://seaborn.pydata.org/ * Selenium: http://docs.seleniumhq.org/docs/ * Self: http://www.selflanguage.org/ -* Substance D: http://docs.pylonsproject.org/projects/substanced/en/latest/ -* Tablib: http://tablib.org/ -* SQLAlchemy: http://www.sqlalchemy.org/docs/ +* Substance D: https://docs.pylonsproject.org/projects/substanced/ +* SQLAlchemy: https://docs.sqlalchemy.org/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ -* Ubuntu packaging guide: http://packaging.ubuntu.com/html/ -* Werkzeug: http://werkzeug.pocoo.org/docs/ -* WFront: http://discorporate.us/projects/WFront/ - -.. _sphinx-py3doc-enhanced-theme: https://pypi.python.org/pypi/sphinx_py3doc_enhanced_theme - +* Ubuntu Packaging Guide: http://packaging.ubuntu.com/html/ +* WebFaction: https://docs.webfaction.com/ +* WTForms: https://wtforms.readthedocs.io/ Homepages and other non-documentation sites ------------------------------------------- -* A personal page: http://www.dehlia.in/ -* Benoit Boissinot: http://bboissin.appspot.com/ -* lunarsite: http://lunaryorn.de/ -* The Wine Cellar Book: http://www.thewinecellarbook.com/doc/en/ -* UC Berkeley Advanced Control Systems course: - http://msc.berkeley.edu/tomizuka/me233spring13/ -* VOR: http://www.vor-cycling.be/ - +* Benoit Boissinot: https://bboissin.appspot.com/ (modified classic) +* Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab): + https://lab.miletic.net/ (sphinx_rtd_theme) +* Loyola University Chicago COMP 339-439 Distributed Systems course: + http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme) +* The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc) +* UC Berkeley ME233 Advanced Control Systems II course: + https://berkeley-me233.github.io/ (sphinxdoc) Books produced using Sphinx --------------------------- -* "The ``repoze.bfg`` Web Application Framework": - http://www.amazon.com/repoze-bfg-Web-Application-Framework-Version/dp/0615345379 -* A Theoretical Physics Reference book: http://www.theoretical-physics.net/ -* "Simple and Steady Way of Learning for Software Engineering" (in Japanese): - http://www.amazon.co.jp/dp/477414259X/ +* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski": + https://literatur.hasecke.com/post/die-wahrheit-des-sehens-dekalog-kieslowski/ * "Expert Python Programming": https://www.packtpub.com/application-development/expert-python-programming * "Expert Python Programming" (Japanese translation): - http://www.amazon.co.jp/dp/4048686291/ -* "Pomodoro Technique Illustrated" (Japanese translation): - http://www.amazon.co.jp/dp/4048689525/ -* "Python Professional Programming" (in Japanese): - http://www.amazon.co.jp/dp/4798032948/ -* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski": - http://www.hasecke.eu/Dekalog/ -* The "Varnish Book": - http://book.varnish-software.com/4.0/ + https://www.amazon.co.jp/dp/4048686291/ +* "LassoGuide": http://www.lassosoft.com/Lasso-Documentation * "Learning Sphinx" (in Japanese): - http://www.oreilly.co.jp/books/9784873116488/ -* "LassoGuide": - http://www.lassosoft.com/Lasso-Documentation -* "Software-Dokumentation mit Sphinx": http://www.amazon.de/dp/1497448689/ + https://www.oreilly.co.jp/books/9784873116488/ +* "Pioneers and Prominent Men of Utah": http://pioneers.rstebbing.com/ +* "Pomodoro Technique Illustrated" (Japanese translation): + https://www.amazon.co.jp/dp/4048689525/ +* "Python Professional Programming" (in Japanese): + https://www.amazon.co.jp/dp/4798032948/ +* "The ``repoze.bfg`` Web Application Framework": + https://www.amazon.com/repoze-bfg-Web-Application-Framework-Version/dp/0615345379 +* "Simple and Steady Way of Learning for Software Engineering" (in Japanese): + https://www.amazon.co.jp/dp/477414259X/ +* "Software-Dokumentation mit Sphinx": https://www.amazon.de/dp/1497448689/ +* "Theoretical Physics Reference": http://www.theoretical-physics.net/ +* "The Varnish Book": + https://info.varnish-software.com/the-varnish-book +Theses produced using Sphinx +---------------------------- -Thesis using Sphinx -------------------- - -* "A Web-Based System for Comparative Analysis of OpenStreetMap Data - by the Use of CouchDB": +* "A Web-Based System for Comparative Analysis of OpenStreetMap Data by the Use + of CouchDB": https://www.yumpu.com/et/document/view/11722645/masterthesis-markusmayr-0542042 +* "Content Conditioning and Distribution for Dynamic Virtual Worlds": + https://www.cs.princeton.edu/research/techreps/TR-941-12 +* "The Sphinx Thesis Resource": https://jterrace.github.io/sphinxtr/ From fa77fe8ac9791814ea89a253c792218cbac5eba8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 16:44:53 +0900 Subject: [PATCH 0025/1814] Fix mypy violations (for mypy-0.520) --- sphinx/application.py | 2 +- sphinx/ext/autodoc.py | 2 +- sphinx/ext/doctest.py | 32 ++++++++++++++++---------------- sphinx/roles.py | 2 +- sphinx/testing/util.py | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 27dfeb2e4..a205c7d5c 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -250,7 +250,7 @@ class Sphinx(object): user_locale_dirs, self.config.language, domains=['sphinx'], charset=self.config.source_encoding): catinfo.write_mo(self.config.language) - locale_dirs = [None, path.join(package_dir, 'locale')] + user_locale_dirs + locale_dirs = [None, path.join(package_dir, 'locale')] + user_locale_dirs # type: ignore else: locale_dirs = [] self.translator, has_translation = locale.init(locale_dirs, self.config.language) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index c50b55387..4af2bb3c6 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -851,7 +851,7 @@ class Documenter(object): self.add_line(line, src[0], src[1]) def get_object_members(self, want_all): - # type: (bool) -> Tuple[bool, List[Tuple[unicode, object]]] + # type: (bool) -> Tuple[bool, List[Tuple[unicode, Any]]] """Return `(members_check_module, members)` where `members` is a list of `(membername, member)` pairs of the members of *self.object*. diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 42363fdfd..4110d9c90 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -134,12 +134,12 @@ class TestDirective(Directive): _("missing '+' or '-' in '%s' option.") % option, line=self.lineno) continue - if option_name not in doctest.OPTIONFLAGS_BY_NAME: # type: ignore + if option_name not in doctest.OPTIONFLAGS_BY_NAME: self.state.document.reporter.warning( _("'%s' is not a valid option.") % option_name, line=self.lineno) continue - flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]] # type: ignore + flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]] node['options'][flag] = (option[0] == '+') if self.name == 'doctest' and 'pyversion' in self.options: try: @@ -148,7 +148,7 @@ class TestDirective(Directive): operand, option_version = [item.strip() for item in option.split()] running_version = platform.python_version() if not compare_version(running_version, option_version, operand): - flag = doctest.OPTIONFLAGS_BY_NAME['SKIP'] # type: ignore + flag = doctest.OPTIONFLAGS_BY_NAME['SKIP'] node['options'][flag] = True # Skip the test except ValueError: self.state.document.reporter.warning( @@ -188,7 +188,7 @@ class TestoutputDirective(TestDirective): } -parser = doctest.DocTestParser() # type: ignore +parser = doctest.DocTestParser() # helper classes @@ -240,14 +240,14 @@ class TestCode(object): self.code, self.type, self.lineno, self.options) -class SphinxDocTestRunner(doctest.DocTestRunner): # type: ignore - def summarize(self, out, verbose=None): +class SphinxDocTestRunner(doctest.DocTestRunner): + def summarize(self, out, verbose=None): # type: ignore # type: (Callable, bool) -> Tuple[int, int] string_io = StringIO() old_stdout = sys.stdout sys.stdout = string_io try: - res = doctest.DocTestRunner.summarize(self, verbose) # type: ignore + res = doctest.DocTestRunner.summarize(self, verbose) finally: sys.stdout = old_stdout out(string_io.getvalue()) @@ -257,7 +257,7 @@ class SphinxDocTestRunner(doctest.DocTestRunner): # type: ignore module_globals=None): # type: (unicode, Any) -> Any # this is overridden from DocTestRunner adding the try-except below - m = self._DocTestRunner__LINECACHE_FILENAME_RE.match(filename) + m = self._DocTestRunner__LINECACHE_FILENAME_RE.match(filename) # type: ignore if m and m.group('name') == self.test.name: try: example = self.test.examples[int(m.group('examplenum'))] @@ -268,7 +268,7 @@ class SphinxDocTestRunner(doctest.DocTestRunner): # type: ignore pass else: return example.source.splitlines(True) - return self.save_linecache_getlines(filename, module_globals) + return self.save_linecache_getlines(filename, module_globals) # type: ignore # the new builder -- use sphinx-build.py -b doctest to run @@ -379,8 +379,8 @@ Doctest summary self.cleanup_runner = SphinxDocTestRunner(verbose=False, optionflags=self.opt) - self.test_runner._fakeout = self.setup_runner._fakeout - self.cleanup_runner._fakeout = self.setup_runner._fakeout + self.test_runner._fakeout = self.setup_runner._fakeout # type: ignore + self.cleanup_runner._fakeout = self.setup_runner._fakeout # type: ignore if self.config.doctest_test_doctest_blocks: def condition(node): @@ -466,7 +466,7 @@ Doctest summary if not examples: return True # simulate a doctest with the code - sim_doctest = doctest.DocTest(examples, {}, # type: ignore + sim_doctest = doctest.DocTest(examples, {}, '%s (%s code)' % (group.name, what), filename_str, 0, None) sim_doctest.globs = ns @@ -487,7 +487,7 @@ Doctest summary if len(code) == 1: # ordinary doctests (code/output interleaved) try: - test = parser.get_doctest( + test = parser.get_doctest( # type: ignore doctest_encode(code[0].code, self.env.config.source_encoding), {}, # type: ignore # NOQA group.name, filename_str, code[0].lineno) except Exception: @@ -507,9 +507,9 @@ Doctest summary output = code[1] and code[1].code or '' options = code[1] and code[1].options or {} # disable processing as it is not needed - options[doctest.DONT_ACCEPT_BLANKLINE] = True # type: ignore + options[doctest.DONT_ACCEPT_BLANKLINE] = True # find out if we're testing an exception - m = parser._EXCEPTION_RE.match(output) + m = parser._EXCEPTION_RE.match(output) # type: ignore if m: exc_msg = m.group('msg') else: @@ -546,6 +546,6 @@ def setup(app): app.add_config_value('doctest_global_cleanup', '', False) app.add_config_value( 'doctest_default_flags', - doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL, # type: ignore # NOQA + doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL, False) return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/roles.py b/sphinx/roles.py index 7b5880873..dbd136fdb 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -69,7 +69,7 @@ class XRefRole(object): * Subclassing and overwriting `process_link()` and/or `result_nodes()`. """ - nodeclass = addnodes.pending_xref + nodeclass = addnodes.pending_xref # type: Type[nodes.Node] innernodeclass = nodes.literal def __init__(self, fix_parens=False, lowercase=False, diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index bfb4628dd..4ec2ee94a 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -337,7 +337,7 @@ class _DeprecationWrapper(object): return getattr(self._mod, attr) -sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( # type: ignore +sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( with_app=(pytest.mark.sphinx, 'pytest.mark.sphinx'), TestApp=(SphinxTestApp, 'SphinxTestApp'), gen_with_app=(gen_with_app, 'pytest.mark.parametrize'), From bcafa5772c3fe273fe9b5a0f781d01d950fc4fa2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 16:47:32 +0900 Subject: [PATCH 0026/1814] Fix flake8 violation --- sphinx/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/application.py b/sphinx/application.py index a205c7d5c..0d6d3d0b3 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -250,7 +250,7 @@ class Sphinx(object): user_locale_dirs, self.config.language, domains=['sphinx'], charset=self.config.source_encoding): catinfo.write_mo(self.config.language) - locale_dirs = [None, path.join(package_dir, 'locale')] + user_locale_dirs # type: ignore + locale_dirs = [None, path.join(package_dir, 'locale')] + user_locale_dirs # type: ignore # NOQA else: locale_dirs = [] self.translator, has_translation = locale.init(locale_dirs, self.config.language) From bb79a0c4d0beae6b9b2adb1e83a1202be6c8de56 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 16:57:17 +0900 Subject: [PATCH 0027/1814] Fix mypy violations --- sphinx/pycode/pgen2/tokenize.py | 2 +- sphinx/util/compat.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py index 8b533d422..5f6abdb2f 100644 --- a/sphinx/pycode/pgen2/tokenize.py +++ b/sphinx/pycode/pgen2/tokenize.py @@ -337,7 +337,7 @@ def generate_tokens(readline): yield (NL, line[nl_pos:], (lnum, nl_pos), (lnum, len(line)), line) else: - yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], # type: ignore + yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], (lnum, pos), (lnum, len(line)), line) continue diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 3a5356ff7..988d41744 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -42,7 +42,7 @@ class _DeprecationWrapper(object): return getattr(self._mod, attr) -sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( # type: ignore +sys.modules[__name__] = _DeprecationWrapper(sys.modules[__name__], dict( docutils_version = docutils_version, Directive = Directive, )) From e77b388f0bc0565183d7e829951807080720a2cb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 17:48:19 +0900 Subject: [PATCH 0028/1814] Fix mypy violations --- sphinx/ext/autodoc/inspector.py | 2 +- sphinx/util/inspect.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/autodoc/inspector.py b/sphinx/ext/autodoc/inspector.py index da779d531..f1faf2043 100644 --- a/sphinx/ext/autodoc/inspector.py +++ b/sphinx/ext/autodoc/inspector.py @@ -122,7 +122,7 @@ def formatargspec(function, args, varargs=None, varkw=None, defaults=None, else: return value - introspected_hints = (typing.get_type_hints(function) + introspected_hints = (typing.get_type_hints(function) # type: ignore if typing and hasattr(function, '__code__') else {}) fd = StringIO() diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 83b9e7f2c..3f95dfcfe 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -271,7 +271,7 @@ class Signature(object): self.argspec = getargspec(subject) try: - self.annotations = typing.get_type_hints(subject) + self.annotations = typing.get_type_hints(subject) # type: ignore except: self.annotations = {} From bfd71cd77bd72e339a90781fae4d05f9c349c748 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 19:27:04 +0900 Subject: [PATCH 0029/1814] Fix #3926: Add ``autodoc_warningiserror`` to suppress the behavior of ``-W`` option --- CHANGES | 3 +++ doc/ext/autodoc.rst | 7 +++++++ sphinx/ext/autodoc.py | 4 +++- sphinx/util/logging.py | 35 ++++++++++++++++++++++++++++++++++- tests/test_util_logging.py | 24 ++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 3ff50f28b..c6c19e7a3 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,9 @@ Deprecated Features added -------------- +* #3926: Add ``autodoc_warningiserror`` to suppress the behavior of ``-W`` + option during importing target modules on autodoc + Bugs fixed ---------- diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index 62079c928..1f1892dbf 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -386,6 +386,13 @@ There are also new config values that you can set: This config value only requires to declare the top-level modules that should be mocked. +.. confval:: autodoc_warningiserror + + This value controls the behavior of :option:`sphinx-build -W` during + importing modules. + If ``False`` is given, autodoc forcely suppresses the error if the imported + module emits warnings. By default, ``True``. + Docstring preprocessing ----------------------- diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 4af2bb3c6..91feb6a2a 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -654,7 +654,8 @@ class Documenter(object): logger.debug('[autodoc] import %s', self.modname) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=ImportWarning) - __import__(self.modname) + with logging.skip_warningiserror(not self.env.config.autodoc_warningiserror): + __import__(self.modname) parent = None obj = self.module = sys.modules[self.modname] logger.debug('[autodoc] => %r', obj) @@ -1883,6 +1884,7 @@ def setup(app): app.add_config_value('autodoc_default_flags', [], True) app.add_config_value('autodoc_docstring_signature', True, True) app.add_config_value('autodoc_mock_imports', [], True) + app.add_config_value('autodoc_warningiserror', True, True) app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 85766a774..04cb5fcab 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -249,6 +249,27 @@ def pending_logging(): memhandler.flushTo(logger) +@contextmanager +def skip_warningiserror(skip=True): + # type: (bool) -> Generator + """contextmanager to skip WarningIsErrorFilter for a while.""" + logger = logging.getLogger() + + if skip is False: + yield + else: + try: + disabler = DisableWarningIsErrorFilter() + for handler in logger.handlers: + # use internal method; filters.insert() directly to install disabler + # before WarningIsErrorFilter + handler.filters.insert(0, disabler) + yield + finally: + for handler in logger.handlers: + handler.removeFilter(disabler) + + class LogCollector(object): def __init__(self): # type: () -> None @@ -330,7 +351,10 @@ class WarningIsErrorFilter(logging.Filter): def filter(self, record): # type: (logging.LogRecord) -> bool - if self.app.warningiserror: + if getattr(record, 'skip_warningsiserror', False): + # disabled by DisableWarningIsErrorFilter + return True + elif self.app.warningiserror: location = getattr(record, 'location', '') if location: raise SphinxWarning(location + ":" + record.msg % record.args) @@ -340,6 +364,15 @@ class WarningIsErrorFilter(logging.Filter): return True +class DisableWarningIsErrorFilter(logging.Filter): + """Disable WarningIsErrorFilter if this filter installed.""" + + def filter(self, record): + # type: (logging.LogRecord) -> bool + record.skip_warningsiserror = True # type: ignore + return True + + class WarningLogRecordTranslator(logging.Filter): """Converts a log record to one Sphinx expects diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py index 7ca7bd655..717aa6cd4 100644 --- a/tests/test_util_logging.py +++ b/tests/test_util_logging.py @@ -272,3 +272,27 @@ def test_output_with_unencodable_char(app, status, warning): status.seek(0) logger.info(u"unicode \u206d...") assert status.getvalue() == "unicode ?...\n" + + +def test_skip_warningiserror(app, status, warning): + logging.setup(app, status, warning) + logger = logging.getLogger(__name__) + + app.warningiserror = True + with logging.skip_warningiserror(): + logger.warning('message') + + # if False, warning raises SphinxWarning exception + with pytest.raises(SphinxWarning): + with logging.skip_warningiserror(False): + logger.warning('message') + + # It also works during pending_warnings. + with logging.pending_warnings(): + with logging.skip_warningiserror(): + logger.warning('message') + + with pytest.raises(SphinxWarning): + with logging.pending_warnings(): + with logging.skip_warningiserror(False): + logger.warning('message') From 26912026b0b27d13806bef36e99aea20f056cf74 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 15 Jul 2017 22:24:28 +0900 Subject: [PATCH 0030/1814] Update CHANGES for PR #3927 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 80bf2340a..a2b5926d3 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ Incompatible changes * #3668: The arguments has changed of main functions for each command * #3893: Unknown html_theme_options throw warnings instead of errors +* #3927: Python parameter/variable types should match classes, not all objects Deprecated ---------- From 1869f4d674f543747972d740a386f7165f414379 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 16 Jul 2017 01:48:09 +0900 Subject: [PATCH 0031/1814] Update docs (refs: #3923) --- doc/extdev/appapi.rst | 22 ++++++++++++++++++++++ doc/extdev/envapi.rst | 4 ---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index a27340d55..ce856d031 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -454,6 +454,28 @@ The application object also provides support for emitting leveled messages. .. automethod:: Sphinx.debug2 +Sphinx runtime information +-------------------------- + +The application object also provides runtime information as attributes. + +.. attribute:: srcdir + + Source directory. + +.. attribute:: confdir + + Directory containing ``conf.py``. + +.. attribute:: doctreedir + + Directory for storing pickled doctrees. + +.. attribute:: outdir + + Directory for storing built document. + + .. _events: Sphinx core events diff --git a/doc/extdev/envapi.rst b/doc/extdev/envapi.rst index 729725fc5..442cfde15 100644 --- a/doc/extdev/envapi.rst +++ b/doc/extdev/envapi.rst @@ -19,10 +19,6 @@ Build environment API Source directory. - .. attribute:: confdir - - Directory containing ``conf.py``. - .. attribute:: doctreedir Directory for storing pickled doctrees. From e8cfd0f3d498ba209550f088c1a09d58b18713ef Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 15 Jul 2017 21:49:35 +0200 Subject: [PATCH 0032/1814] #1685 remove non-existing attributes from custom directive doc --- doc/extdev/markupapi.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index 533660c84..df23f164d 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -70,14 +70,6 @@ using :meth:`.Sphinx.add_directive` or :meth:`.Sphinx.add_directive_to_domain`. The absolute line number on which the directive appeared. This is not always a useful value; use :attr:`srcline` instead. - .. attribute:: src - - The source file of the directive. - - .. attribute:: srcline - - The line number in the source file on which the directive appeared. - .. attribute:: content_offset Internal offset of the directive content. Used when calling From 5873c9644d71dd7fcbf696348ca1c25170f64c70 Mon Sep 17 00:00:00 2001 From: Sam Park Date: Sat, 15 Jul 2017 14:30:39 -0700 Subject: [PATCH 0033/1814] Python rtypes should match classes, not all objects --- sphinx/domains/python.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index a65cf76bb..58c9984e0 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -189,7 +189,7 @@ class PyObject(ObjectDescription): Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), PyField('returntype', label=l_('Return type'), has_arg=False, - names=('rtype',), bodyrolename='obj'), + names=('rtype',), bodyrolename='class'), ] allow_nesting = False From 7020f6b41ddaf6f7d2d2bf01ec2f6ee543e73039 Mon Sep 17 00:00:00 2001 From: Sam Park Date: Sat, 15 Jul 2017 15:18:49 -0700 Subject: [PATCH 0034/1814] Add tests --- tests/roots/test-domain-py/module.rst | 2 ++ tests/test_domain_py.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/roots/test-domain-py/module.rst b/tests/roots/test-domain-py/module.rst index deb54629e..509be6c3b 100644 --- a/tests/roots/test-domain-py/module.rst +++ b/tests/roots/test-domain-py/module.rst @@ -36,3 +36,5 @@ module :type x: int :param y: param y :type y: tuple(str, float) + :rtype: list + diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index b95b85bc2..38327c697 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -113,7 +113,8 @@ def test_domain_py_xrefs(app, status, warning): assert_refnode(refnodes[8], False, False, 'tuple', 'class') assert_refnode(refnodes[9], False, False, 'str', 'class') assert_refnode(refnodes[10], False, False, 'float', 'class') - assert len(refnodes) == 11 + assert_refnode(refnodes[11], False, False, 'list', 'class') + assert len(refnodes) == 12 @pytest.mark.sphinx('dummy', testroot='domain-py') From 68fe4b2d6f41f14ce61e986d8b596a1d4e3ab1ae Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 16 Jul 2017 09:50:08 +0200 Subject: [PATCH 0035/1814] #3751 document -M command line option --- doc/man/sphinx-build.rst | 22 ++++++++++++++++++++++ doc/man/sphinx-quickstart.rst | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 0f969b732..863f83a55 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -89,6 +89,26 @@ Options See :ref:`builders` for a list of all builders shipped with Sphinx. Extensions can add their own builders. +.. _make_mode: + +.. option:: -M buildername + + Alternative to :option:`-b`. Uses the Sphinx :program:`make_mode` module, + which provides the same build functionality as a default :ref:`Makefile or + Make.bat `. In addition to all Sphinx + :ref:`builders `, the following build pipelines are available: + + **latexpdf** + Build LaTeX files and run them through :program:`pdflatex`. + + **latexpdfja** + Build LaTeX files and run them through :program:`platex/dvipdfmx`. + + **info** + Build Texinfo files and run them through :program:`makeinfo`. + + .. versionadded:: 1.2.1 + .. option:: -a If given, always write all output files. The default is to only write output @@ -235,6 +255,8 @@ The :program:`sphinx-build` refers following environment variables: A path to make command. A command name is also allowed. :program:`sphinx-build` uses it to invoke sub-build process on make-mode. +.. _makefile_options: + .. rubric:: Makefile Options The :file:`Makefile` and :file:`make.bat` files created by diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index db552ef2f..62b3a89b7 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -120,7 +120,8 @@ Options .. option:: --use-make-mode, --no-use-make-mode - Makefile/make.bat uses (or not use) make-mode. Default is use. + :file:`Makefile/make.bat` uses (or doesn't use) :ref:`make-mode `. + Default is `use`, which generates a more concise :file:`Makefile/make.bat`. .. versionchanged:: 1.5 make-mode is default. From 6acf701e8a82d2103c69e879edfb103498a38044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vedran=20Mileti=C4=87?= Date: Sun, 16 Jul 2017 12:12:11 +0200 Subject: [PATCH 0036/1814] Add more EXAMPLES, minor updates to existing ones --- EXAMPLES | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/EXAMPLES b/EXAMPLES index 8a4cee2d6..fc6d75d3b 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -12,18 +12,25 @@ interesting examples. Documentation using the alabaster theme --------------------------------------- +* Alabaster: https://alabaster.readthedocs.io/ * Blinker: https://pythonhosted.org/blinker/ * Calibre: https://manual.calibre-ebook.com/ +* Click: http://click.pocoo.org/ (customized) +* coala: https://docs.coala.io/ (customized) * CodePy: https://documen.tician.de/codepy/ +* Fabric: http://docs.fabfile.org/ * Fityk: http://fityk.nieto.pl/ * Flask: http://flask.pocoo.org/docs/ * Flask-OpenID: https://pythonhosted.org/Flask-OpenID/ +* Invoke: http://docs.pyinvoke.org/ * Jinja: http://jinja.pocoo.org/docs/ * Lino: http://www.lino-framework.org/ (customized) +* MDAnalysis: http://www.mdanalysis.org/docs/ (customized) * MeshPy: https://documen.tician.de/meshpy/ * PyCUDA: https://documen.tician.de/pycuda/ * PyOpenCL: https://documen.tician.de/pyopencl/ * PyLangAcq: http://pylangacq.org/ +* pytest: https://docs.pytest.org/ (customized) * python-apt: https://apt.alioth.debian.org/python-apt-doc/ * PyVisfile: https://documen.tician.de/pyvisfile/ * Tablib: http://docs.python-tablib.org/ @@ -33,16 +40,20 @@ Documentation using the classic theme ------------------------------------- * Advanced Generic Widgets: http://xoomer.virgilio.it/infinity77/AGW_Docs/ (customized) +* Apache CouchDB: http://docs.couchdb.org/ (customized) * APSW: https://rogerbinns.github.io/apsw/ * Arb: http://arblib.org/ * Bazaar: http://doc.bazaar.canonical.com/ (customized) * Blender: https://docs.blender.org/api/current/ +* Buildbot: https://docs.buildbot.net/latest/ +* CMake: https://cmake.org/documentation/ (customized) * Chaco: http://docs.enthought.com/chaco/ (customized) * Cormoran: http://cormoran.nhopkg.org/docs/ * DEAP: https://deap.readthedocs.io/ (customized) * Director: https://pythonhosted.org/director/ * EZ-Draw: https://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html (customized) * F2py: http://f2py.sourceforge.net/docs/ +* Generic Mapping Tools (GMT): http://gmt.soest.hawaii.edu/doc/latest/ (customized) * Genomedata: https://noble.gs.washington.edu/proj/genomedata/doc/1.3.3/ * GetFEM++: http://getfem.org/ (customized) * Glasgow Haskell Compiler: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ (customized) @@ -59,12 +70,14 @@ Documentation using the classic theme * OpenEXR: http://excamera.com/articles/26/doc/index.html * OpenGDA: http://www.opengda.org/gdadoc/html/ * Peach^3: https://peach3.nl/doc/latest/userdoc/ (customized) +* Plone: https://docs.plone.org/ (customized) * PyEMD: https://pyemd.readthedocs.io/ * Pyevolve: http://pyevolve.sourceforge.net/ * Pygame: https://www.pygame.org/docs/ (customized) * PyMQI: https://pythonhosted.org/pymqi/ * Python 2: https://docs.python.org/2/ * Python 3: https://docs.python.org/3/ (customized) +* Python Packaging Authority: https://www.pypa.io/ (customized) * Ring programming language: http://ring-lang.sourceforge.net/doc/ (customized) * SageMath: https://doc.sagemath.org/ (customized) * Segway: http://noble.gs.washington.edu/proj/segway/doc/1.1.0/segway.html @@ -83,7 +96,9 @@ Documentation using the classic theme Documentation using the sphinxdoc theme --------------------------------------- +* cartopy: http://scitools.org.uk/cartopy/docs/latest/ * Matplotlib: https://matplotlib.org/ +* MDAnalysis Tutorial: http://www.mdanalysis.org/MDAnalysisTutorial/ * NetworkX: https://networkx.github.io/ * PyCantonese: http://pycantonese.org/ * Pyre: http://docs.danse.us/pyre/sphinx/ @@ -99,6 +114,7 @@ Documentation using the sphinxdoc theme Documentation using the nature theme ------------------------------------ +* Alembic: http://alembic.zzzcomputing.com/ * Cython: http://docs.cython.org/ * jsFiddle: http://doc.jsfiddle.net/ * libLAS: https://www.liblas.org/ (customized) @@ -110,6 +126,7 @@ Documentation using the nature theme Documentation using another builtin theme ----------------------------------------- +* Breathe: https://breathe.readthedocs.io/ (haiku) * MPipe: https://vmlaker.github.io/mpipe/ (sphinx13) * Programmieren mit PyGTK und Glade (German): http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo, customized) @@ -117,65 +134,140 @@ Documentation using another builtin theme * Pylons: http://docs.pylonsproject.org/projects/pylons-webframework/ (pyramid) * Pyramid web framework: https://docs.pylonsproject.org/projects/pyramid/ (pyramid) -* Valence: http://docs.valence.desire2learn.com/ (haiku) +* Sphinx: http://www.sphinx-doc.org/ (sphinx13) :-) +* Valence: http://docs.valence.desire2learn.com/ (haiku, customized) Documentation using sphinx_rtd_theme ------------------------------------ +* Annotator: http://docs.annotatorjs.org/ +* ANNOVAR: http://annovar.openbioinformatics.org/ +* Ansible: https://docs.ansible.com/ (customized) * ASE: https://wiki.fysik.dtu.dk/ase/ +* Autofac: http://docs.autofac.org/ +* BigchainDB: https://docs.bigchaindb.com/ +* Certbot: https://letsencrypt.readthedocs.io/ +* CherryPy: http://docs.cherrypy.org/ +* Chainer: https://docs.chainer.org/ +* CodeIgniter: https://www.codeigniter.com/user_guide/ +* Corda: https://docs.corda.net/ +* Dask: https://dask.pydata.org/ +* Dataiku DSS: https://doc.dataiku.com/ +* Drush: http://www.drush.org/ +* edX: http://docs.edx.org/ +* Electrum: http://docs.electrum.org/ * Elemental: http://libelemental.org/documentation/dev/ * ESWP3: https://eswp3.readthedocs.io/ +* Ethereum Homestead: http://www.ethdocs.org/ +* Flake8: http://flake8.pycqa.org/ +* GeoNode: http://docs.geonode.org/ +* Godot: https://godot.readthedocs.io/ +* Graylog: http://docs.graylog.org/ * GPAW: https://wiki.fysik.dtu.dk/gpaw/ (customized) +* HDF5 for Python (h5py): http://docs.h5py.org/ +* Hyperledger Fabric: https://hyperledger-fabric.readthedocs.io/ +* Hyperledger Sawtooth: https://intelledger.github.io/ +* IdentityServer: http://docs.identityserver.io/ +* Idris: http://docs.idris-lang.org/ +* javasphinx: https://bronto-javasphinx.readthedocs.io/ +* Kalabox: http://docs.kalabox.io/ * Linguistica: https://linguistica-uchicago.github.io/lxa5/ * MathJax: https://docs.mathjax.org/ +* MICrobial Community Analysis (micca): http://micca.org/docs/latest/ +* MicroPython: https://docs.micropython.org/ +* Mink: http://mink.behat.org/ +* Mockery: http://docs.mockery.io/ * MoinMoin: https://moin-20.readthedocs.io/ +* Mopidy: https://docs.mopidy.com/ * MyHDL: http://docs.myhdl.org/ +* Nextflow: https://www.nextflow.io/docs/latest/index.html * NICOS: https://forge.frm2.tum.de/nicos/doc/nicos-master/ (customized) +* Pelican: http://docs.getpelican.com/ +* Pillow: https://pillow.readthedocs.io/ * pip: https://pip.pypa.io/ * Paver: https://paver.readthedocs.io/ +* peewee: http://docs.peewee-orm.com/ +* Phinx: http://docs.phinx.org/ +* phpMyAdmin: https://docs.phpmyadmin.net/ * Pweave: http://mpastell.com/pweave/ * python-sqlparse: https://sqlparse.readthedocs.io/ +* Read The Docs: https://docs.readthedocs.io/ * Free your information from their silos (French): http://redaction-technique.org/ (customized) +* Releases Sphinx extension: https://releases.readthedocs.io/ +* Qtile: http://docs.qtile.org/ * Quex: http://quex.sourceforge.net/doc/html/main.html * Satchmo: http://docs.satchmoproject.com/ * Scapy: https://scapy.readthedocs.io/ * SimPy: http://simpy.readthedocs.io/ +* SlamData: http://docs.slamdata.com/ +* Sonos Controller (SoCo): http://docs.python-soco.com/ +* Sphinx AutoAPI: https://sphinx-autoapi.readthedocs.io/ +* sphinx-argparse: https://sphinx-argparse.readthedocs.io/ +* Sphinx-Gallery: https://sphinx-gallery.readthedocs.io/ (customized) +* StarUML: http://docs.staruml.io/ +* Sublime Text Unofficial Documentation: http://docs.sublimetext.info/ +* SunPy: http://docs.sunpy.org/ +* Sylius: http://docs.sylius.org/ * Tango Controls: https://tango-controls.readthedocs.io/ (customized) +* Topshelf: http://docs.topshelf-project.com/ +* ThreatConnect: https://docs.threatconnect.com/ * Tuleap: https://tuleap.net/doc/en/ +* TYPO3: https://docs.typo3.org/ (customized) +* Wagtail: http://docs.wagtail.io/ +* Web Application Attack and Audit Framework (w3af): http://docs.w3af.org/ +* Weblate: https://docs.weblate.org/ Documentation using sphinx_bootstrap_theme ------------------------------------------ +* Bootstrap Theme: https://ryan-roemer.github.io/sphinx-bootstrap-theme/ * C/C++ Software Development with Eclipse: http://eclipsebook.in/ +* Dataverse: http://guides.dataverse.org/ * e-cidadania: http://e-cidadania.readthedocs.org/ +* Hangfire: http://docs.hangfire.io/ * Hedge: https://documen.tician.de/hedge/ +* ObsPy: https://docs.obspy.org/ * Open Dylan: https://opendylan.org/documentation/ +* Pootle: http://docs.translatehouse.org/projects/pootle/ * PyUblas: https://documen.tician.de/pyublas/ Documentation using a custom theme or integrated in a website ------------------------------------------------------------- +* Apache Cassandra: https://cassandra.apache.org/doc/ +* Astropy: http://docs.astropy.org/ * CakePHP: https://book.cakephp.org/ +* CasperJS: http://docs.casperjs.org/ * Ceph: http://docs.ceph.com/docs/master/ * Chef: https://docs.chef.io/ +* CKAN: http://docs.ckan.org/ +* Confluent Platform: http://docs.confluent.io/ * Django: https://docs.djangoproject.com/ +* Doctrine: http://docs.doctrine-project.org/ * Enterprise Toolkit for Acrobat products: https://www.adobe.com/devnet-docs/acrobatetk/ * Gameduino: http://excamera.com/sphinx/gameduino/ * GeoServer: http://docs.geoserver.org/ * gevent: http://www.gevent.org/ * Guzzle: http://docs.guzzlephp.org/en/stable/ +* H2O.ai: http://docs.h2o.ai/ * Istihza (Turkish Python documentation project): https://belgeler.yazbel.com/python-istihza/ +* Kombu: http://docs.kombu.me/ * Lasso: http://lassoguide.com/ +* Mako: http://docs.makotemplates.org/ * MirrorBrain: http://mirrorbrain.org/docs/ +* MongoDB: https://docs.mongodb.com/ * Music21: http://web.mit.edu/music21/doc/ * nose: https://nose.readthedocs.io/ +* ns-3: https://www.nsnam.org/documentation/ * NumPy: https://docs.scipy.org/doc/numpy/reference/ * ObjectListView: http://objectlistview.sourceforge.net/python/ * OpenERP: https://doc.odoo.com/ * OpenCV: http://docs.opencv.org/ * OpenLayers: http://docs.openlayers.org/ +* Open vSwitch: http://docs.openvswitch.org/ +* PlatformIO: http://docs.platformio.org/ * PyEphem: http://rhodesmill.org/pyephem/ * Pygments: http://pygments.org/docs/ * Plone User Manual (German): https://www.hasecke.com/plone-benutzerhandbuch/4.0/ @@ -186,12 +278,15 @@ Documentation using a custom theme or integrated in a website * QGIS: https://qgis.org/en/docs/index.html * qooxdoo: http://www.qooxdoo.org/current/ * Roundup: http://www.roundup-tracker.org/ +* SaltStack: https://docs.saltstack.com/ * scikit-learn: http://scikit-learn.org/stable/ * SciPy: https://docs.scipy.org/doc/scipy/refrence/ +* Scrapy: https://doc.scrapy.org/ * Seaborn: https://seaborn.pydata.org/ * Selenium: http://docs.seleniumhq.org/docs/ * Self: http://www.selflanguage.org/ * Substance D: https://docs.pylonsproject.org/projects/substanced/ +* Sulu: http://docs.sulu.io/ * SQLAlchemy: https://docs.sqlalchemy.org/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ * Ubuntu Packaging Guide: http://packaging.ubuntu.com/html/ @@ -201,12 +296,17 @@ Documentation using a custom theme or integrated in a website Homepages and other non-documentation sites ------------------------------------------- -* Benoit Boissinot: https://bboissin.appspot.com/ (modified classic) +* Arizona State University PHY494/PHY598/CHM598 Simulation approaches to Bio- + and Nanophysics: + https://becksteinlab.physics.asu.edu/pages/courses/2013/SimBioNano/ (classic) +* Benoit Boissinot: https://bboissin.appspot.com/ (classic, customized) * Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab): https://lab.miletic.net/ (sphinx_rtd_theme) * Loyola University Chicago COMP 339-439 Distributed Systems course: http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme) * The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc) +* Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials: + http://thomas-cokelaer.info/tutorials/ (standard) * UC Berkeley ME233 Advanced Control Systems II course: https://berkeley-me233.github.io/ (sphinxdoc) @@ -222,6 +322,8 @@ Books produced using Sphinx * "LassoGuide": http://www.lassosoft.com/Lasso-Documentation * "Learning Sphinx" (in Japanese): https://www.oreilly.co.jp/books/9784873116488/ +* "Mercurial: the definitive guide (Second edition)": + https://book.mercurial-scm.org/ * "Pioneers and Prominent Men of Utah": http://pioneers.rstebbing.com/ * "Pomodoro Technique Illustrated" (Japanese translation): https://www.amazon.co.jp/dp/4048689525/ From 5ce51728ba5ea9a4a2bf5d6093a49d1c022c3c1c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 16 Jul 2017 11:47:39 +0900 Subject: [PATCH 0037/1814] Fix #3924: docname lost after dynamically parsing RST in extension --- CHANGES | 2 ++ sphinx/environment/__init__.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index c6c19e7a3..5a8891e97 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,8 @@ Features added Bugs fixed ---------- +* #3924: docname lost after dynamically parsing RST in extension + Testing -------- diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 70fdbaeca..edec9ba2f 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -18,6 +18,7 @@ import codecs import fnmatch import warnings from os import path +from copy import copy from collections import defaultdict from six import BytesIO, itervalues, class_types, next @@ -946,6 +947,7 @@ class BuildEnvironment(object): """Apply all post-transforms.""" try: # set env.docname during applying post-transforms + backup = copy(self.temp_data) self.temp_data['docname'] = docname transformer = SphinxTransformer(doctree) @@ -953,7 +955,7 @@ class BuildEnvironment(object): transformer.add_transforms(self.app.post_transforms) transformer.apply_transforms() finally: - self.temp_data.clear() + self.temp_data = backup # allow custom references to be resolved self.app.emit('doctree-resolved', doctree, docname) From 947e01436bc669a9f6f0706bcec1c6a99db73f0d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 17 Jul 2017 17:44:03 +0900 Subject: [PATCH 0038/1814] Fix CHANGES (refs: #3869) --- CHANGES | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 15d9443a2..7099c6088 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,11 @@ Features added * #3638: Allow to change a label of reference to equation using ``math_eqref_format`` +* Now :confval:`suppress_warnings` accepts following configurations: + + - ``ref.python`` (ref: #3866) + + Features removed ---------------- @@ -72,10 +77,6 @@ Deprecated Features added -------------- -* Now :confval:`suppress_warnings` accepts following configurations: - - - ``ref.python`` (ref: #3866) - Bugs fixed ---------- From 112e8fe5e0ea008ced06d830d2eb3b7c4fca48b9 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Tue, 18 Jul 2017 03:52:02 -0500 Subject: [PATCH 0039/1814] Add label for c++ domain Currently it's [#id2](http://www.sphinx-doc.org/en/stable/domains.html#id2) on sphinx-doc documentation --- doc/domains.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/domains.rst b/doc/domains.rst index 4eb3a581c..38343e256 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -540,6 +540,7 @@ defined in the documentation: Reference a C-language type. +.. _cpp-domain: The C++ Domain -------------- From 4fb02e6900675935e8148850759e9436bfef9663 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Thu, 22 Jun 2017 18:46:30 +0100 Subject: [PATCH 0040/1814] Declare loop variables to make them local --- sphinx/themes/basic/static/websupport.js | 2 +- sphinx/themes/bizstyle/static/css3-mediaqueries_src.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/themes/basic/static/websupport.js b/sphinx/themes/basic/static/websupport.js index 53f6a4525..a95bc3a66 100644 --- a/sphinx/themes/basic/static/websupport.js +++ b/sphinx/themes/basic/static/websupport.js @@ -301,7 +301,7 @@ li.hide(); // Determine where in the parents children list to insert this comment. - for(i=0; i < siblings.length; i++) { + for(var i=0; i < siblings.length; i++) { if (comp(comment, siblings[i]) <= 0) { $('#cd' + siblings[i].id) .parent() diff --git a/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js b/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js index 65b44825d..f21dd4949 100644 --- a/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +++ b/sphinx/themes/bizstyle/static/css3-mediaqueries_src.js @@ -432,7 +432,7 @@ var cssHelper = function () { oss[n][oss[n].length] = r; } }; - for (i = 0; i < ors.length; i++) { + for (var i = 0; i < ors.length; i++) { collectSelectors(ors[i]); } From 63d68df1d1d7d61e5e95fe3dacef582c9b07a08c Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 18:10:41 +0100 Subject: [PATCH 0041/1814] Use NotImplementedError for better exception messages NotImplemented would cause a TypeError --- sphinx/transforms/post_transforms/images.py | 4 ++-- sphinx/util/stemmer/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index c57355774..9f07a391f 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -209,7 +209,7 @@ class ImageConverter(BaseImageConverter): def is_available(self): # type: () -> bool """Confirms the converter is available or not.""" - raise NotImplemented + raise NotImplementedError() def guess_mimetypes(self, node): # type: (nodes.Node) -> List[unicode] @@ -248,7 +248,7 @@ class ImageConverter(BaseImageConverter): def convert(self, _from, _to): # type: (unicode, unicode) -> bool """Converts the image to expected one.""" - raise NotImplemented + raise NotImplementedError() def setup(app): diff --git a/sphinx/util/stemmer/__init__.py b/sphinx/util/stemmer/__init__.py index 6f17d6cdf..a41373a81 100644 --- a/sphinx/util/stemmer/__init__.py +++ b/sphinx/util/stemmer/__init__.py @@ -21,7 +21,7 @@ except ImportError: class BaseStemmer(object): def stem(self, word): # type: (unicode) -> unicode - raise NotImplemented + raise NotImplementedError() class PyStemmer(BaseStemmer): From 4ac0a8e2782c13efc8e84a35f37e123ad02bfdf5 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 18:27:41 +0100 Subject: [PATCH 0042/1814] Mark unused loop iteration variable as such --- sphinx/pycode/pgen2/tokenize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py index 5f6abdb2f..d2820d23a 100644 --- a/sphinx/pycode/pgen2/tokenize.py +++ b/sphinx/pycode/pgen2/tokenize.py @@ -431,7 +431,7 @@ def generate_tokens(readline): (lnum, pos), (lnum, pos+1), line) pos = pos + 1 - for indent in indents[1:]: # pop remaining indent levels + for _ in indents[1:]: # pop remaining indent levels yield (DEDENT, '', (lnum, 0), (lnum, 0), '') yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '') From 71e903635f943cf3ffc05c5014caa3246c446f19 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 18:28:22 +0100 Subject: [PATCH 0043/1814] Remove redundant `pass` statement --- sphinx/domains/cpp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 70a806ae5..9a4df9e74 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4673,9 +4673,8 @@ class DefinitionParser(object): else: # For testing purposes. # do it again to get the proper traceback (how do you - # relieable save a traceback when an exception is + # reliably save a traceback when an exception is # constructed?) - pass self.pos = startPos typed = True declSpecs = self._parse_decl_specs(outer=outer, typed=typed) From 3be324efb034d3f4d0499754eaf6573c97602a84 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 18:38:58 +0100 Subject: [PATCH 0044/1814] Remove impossible condition We have just checked that `descname` is truthy, so it can't possibly be falsy immediately afterwards. --- sphinx/builders/changes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 5c3072059..a73125e30 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -73,8 +73,6 @@ class ChangesBuilder(Builder): ttext = self.typemap[type] context = content.replace('\n', ' ') if descname and docname.startswith('c-api'): - if not descname: - continue if context: entry = '%s: %s: %s' % (descname, ttext, context) From 3459de0aeb0d1f4dffcd2108bbb9b11e134b6ac3 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 18:43:11 +0100 Subject: [PATCH 0045/1814] Use `with` on file write to ensure closure --- sphinx/pycode/pgen2/grammar.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sphinx/pycode/pgen2/grammar.py b/sphinx/pycode/pgen2/grammar.py index ac276776e..22d426eec 100644 --- a/sphinx/pycode/pgen2/grammar.py +++ b/sphinx/pycode/pgen2/grammar.py @@ -91,9 +91,8 @@ class Grammar(object): def dump(self, filename): """Dump the grammar tables to a pickle file.""" - f = open(filename, "wb") - pickle.dump(self.__dict__, f, 2) - f.close() + with open(filename, "wb") as f: + pickle.dump(self.__dict__, f, 2) def load(self, filename): """Load the grammar tables from a pickle file.""" From 53ba31a6a5284d13873d6f56cbf2aec0ddb767a5 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 19 Jul 2017 06:36:02 -0500 Subject: [PATCH 0046/1814] Fix typo in TocTree warning --- sphinx/environment/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 1d108729f..c8d3e9c98 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -827,7 +827,7 @@ class BuildEnvironment(object): file relations from it. """ warnings.warn('env.note_toctree() is deprecated. ' - 'Use sphinx.environment.adapters.toctre.TocTree instead.', + 'Use sphinx.environment.adapters.toctree.TocTree instead.', RemovedInSphinx20Warning) TocTree(self).note(docname, toctreenode) From 621eca38bec307a0b33e3c5c837906a11eabf4f0 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 24 Jul 2017 14:51:06 +0200 Subject: [PATCH 0047/1814] Fix #3946 (typo in sphinx.sty) --- sphinx/texinputs/sphinx.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 09d77949d..2eafd1803 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1135,7 +1135,7 @@ % and there is consequently no corresponding package option \definecolor{sphinxnoteBgColor}{rgb}{1,1,1} \definecolor{sphinxhintBgColor}{rgb}{1,1,1} -\definecolor{sphinimportantBgColor}{rgb}{1,1,1} +\definecolor{sphinximportantBgColor}{rgb}{1,1,1} \definecolor{sphinxtipBgColor}{rgb}{1,1,1} % Others get more distinction From 7f9907be61af6d6386c27b131a3a6e4e816cf42b Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 24 Jul 2017 15:08:34 +0200 Subject: [PATCH 0048/1814] Update CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 5a8891e97..4d037ed60 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,7 @@ Bugs fixed ---------- * #3924: docname lost after dynamically parsing RST in extension +* #3946: Typo in sphinx.sty (this was a bug with no effect in default context) Testing -------- From f353bc63d780277026c05a70d75be271fcfa13fe Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 24 Jul 2017 15:15:52 +0200 Subject: [PATCH 0049/1814] Update LaTeX style file version date --- sphinx/texinputs/sphinx.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 2eafd1803..a28220cbc 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -6,7 +6,7 @@ % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{sphinx}[2017/06/17 v1.6.3 LaTeX package (Sphinx markup)] +\ProvidesPackage{sphinx}[2017/07/24 v1.6.4 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but From e97aa92b1ba51e327bcfd01c89f363e9902ef10a Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 24 Jul 2017 15:23:36 +0200 Subject: [PATCH 0050/1814] Update CHANGES for PR #3872 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 7099c6088..6e99b978d 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,8 @@ Features added * Now :confval:`suppress_warnings` accepts following configurations: - ``ref.python`` (ref: #3866) +* #3872: Add latex key to configure literal blocks caption position in PDF + output (refs #3792, #1723) Features removed From ae3b761184cf0f0bca76685da8d79cd008ed8b1a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jul 2017 23:48:39 +0900 Subject: [PATCH 0051/1814] Add testcase for pycode interface --- tests/test_pycode.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/test_pycode.py b/tests/test_pycode.py index 710e11341..45174241f 100644 --- a/tests/test_pycode.py +++ b/tests/test_pycode.py @@ -9,8 +9,41 @@ :license: BSD, see LICENSE for details. """ +import os +from six import PY2 + +import sphinx from sphinx.pycode import ModuleAnalyzer +SPHINX_MODULE_PATH = os.path.splitext(sphinx.__file__)[0] + '.py' + + +def test_ModuleAnalyzer_for_string(): + analyzer = ModuleAnalyzer.for_string('print("Hello world")', 'module_name') + assert analyzer.modname == 'module_name' + assert analyzer.srcname == '' + if PY2: + assert analyzer.encoding == 'ascii' + else: + assert analyzer.encoding is None + + +def test_ModuleAnalyzer_for_file(): + analyzer = ModuleAnalyzer.for_string(SPHINX_MODULE_PATH, 'sphinx') + assert analyzer.modname == 'sphinx' + assert analyzer.srcname == '' + if PY2: + assert analyzer.encoding == 'ascii' + else: + assert analyzer.encoding is None + + +def test_ModuleAnalyzer_for_module(): + analyzer = ModuleAnalyzer.for_module('sphinx') + assert analyzer.modname == 'sphinx' + assert analyzer.srcname == SPHINX_MODULE_PATH + assert analyzer.encoding == 'utf-8' + def test_ModuleAnalyzer_find_tags(): code = ('class Foo(object):\n' # line: 1 @@ -88,3 +121,14 @@ def test_ModuleAnalyzer_find_attr_docs(): assert docs[('Foo', 'attr5')] == ['attribute comment for attr5', ''] assert docs[('Foo', 'attr8')] == ['attribute comment for attr8', ''] assert docs[('Foo', 'attr9')] == ['string after attr9', ''] + assert analyzer.tagorder == {'Foo': 0, + 'Foo.__init__': 6, + 'Foo.attr1': 1, + 'Foo.attr2': 2, + 'Foo.attr3': 3, + 'Foo.attr4': 4, + 'Foo.attr5': 5, + 'Foo.attr8': 8, + 'Foo.attr9': 10, + 'Foo.bar': 11, + 'baz': 12} From 57667b576660e898f48c2f6c0f8d58e6826e4d20 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jul 2017 00:52:07 +0900 Subject: [PATCH 0052/1814] Add testcase for oneliner --- tests/test_pycode.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_pycode.py b/tests/test_pycode.py index 45174241f..152a92a27 100644 --- a/tests/test_pycode.py +++ b/tests/test_pycode.py @@ -105,7 +105,9 @@ def test_ModuleAnalyzer_find_attr_docs(): '\n' 'def baz():\n' ' """function baz"""\n' - ' pass\n') + ' pass\n' + '\n' + 'class Qux: attr1 = 1; attr2 = 2') analyzer = ModuleAnalyzer.for_string(code, 'module') docs = analyzer.find_attr_docs() assert set(docs) == {('Foo', 'attr1'), @@ -131,4 +133,7 @@ def test_ModuleAnalyzer_find_attr_docs(): 'Foo.attr8': 8, 'Foo.attr9': 10, 'Foo.bar': 11, - 'baz': 12} + 'baz': 12, + 'Qux': 13, + 'Qux.attr1': 14, + 'Qux.attr2': 15} From b1f80427a7c60d4cba2f56de1ec0ba425f8117b3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 10 Jul 2017 15:33:44 +0900 Subject: [PATCH 0053/1814] Add testcase for sphinx.util.docstrings --- tests/test_util_docstrings.py | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tests/test_util_docstrings.py diff --git a/tests/test_util_docstrings.py b/tests/test_util_docstrings.py new file mode 100644 index 000000000..1bdda1021 --- /dev/null +++ b/tests/test_util_docstrings.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +""" + test_util_docstrings + ~~~~~~~~~~~~~~~~~~~~ + + Test sphinx.util.docstrings. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc + + +def test_prepare_docstring(): + docstring = """multiline docstring + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua:: + + Ut enim ad minim veniam, quis nostrud exercitation + ullamco laboris nisi ut aliquip ex ea commodo consequat. + """ + + assert (prepare_docstring(docstring) == + ["multiline docstring", + "", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit,", + "sed do eiusmod tempor incididunt ut labore et dolore magna", + "aliqua::", + "", + " Ut enim ad minim veniam, quis nostrud exercitation", + " ullamco laboris nisi ut aliquip ex ea commodo consequat.", + ""]) + assert (prepare_docstring(docstring, 5) == + ["multiline docstring", + "", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit,", + "sed do eiusmod tempor incididunt ut labore et dolore magna", + "aliqua::", + "", + "Ut enim ad minim veniam, quis nostrud exercitation", + " ullamco laboris nisi ut aliquip ex ea commodo consequat.", + ""]) + + docstring = """ + + multiline docstring with leading empty lines + """ + assert (prepare_docstring(docstring) == + ["multiline docstring with leading empty lines", + ""]) + + docstring = "single line docstring" + assert (prepare_docstring(docstring) == + ["single line docstring", + ""]) + + +def test_prepare_commentdoc(): + assert prepare_commentdoc("hello world") == [] + assert prepare_commentdoc("#: hello world") == ["hello world", ""] + assert prepare_commentdoc("#: hello world") == [" hello world", ""] + assert prepare_commentdoc("#: hello\n#: world\n") == ["hello", "world", ""] From 6900d19b7126c2719283e88218e10f9e88530a49 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 10 Jul 2017 01:19:49 +0900 Subject: [PATCH 0054/1814] pycode: Add new parser! --- sphinx/pycode/parser.py | 463 ++++++++++++++++++++++++++++++++++++ tests/test_pycode_parser.py | 261 ++++++++++++++++++++ 2 files changed, 724 insertions(+) create mode 100644 sphinx/pycode/parser.py create mode 100644 tests/test_pycode_parser.py diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py new file mode 100644 index 000000000..1be62a4e0 --- /dev/null +++ b/sphinx/pycode/parser.py @@ -0,0 +1,463 @@ +# -*- coding: utf-8 -*- +""" + sphinx.pycode.parser + ~~~~~~~~~~~~~~~~~~~~ + + Utilities parsing and analyzing Python code. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +import re +import ast +import inspect +import tokenize +import itertools +from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING +from tokenize import COMMENT, NL + +from six import PY2, text_type + +if False: + # For type annotation + from typing import Any, Dict, IO, List, Tuple # NOQA + +comment_re = re.compile(u'^\\s*#: ?(.*)\r?\n?$') +indent_re = re.compile(u'^\\s*$') +emptyline_re = re.compile(u'^\\s*(#.*)?$') + + +def get_lvar_names(node, self=None): + # type: (ast.AST, ast.expr) -> List[unicode] + """Convert assignment-AST to variable names. + + This raises `TypeError` if the assignment does not create new variable:: + + ary[0] = 'foo' + dic["bar"] = 'baz' + # => TypeError + """ + if self: + if PY2: + self_id = self.id # type: ignore + else: + self_id = self.arg + + node_name = node.__class__.__name__ + if node_name in ('Index', 'Num', 'Slice', 'Str', 'Subscript'): + raise TypeError('%r does not create new variable' % node) + elif node_name == 'Name': + if self is None or node.id == self_id: # type: ignore + return [node.id] # type: ignore + else: + raise TypeError('The assignment %r is not instance variable' % node) + elif node_name == 'Tuple': + members = [get_lvar_names(elt) for elt in node.elts] # type: ignore + return sum(members, []) + elif node_name == 'Attribute': + if node.value.__class__.__name__ == 'Name' and self and node.value.id == self_id: # type: ignore # NOQA + # instance variable + return ["%s" % get_lvar_names(node.attr, self)[0]] # type: ignore + else: + raise TypeError('The assignment %r is not instance variable' % node) + elif node_name == 'str': + return [node] # type: ignore + else: + raise NotImplementedError + + +def dedent_docstring(s): + # type: (unicode) -> unicode + """Remove common leading indentation from docstring.""" + def dummy(): + # dummy function to mock `inspect.getdoc`. + pass + + dummy.__doc__ = s # type: ignore + docstring = inspect.getdoc(dummy) + return docstring.lstrip("\r\n").rstrip("\r\n") + + +class Token(object): + """Better token wrapper for tokenize module.""" + + def __init__(self, kind, value, start, end, source): + # type: (int, Any, Tuple[int, int], Tuple[int, int], unicode) -> None # NOQA + self.kind = kind + self.value = value + self.start = start + self.end = end + self.source = source + + def __eq__(self, other): + # type: (Any) -> bool + if isinstance(other, int): + return self.kind == other + elif isinstance(other, str): + return self.value == other + elif isinstance(other, (list, tuple)): + return [self.kind, self.value] == list(other) + elif other is None: + return False + else: + raise ValueError('Unknown value: %r' % other) + + def __ne__(self, other): + # type: (Any) -> bool + return not (self == other) + + def match(self, *conditions): + # type: (Any) -> bool + return any(self == candidate for candidate in conditions) + + def __repr__(self): + # type: () -> str + return '' % (tokenize.tok_name[self.kind], + self.value.strip()) + + +class TokenProcessor(object): + def __init__(self, buffers): + # type: (List[unicode]) -> None + lines = iter(buffers) + self.buffers = buffers + self.tokens = tokenize.generate_tokens(lambda: next(lines)) # type: ignore # NOQA + self.current = None # type: Token + self.previous = None # type: Token + + def get_line(self, lineno): + # type: (int) -> unicode + """Returns specified line.""" + return self.buffers[lineno - 1] + + def fetch_token(self): + # type: () -> Token + """Fetch a next token from source code. + + Returns ``False`` if sequence finished. + """ + try: + self.previous = self.current + self.current = Token(*next(self.tokens)) + except StopIteration: + self.current = None + + return self.current + + def fetch_until(self, condition): + # type: (Any) -> List[Token] + """Fetch tokens until specified token appeared. + + .. note:: This also handles parenthesis well. + """ + tokens = [] + while self.fetch_token(): + tokens.append(self.current) + if self.current == condition: + break + elif self.current == [OP, '(']: + tokens += self.fetch_until([OP, ')']) + elif self.current == [OP, '{']: + tokens += self.fetch_until([OP, '}']) + elif self.current == [OP, '[']: + tokens += self.fetch_until([OP, ']']) + + return tokens + + +class AfterCommentParser(TokenProcessor): + """Python source code parser to pick up comment after assignment. + + This parser takes a python code starts with assignment statement, + and returns the comments for variable if exists. + """ + + def __init__(self, lines): + # type: (List[unicode]) -> None + super(AfterCommentParser, self).__init__(lines) + self.comment = None # type: unicode + + def fetch_rvalue(self): + # type: () -> List[Token] + """Fetch right-hand value of assignment.""" + tokens = [] + while self.fetch_token(): + tokens.append(self.current) + if self.current == [OP, '(']: + tokens += self.fetch_until([OP, ')']) + elif self.current == [OP, '{']: + tokens += self.fetch_until([OP, '}']) + elif self.current == [OP, '[']: + tokens += self.fetch_until([OP, ']']) + elif self.current == INDENT: + tokens += self.fetch_until(DEDENT) + elif self.current == [OP, ';']: + break + elif self.current.kind not in (OP, NAME, NUMBER, STRING): + break + + return tokens + + def parse(self): + # type: () -> None + """Parse the code and obtain comment after assignment.""" + # skip lvalue (until '=' operator) + while self.fetch_token() != [OP, '=']: + assert self.current + + # skip rvalue + self.fetch_rvalue() + + if self.current == COMMENT: + self.comment = self.current.value + + +class VariableCommentPicker(ast.NodeVisitor): + """Python source code parser to pick up variable comments.""" + + def __init__(self, buffers, encoding): + # type: (List[unicode], unicode) -> None + self.counter = itertools.count() + self.buffers = buffers + self.encoding = encoding + self.context = [] # type: List[unicode] + self.current_classes = [] # type: List[unicode] + self.current_function = None # type: ast.FunctionDef + self.comments = {} # type: Dict[Tuple[unicode, unicode], unicode] + self.previous = None # type: ast.AST + self.deforders = {} # type: Dict[unicode, int] + super(VariableCommentPicker, self).__init__() + + def add_entry(self, name): + # type: (unicode) -> None + if self.current_function: + if self.current_classes and self.context[-1] == "__init__": + # store variable comments inside __init__ method of classes + definition = self.context[:-1] + [name] + else: + return + else: + definition = self.context + [name] + + self.deforders[".".join(definition)] = next(self.counter) + + def add_variable_comment(self, name, comment): + # type: (unicode, unicode) -> None + if self.current_function: + if self.current_classes and self.context[-1] == "__init__": + # store variable comments inside __init__ method of classes + context = ".".join(self.context[:-1]) + else: + return + else: + context = ".".join(self.context) + + self.comments[(context, name)] = comment + + def get_self(self): + # type: () -> ast.expr + """Returns the name of first argument if in function.""" + if self.current_function and self.current_function.args.args: + return self.current_function.args.args[0] + else: + return None + + def get_line(self, lineno): + # type: (int) -> unicode + """Returns specified line.""" + return self.buffers[lineno - 1] + + def visit(self, node): + # type: (ast.AST) -> None + """Updates self.previous to .""" + super(VariableCommentPicker, self).visit(node) + self.previous = node + + def visit_Assign(self, node): + # type: (ast.Assign) -> None + """Handles Assign node and pick up a variable comment.""" + try: + varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], []) # type: ignore # NOQA + current_line = self.get_line(node.lineno) + except TypeError: + return # this assignment is not new definition! + + # check comments after assignment + parser = AfterCommentParser([current_line[node.col_offset:]] + + self.buffers[node.lineno:]) + parser.parse() + if parser.comment and comment_re.match(parser.comment): + for varname in varnames: + self.add_variable_comment(varname, comment_re.sub('\\1', parser.comment)) + self.add_entry(varname) + return + + # check comments before assignment + if indent_re.match(current_line[:node.col_offset]): + comment_lines = [] + for i in range(node.lineno - 1): + before_line = self.get_line(node.lineno - 1 - i) + if comment_re.match(before_line): + comment_lines.append(comment_re.sub('\\1', before_line)) + else: + break + + if comment_lines: + comment = dedent_docstring('\n'.join(reversed(comment_lines))) + for varname in varnames: + self.add_variable_comment(varname, comment) + self.add_entry(varname) + return + + # not commented (record deforders only) + for varname in varnames: + self.add_entry(varname) + + def visit_Expr(self, node): + # type: (ast.Expr) -> None + """Handles Expr node and pick up a comment if string.""" + if (isinstance(self.previous, ast.Assign) and isinstance(node.value, ast.Str)): + try: + varnames = get_lvar_names(self.previous.targets[0], self.get_self()) + for varname in varnames: + if isinstance(node.value.s, text_type): + docstring = node.value.s + else: + docstring = node.value.s.decode(self.encoding or 'utf-8') + + self.add_variable_comment(varname, dedent_docstring(docstring)) + self.add_entry(varname) + except TypeError: + pass # this assignment is not new definition! + + def visit_ClassDef(self, node): + # type: (ast.ClassDef) -> None + """Handles ClassDef node and set context.""" + self.current_classes.append(node.name) + self.add_entry(node.name) + self.context.append(node.name) + for child in node.body: + self.visit(child) + self.context.pop() + self.current_classes.pop() + + def visit_FunctionDef(self, node): + # type: (ast.FunctionDef) -> None + """Handles FunctionDef node and set context.""" + if self.current_function is None: + self.add_entry(node.name) # should be called before setting self.current_function + self.context.append(node.name) + self.current_function = node + for child in node.body: + self.visit(child) + self.context.pop() + self.current_function = None + + +class DefinitionFinder(TokenProcessor): + def __init__(self, lines): + # type: (List[unicode]) -> None + super(DefinitionFinder, self).__init__(lines) + self.decorator = None # type: Token + self.context = [] # type: List[unicode] + self.indents = [] # type: List + self.definitions = {} # type: Dict[unicode, Tuple[unicode, int, int]] + + def add_definition(self, name, entry): + # type: (unicode, Tuple[unicode, int, int]) -> None + if self.indents and self.indents[-1][0] == 'def' and entry[0] == 'def': + # ignore definition of inner function + pass + else: + self.definitions[name] = entry + + def parse(self): + # type: () -> None + while True: + token = self.fetch_token() + if token is None: + break + elif token == COMMENT: + pass + elif token == [OP, '@'] and (self.previous is None or + self.previous.match(NEWLINE, NL, INDENT, DEDENT)): + if self.decorator is None: + self.decorator = token + elif token.match([NAME, 'class']): + self.parse_definition('class') + elif token.match([NAME, 'def']): + self.parse_definition('def') + elif token == INDENT: + self.indents.append(('other', None, None)) + elif token == DEDENT: + self.finalize_block() + + def parse_definition(self, typ): + # type: (unicode) -> None + name = self.fetch_token() + self.context.append(name.value) + funcname = '.'.join(self.context) + + if self.decorator: + start_pos = self.decorator.start[0] + self.decorator = None + else: + start_pos = name.start[0] + + self.fetch_until([OP, ':']) + if self.fetch_token().match(COMMENT, NEWLINE): + self.fetch_until(INDENT) + self.indents.append((typ, funcname, start_pos)) + else: + # one-liner + self.add_definition(funcname, (typ, start_pos, name.end[0])) + self.context.pop() + + def finalize_block(self): + # type: () -> None + definition = self.indents.pop() + if definition[0] != 'other': + typ, funcname, start_pos = definition + end_pos = self.current.end[0] - 1 + while emptyline_re.match(self.get_line(end_pos)): + end_pos -= 1 + + self.add_definition(funcname, (typ, start_pos, end_pos)) + self.context.pop() + + +class Parser(object): + """Python source code parser to pick up variable comments. + + This is a better wrapper for ``VariableCommentPicker``. + """ + + def __init__(self, code, encoding='utf-8'): + # type: (unicode, unicode) -> None + self.code = code + self.encoding = encoding + self.comments = {} # type: Dict[Tuple[unicode, unicode], unicode] + self.deforders = {} # type: Dict[unicode, int] + self.definitions = {} # type: Dict[unicode, Tuple[unicode, int, int]] + + def parse(self): + # type: () -> None + """Parse the source code.""" + self.parse_comments() + self.parse_definition() + + def parse_comments(self): + # type: () -> None + """Parse the code and pick up comments.""" + tree = ast.parse(self.code.encode('utf-8')) + picker = VariableCommentPicker(self.code.splitlines(True), self.encoding) + picker.visit(tree) + self.comments = picker.comments + self.deforders = picker.deforders + + def parse_definition(self): + # type: () -> None + """Parse the location of definitions from the code.""" + parser = DefinitionFinder(self.code.splitlines(True)) + parser.parse() + self.definitions = parser.definitions diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py new file mode 100644 index 000000000..0f5208a8b --- /dev/null +++ b/tests/test_pycode_parser.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +""" + test_pycode_parser + ~~~~~~~~~~~~~~~~~~ + + Test pycode.parser. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from sphinx.pycode.parser import Parser + + +def test_comment_picker_basic(): + source = ('a = 1 + 1 #: assignment\n' + 'b = 1 +\\\n 1 #: assignment including a CR\n' + 'c = (1 +\n 1) #: tuple \n' + 'd = {1, \n 1} #: set\n' + 'e = [1, \n 1] #: list #: additional comment\n' + 'f = "abc"\n' + '#: string; comment on next line (ignored)\n' + 'g = 1.0\n' + '"""float; string on next line"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'assignment', + ('', 'b'): 'assignment including a CR', + ('', 'c'): 'tuple ', + ('', 'd'): ' set', + ('', 'e'): 'list #: additional comment', + ('', 'g'): 'float; string on next line'} + + +def test_comment_picker_location(): + # multiple "before" comments + source = ('#: comment before assignment1\n' + '#:\n' + '#: comment before assignment2\n' + 'a = 1 + 1\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): ('comment before assignment1\n' + '\n' + 'comment before assignment2')} + + # before and after comments + source = ('#: comment before assignment\n' + 'a = 1 + 1 #: comment after assignment\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'comment after assignment'} + + # after comment and next line string + source = ('a = 1 + 1\n #: comment after assignment\n' + '"""string on next line"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'string on next line'} + + # before comment and next line string + source = ('#: comment before assignment\n' + 'a = 1 + 1\n' + '"""string on next line"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'string on next line'} + + # before comment, after comment and next line string + source = ('#: comment before assignment\n' + 'a = 1 + 1 #: comment after assignment\n' + '"""string on next line"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'string on next line'} + + # inside __init__ method + source = ('class Foo(object):\n' + ' def __init__(self):\n' + ' #: comment before assignment\n' + ' self.attr1 = None\n' + ' self.attr2 = None #: comment after assignment\n' + '\n' + ' #: comment for attr3(1)\n' + ' self.attr3 = None #: comment for attr3(2)\n' + ' """comment for attr3(3)"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('Foo', 'attr1'): 'comment before assignment', + ('Foo', 'attr2'): 'comment after assignment', + ('Foo', 'attr3'): 'comment for attr3(3)'} + + +def test_complex_assignment(): + source = ('a = 1 + 1; b = a #: compound statement\n' + 'c, d = (1, 1) #: unpack assignment\n' + 'e = True #: first assignment\n' + 'e = False #: second assignment\n' + 'f = g = None #: multiple assignment at once\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'b'): 'compound statement', + ('', 'c'): 'unpack assignment', + ('', 'd'): 'unpack assignment', + ('', 'e'): 'second assignment', + ('', 'f'): 'multiple assignment at once', + ('', 'g'): 'multiple assignment at once'} + assert parser.definitions == {} + + +def test_obj_assignment(): + source = ('obj = SomeObject() #: some object\n' + 'obj.attr = 1 #: attr1\n' + 'obj.attr.attr = 1 #: attr2\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'obj'): 'some object'} + assert parser.definitions == {} + + +def test_container_assignment(): + source = ('l = [] #: list\n' + 'l[1] = True #: list assignment\n' + 'l[0:0] = [] #: list assignment\n' + 'l[_from:_to] = [] #: list assignment\n' + 'd = {} #: dict\n' + 'd["doc"] = 1 #: dict assignment\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'l'): 'list', + ('', 'd'): 'dict'} + assert parser.definitions == {} + + +def test_function(): + source = ('def some_function():\n' + ' """docstring"""\n' + ' a = 1 + 1 #: comment1\n' + '\n' + ' b = a #: comment2\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {} + assert parser.definitions == {'some_function': ('def', 1, 5)} + assert parser.deforders == {'some_function': 0} + + +def test_nested_function(): + source = ('def some_function():\n' + ' a = 1 + 1 #: comment1\n' + '\n' + ' def inner_function():\n' + ' b = 1 + 1 #: comment2\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {} + assert parser.definitions == {'some_function': ('def', 1, 5)} + assert parser.deforders == {'some_function': 0} + + +def test_class(): + source = ('class Foo(object):\n' + ' attr1 = None #: comment1\n' + ' attr2 = None #: comment2\n' + '\n' + ' def __init__(self):\n' + ' self.a = 1 + 1 #: comment3\n' + ' self.attr2 = 1 + 1 #: overrided\n' + ' b = 1 + 1 #: comment5\n' + '\n' + ' def some_method(self):\n' + ' c = 1 + 1 #: comment6\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('Foo', 'attr1'): 'comment1', + ('Foo', 'a'): 'comment3', + ('Foo', 'attr2'): 'overrided'} + assert parser.definitions == {'Foo': ('class', 1, 11), + 'Foo.__init__': ('def', 5, 8), + 'Foo.some_method': ('def', 10, 11)} + assert parser.deforders == {'Foo': 0, + 'Foo.attr1': 1, + 'Foo.__init__': 3, + 'Foo.a': 4, + 'Foo.attr2': 5, + 'Foo.some_method': 6} + + +def test_class_uses_non_self(): + source = ('class Foo(object):\n' + ' def __init__(this):\n' + ' this.a = 1 + 1 #: comment\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('Foo', 'a'): 'comment'} + assert parser.definitions == {'Foo': ('class', 1, 3), + 'Foo.__init__': ('def', 2, 3)} + assert parser.deforders == {'Foo': 0, + 'Foo.__init__': 1, + 'Foo.a': 2} + + +def test_nested_class(): + source = ('class Foo(object):\n' + ' attr1 = None #: comment1\n' + '\n' + ' class Bar(object):\n' + ' attr2 = None #: comment2\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('Foo', 'attr1'): 'comment1', + ('Foo.Bar', 'attr2'): 'comment2'} + assert parser.definitions == {'Foo': ('class', 1, 5), + 'Foo.Bar': ('class', 4, 5)} + assert parser.deforders == {'Foo': 0, + 'Foo.attr1': 1, + 'Foo.Bar': 2, + 'Foo.Bar.attr2': 3} + + +def test_comment_picker_multiline_string(): + source = ('class Foo(object):\n' + ' a = None\n' + ' """multiline\n' + ' docstring\n' + ' """\n' + ' b = None\n' + ' """\n' + ' docstring\n' + ' starts with::\n' + '\n' + ' empty line"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {('Foo', 'a'): 'multiline\ndocstring', + ('Foo', 'b'): 'docstring\nstarts with::\n\n empty line'} + + +def test_decorators(): + source = ('@deco\n' + 'def func1(): pass\n' + '\n' + '@deco(param1, param2)\n' + 'def func2(): pass\n' + '\n' + '@deco1\n' + '@deco2\n' + 'def func3(): pass\n' + '\n' + '@deco\n' + 'class Foo():\n' + ' @deco1\n' + ' @deco2\n' + ' def method(self): pass\n') + parser = Parser(source) + parser.parse() + assert parser.definitions == {'func1': ('def', 1, 2), + 'func2': ('def', 4, 5), + 'func3': ('def', 7, 9), + 'Foo': ('class', 11, 15), + 'Foo.method': ('def', 13, 15)} From 8683823536505aef3b96627ce9ea4784d5385eb0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 10 Jul 2017 01:20:19 +0900 Subject: [PATCH 0055/1814] pycode: Replace pgen2 by own parser --- MANIFEST.in | 2 - sphinx/directives/code.py | 2 +- sphinx/pycode/Grammar-py2.txt | 135 - sphinx/pycode/Grammar-py3.txt | 143 - sphinx/pycode/__init__.py | 311 +-- sphinx/pycode/nodes.py | 212 -- sphinx/pycode/pgen2/__init__.py | 4 - sphinx/pycode/pgen2/driver.py | 154 -- sphinx/pycode/pgen2/grammar.py | 177 -- sphinx/pycode/pgen2/literals.py | 100 - sphinx/pycode/pgen2/parse.c | 4544 ------------------------------- sphinx/pycode/pgen2/parse.py | 206 -- sphinx/pycode/pgen2/parse.pyx | 165 -- sphinx/pycode/pgen2/pgen.py | 403 --- sphinx/pycode/pgen2/token.py | 86 - sphinx/pycode/pgen2/tokenize.py | 441 --- tests/test_pycode.py | 52 +- utils/release-checklist | 1 - 18 files changed, 74 insertions(+), 7064 deletions(-) delete mode 100644 sphinx/pycode/Grammar-py2.txt delete mode 100644 sphinx/pycode/Grammar-py3.txt delete mode 100644 sphinx/pycode/nodes.py delete mode 100644 sphinx/pycode/pgen2/__init__.py delete mode 100644 sphinx/pycode/pgen2/driver.py delete mode 100644 sphinx/pycode/pgen2/grammar.py delete mode 100644 sphinx/pycode/pgen2/literals.py delete mode 100644 sphinx/pycode/pgen2/parse.c delete mode 100644 sphinx/pycode/pgen2/parse.py delete mode 100644 sphinx/pycode/pgen2/parse.pyx delete mode 100644 sphinx/pycode/pgen2/pgen.py delete mode 100755 sphinx/pycode/pgen2/token.py delete mode 100644 sphinx/pycode/pgen2/tokenize.py diff --git a/MANIFEST.in b/MANIFEST.in index 6fe5c7d6d..c55e44fb1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -19,13 +19,11 @@ include sphinx/locale/.tx/config recursive-include sphinx/templates * recursive-include sphinx/texinputs * recursive-include sphinx/themes * -recursive-include sphinx/pycode/pgen2 *.c *.pyx recursive-include sphinx/locale *.js *.pot *.po *.mo recursive-include sphinx/search/non-minified-js *.js recursive-include sphinx/ext/autosummary/templates * recursive-include tests * recursive-include utils * -include sphinx/pycode/Grammar-py* recursive-include doc * prune doc/_build diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 41a593aa3..111f6b189 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -256,7 +256,7 @@ class LiteralIncludeReader(object): else: start = tags[pyobject][1] end = tags[pyobject][2] - lines = lines[start - 1:end - 1] + lines = lines[start - 1:end] if 'lineno-match' in self.options: self.lineno_start = start diff --git a/sphinx/pycode/Grammar-py2.txt b/sphinx/pycode/Grammar-py2.txt deleted file mode 100644 index 98bd1f22b..000000000 --- a/sphinx/pycode/Grammar-py2.txt +++ /dev/null @@ -1,135 +0,0 @@ -# Grammar for Python 2.x - -# IMPORTANT: when copying over a new Grammar file, make sure file_input -# is the first nonterminal in the file! - -# Start symbols for the grammar: -# single_input is a single interactive statement; -# file_input is a module or sequence of commands read from an input file; -# eval_input is the input for the eval() and input() functions. -# NB: compound_stmt in single_input is followed by extra NEWLINE! -file_input: (NEWLINE | stmt)* ENDMARKER -single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE -eval_input: testlist NEWLINE* ENDMARKER - -decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE -decorators: decorator+ -decorated: decorators (classdef | funcdef) -funcdef: 'def' NAME parameters ':' suite -parameters: '(' [varargslist] ')' -varargslist: ((fpdef ['=' test] ',')* - ('*' NAME [',' '**' NAME] | '**' NAME) | - fpdef ['=' test] (',' fpdef ['=' test])* [',']) -fpdef: NAME | '(' fplist ')' -fplist: fpdef (',' fpdef)* [','] - -stmt: simple_stmt | compound_stmt -simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE -small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | - import_stmt | global_stmt | exec_stmt | assert_stmt) -expr_stmt: testlist (augassign (yield_expr|testlist) | - ('=' (yield_expr|testlist))*) -augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | - '<<=' | '>>=' | '**=' | '//=') -# For normal assignments, additional restrictions enforced by the interpreter -print_stmt: 'print' ( [ test (',' test)* [','] ] | - '>>' test [ (',' test)+ [','] ] ) -del_stmt: 'del' exprlist -pass_stmt: 'pass' -flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt -break_stmt: 'break' -continue_stmt: 'continue' -return_stmt: 'return' [testlist] -yield_stmt: yield_expr -raise_stmt: 'raise' [test [',' test [',' test]]] -import_stmt: import_name | import_from -import_name: 'import' dotted_as_names -import_from: ('from' ('.'* dotted_name | '.'+) - 'import' ('*' | '(' import_as_names ')' | import_as_names)) -import_as_name: NAME ['as' NAME] -dotted_as_name: dotted_name ['as' NAME] -import_as_names: import_as_name (',' import_as_name)* [','] -dotted_as_names: dotted_as_name (',' dotted_as_name)* -dotted_name: NAME ('.' NAME)* -global_stmt: 'global' NAME (',' NAME)* -exec_stmt: 'exec' expr ['in' test [',' test]] -assert_stmt: 'assert' test [',' test] - -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated -if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] -while_stmt: 'while' test ':' suite ['else' ':' suite] -for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] -try_stmt: ('try' ':' suite - ((except_clause ':' suite)+ - ['else' ':' suite] - ['finally' ':' suite] | - 'finally' ':' suite)) -with_stmt: 'with' with_item (',' with_item)* ':' suite -with_item: test ['as' expr] -# NB compile.c makes sure that the default except clause is last -except_clause: 'except' [test [('as' | ',') test]] -suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT - -# Backward compatibility cruft to support: -# [ x for x in lambda: True, lambda: False if x() ] -# even while also allowing: -# lambda x: 5 if x else 2 -# (But not a mix of the two) -testlist_safe: old_test [(',' old_test)+ [',']] -old_test: or_test | old_lambdef -old_lambdef: 'lambda' [varargslist] ':' old_test - -test: or_test ['if' or_test 'else' test] | lambdef -or_test: and_test ('or' and_test)* -and_test: not_test ('and' not_test)* -not_test: 'not' not_test | comparison -comparison: expr (comp_op expr)* -comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' -expr: xor_expr ('|' xor_expr)* -xor_expr: and_expr ('^' and_expr)* -and_expr: shift_expr ('&' shift_expr)* -shift_expr: arith_expr (('<<'|'>>') arith_expr)* -arith_expr: term (('+'|'-') term)* -term: factor (('*'|'/'|'%'|'//') factor)* -factor: ('+'|'-'|'~') factor | power -power: atom trailer* ['**' factor] -atom: ('(' [yield_expr|testlist_comp] ')' | - '[' [listmaker] ']' | - '{' [dictorsetmaker] '}' | - '`' testlist1 '`' | - NAME | NUMBER | STRING+) -listmaker: test ( list_for | (',' test)* [','] ) -testlist_comp: test ( comp_for | (',' test)* [','] ) -lambdef: 'lambda' [varargslist] ':' test -trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME -subscriptlist: subscript (',' subscript)* [','] -subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] -sliceop: ':' [test] -exprlist: expr (',' expr)* [','] -testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | - (test (comp_for | (',' test)* [','])) ) - -classdef: 'class' NAME ['(' [testlist] ')'] ':' suite - -arglist: (argument ',')* (argument [','] - |'*' test (',' argument)* [',' '**' test] - |'**' test) -# The reason that keywords are test nodes instead of NAME is that using NAME -# results in an ambiguity. ast.c makes sure it's a NAME. -argument: test [comp_for] | test '=' test - -list_iter: list_for | list_if -list_for: 'for' exprlist 'in' testlist_safe [list_iter] -list_if: 'if' old_test [list_iter] - -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] -comp_if: 'if' old_test [comp_iter] - -testlist1: test (',' test)* - -# not used in grammar, but may appear in "node" passed from Parser to Compiler -encoding_decl: NAME - -yield_expr: 'yield' [testlist] diff --git a/sphinx/pycode/Grammar-py3.txt b/sphinx/pycode/Grammar-py3.txt deleted file mode 100644 index d05b758ee..000000000 --- a/sphinx/pycode/Grammar-py3.txt +++ /dev/null @@ -1,143 +0,0 @@ -# Grammar for Python 3.x (with at least x <= 5) - - -# IMPORTANT: when copying over a new Grammar file, make sure file_input -# is the first nonterminal in the file! - -# Start symbols for the grammar: -# single_input is a single interactive statement; -# file_input is a module or sequence of commands read from an input file; -# eval_input is the input for the eval() functions. -# NB: compound_stmt in single_input is followed by extra NEWLINE! -file_input: (NEWLINE | stmt)* ENDMARKER -single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE -eval_input: testlist NEWLINE* ENDMARKER - -decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE -decorators: decorator+ -decorated: decorators (classdef | funcdef | async_funcdef) - -async_funcdef: ASYNC funcdef -funcdef: 'def' NAME parameters ['->' test] ':' suite - -parameters: '(' [typedargslist] ')' -typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' - ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] - | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef) -tfpdef: NAME [':' test] -varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' - ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] - | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef) -vfpdef: NAME - -stmt: simple_stmt | compound_stmt -simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE -small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | - import_stmt | global_stmt | nonlocal_stmt | assert_stmt) -expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | - ('=' (yield_expr|testlist_star_expr))*) -testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] -augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | - '<<=' | '>>=' | '**=' | '//=') -# For normal assignments, additional restrictions enforced by the interpreter -del_stmt: 'del' exprlist -pass_stmt: 'pass' -flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt -break_stmt: 'break' -continue_stmt: 'continue' -return_stmt: 'return' [testlist] -yield_stmt: yield_expr -raise_stmt: 'raise' [test ['from' test]] -import_stmt: import_name | import_from -import_name: 'import' dotted_as_names -# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS -import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) - 'import' ('*' | '(' import_as_names ')' | import_as_names)) -import_as_name: NAME ['as' NAME] -dotted_as_name: dotted_name ['as' NAME] -import_as_names: import_as_name (',' import_as_name)* [','] -dotted_as_names: dotted_as_name (',' dotted_as_name)* -dotted_name: NAME ('.' NAME)* -global_stmt: 'global' NAME (',' NAME)* -nonlocal_stmt: 'nonlocal' NAME (',' NAME)* -assert_stmt: 'assert' test [',' test] - -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt -async_stmt: ASYNC (funcdef | with_stmt | for_stmt) -if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] -while_stmt: 'while' test ':' suite ['else' ':' suite] -for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] -try_stmt: ('try' ':' suite - ((except_clause ':' suite)+ - ['else' ':' suite] - ['finally' ':' suite] | - 'finally' ':' suite)) -with_stmt: 'with' with_item (',' with_item)* ':' suite -with_item: test ['as' expr] -# NB compile.c makes sure that the default except clause is last -except_clause: 'except' [test ['as' NAME]] -suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT - -test: or_test ['if' or_test 'else' test] | lambdef -test_nocond: or_test | lambdef_nocond -lambdef: 'lambda' [varargslist] ':' test -lambdef_nocond: 'lambda' [varargslist] ':' test_nocond -or_test: and_test ('or' and_test)* -and_test: not_test ('and' not_test)* -not_test: 'not' not_test | comparison -comparison: expr (comp_op expr)* -# <> isn't actually a valid comparison operator in Python. It's here for the -# sake of a __future__ import described in PEP 401 (which really works :-) -comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' -star_expr: '*' expr -expr: xor_expr ('|' xor_expr)* -xor_expr: and_expr ('^' and_expr)* -and_expr: shift_expr ('&' shift_expr)* -shift_expr: arith_expr (('<<'|'>>') arith_expr)* -arith_expr: term (('+'|'-') term)* -term: factor (('*'|'@'|'/'|'%'|'//') factor)* -factor: ('+'|'-'|'~') factor | power -power: [AWAIT] atom trailer* ['**' factor] -atom: ('(' [yield_expr|testlist_comp] ')' | - '[' [testlist_comp] ']' | - '{' [dictorsetmaker] '}' | - NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') -testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) -trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME -subscriptlist: subscript (',' subscript)* [','] -subscript: test | [test] ':' [test] [sliceop] -sliceop: ':' [test] -exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] -testlist: test (',' test)* [','] -dictorsetmaker: ( ((test ':' test | '**' expr) - (comp_for | (',' (test ':' test | '**' expr))* [','])) | - ((test | star_expr) - (comp_for | (',' (test | star_expr))* [','])) ) - -classdef: 'class' NAME ['(' [arglist] ')'] ':' suite - -arglist: argument (',' argument)* [','] - -# The reason that keywords are test nodes instead of NAME is that using NAME -# results in an ambiguity. ast.c makes sure it's a NAME. -# "test '=' test" is really "keyword '=' test", but we have no such token. -# These need to be in a single rule to avoid grammar that is ambiguous -# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, -# we explicitly match '*' here, too, to give it proper precedence. -# Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguements are blocked; keyword unpackings -# that precede iterable unpackings are blocked; etc. -argument: ( test [comp_for] | - test '=' test | - '**' test | - '*' test ) - -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] -comp_if: 'if' test_nocond [comp_iter] - -# not used in grammar, but may appear in "node" passed from Parser to Compiler -encoding_decl: NAME - -yield_expr: 'yield' [yield_arg] -yield_arg: 'from' test | testlist diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index eabcc8188..29aa4356f 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -11,175 +11,20 @@ from __future__ import print_function import re -import sys -from os import path -from six import iteritems, text_type, BytesIO, StringIO +from six import iteritems, BytesIO, StringIO -from sphinx import package_dir from sphinx.errors import PycodeError -from sphinx.pycode import nodes -from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals +from sphinx.pycode.parser import Parser from sphinx.util import get_module_source, detect_encoding -from sphinx.util.pycompat import TextIOWrapper -from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc if False: # For type annotation - from typing import Any, Dict, List, Tuple # NOQA - - -# load the Python grammar -_grammarfile = path.join(package_dir, 'pycode', - 'Grammar-py%d.txt' % sys.version_info[0]) -pygrammar = driver.load_grammar(_grammarfile) -pydriver = driver.Driver(pygrammar, convert=nodes.convert) - - -# an object with attributes corresponding to token and symbol names -class sym(object): - pass - - -for k, v in iteritems(pygrammar.symbol2number): - setattr(sym, k, v) -for k, v in iteritems(token.tok_name): - setattr(sym, v, k) - -# a dict mapping terminal and nonterminal numbers to their names -number2name = pygrammar.number2symbol.copy() -number2name.update(token.tok_name) - -_eq = nodes.Leaf(token.EQUAL, '=') + from typing import Any, Dict, IO, List, Tuple # NOQA emptyline_re = re.compile(r'^\s*(#.*)?$') -class AttrDocVisitor(nodes.NodeVisitor): - """ - Visitor that collects docstrings for attribute assignments on toplevel and - in classes (class attributes and attributes set in __init__). - - The docstrings can either be in special '#:' comments before the assignment - or in a docstring after it. - """ - def init(self, scope, encoding): - self.scope = scope - self.in_init = 0 - self.encoding = encoding - self.namespace = [] # type: List[unicode] - self.collected = {} # type: Dict[Tuple[unicode, unicode], unicode] - self.tagnumber = 0 - self.tagorder = {} # type: Dict[unicode, int] - - def add_tag(self, name): - name = '.'.join(self.namespace + [name]) - self.tagorder[name] = self.tagnumber - self.tagnumber += 1 - - def visit_classdef(self, node): - """Visit a class.""" - self.add_tag(node[1].value) - self.namespace.append(node[1].value) - self.generic_visit(node) - self.namespace.pop() - - def visit_funcdef(self, node): - """Visit a function (or method).""" - # usually, don't descend into functions -- nothing interesting there - self.add_tag(node[1].value) - if node[1].value == '__init__': - # however, collect attributes set in __init__ methods - self.in_init += 1 - self.generic_visit(node) - self.in_init -= 1 - - def visit_expr_stmt(self, node): - """Visit an assignment which may have a special comment before (or - after) it. - """ - if _eq not in node.children: - # not an assignment (we don't care for augmented assignments) - return - # look *after* the node; there may be a comment prefixing the NEWLINE - # of the simple_stmt - parent = node.parent - idx = parent.children.index(node) + 1 - while idx < len(parent): - if parent[idx].type == sym.SEMI: # type: ignore - idx += 1 - continue # skip over semicolon - if parent[idx].type == sym.NEWLINE: # type: ignore - prefix = parent[idx].get_prefix() - if not isinstance(prefix, text_type): - prefix = prefix.decode(self.encoding) - docstring = prepare_commentdoc(prefix) - if docstring: - self.add_docstring(node, docstring) - return # don't allow docstrings both before and after - break - # now look *before* the node - pnode = node[0] - prefix = pnode.get_prefix() - # if the assignment is the first statement on a new indentation - # level, its preceding whitespace and comments are not assigned - # to that token, but the first INDENT or DEDENT token - while not prefix: - pnode = pnode.get_prev_leaf() - if not pnode or pnode.type not in (token.INDENT, token.DEDENT): - break - prefix = pnode.get_prefix() - if not isinstance(prefix, text_type): - prefix = prefix.decode(self.encoding) - docstring = prepare_commentdoc(prefix) - self.add_docstring(node, docstring) - - def visit_simple_stmt(self, node): - """Visit a docstring statement which may have an assignment before.""" - if node[0].type != token.STRING: - # not a docstring; but still need to visit children - return self.generic_visit(node) - prev = node.get_prev_sibling() - if not prev: - return - if (prev.type == sym.simple_stmt and # type: ignore - prev[0].type == sym.expr_stmt and _eq in prev[0].children): # type: ignore - # need to "eval" the string because it's returned in its - # original form - docstring = literals.evalString(node[0].value, self.encoding) - docstring = prepare_docstring(docstring) - self.add_docstring(prev[0], docstring) - - def add_docstring(self, node, docstring): - # add an item for each assignment target - for i in range(0, len(node) - 1, 2): - target = node[i] - if self.in_init and self.number2name[target.type] == 'power': - # maybe an attribute assignment -- check necessary conditions - if ( # node must have two children - len(target) != 2 or - # first child must be "self" - target[0].type != token.NAME or target[0].value != 'self' or - # second child must be a "trailer" with two children - self.number2name[target[1].type] != 'trailer' or - len(target[1]) != 2 or - # first child must be a dot, second child a name - target[1][0].type != token.DOT or - target[1][1].type != token.NAME): - continue - name = target[1][1].value - elif target.type != token.NAME: - # don't care about other complex targets - continue - else: - name = target.value - self.add_tag(name) - if docstring: - namespace = '.'.join(self.namespace) - if namespace.startswith(self.scope): - self.collected[namespace, name] = docstring - - class ModuleAnalyzer(object): # cache for analyzer objects -- caches both by module and file name cache = {} # type: Dict[Tuple[unicode, unicode], Any] @@ -223,137 +68,59 @@ class ModuleAnalyzer(object): return obj def __init__(self, source, modname, srcname, decoded=False): - # name of the module - self.modname = modname - # name of the source file - self.srcname = srcname - # file-like object yielding source lines - self.source = source + # type: (IO, unicode, unicode, bool) -> None + self.modname = modname # name of the module + self.srcname = srcname # name of the source file # cache the source code as well - pos = self.source.tell() + pos = source.tell() if not decoded: - self.encoding = detect_encoding(self.source.readline) - self.source.seek(pos) - self.code = self.source.read().decode(self.encoding) - self.source.seek(pos) - self.source = TextIOWrapper(self.source, self.encoding) + self.encoding = detect_encoding(source.readline) + source.seek(pos) + self.code = source.read().decode(self.encoding) else: self.encoding = None - self.code = self.source.read() - self.source.seek(pos) + self.code = source.read() - # will be filled by tokenize() - self.tokens = None # type: List[unicode] # will be filled by parse() - self.parsetree = None # type: Any - # will be filled by find_attr_docs() - self.attr_docs = None # type: List[unicode] + self.attr_docs = None # type: Dict[Tuple[unicode, unicode], List[unicode]] self.tagorder = None # type: Dict[unicode, int] - # will be filled by find_tags() - self.tags = None # type: List[unicode] - - def tokenize(self): - """Generate tokens from the source.""" - if self.tokens is not None: - return - try: - self.tokens = list(tokenize.generate_tokens(self.source.readline)) - except tokenize.TokenError as err: - raise PycodeError('tokenizing failed', err) - self.source.close() + self.tags = None # type: Dict[unicode, Tuple[unicode, int, int]] def parse(self): - """Parse the generated source tokens.""" - if self.parsetree is not None: - return - self.tokenize() + # type: () -> None + """Parse the source code.""" try: - self.parsetree = pydriver.parse_tokens(self.tokens) - except parse.ParseError as err: - raise PycodeError('parsing failed', err) + parser = Parser(self.code, self.encoding) + parser.parse() - def find_attr_docs(self, scope=''): + self.attr_docs = {} + for (scope, comment) in iteritems(parser.comments): + if comment: + self.attr_docs[scope] = comment.splitlines() + [''] + else: + self.attr_docs[scope] = [''] + + self.tags = parser.definitions + self.tagorder = parser.deforders + except Exception as exc: + raise PycodeError('parsing failed: %r' % exc) + + def find_attr_docs(self): + # type: () -> Dict[Tuple[unicode, unicode], List[unicode]] """Find class and module-level attributes and their documentation.""" - if self.attr_docs is not None: - return self.attr_docs - self.parse() - attr_visitor = AttrDocVisitor(number2name, scope, self.encoding) - attr_visitor.visit(self.parsetree) - self.attr_docs = attr_visitor.collected - self.tagorder = attr_visitor.tagorder - # now that we found everything we could in the tree, throw it away - # (it takes quite a bit of memory for large modules) - self.parsetree = None - return attr_visitor.collected + if self.attr_docs is None: + self.parse() + + return self.attr_docs def find_tags(self): + # type: () -> Dict[unicode, Tuple[unicode, int, int]] """Find class, function and method definitions and their location.""" - if self.tags is not None: - return self.tags - self.tokenize() - result = {} - namespace = [] # type: List[unicode] - stack = [] # type: List[Tuple[unicode, unicode, unicode, int]] - indent = 0 - decopos = None - defline = False - expect_indent = False - emptylines = 0 + if self.tags is None: + self.parse() - def tokeniter(ignore = (token.COMMENT,)): - for tokentup in self.tokens: - if tokentup[0] not in ignore: - yield tokentup - tokeniter = tokeniter() - for type, tok, spos, epos, line in tokeniter: # type: ignore - if expect_indent and type != token.NL: - if type != token.INDENT: - # no suite -- one-line definition - assert stack - dtype, fullname, startline, _ = stack.pop() - endline = epos[0] - namespace.pop() - result[fullname] = (dtype, startline, endline - emptylines) - expect_indent = False - if tok in ('def', 'class'): - name = next(tokeniter)[1] # type: ignore - namespace.append(name) - fullname = '.'.join(namespace) - stack.append((tok, fullname, decopos or spos[0], indent)) - defline = True - decopos = None - elif type == token.OP and tok == '@': - if decopos is None: - decopos = spos[0] - elif type == token.INDENT: - expect_indent = False - indent += 1 - elif type == token.DEDENT: - indent -= 1 - # if the stacklevel is the same as it was before the last - # def/class block, this dedent closes that block - if stack and indent == stack[-1][3]: - dtype, fullname, startline, _ = stack.pop() - endline = spos[0] - namespace.pop() - result[fullname] = (dtype, startline, endline - emptylines) - elif type == token.NEWLINE: - # if this line contained a definition, expect an INDENT - # to start the suite; if there is no such INDENT - # it's a one-line definition - if defline: - defline = False - expect_indent = True - emptylines = 0 - elif type == token.NL: - # count up if line is empty or comment only - if emptyline_re.match(line): - emptylines += 1 - else: - emptylines = 0 - self.tags = result - return result + return self.tags if __name__ == '__main__': diff --git a/sphinx/pycode/nodes.py b/sphinx/pycode/nodes.py deleted file mode 100644 index cecde9bd0..000000000 --- a/sphinx/pycode/nodes.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- coding: utf-8 -*- -""" - sphinx.pycode.nodes - ~~~~~~~~~~~~~~~~~~~ - - Parse tree node implementations. - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -if False: - # For type annotation - from typing import Callable # NOQA - - -class BaseNode(object): - """ - Node superclass for both terminal and nonterminal nodes. - """ - parent = None # type: BaseNode - - def _eq(self, other): - raise NotImplementedError - - def __eq__(self, other): - if self.__class__ is not other.__class__: - return NotImplemented - return self._eq(other) - - def __ne__(self, other): - if self.__class__ is not other.__class__: - return NotImplemented - return not self._eq(other) - - __hash__ = None # type: Callable[[object], int] - - def get_prev_sibling(self): - """Return previous child in parent's children, or None.""" - if self.parent is None: - return None - for i, child in enumerate(self.parent.children): - if child is self: - if i == 0: - return None - return self.parent.children[i - 1] - - def get_next_sibling(self): - """Return next child in parent's children, or None.""" - if self.parent is None: - return None - for i, child in enumerate(self.parent.children): - if child is self: - try: - return self.parent.children[i + 1] - except IndexError: - return None - - def get_prev_leaf(self): - """Return the leaf node that precedes this node in the parse tree.""" - def last_child(node): - if isinstance(node, Leaf): - return node - elif not node.children: - return None - else: - return last_child(node.children[-1]) - if self.parent is None: - return None - prev = self.get_prev_sibling() - if isinstance(prev, Leaf): - return prev - elif prev is not None: - return last_child(prev) - return self.parent.get_prev_leaf() - - def get_next_leaf(self): - """Return self if leaf, otherwise the leaf node that succeeds this - node in the parse tree. - """ - node = self - while not isinstance(node, Leaf): - assert node.children - node = node.children[0] - return node - - def get_lineno(self): - """Return the line number which generated the invocant node.""" - return self.get_next_leaf().lineno - - def get_prefix(self): - """Return the prefix of the next leaf node.""" - # only leaves carry a prefix - return self.get_next_leaf().prefix - - -class Node(BaseNode): - """ - Node implementation for nonterminals. - """ - - def __init__(self, type, children, context=None): - # type of nonterminals is >= 256 - # assert type >= 256, type - self.type = type - self.children = list(children) - for ch in self.children: - # assert ch.parent is None, repr(ch) - ch.parent = self - - def __repr__(self): - return '%s(%s, %r)' % (self.__class__.__name__, - self.type, self.children) - - def __str__(self): - """This reproduces the input source exactly.""" - return ''.join(map(str, self.children)) - - def _eq(self, other): - return (self.type, self.children) == (other.type, other.children) - - # support indexing the node directly instead of .children - - def __getitem__(self, index): - return self.children[index] - - def __iter__(self): - return iter(self.children) - - def __len__(self): - return len(self.children) - - -class Leaf(BaseNode): - """ - Node implementation for leaf nodes (terminals). - """ - prefix = '' # Whitespace and comments preceding this token in the input - lineno = 0 # Line where this token starts in the input - column = 0 # Column where this token tarts in the input - - def __init__(self, type, value, context=None): - # type of terminals is below 256 - # assert 0 <= type < 256, type - self.type = type - self.value = value - if context is not None: - self.prefix, (self.lineno, self.column) = context - - def __repr__(self): - return '%s(%r, %r, %r)' % (self.__class__.__name__, - self.type, self.value, self.prefix) - - def __str__(self): - """This reproduces the input source exactly.""" - return self.prefix + str(self.value) - - def _eq(self, other): - """Compares two nodes for equality.""" - return (self.type, self.value) == (other.type, other.value) - - -def convert(grammar, raw_node): - """Convert raw node to a Node or Leaf instance.""" - type, value, context, children = raw_node - if children or type in grammar.number2symbol: - # If there's exactly one child, return that child instead of - # creating a new node. - if len(children) == 1: - return children[0] - return Node(type, children, context=context) - else: - return Leaf(type, value, context=context) - - -def nice_repr(node, number2name, prefix=False): - def _repr(node): - if isinstance(node, Leaf): - return "%s(%r)" % (number2name[node.type], node.value) - else: - return "%s(%s)" % (number2name[node.type], - ', '.join(map(_repr, node.children))) - - def _prepr(node): - if isinstance(node, Leaf): - return "%s(%r, %r)" % (number2name[node.type], - node.prefix, node.value) - else: - return "%s(%s)" % (number2name[node.type], - ', '.join(map(_prepr, node.children))) - return (prefix and _prepr or _repr)(node) - - -class NodeVisitor(object): - def __init__(self, number2name, *args): - self.number2name = number2name - self.init(*args) - - def init(self, *args): - pass - - def visit(self, node): - """Visit a node.""" - method = 'visit_' + self.number2name[node.type] - visitor = getattr(self, method, self.generic_visit) - return visitor(node) - - def generic_visit(self, node): - """Called if no explicit visitor function exists for a node.""" - if isinstance(node, Node): - for child in node: # type: ignore - self.visit(child) diff --git a/sphinx/pycode/pgen2/__init__.py b/sphinx/pycode/pgen2/__init__.py deleted file mode 100644 index af3904845..000000000 --- a/sphinx/pycode/pgen2/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""The pgen2 package.""" diff --git a/sphinx/pycode/pgen2/driver.py b/sphinx/pycode/pgen2/driver.py deleted file mode 100644 index 90476ed00..000000000 --- a/sphinx/pycode/pgen2/driver.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# Modifications: -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Parser driver. - -This provides a high-level interface to parse a file into a syntax tree. - -""" - -__author__ = "Guido van Rossum " - -__all__ = ["Driver", "load_grammar"] - -# Python imports -import os -import logging - -import sphinx - -# Pgen imports -from sphinx.pycode.pgen2 import grammar, parse, token, tokenize, pgen - - -class Driver(object): - - def __init__(self, grammar, convert=None, logger=None): - self.grammar = grammar - if logger is None: - logger = logging.getLogger() - self.logger = logger - self.convert = convert - - def parse_tokens(self, tokens, debug=False): - """Parse a series of tokens and return the syntax tree.""" - # X X X Move the prefix computation into a wrapper around tokenize. - p = parse.Parser(self.grammar, self.convert) - p.setup() - lineno = 1 - column = 0 - type = value = start = end = line_text = None - prefix = "" - opmap = grammar.opmap - for type, value, start, end, line_text in tokens: - if start != (lineno, column): - assert (lineno, column) <= start, ((lineno, column), start) - s_lineno, s_column = start - if lineno < s_lineno: - prefix += "\n" * (s_lineno - lineno) - lineno = s_lineno - column = 0 - if column < s_column: - prefix += line_text[column:s_column] - column = s_column - if type in (tokenize.COMMENT, tokenize.NL): - prefix += value - lineno, column = end - if value.endswith("\n"): - lineno += 1 - column = 0 - continue - if type == token.OP: - type = opmap[value] - # if debug: - # self.logger.debug("%s %r (prefix=%r)", - # token.tok_name[type], value, prefix) - if p.addtoken(type, value, (prefix, start)): - # if debug: - # self.logger.debug("Stop.") - break - prefix = "" - lineno, column = end - if value.endswith("\n"): - lineno += 1 - column = 0 - else: - # We never broke out -- EOF is too soon (how can this happen???) - raise parse.ParseError("incomplete input", type, value, line_text) - return p.rootnode - - def parse_stream_raw(self, stream, debug=False): - """Parse a stream and return the syntax tree.""" - tokens = tokenize.generate_tokens(stream.readline) - return self.parse_tokens(tokens, debug) - - def parse_stream(self, stream, debug=False): - """Parse a stream and return the syntax tree.""" - return self.parse_stream_raw(stream, debug) - - def parse_file(self, filename, debug=False): - """Parse a file and return the syntax tree.""" - with open(filename) as stream: - return self.parse_stream(stream, debug) - - def parse_string(self, text, debug=False): - """Parse a string and return the syntax tree.""" - tokens = tokenize.generate_tokens(generate_lines(text).next) - return self.parse_tokens(tokens, debug) - - -def generate_lines(text): - """Generator that behaves like readline without using StringIO.""" - for line in text.splitlines(True): - yield line - while True: - yield "" - - -def get_compiled_path(filename): - head, tail = os.path.splitext(filename) - if tail == ".txt": - tail = "" - return "%s%s.pickle" % (head, tail) - - -def compile_grammar(gt='Grammar.txt', logger=None): - """Compile the grammer.""" - if logger is None: - logger = logging.getLogger() - - logger.info("Generating grammar tables from %s", gt) - g = pgen.generate_grammar(gt) - gp = get_compiled_path(gt) - logger.info("Writing grammar tables to %s", gp) - try: - g.dump(gp) - except IOError as e: - logger.info("Writing failed:"+str(e)) - - -def load_grammar(gt="Grammar.txt", logger=None): - """Load the grammar (maybe from a pickle).""" - if logger is None: - logger = logging.getLogger() - gp = get_compiled_path(gt) - if not os.path.exists(gp): - logger.info("Generating grammar tables from %s", gt) - g = pgen.generate_grammar(gt) - else: - g = grammar.Grammar() - g.load(gp) - return g - - -def _newer(a, b): - """Inquire whether file a was written since file b.""" - if not os.path.exists(a): - return False - if not os.path.exists(b): - return True - return os.path.getmtime(a) >= os.path.getmtime(b) diff --git a/sphinx/pycode/pgen2/grammar.py b/sphinx/pycode/pgen2/grammar.py deleted file mode 100644 index 22d426eec..000000000 --- a/sphinx/pycode/pgen2/grammar.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""This module defines the data structures used to represent a grammar. - -These are a bit arcane because they are derived from the data -structures used by Python's 'pgen' parser generator. - -There's also a table here mapping operators to their names in the -token module; the Python tokenize module reports all operators as the -fallback token code OP, but the parser needs the actual token code. - -""" -from __future__ import print_function - -# Python imports -import pickle - -# Local imports -from sphinx.pycode.pgen2 import token - -if False: - # For type annotation - from typing import Dict, List, Tuple # NOQA - - -class Grammar(object): - """Pgen parsing tables tables conversion class. - - Once initialized, this class supplies the grammar tables for the - parsing engine implemented by parse.py. The parsing engine - accesses the instance variables directly. The class here does not - provide initialization of the tables; several subclasses exist to - do this (see the conv and pgen modules). - - The load() method reads the tables from a pickle file, which is - much faster than the other ways offered by subclasses. The pickle - file is written by calling dump() (after loading the grammar - tables using a subclass). The report() method prints a readable - representation of the tables to stdout, for debugging. - - The instance variables are as follows: - - symbol2number -- a dict mapping symbol names to numbers. Symbol - numbers are always 256 or higher, to distinguish - them from token numbers, which are between 0 and - 255 (inclusive). - - number2symbol -- a dict mapping numbers to symbol names; - these two are each other's inverse. - - states -- a list of DFAs, where each DFA is a list of - states, each state is is a list of arcs, and each - arc is a (i, j) pair where i is a label and j is - a state number. The DFA number is the index into - this list. (This name is slightly confusing.) - Final states are represented by a special arc of - the form (0, j) where j is its own state number. - - dfas -- a dict mapping symbol numbers to (DFA, first) - pairs, where DFA is an item from the states list - above, and first is a set of tokens that can - begin this grammar rule (represented by a dict - whose values are always 1). - - labels -- a list of (x, y) pairs where x is either a token - number or a symbol number, and y is either None - or a string; the strings are keywords. The label - number is the index in this list; label numbers - are used to mark state transitions (arcs) in the - DFAs. - - start -- the number of the grammar's start symbol. - - keywords -- a dict mapping keyword strings to arc labels. - - tokens -- a dict mapping token numbers to arc labels. - - """ - - def __init__(self): - self.symbol2number = {} # type: Dict[unicode, int] - self.number2symbol = {} # type: Dict[int, unicode] - self.states = [] # type: List[List[List[Tuple[int, int]]]] - self.dfas = {} # type: Dict[int, Tuple[List[List[Tuple[int, int]]], unicode]] - self.labels = [(0, "EMPTY")] - self.keywords = {} # type: Dict[unicode, unicode] - self.tokens = {} # type: Dict[unicode, unicode] - self.symbol2label = {} # type: Dict[unicode, unicode] - self.start = 256 - - def dump(self, filename): - """Dump the grammar tables to a pickle file.""" - with open(filename, "wb") as f: - pickle.dump(self.__dict__, f, 2) - - def load(self, filename): - """Load the grammar tables from a pickle file.""" - f = open(filename, "rb") - d = pickle.load(f) - f.close() - self.__dict__.update(d) - - def report(self): - """Dump the grammar tables to standard output, for debugging.""" - from pprint import pprint - print("s2n") - pprint(self.symbol2number) - print("n2s") - pprint(self.number2symbol) - print("states") - pprint(self.states) - print("dfas") - pprint(self.dfas) - print("labels") - pprint(self.labels) - print("start", self.start) - - -# Map from operator to number (since tokenize doesn't do this) - -opmap_raw = """ -( LPAR -) RPAR -[ LSQB -] RSQB -: COLON -, COMMA -; SEMI -+ PLUS -- MINUS -* STAR -/ SLASH -| VBAR -& AMPER -< LESS -> GREATER -= EQUAL -. DOT -% PERCENT -` BACKQUOTE -{ LBRACE -} RBRACE -@ AT -@= ATEQUAL -== EQEQUAL -!= NOTEQUAL -<> NOTEQUAL -<= LESSEQUAL ->= GREATEREQUAL -~ TILDE -^ CIRCUMFLEX -<< LEFTSHIFT ->> RIGHTSHIFT -** DOUBLESTAR -+= PLUSEQUAL --= MINEQUAL -*= STAREQUAL -/= SLASHEQUAL -%= PERCENTEQUAL -&= AMPEREQUAL -|= VBAREQUAL -^= CIRCUMFLEXEQUAL -<<= LEFTSHIFTEQUAL ->>= RIGHTSHIFTEQUAL -**= DOUBLESTAREQUAL -// DOUBLESLASH -//= DOUBLESLASHEQUAL --> RARROW -... ELLIPSIS -""" - -opmap = {} -for line in opmap_raw.splitlines(): - if line: - op, name = line.split() - opmap[op] = getattr(token, name) diff --git a/sphinx/pycode/pgen2/literals.py b/sphinx/pycode/pgen2/literals.py deleted file mode 100644 index 25e09b62d..000000000 --- a/sphinx/pycode/pgen2/literals.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# Extended to handle raw and unicode literals by Georg Brandl. - -"""Safely evaluate Python string literals without using eval().""" -from __future__ import print_function - -import re - -from six import text_type - - -simple_escapes = {"a": "\a", - "b": "\b", - "f": "\f", - "n": "\n", - "r": "\r", - "t": "\t", - "v": "\v", - "'": "'", - '"': '"', - "\\": "\\"} - -def convert_hex(x, n): - if len(x) < n+1: - raise ValueError("invalid hex string escape ('\\%s')" % x) - try: - return int(x[1:], 16) - except ValueError: - raise ValueError("invalid hex string escape ('\\%s')" % x) - -def escape(m): - all, tail = m.group(0, 1) - assert all.startswith("\\") - esc = simple_escapes.get(tail) - if esc is not None: - return esc - elif tail.startswith("x"): - return chr(convert_hex(tail, 2)) - elif tail.startswith('u'): - return unichr(convert_hex(tail, 4)) - elif tail.startswith('U'): - return unichr(convert_hex(tail, 8)) - elif tail.startswith('N'): - import unicodedata - try: - return unicodedata.lookup(tail[1:-1]) - except KeyError: - raise ValueError("undefined character name %r" % tail[1:-1]) - else: - try: - return chr(int(tail, 8)) - except ValueError: - raise ValueError("invalid octal string escape ('\\%s')" % tail) - -def escaperaw(m): - all, tail = m.group(0, 1) - if tail.startswith('u'): - return unichr(convert_hex(tail, 4)) - elif tail.startswith('U'): - return unichr(convert_hex(tail, 8)) - else: - return all - -escape_re = re.compile(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})") -uni_escape_re = re.compile(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3}|" - r"u[0-9a-fA-F]{0,4}|U[0-9a-fA-F]{0,8}|N\{.+?\})") - -def evalString(s, encoding=None): - regex = escape_re - repl = escape - if encoding and not isinstance(s, text_type): - s = s.decode(encoding) - if s.startswith('u') or s.startswith('U'): - regex = uni_escape_re - s = s[1:] - if s.startswith('r') or s.startswith('R'): - repl = escaperaw - s = s[1:] - assert s.startswith("'") or s.startswith('"'), repr(s[:1]) - q = s[0] - if s[:3] == q*3: - q = q*3 - assert s.endswith(q), repr(s[-len(q):]) - assert len(s) >= 2*len(q) - s = s[len(q):-len(q)] - return regex.sub(repl, s) - -def test(): - for i in range(256): - c = chr(i) - s = repr(c) - e = evalString(s) - if e != c: - print(i, c, s, e) - - -if __name__ == "__main__": - test() diff --git a/sphinx/pycode/pgen2/parse.c b/sphinx/pycode/pgen2/parse.c deleted file mode 100644 index 96fa6c8b2..000000000 --- a/sphinx/pycode/pgen2/parse.c +++ /dev/null @@ -1,4544 +0,0 @@ -/* Generated by Cython 0.12 on Fri Jan 22 10:39:58 2010 */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#include "structmember.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#else -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#if PY_VERSION_HEX < 0x02040000 - #define METH_COEXIST 0 - #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) - #define PyDict_Contains(d,o) PySequence_Contains(d,o) -#endif -#if PY_VERSION_HEX < 0x02050000 - typedef int Py_ssize_t; - #define PY_SSIZE_T_MAX INT_MAX - #define PY_SSIZE_T_MIN INT_MIN - #define PY_FORMAT_SIZE_T "" - #define PyInt_FromSsize_t(z) PyInt_FromLong(z) - #define PyInt_AsSsize_t(o) PyInt_AsLong(o) - #define PyNumber_Index(o) PyNumber_Int(o) - #define PyIndex_Check(o) PyNumber_Check(o) -#endif -#if PY_VERSION_HEX < 0x02060000 - #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) - #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) - #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) - #define PyVarObject_HEAD_INIT(type, size) \ - PyObject_HEAD_INIT(type) size, - #define PyType_Modified(t) - - typedef struct { - void *buf; - PyObject *obj; - Py_ssize_t len; - Py_ssize_t itemsize; - int readonly; - int ndim; - char *format; - Py_ssize_t *shape; - Py_ssize_t *strides; - Py_ssize_t *suboffsets; - void *internal; - } Py_buffer; - - #define PyBUF_SIMPLE 0 - #define PyBUF_WRITABLE 0x0001 - #define PyBUF_FORMAT 0x0004 - #define PyBUF_ND 0x0008 - #define PyBUF_STRIDES (0x0010 | PyBUF_ND) - #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) - #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) - #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) - #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) - -#endif -#if PY_MAJOR_VERSION < 3 - #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" -#else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" -#endif -#if PY_MAJOR_VERSION >= 3 - #define Py_TPFLAGS_CHECKTYPES 0 - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3) - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyBaseString_Type PyUnicode_Type - #define PyString_Type PyUnicode_Type - #define PyString_CheckExact PyUnicode_CheckExact -#else - #define PyBytes_Type PyString_Type - #define PyBytes_CheckExact PyString_CheckExact -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyInt_Type PyLong_Type - #define PyInt_Check(op) PyLong_Check(op) - #define PyInt_CheckExact(op) PyLong_CheckExact(op) - #define PyInt_FromString PyLong_FromString - #define PyInt_FromUnicode PyLong_FromUnicode - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyInt_FromSsize_t PyLong_FromSsize_t - #define PyInt_AsLong PyLong_AsLong - #define PyInt_AS_LONG PyLong_AS_LONG - #define PyInt_AsSsize_t PyLong_AsSsize_t - #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask - #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask - #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#else - #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyMethod_New(func, self, klass) PyInstanceMethod_New(func) -#endif -#if !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#else - #define _USE_MATH_DEFINES -#endif -#if PY_VERSION_HEX < 0x02050000 - #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),((char *)(n))) - #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a)) - #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),((char *)(n))) -#else - #define __Pyx_GetAttrString(o,n) PyObject_GetAttrString((o),(n)) - #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a)) - #define __Pyx_DelAttrString(o,n) PyObject_DelAttrString((o),(n)) -#endif -#if PY_VERSION_HEX < 0x02050000 - #define __Pyx_NAMESTR(n) ((char *)(n)) - #define __Pyx_DOCSTR(n) ((char *)(n)) -#else - #define __Pyx_NAMESTR(n) (n) - #define __Pyx_DOCSTR(n) (n) -#endif -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern -#endif -#include -#define __PYX_HAVE_API__sphinx__pycode__pgen2__parse - -#ifdef __GNUC__ -#define INLINE __inline__ -#elif _WIN32 -#define INLINE __inline -#else -#define INLINE -#endif - -typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/ - - -/* Type Conversion Predeclarations */ - -#if PY_MAJOR_VERSION < 3 -#define __Pyx_PyBytes_FromString PyString_FromString -#define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize -#define __Pyx_PyBytes_AsString PyString_AsString -#else -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -#define __Pyx_PyBytes_AsString PyBytes_AsString -#endif - -#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s) -#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) __Pyx_PyBytes_AsString(s)) - -#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) -static INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); - -#if !defined(T_PYSSIZET) -#if PY_VERSION_HEX < 0x02050000 -#define T_PYSSIZET T_INT -#elif !defined(T_LONGLONG) -#define T_PYSSIZET \ - ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \ - ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : -1)) -#else -#define T_PYSSIZET \ - ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \ - ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : \ - ((sizeof(Py_ssize_t) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))) -#endif -#endif - - -#if !defined(T_ULONGLONG) -#define __Pyx_T_UNSIGNED_INT(x) \ - ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \ - ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \ - ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \ - ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : -1)))) -#else -#define __Pyx_T_UNSIGNED_INT(x) \ - ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \ - ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \ - ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \ - ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : \ - ((sizeof(x) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))))) -#endif -#if !defined(T_LONGLONG) -#define __Pyx_T_SIGNED_INT(x) \ - ((sizeof(x) == sizeof(char)) ? T_BYTE : \ - ((sizeof(x) == sizeof(short)) ? T_SHORT : \ - ((sizeof(x) == sizeof(int)) ? T_INT : \ - ((sizeof(x) == sizeof(long)) ? T_LONG : -1)))) -#else -#define __Pyx_T_SIGNED_INT(x) \ - ((sizeof(x) == sizeof(char)) ? T_BYTE : \ - ((sizeof(x) == sizeof(short)) ? T_SHORT : \ - ((sizeof(x) == sizeof(int)) ? T_INT : \ - ((sizeof(x) == sizeof(long)) ? T_LONG : \ - ((sizeof(x) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))))) -#endif - -#define __Pyx_T_FLOATING(x) \ - ((sizeof(x) == sizeof(float)) ? T_FLOAT : \ - ((sizeof(x) == sizeof(double)) ? T_DOUBLE : -1)) - -#if !defined(T_SIZET) -#if !defined(T_ULONGLONG) -#define T_SIZET \ - ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \ - ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : -1)) -#else -#define T_SIZET \ - ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \ - ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : \ - ((sizeof(size_t) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))) -#endif -#endif - -static INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -static INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); - -#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) - - -#ifdef __GNUC__ -/* Test for GCC > 2.95 */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else /* __GNUC__ > 2 ... */ -#define likely(x) (x) -#define unlikely(x) (x) -#endif /* __GNUC__ > 2 ... */ -#else /* __GNUC__ */ -#define likely(x) (x) -#define unlikely(x) (x) -#endif /* __GNUC__ */ - -static PyObject *__pyx_m; -static PyObject *__pyx_b; -static PyObject *__pyx_empty_tuple; -static PyObject *__pyx_empty_bytes; -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * __pyx_cfilenm= __FILE__; -static const char *__pyx_filename; -static const char **__pyx_f; - - -/* Type declarations */ - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":31 - * - * - * cdef class Parser: # <<<<<<<<<<<<<< - * cdef public object grammar - * cdef public object rootnode - */ - -struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser { - PyObject_HEAD - struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_vtab; - PyObject *grammar; - PyObject *rootnode; - PyObject *stack; - PyObject *used_names; - int _grammar_start; - PyObject *_grammar_labels; - PyObject *_grammar_dfas; - PyObject *_grammar_keywords; - PyObject *_grammar_tokens; - PyObject *_grammar_number2symbol; -}; - - -struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser { - int (*classify)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, int, PyObject *, PyObject *); - void (*shift)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *, PyObject *, PyObject *, PyObject *); - void (*push)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *, PyObject *, PyObject *, PyObject *); - void (*pop)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *); - PyObject *(*convert)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *); -}; -static struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_vtabptr_6sphinx_6pycode_5pgen2_5parse_Parser; - -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif - -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, int); - void (*DECREF)(void*, PyObject*, int); - void (*GOTREF)(void*, PyObject*, int); - void (*GIVEREF)(void*, PyObject*, int); - void* (*SetupContext)(const char*, int, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule((char *)modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); - end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; - } - #define __Pyx_RefNannySetupContext(name) void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) - #define __Pyx_RefNannyFinishContext() __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0) -#else - #define __Pyx_RefNannySetupContext(name) - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) -#endif /* CYTHON_REFNANNY */ -#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0) -#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0) - -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, PyObject* kw_name); /*proto*/ - -static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, - Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/ - -static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name); /*proto*/ - -static INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { - PyObject *r; - if (!j) return NULL; - r = PyObject_GetItem(o, j); - Py_DECREF(j); - return r; -} - - -#define __Pyx_GetItemInt_List(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ - __Pyx_GetItemInt_List_Fast(o, i, size <= sizeof(long)) : \ - __Pyx_GetItemInt_Generic(o, to_py_func(i))) - -static INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, int fits_long) { - if (likely(o != Py_None)) { - if (likely((0 <= i) & (i < PyList_GET_SIZE(o)))) { - PyObject *r = PyList_GET_ITEM(o, i); - Py_INCREF(r); - return r; - } - else if ((-PyList_GET_SIZE(o) <= i) & (i < 0)) { - PyObject *r = PyList_GET_ITEM(o, PyList_GET_SIZE(o) + i); - Py_INCREF(r); - return r; - } - } - return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); -} - -#define __Pyx_GetItemInt_Tuple(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ - __Pyx_GetItemInt_Tuple_Fast(o, i, size <= sizeof(long)) : \ - __Pyx_GetItemInt_Generic(o, to_py_func(i))) - -static INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, int fits_long) { - if (likely(o != Py_None)) { - if (likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { - PyObject *r = PyTuple_GET_ITEM(o, i); - Py_INCREF(r); - return r; - } - else if ((-PyTuple_GET_SIZE(o) <= i) & (i < 0)) { - PyObject *r = PyTuple_GET_ITEM(o, PyTuple_GET_SIZE(o) + i); - Py_INCREF(r); - return r; - } - } - return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); -} - - -#define __Pyx_GetItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ - __Pyx_GetItemInt_Fast(o, i, size <= sizeof(long)) : \ - __Pyx_GetItemInt_Generic(o, to_py_func(i))) - -static INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) { - PyObject *r; - if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { - r = PyList_GET_ITEM(o, i); - Py_INCREF(r); - } - else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) { - r = PyTuple_GET_ITEM(o, i); - Py_INCREF(r); - } - else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) { - r = PySequence_GetItem(o, i); - } - else { - r = __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i)); - } - return r; -} - -static INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); - -static INLINE void __Pyx_RaiseTooManyValuesError(void); - -static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/ -static int __Pyx_EndUnpack(PyObject *); /*proto*/ - -static INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; } -static INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) { - return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b); -} - -static INLINE void __Pyx_RaiseNoneNotIterableError(void); - -static INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { - if (likely(PyList_CheckExact(L))) { - if (PyList_Append(L, x) < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; /* this is just to have an accurate signature */ - } - else { - PyObject *r, *m; - m = __Pyx_GetAttrString(L, "append"); - if (!m) return NULL; - r = PyObject_CallFunctionObjArgs(m, x, NULL); - Py_DECREF(m); - return r; - } -} - -#define __Pyx_SetItemInt(o, i, v, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \ - __Pyx_SetItemInt_Fast(o, i, v, size <= sizeof(long)) : \ - __Pyx_SetItemInt_Generic(o, to_py_func(i), v)) - -static INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { - int r; - if (!j) return -1; - r = PyObject_SetItem(o, j, v); - Py_DECREF(j); - return r; -} - -static INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int fits_long) { - if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) { - Py_INCREF(v); - Py_DECREF(PyList_GET_ITEM(o, i)); - PyList_SET_ITEM(o, i, v); - return 1; - } - else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0))) - return PySequence_SetItem(o, i, v); - else { - PyObject *j = fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i); - return __Pyx_SetItemInt_Generic(o, j, v); - } -} - -static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/ - -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/ - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ - -static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, const char *modname); /*proto*/ - -static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ - -static INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *); - -static INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *); - -static INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *); - -static INLINE char __Pyx_PyInt_AsChar(PyObject *); - -static INLINE short __Pyx_PyInt_AsShort(PyObject *); - -static INLINE int __Pyx_PyInt_AsInt(PyObject *); - -static INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *); - -static INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *); - -static INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *); - -static INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *); - -static INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *); - -static INLINE long __Pyx_PyInt_AsLong(PyObject *); - -static INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *); - -static INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *); - -static INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *); - -static void __Pyx_WriteUnraisable(const char *name); /*proto*/ - -static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/ - -static void __Pyx_AddTraceback(const char *funcname); /*proto*/ - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -/* Module declarations from sphinx.pycode.pgen2.parse */ - -static PyTypeObject *__pyx_ptype_6sphinx_6pycode_5pgen2_5parse_Parser = 0; -#define __Pyx_MODULE_NAME "sphinx.pycode.pgen2.parse" -int __pyx_module_is_main_sphinx__pycode__pgen2__parse = 0; - -/* Implementation of sphinx.pycode.pgen2.parse */ -static PyObject *__pyx_builtin_Exception; -static char __pyx_k_1[] = "%s: type=%r, value=%r, context=%r"; -static char __pyx_k_2[] = "_grammar_number2symbol"; -static char __pyx_k_3[] = "too much input"; -static char __pyx_k_4[] = "bad input"; -static char __pyx_k_5[] = "bad token"; -static char __pyx_k_6[] = "Parser engine for the grammar tables generated by pgen.\n\nThe grammar table must be loaded first.\n\nSee Parser/parser.c in the Python distribution for additional info on\nhow this parsing engine works.\n\n"; -static char __pyx_k_7[] = "sphinx.pycode.nodes"; -static char __pyx_k_8[] = "Exception to signal the parser is stuck."; -static char __pyx_k_9[] = "Parser.addtoken (line 66)"; -static char __pyx_k__add[] = "add"; -static char __pyx_k__msg[] = "msg"; -static char __pyx_k__pop[] = "pop"; -static char __pyx_k__Leaf[] = "Leaf"; -static char __pyx_k__Node[] = "Node"; -static char __pyx_k__dfas[] = "dfas"; -static char __pyx_k__push[] = "push"; -static char __pyx_k__self[] = "self"; -static char __pyx_k__type[] = "type"; -static char __pyx_k__shift[] = "shift"; -static char __pyx_k__stack[] = "stack"; -static char __pyx_k__start[] = "start"; -static char __pyx_k__value[] = "value"; -static char __pyx_k__Parser[] = "Parser"; -static char __pyx_k__labels[] = "labels"; -static char __pyx_k__tokens[] = "tokens"; -static char __pyx_k__context[] = "context"; -static char __pyx_k__convert[] = "convert"; -static char __pyx_k__grammar[] = "grammar"; -static char __pyx_k____init__[] = "__init__"; -static char __pyx_k____main__[] = "__main__"; -static char __pyx_k____test__[] = "__test__"; -static char __pyx_k__addtoken[] = "addtoken"; -static char __pyx_k__classify[] = "classify"; -static char __pyx_k__keywords[] = "keywords"; -static char __pyx_k__rootnode[] = "rootnode"; -static char __pyx_k__Exception[] = "Exception"; -static char __pyx_k__ParseError[] = "ParseError"; -static char __pyx_k__used_names[] = "used_names"; -static char __pyx_k___grammar_dfas[] = "_grammar_dfas"; -static char __pyx_k__number2symbol[] = "number2symbol"; -static char __pyx_k___grammar_start[] = "_grammar_start"; -static char __pyx_k___grammar_labels[] = "_grammar_labels"; -static char __pyx_k___grammar_tokens[] = "_grammar_tokens"; -static char __pyx_k___grammar_keywords[] = "_grammar_keywords"; -static PyObject *__pyx_kp_s_1; -static PyObject *__pyx_n_s_2; -static PyObject *__pyx_kp_s_3; -static PyObject *__pyx_kp_s_4; -static PyObject *__pyx_kp_s_5; -static PyObject *__pyx_n_s_7; -static PyObject *__pyx_kp_s_8; -static PyObject *__pyx_kp_u_9; -static PyObject *__pyx_n_s__Exception; -static PyObject *__pyx_n_s__Leaf; -static PyObject *__pyx_n_s__Node; -static PyObject *__pyx_n_s__ParseError; -static PyObject *__pyx_n_s__Parser; -static PyObject *__pyx_n_s____init__; -static PyObject *__pyx_n_s____main__; -static PyObject *__pyx_n_s____test__; -static PyObject *__pyx_n_s___grammar_dfas; -static PyObject *__pyx_n_s___grammar_keywords; -static PyObject *__pyx_n_s___grammar_labels; -static PyObject *__pyx_n_s___grammar_start; -static PyObject *__pyx_n_s___grammar_tokens; -static PyObject *__pyx_n_s__add; -static PyObject *__pyx_n_s__addtoken; -static PyObject *__pyx_n_s__classify; -static PyObject *__pyx_n_s__context; -static PyObject *__pyx_n_s__convert; -static PyObject *__pyx_n_s__dfas; -static PyObject *__pyx_n_s__grammar; -static PyObject *__pyx_n_s__keywords; -static PyObject *__pyx_n_s__labels; -static PyObject *__pyx_n_s__msg; -static PyObject *__pyx_n_s__number2symbol; -static PyObject *__pyx_n_s__pop; -static PyObject *__pyx_n_s__push; -static PyObject *__pyx_n_s__rootnode; -static PyObject *__pyx_n_s__self; -static PyObject *__pyx_n_s__shift; -static PyObject *__pyx_n_s__stack; -static PyObject *__pyx_n_s__start; -static PyObject *__pyx_n_s__tokens; -static PyObject *__pyx_n_s__type; -static PyObject *__pyx_n_s__used_names; -static PyObject *__pyx_n_s__value; -static PyObject *__pyx_int_0; - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":22 - * """Exception to signal the parser is stuck.""" - * - * def __init__(self, msg, type, value, context): # <<<<<<<<<<<<<< - * Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - * (msg, type, value, context)) - */ - -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_10ParseError___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyMethodDef __pyx_mdef_6sphinx_6pycode_5pgen2_5parse_10ParseError___init__ = {__Pyx_NAMESTR("__init__"), (PyCFunction)__pyx_pf_6sphinx_6pycode_5pgen2_5parse_10ParseError___init__, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)}; -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_10ParseError___init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_msg = 0; - PyObject *__pyx_v_type = 0; - PyObject *__pyx_v_value = 0; - PyObject *__pyx_v_context = 0; - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__self,&__pyx_n_s__msg,&__pyx_n_s__type,&__pyx_n_s__value,&__pyx_n_s__context,0}; - __Pyx_RefNannySetupContext("__init__"); - __pyx_self = __pyx_self; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[5] = {0,0,0,0,0}; - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); - case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__self); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__msg); - if (likely(values[1])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 5, 5, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 2: - values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__type); - if (likely(values[2])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 5, 5, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 3: - values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__value); - if (likely(values[3])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 5, 5, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 4: - values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__context); - if (likely(values[4])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 5, 5, 4); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_self = values[0]; - __pyx_v_msg = values[1]; - __pyx_v_type = values[2]; - __pyx_v_value = values[3]; - __pyx_v_context = values[4]; - } else if (PyTuple_GET_SIZE(__pyx_args) != 5) { - goto __pyx_L5_argtuple_error; - } else { - __pyx_v_self = PyTuple_GET_ITEM(__pyx_args, 0); - __pyx_v_msg = PyTuple_GET_ITEM(__pyx_args, 1); - __pyx_v_type = PyTuple_GET_ITEM(__pyx_args, 2); - __pyx_v_value = PyTuple_GET_ITEM(__pyx_args, 3); - __pyx_v_context = PyTuple_GET_ITEM(__pyx_args, 4); - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 5, 5, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_L3_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.ParseError.__init__"); - return NULL; - __pyx_L4_argument_unpacking_done:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":23 - * - * def __init__(self, msg, type, value, context): - * Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % # <<<<<<<<<<<<<< - * (msg, type, value, context)) - * self.msg = msg - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_builtin_Exception, __pyx_n_s____init__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":24 - * def __init__(self, msg, type, value, context): - * Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - * (msg, type, value, context)) # <<<<<<<<<<<<<< - * self.msg = msg - * self.type = type - */ - __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_v_msg); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_msg); - __Pyx_GIVEREF(__pyx_v_msg); - __Pyx_INCREF(__pyx_v_type); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_type); - __Pyx_GIVEREF(__pyx_v_type); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_1), __pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_v_self); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_self); - __Pyx_GIVEREF(__pyx_v_self); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_3); - __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_t_1, __pyx_t_2, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":25 - * Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - * (msg, type, value, context)) - * self.msg = msg # <<<<<<<<<<<<<< - * self.type = type - * self.value = value - */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__msg, __pyx_v_msg) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":26 - * (msg, type, value, context)) - * self.msg = msg - * self.type = type # <<<<<<<<<<<<<< - * self.value = value - * self.context = context - */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__type, __pyx_v_type) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":27 - * self.msg = msg - * self.type = type - * self.value = value # <<<<<<<<<<<<<< - * self.context = context - * - */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__value, __pyx_v_value) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":28 - * self.type = type - * self.value = value - * self.context = context # <<<<<<<<<<<<<< - * - * - */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__context, __pyx_v_context) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.ParseError.__init__"); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":34 - * cdef public object grammar - * cdef public object rootnode - * cdef public list stack # <<<<<<<<<<<<<< - * cdef public set used_names - * cdef int _grammar_start - */ - -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___get__(PyObject *__pyx_v_self); /*proto*/ -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___get__(PyObject *__pyx_v_self) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannySetupContext("__get__"); - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack)); - __pyx_r = ((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack); - goto __pyx_L0; - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/ -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) { - int __pyx_r; - __Pyx_RefNannySetupContext("__set__"); - if (!(likely(PyList_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected list, got %.200s", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_INCREF(__pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack = ((PyObject *)__pyx_v_value); - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.stack.__set__"); - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":35 - * cdef public object rootnode - * cdef public list stack - * cdef public set used_names # <<<<<<<<<<<<<< - * cdef int _grammar_start - * cdef list _grammar_labels - */ - -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___get__(PyObject *__pyx_v_self); /*proto*/ -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___get__(PyObject *__pyx_v_self) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannySetupContext("__get__"); - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names)); - __pyx_r = ((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names); - goto __pyx_L0; - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/ -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) { - int __pyx_r; - __Pyx_RefNannySetupContext("__set__"); - if (!(likely(PyAnySet_CheckExact(__pyx_v_value))||((__pyx_v_value) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected set, got %.200s", Py_TYPE(__pyx_v_value)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_INCREF(__pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names = ((PyObject *)__pyx_v_value); - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.used_names.__set__"); - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":43 - * cdef dict _grammar_number2symbol - * - * def __init__(self, grammar, convert=None): # <<<<<<<<<<<<<< - * self.grammar = grammar - * #self.convert = convert or noconvert - */ - -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_grammar = 0; - PyObject *__pyx_v_convert = 0; - int __pyx_r; - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__grammar,&__pyx_n_s__convert,0}; - __Pyx_RefNannySetupContext("__init__"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[2] = {0,0}; - values[1] = ((PyObject *)Py_None); - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__grammar); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - if (kw_args > 1) { - PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__convert); - if (unlikely(value)) { values[1] = value; kw_args--; } - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_grammar = values[0]; - __pyx_v_convert = values[1]; - } else { - __pyx_v_convert = ((PyObject *)Py_None); - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 2: __pyx_v_convert = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: __pyx_v_grammar = PyTuple_GET_ITEM(__pyx_args, 0); - break; - default: goto __pyx_L5_argtuple_error; - } - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_L3_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.__init__"); - return -1; - __pyx_L4_argument_unpacking_done:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":44 - * - * def __init__(self, grammar, convert=None): - * self.grammar = grammar # <<<<<<<<<<<<<< - * #self.convert = convert or noconvert - * - */ - __Pyx_INCREF(__pyx_v_grammar); - __Pyx_GIVEREF(__pyx_v_grammar); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->grammar); - __Pyx_DECREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->grammar); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->grammar = __pyx_v_grammar; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":47 - * #self.convert = convert or noconvert - * - * self._grammar_dfas = grammar.dfas # <<<<<<<<<<<<<< - * self._grammar_labels = grammar.labels - * self._grammar_keywords = grammar.keywords - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__dfas); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected dict, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_dfas); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_dfas)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_dfas = ((PyObject *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":48 - * - * self._grammar_dfas = grammar.dfas - * self._grammar_labels = grammar.labels # <<<<<<<<<<<<<< - * self._grammar_keywords = grammar.keywords - * self._grammar_tokens = grammar.tokens - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__labels); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyList_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected list, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_labels); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_labels)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_labels = ((PyObject *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":49 - * self._grammar_dfas = grammar.dfas - * self._grammar_labels = grammar.labels - * self._grammar_keywords = grammar.keywords # <<<<<<<<<<<<<< - * self._grammar_tokens = grammar.tokens - * self._grammar_number2symbol = grammar.number2symbol - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__keywords); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected dict, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_keywords); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_keywords)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_keywords = ((PyObject *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":50 - * self._grammar_labels = grammar.labels - * self._grammar_keywords = grammar.keywords - * self._grammar_tokens = grammar.tokens # <<<<<<<<<<<<<< - * self._grammar_number2symbol = grammar.number2symbol - * self._grammar_start = grammar.start - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__tokens); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected dict, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_tokens); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_tokens)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_tokens = ((PyObject *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":51 - * self._grammar_keywords = grammar.keywords - * self._grammar_tokens = grammar.tokens - * self._grammar_number2symbol = grammar.number2symbol # <<<<<<<<<<<<<< - * self._grammar_start = grammar.start - * - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__number2symbol); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyDict_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected dict, got %.200s", Py_TYPE(__pyx_t_1)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_number2symbol); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_number2symbol)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_number2symbol = ((PyObject *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":52 - * self._grammar_tokens = grammar.tokens - * self._grammar_number2symbol = grammar.number2symbol - * self._grammar_start = grammar.start # <<<<<<<<<<<<<< - * - * def setup(self, start=None): - */ - __pyx_t_1 = PyObject_GetAttr(__pyx_v_grammar, __pyx_n_s__start); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_start = __pyx_t_2; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.__init__"); - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":54 - * self._grammar_start = grammar.start - * - * def setup(self, start=None): # <<<<<<<<<<<<<< - * if start is None: - * start = self._grammar_start - */ - -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_setup(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_setup(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_start = 0; - PyObject *__pyx_v_newnode; - PyObject *__pyx_v_stackentry; - PyObject *__pyx_r = NULL; - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__start,0}; - __Pyx_RefNannySetupContext("setup"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[1] = {0}; - values[0] = ((PyObject *)Py_None); - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - if (kw_args > 1) { - PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__start); - if (unlikely(value)) { values[0] = value; kw_args--; } - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "setup") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_start = values[0]; - } else { - __pyx_v_start = ((PyObject *)Py_None); - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 1: __pyx_v_start = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("setup", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_L3_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.setup"); - return NULL; - __pyx_L4_argument_unpacking_done:; - __Pyx_INCREF((PyObject *)__pyx_v_self); - __Pyx_INCREF(__pyx_v_start); - __pyx_v_newnode = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_stackentry = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":55 - * - * def setup(self, start=None): - * if start is None: # <<<<<<<<<<<<<< - * start = self._grammar_start - * # Each stack entry is a tuple: (dfa, state, node). - */ - __pyx_t_1 = (__pyx_v_start == Py_None); - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":56 - * def setup(self, start=None): - * if start is None: - * start = self._grammar_start # <<<<<<<<<<<<<< - * # Each stack entry is a tuple: (dfa, state, node). - * # A node is a tuple: (type, value, context, children), - */ - __pyx_t_2 = PyInt_FromLong(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_start); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_v_start); - __pyx_v_start = __pyx_t_2; - __pyx_t_2 = 0; - goto __pyx_L6; - } - __pyx_L6:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":60 - * # A node is a tuple: (type, value, context, children), - * # where children is a list of nodes or None, and context may be None. - * newnode = (start, None, None, []) # <<<<<<<<<<<<<< - * stackentry = (self._grammar_dfas[start], 0, newnode) - * self.stack = [stackentry] - */ - __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - __pyx_t_3 = PyTuple_New(4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_INCREF(__pyx_v_start); - PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_start); - __Pyx_GIVEREF(__pyx_v_start); - __Pyx_INCREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_3, 1, Py_None); - __Pyx_GIVEREF(Py_None); - __Pyx_INCREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_3, 2, Py_None); - __Pyx_GIVEREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_3, 3, ((PyObject *)__pyx_t_2)); - __Pyx_GIVEREF(((PyObject *)__pyx_t_2)); - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_newnode); - __pyx_v_newnode = __pyx_t_3; - __pyx_t_3 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":61 - * # where children is a list of nodes or None, and context may be None. - * newnode = (start, None, None, []) - * stackentry = (self._grammar_dfas[start], 0, newnode) # <<<<<<<<<<<<<< - * self.stack = [stackentry] - * self.rootnode = None - */ - __pyx_t_3 = PyObject_GetItem(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_dfas), __pyx_v_start); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_3); - __Pyx_INCREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_0); - __Pyx_GIVEREF(__pyx_int_0); - __Pyx_INCREF(__pyx_v_newnode); - PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_v_newnode); - __Pyx_GIVEREF(__pyx_v_newnode); - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_stackentry); - __pyx_v_stackentry = __pyx_t_2; - __pyx_t_2 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":62 - * newnode = (start, None, None, []) - * stackentry = (self._grammar_dfas[start], 0, newnode) - * self.stack = [stackentry] # <<<<<<<<<<<<<< - * self.rootnode = None - * self.used_names = set() # Aliased to self.rootnode.used_names in pop() - */ - __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - __Pyx_INCREF(__pyx_v_stackentry); - PyList_SET_ITEM(__pyx_t_2, 0, __pyx_v_stackentry); - __Pyx_GIVEREF(__pyx_v_stackentry); - __Pyx_GIVEREF(((PyObject *)__pyx_t_2)); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack = __pyx_t_2; - __pyx_t_2 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":63 - * stackentry = (self._grammar_dfas[start], 0, newnode) - * self.stack = [stackentry] - * self.rootnode = None # <<<<<<<<<<<<<< - * self.used_names = set() # Aliased to self.rootnode.used_names in pop() - * - */ - __Pyx_INCREF(Py_None); - __Pyx_GIVEREF(Py_None); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->rootnode); - __Pyx_DECREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->rootnode); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->rootnode = Py_None; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":64 - * self.stack = [stackentry] - * self.rootnode = None - * self.used_names = set() # Aliased to self.rootnode.used_names in pop() # <<<<<<<<<<<<<< - * - * def addtoken(self, int type, value, context): - */ - __pyx_t_2 = PySet_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - if (!(likely(PyAnySet_CheckExact(((PyObject *)__pyx_t_2)))||((((PyObject *)__pyx_t_2)) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected set, got %.200s", Py_TYPE(((PyObject *)__pyx_t_2))->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GIVEREF(__pyx_t_2); - __Pyx_GOTREF(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names); - __Pyx_DECREF(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names)); - ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->used_names = ((PyObject *)__pyx_t_2); - __pyx_t_2 = 0; - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.setup"); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_DECREF(__pyx_v_newnode); - __Pyx_DECREF(__pyx_v_stackentry); - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_DECREF(__pyx_v_start); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":66 - * self.used_names = set() # Aliased to self.rootnode.used_names in pop() - * - * def addtoken(self, int type, value, context): # <<<<<<<<<<<<<< - * """Add a token; return True iff this is the end of the program.""" - * cdef int ilabel, i, t, state, newstate - */ - -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_addtoken(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_6sphinx_6pycode_5pgen2_5parse_6Parser_addtoken[] = "Add a token; return True iff this is the end of the program."; -static PyObject *__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_addtoken(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_type; - PyObject *__pyx_v_value = 0; - PyObject *__pyx_v_context = 0; - int __pyx_v_ilabel; - int __pyx_v_i; - int __pyx_v_t; - int __pyx_v_state; - int __pyx_v_newstate; - PyObject *__pyx_v_dfa; - PyObject *__pyx_v_node; - PyObject *__pyx_v_states; - PyObject *__pyx_v_first; - PyObject *__pyx_v_arcs; - PyObject *__pyx_v_v; - PyObject *__pyx_v_itsdfa; - PyObject *__pyx_v_itsstates; - PyObject *__pyx_v_itsfirst; - PyObject *__pyx_r = NULL; - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - PyObject *__pyx_t_7 = NULL; - Py_ssize_t __pyx_t_8; - int __pyx_t_9; - int __pyx_t_10; - PyObject *__pyx_t_11 = NULL; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__type,&__pyx_n_s__value,&__pyx_n_s__context,0}; - __Pyx_RefNannySetupContext("addtoken"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[3] = {0,0,0}; - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__type); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__value); - if (likely(values[1])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("addtoken", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 2: - values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__context); - if (likely(values[2])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("addtoken", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "addtoken") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_type = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_type == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_value = values[1]; - __pyx_v_context = values[2]; - } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { - goto __pyx_L5_argtuple_error; - } else { - __pyx_v_type = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_type == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_value = PyTuple_GET_ITEM(__pyx_args, 1); - __pyx_v_context = PyTuple_GET_ITEM(__pyx_args, 2); - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("addtoken", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_L3_error:; - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.addtoken"); - return NULL; - __pyx_L4_argument_unpacking_done:; - __Pyx_INCREF((PyObject *)__pyx_v_self); - __Pyx_INCREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - __pyx_v_dfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_node = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_states = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_first = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_arcs = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_v = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_itsdfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_itsstates = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_itsfirst = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":70 - * cdef int ilabel, i, t, state, newstate - * # Map from token to label - * ilabel = self.classify(type, value, context) # <<<<<<<<<<<<<< - * # Loop until the token is shifted; may raise exceptions - * while True: - */ - __pyx_v_ilabel = ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->__pyx_vtab)->classify(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self), __pyx_v_type, __pyx_v_value, __pyx_v_context); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":72 - * ilabel = self.classify(type, value, context) - * # Loop until the token is shifted; may raise exceptions - * while True: # <<<<<<<<<<<<<< - * dfa, state, node = self.stack[-1] - * states, first = dfa - */ - while (1) { - __pyx_t_1 = 1; - if (!__pyx_t_1) break; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":73 - * # Loop until the token is shifted; may raise exceptions - * while True: - * dfa, state, node = self.stack[-1] # <<<<<<<<<<<<<< - * states, first = dfa - * arcs = states[state] - */ - __pyx_t_2 = __Pyx_GetItemInt_List(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 3)) { - PyObject* tuple = __pyx_t_2; - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_5 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_3; - __pyx_t_3 = 0; - __pyx_v_state = __pyx_t_6; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_5; - __pyx_t_5 = 0; - } else { - __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_7, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_7, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_7, 2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - if (__Pyx_EndUnpack(__pyx_t_7) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_3; - __pyx_t_3 = 0; - __pyx_v_state = __pyx_t_6; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_5; - __pyx_t_5 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":74 - * while True: - * dfa, state, node = self.stack[-1] - * states, first = dfa # <<<<<<<<<<<<<< - * arcs = states[state] - * # Look for a state with this label - */ - if (PyTuple_CheckExact(__pyx_v_dfa) && likely(PyTuple_GET_SIZE(__pyx_v_dfa) == 2)) { - PyObject* tuple = __pyx_v_dfa; - __pyx_t_2 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_2); - __pyx_t_5 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_5); - __Pyx_DECREF(__pyx_v_states); - __pyx_v_states = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_first); - __pyx_v_first = __pyx_t_5; - __pyx_t_5 = 0; - } else { - __pyx_t_4 = PyObject_GetIter(__pyx_v_dfa); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_4, 0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = __Pyx_UnpackItem(__pyx_t_4, 1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - if (__Pyx_EndUnpack(__pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_v_states); - __pyx_v_states = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_first); - __pyx_v_first = __pyx_t_5; - __pyx_t_5 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":75 - * dfa, state, node = self.stack[-1] - * states, first = dfa - * arcs = states[state] # <<<<<<<<<<<<<< - * # Look for a state with this label - * for i, newstate in arcs: - */ - __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_states, __pyx_v_state, sizeof(int), PyInt_FromLong); if (!__pyx_t_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_v_arcs); - __pyx_v_arcs = __pyx_t_5; - __pyx_t_5 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":77 - * arcs = states[state] - * # Look for a state with this label - * for i, newstate in arcs: # <<<<<<<<<<<<<< - * t, v = self._grammar_labels[i] - * if ilabel == i: - */ - if (PyList_CheckExact(__pyx_v_arcs) || PyTuple_CheckExact(__pyx_v_arcs)) { - __pyx_t_8 = 0; __pyx_t_5 = __pyx_v_arcs; __Pyx_INCREF(__pyx_t_5); - } else { - __pyx_t_8 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_v_arcs); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - } - for (;;) { - if (likely(PyList_CheckExact(__pyx_t_5))) { - if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_5)) break; - __pyx_t_2 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++; - } else if (likely(PyTuple_CheckExact(__pyx_t_5))) { - if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_5)) break; - __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++; - } else { - __pyx_t_2 = PyIter_Next(__pyx_t_5); - if (!__pyx_t_2) { - if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - break; - } - __Pyx_GOTREF(__pyx_t_2); - } - if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 2)) { - PyObject* tuple = __pyx_t_2; - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __pyx_t_9 = __Pyx_PyInt_AsInt(__pyx_t_3); if (unlikely((__pyx_t_9 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_v_i = __pyx_t_6; - __pyx_v_newstate = __pyx_t_9; - } else { - __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_7, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_9 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_9 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_7, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_3); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_EndUnpack(__pyx_t_7) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_v_i = __pyx_t_9; - __pyx_v_newstate = __pyx_t_6; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":78 - * # Look for a state with this label - * for i, newstate in arcs: - * t, v = self._grammar_labels[i] # <<<<<<<<<<<<<< - * if ilabel == i: - * # Look it up in the list of labels - */ - __pyx_t_2 = __Pyx_GetItemInt_List(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_labels), __pyx_v_i, sizeof(int), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 2)) { - PyObject* tuple = __pyx_t_2; - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_3); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_3); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_v_t = __pyx_t_6; - __Pyx_DECREF(__pyx_v_v); - __pyx_v_v = __pyx_t_4; - __pyx_t_4 = 0; - } else { - __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_7, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_3); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_7, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - if (__Pyx_EndUnpack(__pyx_t_7) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_v_t = __pyx_t_6; - __Pyx_DECREF(__pyx_v_v); - __pyx_v_v = __pyx_t_4; - __pyx_t_4 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":79 - * for i, newstate in arcs: - * t, v = self._grammar_labels[i] - * if ilabel == i: # <<<<<<<<<<<<<< - * # Look it up in the list of labels - * ## assert t < 256 - */ - __pyx_t_1 = (__pyx_v_ilabel == __pyx_v_i); - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":83 - * ## assert t < 256 - * # Shift a token; we're done with it - * self.shift(type, value, newstate, context) # <<<<<<<<<<<<<< - * # Pop while we are in an accept-only state - * state = newstate - */ - __pyx_t_2 = PyInt_FromLong(__pyx_v_type); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 83; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_4 = PyInt_FromLong(__pyx_v_newstate); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 83; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->__pyx_vtab)->shift(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self), __pyx_t_2, __pyx_v_value, __pyx_t_4, __pyx_v_context); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":85 - * self.shift(type, value, newstate, context) - * # Pop while we are in an accept-only state - * state = newstate # <<<<<<<<<<<<<< - * while states[state] == [(0, state)]: - * self.pop() - */ - __pyx_v_state = __pyx_v_newstate; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":86 - * # Pop while we are in an accept-only state - * state = newstate - * while states[state] == [(0, state)]: # <<<<<<<<<<<<<< - * self.pop() - * if not self.stack: - */ - while (1) { - __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_states, __pyx_v_state, sizeof(int), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_2 = PyInt_FromLong(__pyx_v_state); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_INCREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_int_0); - __Pyx_GIVEREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2); - __Pyx_GIVEREF(__pyx_t_2); - __pyx_t_2 = 0; - __pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - PyList_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_3); - __pyx_t_3 = 0; - __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, ((PyObject *)__pyx_t_2), Py_EQ); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; - __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (!__pyx_t_1) break; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":87 - * state = newstate - * while states[state] == [(0, state)]: - * self.pop() # <<<<<<<<<<<<<< - * if not self.stack: - * # Done parsing! - */ - ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->__pyx_vtab)->pop(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":88 - * while states[state] == [(0, state)]: - * self.pop() - * if not self.stack: # <<<<<<<<<<<<<< - * # Done parsing! - * return True - */ - __pyx_t_1 = __Pyx_PyObject_IsTrue(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack)); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_10 = (!__pyx_t_1); - if (__pyx_t_10) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":90 - * if not self.stack: - * # Done parsing! - * return True # <<<<<<<<<<<<<< - * dfa, state, node = self.stack[-1] - * states, first = dfa - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = __Pyx_PyBool_FromLong(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_r = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - goto __pyx_L0; - goto __pyx_L13; - } - __pyx_L13:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":91 - * # Done parsing! - * return True - * dfa, state, node = self.stack[-1] # <<<<<<<<<<<<<< - * states, first = dfa - * # Done with this token - */ - __pyx_t_3 = __Pyx_GetItemInt_List(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - if (PyTuple_CheckExact(__pyx_t_3) && likely(PyTuple_GET_SIZE(__pyx_t_3) == 3)) { - PyObject* tuple = __pyx_t_3; - __pyx_t_2 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_2); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_7 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __pyx_v_state = __pyx_t_6; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_7; - __pyx_t_7 = 0; - } else { - __pyx_t_11 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_11, 0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_11, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_6 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_7 = __Pyx_UnpackItem(__pyx_t_11, 2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - if (__Pyx_EndUnpack(__pyx_t_11) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __pyx_v_state = __pyx_t_6; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_7; - __pyx_t_7 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":92 - * return True - * dfa, state, node = self.stack[-1] - * states, first = dfa # <<<<<<<<<<<<<< - * # Done with this token - * return False - */ - if (PyTuple_CheckExact(__pyx_v_dfa) && likely(PyTuple_GET_SIZE(__pyx_v_dfa) == 2)) { - PyObject* tuple = __pyx_v_dfa; - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_3); - __pyx_t_7 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_7); - __Pyx_DECREF(__pyx_v_states); - __pyx_v_states = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_first); - __pyx_v_first = __pyx_t_7; - __pyx_t_7 = 0; - } else { - __pyx_t_4 = PyObject_GetIter(__pyx_v_dfa); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_4, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7 = __Pyx_UnpackItem(__pyx_t_4, 1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - if (__Pyx_EndUnpack(__pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_v_states); - __pyx_v_states = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_first); - __pyx_v_first = __pyx_t_7; - __pyx_t_7 = 0; - } - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":94 - * states, first = dfa - * # Done with this token - * return False # <<<<<<<<<<<<<< - * elif t >= 256: - * # See if it's a symbol and if we're in its first set - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_7 = __Pyx_PyBool_FromLong(0); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __pyx_r = __pyx_t_7; - __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - goto __pyx_L0; - goto __pyx_L10; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":95 - * # Done with this token - * return False - * elif t >= 256: # <<<<<<<<<<<<<< - * # See if it's a symbol and if we're in its first set - * itsdfa = self._grammar_dfas[t] - */ - __pyx_t_10 = (__pyx_v_t >= 256); - if (__pyx_t_10) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":97 - * elif t >= 256: - * # See if it's a symbol and if we're in its first set - * itsdfa = self._grammar_dfas[t] # <<<<<<<<<<<<<< - * itsstates, itsfirst = itsdfa - * if ilabel in itsfirst: - */ - __pyx_t_7 = __Pyx_GetItemInt(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->_grammar_dfas), __pyx_v_t, sizeof(int), PyInt_FromLong); if (!__pyx_t_7) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_v_itsdfa); - __pyx_v_itsdfa = __pyx_t_7; - __pyx_t_7 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":98 - * # See if it's a symbol and if we're in its first set - * itsdfa = self._grammar_dfas[t] - * itsstates, itsfirst = itsdfa # <<<<<<<<<<<<<< - * if ilabel in itsfirst: - * # Push a symbol - */ - if (PyTuple_CheckExact(__pyx_v_itsdfa) && likely(PyTuple_GET_SIZE(__pyx_v_itsdfa) == 2)) { - PyObject* tuple = __pyx_v_itsdfa; - __pyx_t_7 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_7); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __Pyx_DECREF(__pyx_v_itsstates); - __pyx_v_itsstates = __pyx_t_7; - __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_v_itsfirst); - __pyx_v_itsfirst = __pyx_t_3; - __pyx_t_3 = 0; - } else { - __pyx_t_4 = PyObject_GetIter(__pyx_v_itsdfa); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_7 = __Pyx_UnpackItem(__pyx_t_4, 0); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_4, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - if (__Pyx_EndUnpack(__pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_v_itsstates); - __pyx_v_itsstates = __pyx_t_7; - __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_v_itsfirst); - __pyx_v_itsfirst = __pyx_t_3; - __pyx_t_3 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":99 - * itsdfa = self._grammar_dfas[t] - * itsstates, itsfirst = itsdfa - * if ilabel in itsfirst: # <<<<<<<<<<<<<< - * # Push a symbol - * self.push(t, itsdfa, newstate, context) - */ - __pyx_t_3 = PyInt_FromLong(__pyx_v_ilabel); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_10 = ((PySequence_Contains(__pyx_v_itsfirst, __pyx_t_3))); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__pyx_t_10) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":101 - * if ilabel in itsfirst: - * # Push a symbol - * self.push(t, itsdfa, newstate, context) # <<<<<<<<<<<<<< - * break # To continue the outer while loop - * else: - */ - __pyx_t_3 = PyInt_FromLong(__pyx_v_t); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7 = PyInt_FromLong(__pyx_v_newstate); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->__pyx_vtab)->push(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self), __pyx_t_3, __pyx_v_itsdfa, __pyx_t_7, __pyx_v_context); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":102 - * # Push a symbol - * self.push(t, itsdfa, newstate, context) - * break # To continue the outer while loop # <<<<<<<<<<<<<< - * else: - * if (0, state) in arcs: - */ - goto __pyx_L9_break; - goto __pyx_L14; - } - __pyx_L14:; - goto __pyx_L10; - } - __pyx_L10:; - } - /*else*/ { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":104 - * break # To continue the outer while loop - * else: - * if (0, state) in arcs: # <<<<<<<<<<<<<< - * # An accepting state, pop it and try something else - * self.pop() - */ - __pyx_t_7 = PyInt_FromLong(__pyx_v_state); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_INCREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_int_0); - __Pyx_GIVEREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_7); - __Pyx_GIVEREF(__pyx_t_7); - __pyx_t_7 = 0; - __pyx_t_10 = ((PySequence_Contains(__pyx_v_arcs, __pyx_t_3))); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__pyx_t_10) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":106 - * if (0, state) in arcs: - * # An accepting state, pop it and try something else - * self.pop() # <<<<<<<<<<<<<< - * if not self.stack: - * # Done parsing, but another token is input - */ - ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->__pyx_vtab)->pop(((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":107 - * # An accepting state, pop it and try something else - * self.pop() - * if not self.stack: # <<<<<<<<<<<<<< - * # Done parsing, but another token is input - * raise ParseError("too much input", - */ - __pyx_t_10 = __Pyx_PyObject_IsTrue(((PyObject *)((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self)->stack)); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_1 = (!__pyx_t_10); - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":109 - * if not self.stack: - * # Done parsing, but another token is input - * raise ParseError("too much input", # <<<<<<<<<<<<<< - * type, value, context) - * else: - */ - __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":110 - * # Done parsing, but another token is input - * raise ParseError("too much input", - * type, value, context) # <<<<<<<<<<<<<< - * else: - * # No success finding a transition - */ - __pyx_t_7 = PyInt_FromLong(__pyx_v_type); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_4 = PyTuple_New(4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_INCREF(((PyObject *)__pyx_kp_s_3)); - PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)__pyx_kp_s_3)); - __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_3)); - PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_7); - __Pyx_GIVEREF(__pyx_t_7); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_4, 3, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - __pyx_t_7 = 0; - __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_Raise(__pyx_t_7, 0, 0); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - goto __pyx_L16; - } - __pyx_L16:; - goto __pyx_L15; - } - /*else*/ { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":113 - * else: - * # No success finding a transition - * raise ParseError("bad input", type, value, context) # <<<<<<<<<<<<<< - * - * cdef int classify(self, int type, value, context): - */ - __pyx_t_7 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseError); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_4 = PyInt_FromLong(__pyx_v_type); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = PyTuple_New(4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_INCREF(((PyObject *)__pyx_kp_s_4)); - PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_kp_s_4)); - __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_4)); - PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_3, 3, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - __pyx_t_4 = 0; - __pyx_t_4 = PyObject_Call(__pyx_t_7, __pyx_t_3, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_Raise(__pyx_t_4, 0, 0); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - __pyx_L15:; - } - __pyx_L9_break:; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - } - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.addtoken"); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_DECREF(__pyx_v_dfa); - __Pyx_DECREF(__pyx_v_node); - __Pyx_DECREF(__pyx_v_states); - __Pyx_DECREF(__pyx_v_first); - __Pyx_DECREF(__pyx_v_arcs); - __Pyx_DECREF(__pyx_v_v); - __Pyx_DECREF(__pyx_v_itsdfa); - __Pyx_DECREF(__pyx_v_itsstates); - __Pyx_DECREF(__pyx_v_itsfirst); - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_DECREF(__pyx_v_value); - __Pyx_DECREF(__pyx_v_context); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":115 - * raise ParseError("bad input", type, value, context) - * - * cdef int classify(self, int type, value, context): # <<<<<<<<<<<<<< - * """Turn a token into a label. (Internal)""" - * if type == NAME: - */ - -static int __pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_classify(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_v_self, int __pyx_v_type, PyObject *__pyx_v_value, PyObject *__pyx_v_context) { - int __pyx_r; - int __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - __Pyx_RefNannySetupContext("classify"); - __Pyx_INCREF((PyObject *)__pyx_v_self); - __Pyx_INCREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":117 - * cdef int classify(self, int type, value, context): - * """Turn a token into a label. (Internal)""" - * if type == NAME: # <<<<<<<<<<<<<< - * # Keep a listing of all used names - * self.used_names.add(value) - */ - __pyx_t_1 = (__pyx_v_type == 1); - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":119 - * if type == NAME: - * # Keep a listing of all used names - * self.used_names.add(value) # <<<<<<<<<<<<<< - * # Check for reserved words - * if value in self._grammar_keywords: - */ - __pyx_t_2 = PySet_Add(((PyObject *)__pyx_v_self->used_names), __pyx_v_value); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":121 - * self.used_names.add(value) - * # Check for reserved words - * if value in self._grammar_keywords: # <<<<<<<<<<<<<< - * return self._grammar_keywords[value] - * if type not in self._grammar_tokens: - */ - if (unlikely(((PyObject *)__pyx_v_self->_grammar_keywords) == Py_None)) { - __Pyx_RaiseNoneNotIterableError(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } else { - __pyx_t_1 = ((PyDict_Contains(((PyObject *)__pyx_v_self->_grammar_keywords), __pyx_v_value))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":122 - * # Check for reserved words - * if value in self._grammar_keywords: - * return self._grammar_keywords[value] # <<<<<<<<<<<<<< - * if type not in self._grammar_tokens: - * raise ParseError("bad token", type, value, context) - */ - __pyx_t_3 = PyObject_GetItem(((PyObject *)__pyx_v_self->_grammar_keywords), __pyx_v_value); if (!__pyx_t_3) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_3); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_r = __pyx_t_2; - goto __pyx_L0; - goto __pyx_L4; - } - __pyx_L4:; - goto __pyx_L3; - } - __pyx_L3:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":123 - * if value in self._grammar_keywords: - * return self._grammar_keywords[value] - * if type not in self._grammar_tokens: # <<<<<<<<<<<<<< - * raise ParseError("bad token", type, value, context) - * return self._grammar_tokens[type] - */ - __pyx_t_3 = PyInt_FromLong(__pyx_v_type); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - if (unlikely(((PyObject *)__pyx_v_self->_grammar_tokens) == Py_None)) { - __Pyx_RaiseNoneNotIterableError(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } else { - __pyx_t_1 = (__Pyx_NegateNonNeg(PyDict_Contains(((PyObject *)__pyx_v_self->_grammar_tokens), __pyx_t_3))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__pyx_t_1) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":124 - * return self._grammar_keywords[value] - * if type not in self._grammar_tokens: - * raise ParseError("bad token", type, value, context) # <<<<<<<<<<<<<< - * return self._grammar_tokens[type] - * - */ - __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyInt_FromLong(__pyx_v_type); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_INCREF(((PyObject *)__pyx_kp_s_5)); - PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_kp_s_5)); - __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_5)); - PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - __pyx_t_4 = 0; - __pyx_t_4 = PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_Raise(__pyx_t_4, 0, 0); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - goto __pyx_L5; - } - __pyx_L5:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":125 - * if type not in self._grammar_tokens: - * raise ParseError("bad token", type, value, context) - * return self._grammar_tokens[type] # <<<<<<<<<<<<<< - * - * cdef void shift(self, type, value, newstate, context): - */ - __pyx_t_4 = __Pyx_GetItemInt(((PyObject *)__pyx_v_self->_grammar_tokens), __pyx_v_type, sizeof(int), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_r = __pyx_t_2; - goto __pyx_L0; - - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_WriteUnraisable("sphinx.pycode.pgen2.parse.Parser.classify"); - __pyx_r = 0; - __pyx_L0:; - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_DECREF(__pyx_v_value); - __Pyx_DECREF(__pyx_v_context); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":127 - * return self._grammar_tokens[type] - * - * cdef void shift(self, type, value, newstate, context): # <<<<<<<<<<<<<< - * """Shift a token. (Internal)""" - * cdef tuple node - */ - -static void __pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_shift(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_v_self, PyObject *__pyx_v_type, PyObject *__pyx_v_value, PyObject *__pyx_v_newstate, PyObject *__pyx_v_context) { - PyObject *__pyx_v_node; - PyObject *__pyx_v_dfa; - PyObject *__pyx_v_state; - PyObject *__pyx_v_newnode; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - __Pyx_RefNannySetupContext("shift"); - __Pyx_INCREF((PyObject *)__pyx_v_self); - __Pyx_INCREF(__pyx_v_type); - __Pyx_INCREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_newstate); - __Pyx_INCREF(__pyx_v_context); - __pyx_v_node = ((PyObject *)Py_None); __Pyx_INCREF(Py_None); - __pyx_v_dfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_state = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_newnode = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":130 - * """Shift a token. (Internal)""" - * cdef tuple node - * dfa, state, node = self.stack[-1] # <<<<<<<<<<<<<< - * newnode = (type, value, context, None) - * newnode = self.convert(newnode) - */ - __pyx_t_1 = __Pyx_GetItemInt_List(((PyObject *)__pyx_v_self->stack), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyTuple_CheckExact(__pyx_t_1) && likely(PyTuple_GET_SIZE(__pyx_t_1) == 3)) { - PyObject* tuple = __pyx_t_1; - __pyx_t_2 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_4); - if (!(likely(PyTuple_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(((PyObject *)__pyx_v_node)); - __pyx_v_node = ((PyObject *)__pyx_t_4); - __pyx_t_4 = 0; - } else { - __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_5, 0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_5, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_5, 2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - if (!(likely(PyTuple_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_EndUnpack(__pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(((PyObject *)__pyx_v_node)); - __pyx_v_node = ((PyObject *)__pyx_t_4); - __pyx_t_4 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":131 - * cdef tuple node - * dfa, state, node = self.stack[-1] - * newnode = (type, value, context, None) # <<<<<<<<<<<<<< - * newnode = self.convert(newnode) - * if newnode is not None: - */ - __pyx_t_1 = PyTuple_New(4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_v_type); - PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_type); - __Pyx_GIVEREF(__pyx_v_type); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - __Pyx_INCREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_1, 3, Py_None); - __Pyx_GIVEREF(Py_None); - __Pyx_DECREF(__pyx_v_newnode); - __pyx_v_newnode = __pyx_t_1; - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":132 - * dfa, state, node = self.stack[-1] - * newnode = (type, value, context, None) - * newnode = self.convert(newnode) # <<<<<<<<<<<<<< - * if newnode is not None: - * node[-1].append(newnode) - */ - if (!(likely(PyTuple_CheckExact(__pyx_v_newnode))||((__pyx_v_newnode) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_v_newnode)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_1 = ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self->__pyx_vtab)->convert(__pyx_v_self, ((PyObject *)__pyx_v_newnode)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_v_newnode); - __pyx_v_newnode = __pyx_t_1; - __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":133 - * newnode = (type, value, context, None) - * newnode = self.convert(newnode) - * if newnode is not None: # <<<<<<<<<<<<<< - * node[-1].append(newnode) - * self.stack[-1] = (dfa, newstate, node) - */ - __pyx_t_6 = (__pyx_v_newnode != Py_None); - if (__pyx_t_6) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":134 - * newnode = self.convert(newnode) - * if newnode is not None: - * node[-1].append(newnode) # <<<<<<<<<<<<<< - * self.stack[-1] = (dfa, newstate, node) - * - */ - __pyx_t_1 = __Pyx_GetItemInt_Tuple(((PyObject *)__pyx_v_node), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_4 = __Pyx_PyObject_Append(__pyx_t_1, __pyx_v_newnode); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - goto __pyx_L3; - } - __pyx_L3:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":135 - * if newnode is not None: - * node[-1].append(newnode) - * self.stack[-1] = (dfa, newstate, node) # <<<<<<<<<<<<<< - * - * cdef void push(self, type, newdfa, newstate, context): - */ - __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_dfa); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_dfa); - __Pyx_GIVEREF(__pyx_v_dfa); - __Pyx_INCREF(__pyx_v_newstate); - PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_v_newstate); - __Pyx_GIVEREF(__pyx_v_newstate); - __Pyx_INCREF(((PyObject *)__pyx_v_node)); - PyTuple_SET_ITEM(__pyx_t_4, 2, ((PyObject *)__pyx_v_node)); - __Pyx_GIVEREF(((PyObject *)__pyx_v_node)); - if (__Pyx_SetItemInt(((PyObject *)__pyx_v_self->stack), -1, __pyx_t_4, sizeof(long), PyInt_FromLong) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_WriteUnraisable("sphinx.pycode.pgen2.parse.Parser.shift"); - __pyx_L0:; - __Pyx_DECREF(__pyx_v_node); - __Pyx_DECREF(__pyx_v_dfa); - __Pyx_DECREF(__pyx_v_state); - __Pyx_DECREF(__pyx_v_newnode); - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_DECREF(__pyx_v_type); - __Pyx_DECREF(__pyx_v_value); - __Pyx_DECREF(__pyx_v_newstate); - __Pyx_DECREF(__pyx_v_context); - __Pyx_RefNannyFinishContext(); -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":137 - * self.stack[-1] = (dfa, newstate, node) - * - * cdef void push(self, type, newdfa, newstate, context): # <<<<<<<<<<<<<< - * """Push a nonterminal. (Internal)""" - * dfa, state, node = self.stack[-1] - */ - -static void __pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_push(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_v_self, PyObject *__pyx_v_type, PyObject *__pyx_v_newdfa, PyObject *__pyx_v_newstate, PyObject *__pyx_v_context) { - PyObject *__pyx_v_dfa; - PyObject *__pyx_v_state; - PyObject *__pyx_v_node; - PyObject *__pyx_v_newnode; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - __Pyx_RefNannySetupContext("push"); - __pyx_v_dfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_state = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_node = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_newnode = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":139 - * cdef void push(self, type, newdfa, newstate, context): - * """Push a nonterminal. (Internal)""" - * dfa, state, node = self.stack[-1] # <<<<<<<<<<<<<< - * newnode = (type, None, context, []) - * self.stack[-1] = (dfa, newstate, node) - */ - __pyx_t_1 = __Pyx_GetItemInt_List(((PyObject *)__pyx_v_self->stack), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyTuple_CheckExact(__pyx_t_1) && likely(PyTuple_GET_SIZE(__pyx_t_1) == 3)) { - PyObject* tuple = __pyx_t_1; - __pyx_t_2 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_4; - __pyx_t_4 = 0; - } else { - __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_2 = __Pyx_UnpackItem(__pyx_t_5, 0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_5, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_5, 2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - if (__Pyx_EndUnpack(__pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_4; - __pyx_t_4 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":140 - * """Push a nonterminal. (Internal)""" - * dfa, state, node = self.stack[-1] - * newnode = (type, None, context, []) # <<<<<<<<<<<<<< - * self.stack[-1] = (dfa, newstate, node) - * self.stack.append((newdfa, 0, newnode)) - */ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - __pyx_t_4 = PyTuple_New(4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_type); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_type); - __Pyx_GIVEREF(__pyx_v_type); - __Pyx_INCREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_4, 1, Py_None); - __Pyx_GIVEREF(Py_None); - __Pyx_INCREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_context); - __Pyx_GIVEREF(__pyx_v_context); - PyTuple_SET_ITEM(__pyx_t_4, 3, ((PyObject *)__pyx_t_1)); - __Pyx_GIVEREF(((PyObject *)__pyx_t_1)); - __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_newnode); - __pyx_v_newnode = __pyx_t_4; - __pyx_t_4 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":141 - * dfa, state, node = self.stack[-1] - * newnode = (type, None, context, []) - * self.stack[-1] = (dfa, newstate, node) # <<<<<<<<<<<<<< - * self.stack.append((newdfa, 0, newnode)) - * - */ - __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_dfa); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_dfa); - __Pyx_GIVEREF(__pyx_v_dfa); - __Pyx_INCREF(__pyx_v_newstate); - PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_v_newstate); - __Pyx_GIVEREF(__pyx_v_newstate); - __Pyx_INCREF(__pyx_v_node); - PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_node); - __Pyx_GIVEREF(__pyx_v_node); - if (__Pyx_SetItemInt(((PyObject *)__pyx_v_self->stack), -1, __pyx_t_4, sizeof(long), PyInt_FromLong) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":142 - * newnode = (type, None, context, []) - * self.stack[-1] = (dfa, newstate, node) - * self.stack.append((newdfa, 0, newnode)) # <<<<<<<<<<<<<< - * - * cdef void pop(self): - */ - if (unlikely(__pyx_v_self->stack == Py_None)) { - PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_INCREF(__pyx_v_newdfa); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_newdfa); - __Pyx_GIVEREF(__pyx_v_newdfa); - __Pyx_INCREF(__pyx_int_0); - PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_int_0); - __Pyx_GIVEREF(__pyx_int_0); - __Pyx_INCREF(__pyx_v_newnode); - PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_newnode); - __Pyx_GIVEREF(__pyx_v_newnode); - __pyx_t_6 = PyList_Append(((PyObject *)__pyx_v_self->stack), __pyx_t_4); if (unlikely(__pyx_t_6 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_WriteUnraisable("sphinx.pycode.pgen2.parse.Parser.push"); - __pyx_L0:; - __Pyx_DECREF(__pyx_v_dfa); - __Pyx_DECREF(__pyx_v_state); - __Pyx_DECREF(__pyx_v_node); - __Pyx_DECREF(__pyx_v_newnode); - __Pyx_RefNannyFinishContext(); -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":144 - * self.stack.append((newdfa, 0, newnode)) - * - * cdef void pop(self): # <<<<<<<<<<<<<< - * """Pop a nonterminal. (Internal)""" - * popdfa, popstate, popnode = self.stack.pop() - */ - -static void __pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_pop(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_v_self) { - PyObject *__pyx_v_popdfa; - PyObject *__pyx_v_popstate; - PyObject *__pyx_v_popnode; - PyObject *__pyx_v_newnode; - PyObject *__pyx_v_dfa; - PyObject *__pyx_v_state; - PyObject *__pyx_v_node; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - __Pyx_RefNannySetupContext("pop"); - __Pyx_INCREF((PyObject *)__pyx_v_self); - __pyx_v_popdfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_popstate = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_popnode = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_newnode = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_dfa = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_state = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_node = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":146 - * cdef void pop(self): - * """Pop a nonterminal. (Internal)""" - * popdfa, popstate, popnode = self.stack.pop() # <<<<<<<<<<<<<< - * newnode = self.convert(popnode) - * if newnode is not None: - */ - __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_self->stack), __pyx_n_s__pop); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 3)) { - PyObject* tuple = __pyx_t_2; - __pyx_t_1 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_1); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_popdfa); - __pyx_v_popdfa = __pyx_t_1; - __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_popstate); - __pyx_v_popstate = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_popnode); - __pyx_v_popnode = __pyx_t_4; - __pyx_t_4 = 0; - } else { - __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_5, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_5, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_5, 2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - if (__Pyx_EndUnpack(__pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_v_popdfa); - __pyx_v_popdfa = __pyx_t_1; - __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_popstate); - __pyx_v_popstate = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_popnode); - __pyx_v_popnode = __pyx_t_4; - __pyx_t_4 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":147 - * """Pop a nonterminal. (Internal)""" - * popdfa, popstate, popnode = self.stack.pop() - * newnode = self.convert(popnode) # <<<<<<<<<<<<<< - * if newnode is not None: - * if self.stack: - */ - if (!(likely(PyTuple_CheckExact(__pyx_v_popnode))||((__pyx_v_popnode) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected tuple, got %.200s", Py_TYPE(__pyx_v_popnode)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_2 = ((struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser *)__pyx_v_self->__pyx_vtab)->convert(__pyx_v_self, ((PyObject *)__pyx_v_popnode)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_v_newnode); - __pyx_v_newnode = __pyx_t_2; - __pyx_t_2 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":148 - * popdfa, popstate, popnode = self.stack.pop() - * newnode = self.convert(popnode) - * if newnode is not None: # <<<<<<<<<<<<<< - * if self.stack: - * dfa, state, node = self.stack[-1] - */ - __pyx_t_6 = (__pyx_v_newnode != Py_None); - if (__pyx_t_6) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":149 - * newnode = self.convert(popnode) - * if newnode is not None: - * if self.stack: # <<<<<<<<<<<<<< - * dfa, state, node = self.stack[-1] - * node[-1].append(newnode) - */ - __pyx_t_6 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_self->stack)); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 149; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__pyx_t_6) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":150 - * if newnode is not None: - * if self.stack: - * dfa, state, node = self.stack[-1] # <<<<<<<<<<<<<< - * node[-1].append(newnode) - * else: - */ - __pyx_t_2 = __Pyx_GetItemInt_List(((PyObject *)__pyx_v_self->stack), -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - if (PyTuple_CheckExact(__pyx_t_2) && likely(PyTuple_GET_SIZE(__pyx_t_2) == 3)) { - PyObject* tuple = __pyx_t_2; - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_4); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_3); - __pyx_t_1 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_4; - __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_1; - __pyx_t_1 = 0; - } else { - __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = __Pyx_UnpackItem(__pyx_t_5, 0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = __Pyx_UnpackItem(__pyx_t_5, 1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_1 = __Pyx_UnpackItem(__pyx_t_5, 2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_EndUnpack(__pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_v_dfa); - __pyx_v_dfa = __pyx_t_4; - __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_v_state); - __pyx_v_state = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_node); - __pyx_v_node = __pyx_t_1; - __pyx_t_1 = 0; - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":151 - * if self.stack: - * dfa, state, node = self.stack[-1] - * node[-1].append(newnode) # <<<<<<<<<<<<<< - * else: - * self.rootnode = newnode - */ - __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_node, -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_1 = __Pyx_PyObject_Append(__pyx_t_2, __pyx_v_newnode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L4; - } - /*else*/ { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":153 - * node[-1].append(newnode) - * else: - * self.rootnode = newnode # <<<<<<<<<<<<<< - * self.rootnode.used_names = self.used_names - * - */ - __Pyx_INCREF(__pyx_v_newnode); - __Pyx_GIVEREF(__pyx_v_newnode); - __Pyx_GOTREF(__pyx_v_self->rootnode); - __Pyx_DECREF(__pyx_v_self->rootnode); - __pyx_v_self->rootnode = __pyx_v_newnode; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":154 - * else: - * self.rootnode = newnode - * self.rootnode.used_names = self.used_names # <<<<<<<<<<<<<< - * - * cdef convert(self, tuple raw_node): - */ - if (PyObject_SetAttr(__pyx_v_self->rootnode, __pyx_n_s__used_names, ((PyObject *)__pyx_v_self->used_names)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - __pyx_L4:; - goto __pyx_L3; - } - __pyx_L3:; - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_WriteUnraisable("sphinx.pycode.pgen2.parse.Parser.pop"); - __pyx_L0:; - __Pyx_DECREF(__pyx_v_popdfa); - __Pyx_DECREF(__pyx_v_popstate); - __Pyx_DECREF(__pyx_v_popnode); - __Pyx_DECREF(__pyx_v_newnode); - __Pyx_DECREF(__pyx_v_dfa); - __Pyx_DECREF(__pyx_v_state); - __Pyx_DECREF(__pyx_v_node); - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_RefNannyFinishContext(); -} - -/* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":156 - * self.rootnode.used_names = self.used_names - * - * cdef convert(self, tuple raw_node): # <<<<<<<<<<<<<< - * type, value, context, children = raw_node - * if children or type in self._grammar_number2symbol: - */ - -static PyObject *__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_convert(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *__pyx_v_self, PyObject *__pyx_v_raw_node) { - PyObject *__pyx_v_type; - PyObject *__pyx_v_value; - PyObject *__pyx_v_context; - PyObject *__pyx_v_children; - PyObject *__pyx_r = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; - int __pyx_t_6; - int __pyx_t_7; - Py_ssize_t __pyx_t_8; - __Pyx_RefNannySetupContext("convert"); - __Pyx_INCREF((PyObject *)__pyx_v_self); - __Pyx_INCREF(__pyx_v_raw_node); - __pyx_v_type = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_value = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_context = Py_None; __Pyx_INCREF(Py_None); - __pyx_v_children = Py_None; __Pyx_INCREF(Py_None); - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":157 - * - * cdef convert(self, tuple raw_node): - * type, value, context, children = raw_node # <<<<<<<<<<<<<< - * if children or type in self._grammar_number2symbol: - * # If there's exactly one child, return that child instead of - */ - if (likely(((PyObject *)__pyx_v_raw_node) != Py_None) && likely(PyTuple_GET_SIZE(((PyObject *)__pyx_v_raw_node)) == 4)) { - PyObject* tuple = ((PyObject *)__pyx_v_raw_node); - __pyx_t_1 = PyTuple_GET_ITEM(tuple, 0); __Pyx_INCREF(__pyx_t_1); - __pyx_t_2 = PyTuple_GET_ITEM(tuple, 1); __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = PyTuple_GET_ITEM(tuple, 2); __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = PyTuple_GET_ITEM(tuple, 3); __Pyx_INCREF(__pyx_t_4); - __Pyx_DECREF(__pyx_v_type); - __pyx_v_type = __pyx_t_1; - __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_v_value); - __pyx_v_value = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_v_context); - __pyx_v_context = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_v_children); - __pyx_v_children = __pyx_t_4; - __pyx_t_4 = 0; - } else { - __Pyx_UnpackTupleError(((PyObject *)__pyx_v_raw_node), 4); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":158 - * cdef convert(self, tuple raw_node): - * type, value, context, children = raw_node - * if children or type in self._grammar_number2symbol: # <<<<<<<<<<<<<< - * # If there's exactly one child, return that child instead of - * # creating a new node. - */ - __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_v_children); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (!__pyx_t_5) { - if (unlikely(((PyObject *)__pyx_v_self->_grammar_number2symbol) == Py_None)) { - __Pyx_RaiseNoneNotIterableError(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } else { - __pyx_t_6 = ((PyDict_Contains(((PyObject *)__pyx_v_self->_grammar_number2symbol), __pyx_v_type))); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - __pyx_t_7 = __pyx_t_6; - } else { - __pyx_t_7 = __pyx_t_5; - } - if (__pyx_t_7) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":161 - * # If there's exactly one child, return that child instead of - * # creating a new node. - * if len(children) == 1: # <<<<<<<<<<<<<< - * return children[0] - * return Node(type, children, context=context) - */ - __pyx_t_8 = PyObject_Length(__pyx_v_children); if (unlikely(__pyx_t_8 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_7 = (__pyx_t_8 == 1); - if (__pyx_t_7) { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":162 - * # creating a new node. - * if len(children) == 1: - * return children[0] # <<<<<<<<<<<<<< - * return Node(type, children, context=context) - * else: - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_children, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_r = __pyx_t_4; - __pyx_t_4 = 0; - goto __pyx_L0; - goto __pyx_L4; - } - __pyx_L4:; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":163 - * if len(children) == 1: - * return children[0] - * return Node(type, children, context=context) # <<<<<<<<<<<<<< - * else: - * return Leaf(type, value, context=context) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = __Pyx_GetName(__pyx_m, __pyx_n_s__Node); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_INCREF(__pyx_v_type); - PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_type); - __Pyx_GIVEREF(__pyx_v_type); - __Pyx_INCREF(__pyx_v_children); - PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_v_children); - __Pyx_GIVEREF(__pyx_v_children); - __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__context), __pyx_v_context) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_1 = PyEval_CallObjectWithKeywords(__pyx_t_4, __pyx_t_3, ((PyObject *)__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - goto __pyx_L3; - } - /*else*/ { - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":165 - * return Node(type, children, context=context) - * else: - * return Leaf(type, value, context=context) # <<<<<<<<<<<<<< - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__Leaf); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_v_type); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_type); - __Pyx_GIVEREF(__pyx_v_type); - __Pyx_INCREF(__pyx_v_value); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_value); - __Pyx_GIVEREF(__pyx_v_value); - __pyx_t_3 = PyDict_New(); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - if (PyDict_SetItem(__pyx_t_3, ((PyObject *)__pyx_n_s__context), __pyx_v_context) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_4 = PyEval_CallObjectWithKeywords(__pyx_t_1, __pyx_t_2, ((PyObject *)__pyx_t_3)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; - __pyx_r = __pyx_t_4; - __pyx_t_4 = 0; - goto __pyx_L0; - } - __pyx_L3:; - - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("sphinx.pycode.pgen2.parse.Parser.convert"); - __pyx_r = 0; - __pyx_L0:; - __Pyx_DECREF(__pyx_v_type); - __Pyx_DECREF(__pyx_v_value); - __Pyx_DECREF(__pyx_v_context); - __Pyx_DECREF(__pyx_v_children); - __Pyx_DECREF((PyObject *)__pyx_v_self); - __Pyx_DECREF(__pyx_v_raw_node); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} -static struct __pyx_vtabstruct_6sphinx_6pycode_5pgen2_5parse_Parser __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser; - -static PyObject *__pyx_tp_new_6sphinx_6pycode_5pgen2_5parse_Parser(PyTypeObject *t, PyObject *a, PyObject *k) { - struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *p; - PyObject *o = (*t->tp_alloc)(t, 0); - if (!o) return 0; - p = ((struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)o); - p->__pyx_vtab = __pyx_vtabptr_6sphinx_6pycode_5pgen2_5parse_Parser; - p->grammar = Py_None; Py_INCREF(Py_None); - p->rootnode = Py_None; Py_INCREF(Py_None); - p->stack = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->used_names = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->_grammar_labels = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->_grammar_dfas = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->_grammar_keywords = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->_grammar_tokens = ((PyObject *)Py_None); Py_INCREF(Py_None); - p->_grammar_number2symbol = ((PyObject *)Py_None); Py_INCREF(Py_None); - return o; -} - -static void __pyx_tp_dealloc_6sphinx_6pycode_5pgen2_5parse_Parser(PyObject *o) { - struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *p = (struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)o; - Py_XDECREF(p->grammar); - Py_XDECREF(p->rootnode); - Py_XDECREF(((PyObject *)p->stack)); - Py_XDECREF(((PyObject *)p->used_names)); - Py_XDECREF(((PyObject *)p->_grammar_labels)); - Py_XDECREF(((PyObject *)p->_grammar_dfas)); - Py_XDECREF(((PyObject *)p->_grammar_keywords)); - Py_XDECREF(((PyObject *)p->_grammar_tokens)); - Py_XDECREF(((PyObject *)p->_grammar_number2symbol)); - (*Py_TYPE(o)->tp_free)(o); -} - -static int __pyx_tp_traverse_6sphinx_6pycode_5pgen2_5parse_Parser(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *p = (struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)o; - if (p->grammar) { - e = (*v)(p->grammar, a); if (e) return e; - } - if (p->rootnode) { - e = (*v)(p->rootnode, a); if (e) return e; - } - if (p->stack) { - e = (*v)(p->stack, a); if (e) return e; - } - if (p->used_names) { - e = (*v)(p->used_names, a); if (e) return e; - } - if (p->_grammar_labels) { - e = (*v)(p->_grammar_labels, a); if (e) return e; - } - if (p->_grammar_dfas) { - e = (*v)(p->_grammar_dfas, a); if (e) return e; - } - if (p->_grammar_keywords) { - e = (*v)(p->_grammar_keywords, a); if (e) return e; - } - if (p->_grammar_tokens) { - e = (*v)(p->_grammar_tokens, a); if (e) return e; - } - if (p->_grammar_number2symbol) { - e = (*v)(p->_grammar_number2symbol, a); if (e) return e; - } - return 0; -} - -static int __pyx_tp_clear_6sphinx_6pycode_5pgen2_5parse_Parser(PyObject *o) { - struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *p = (struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *)o; - PyObject* tmp; - tmp = ((PyObject*)p->grammar); - p->grammar = Py_None; Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->rootnode); - p->rootnode = Py_None; Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->stack); - p->stack = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->used_names); - p->used_names = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_grammar_labels); - p->_grammar_labels = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_grammar_dfas); - p->_grammar_dfas = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_grammar_keywords); - p->_grammar_keywords = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_grammar_tokens); - p->_grammar_tokens = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_grammar_number2symbol); - p->_grammar_number2symbol = ((PyObject *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - return 0; -} - -static PyObject *__pyx_getprop_6sphinx_6pycode_5pgen2_5parse_6Parser_stack(PyObject *o, void *x) { - return __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___get__(o); -} - -static int __pyx_setprop_6sphinx_6pycode_5pgen2_5parse_6Parser_stack(PyObject *o, PyObject *v, void *x) { - if (v) { - return __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_5stack___set__(o, v); - } - else { - PyErr_SetString(PyExc_NotImplementedError, "__del__"); - return -1; - } -} - -static PyObject *__pyx_getprop_6sphinx_6pycode_5pgen2_5parse_6Parser_used_names(PyObject *o, void *x) { - return __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___get__(o); -} - -static int __pyx_setprop_6sphinx_6pycode_5pgen2_5parse_6Parser_used_names(PyObject *o, PyObject *v, void *x) { - if (v) { - return __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_10used_names___set__(o, v); - } - else { - PyErr_SetString(PyExc_NotImplementedError, "__del__"); - return -1; - } -} - -static struct PyMethodDef __pyx_methods_6sphinx_6pycode_5pgen2_5parse_Parser[] = { - {__Pyx_NAMESTR("setup"), (PyCFunction)__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_setup, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)}, - {__Pyx_NAMESTR("addtoken"), (PyCFunction)__pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser_addtoken, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_6sphinx_6pycode_5pgen2_5parse_6Parser_addtoken)}, - {0, 0, 0, 0} -}; - -static struct PyMemberDef __pyx_members_6sphinx_6pycode_5pgen2_5parse_Parser[] = { - {(char *)"grammar", T_OBJECT, offsetof(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser, grammar), 0, 0}, - {(char *)"rootnode", T_OBJECT, offsetof(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser, rootnode), 0, 0}, - {0, 0, 0, 0, 0} -}; - -static struct PyGetSetDef __pyx_getsets_6sphinx_6pycode_5pgen2_5parse_Parser[] = { - {(char *)"stack", __pyx_getprop_6sphinx_6pycode_5pgen2_5parse_6Parser_stack, __pyx_setprop_6sphinx_6pycode_5pgen2_5parse_6Parser_stack, 0, 0}, - {(char *)"used_names", __pyx_getprop_6sphinx_6pycode_5pgen2_5parse_6Parser_used_names, __pyx_setprop_6sphinx_6pycode_5pgen2_5parse_6Parser_used_names, 0, 0}, - {0, 0, 0, 0, 0} -}; - -static PyNumberMethods __pyx_tp_as_number_Parser = { - 0, /*nb_add*/ - 0, /*nb_subtract*/ - 0, /*nb_multiply*/ - #if PY_MAJOR_VERSION < 3 - 0, /*nb_divide*/ - #endif - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - 0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - #if PY_MAJOR_VERSION < 3 - 0, /*nb_coerce*/ - #endif - 0, /*nb_int*/ - #if PY_MAJOR_VERSION >= 3 - 0, /*reserved*/ - #else - 0, /*nb_long*/ - #endif - 0, /*nb_float*/ - #if PY_MAJOR_VERSION < 3 - 0, /*nb_oct*/ - #endif - #if PY_MAJOR_VERSION < 3 - 0, /*nb_hex*/ - #endif - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - #if PY_MAJOR_VERSION < 3 - 0, /*nb_inplace_divide*/ - #endif - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - 0, /*nb_floor_divide*/ - 0, /*nb_true_divide*/ - 0, /*nb_inplace_floor_divide*/ - 0, /*nb_inplace_true_divide*/ - #if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX) - 0, /*nb_index*/ - #endif -}; - -static PySequenceMethods __pyx_tp_as_sequence_Parser = { - 0, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - 0, /*sq_item*/ - 0, /*sq_slice*/ - 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ - 0, /*sq_inplace_concat*/ - 0, /*sq_inplace_repeat*/ -}; - -static PyMappingMethods __pyx_tp_as_mapping_Parser = { - 0, /*mp_length*/ - 0, /*mp_subscript*/ - 0, /*mp_ass_subscript*/ -}; - -static PyBufferProcs __pyx_tp_as_buffer_Parser = { - #if PY_MAJOR_VERSION < 3 - 0, /*bf_getreadbuffer*/ - #endif - #if PY_MAJOR_VERSION < 3 - 0, /*bf_getwritebuffer*/ - #endif - #if PY_MAJOR_VERSION < 3 - 0, /*bf_getsegcount*/ - #endif - #if PY_MAJOR_VERSION < 3 - 0, /*bf_getcharbuffer*/ - #endif - #if PY_VERSION_HEX >= 0x02060000 - 0, /*bf_getbuffer*/ - #endif - #if PY_VERSION_HEX >= 0x02060000 - 0, /*bf_releasebuffer*/ - #endif -}; - -PyTypeObject __pyx_type_6sphinx_6pycode_5pgen2_5parse_Parser = { - PyVarObject_HEAD_INIT(0, 0) - __Pyx_NAMESTR("sphinx.pycode.pgen2.parse.Parser"), /*tp_name*/ - sizeof(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &__pyx_tp_as_number_Parser, /*tp_as_number*/ - &__pyx_tp_as_sequence_Parser, /*tp_as_sequence*/ - &__pyx_tp_as_mapping_Parser, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - &__pyx_tp_as_buffer_Parser, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_traverse*/ - __pyx_tp_clear_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_methods*/ - __pyx_members_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_members*/ - __pyx_getsets_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - __pyx_pf_6sphinx_6pycode_5pgen2_5parse_6Parser___init__, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_6sphinx_6pycode_5pgen2_5parse_Parser, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - #if PY_VERSION_HEX >= 0x02060000 - 0, /*tp_version_tag*/ - #endif -}; - -static struct PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; - -static void __pyx_init_filenames(void); /*proto*/ - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef __pyx_moduledef = { - PyModuleDef_HEAD_INIT, - __Pyx_NAMESTR("parse"), - __Pyx_DOCSTR(__pyx_k_6), /* m_doc */ - -1, /* m_size */ - __pyx_methods /* m_methods */, - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; -#endif - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 0}, - {&__pyx_n_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 1}, - {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0}, - {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0}, - {&__pyx_kp_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 0}, - {&__pyx_n_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 1}, - {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0}, - {&__pyx_kp_u_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 1, 0, 0}, - {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1}, - {&__pyx_n_s__Leaf, __pyx_k__Leaf, sizeof(__pyx_k__Leaf), 0, 0, 1, 1}, - {&__pyx_n_s__Node, __pyx_k__Node, sizeof(__pyx_k__Node), 0, 0, 1, 1}, - {&__pyx_n_s__ParseError, __pyx_k__ParseError, sizeof(__pyx_k__ParseError), 0, 0, 1, 1}, - {&__pyx_n_s__Parser, __pyx_k__Parser, sizeof(__pyx_k__Parser), 0, 0, 1, 1}, - {&__pyx_n_s____init__, __pyx_k____init__, sizeof(__pyx_k____init__), 0, 0, 1, 1}, - {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, - {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1}, - {&__pyx_n_s___grammar_dfas, __pyx_k___grammar_dfas, sizeof(__pyx_k___grammar_dfas), 0, 0, 1, 1}, - {&__pyx_n_s___grammar_keywords, __pyx_k___grammar_keywords, sizeof(__pyx_k___grammar_keywords), 0, 0, 1, 1}, - {&__pyx_n_s___grammar_labels, __pyx_k___grammar_labels, sizeof(__pyx_k___grammar_labels), 0, 0, 1, 1}, - {&__pyx_n_s___grammar_start, __pyx_k___grammar_start, sizeof(__pyx_k___grammar_start), 0, 0, 1, 1}, - {&__pyx_n_s___grammar_tokens, __pyx_k___grammar_tokens, sizeof(__pyx_k___grammar_tokens), 0, 0, 1, 1}, - {&__pyx_n_s__add, __pyx_k__add, sizeof(__pyx_k__add), 0, 0, 1, 1}, - {&__pyx_n_s__addtoken, __pyx_k__addtoken, sizeof(__pyx_k__addtoken), 0, 0, 1, 1}, - {&__pyx_n_s__classify, __pyx_k__classify, sizeof(__pyx_k__classify), 0, 0, 1, 1}, - {&__pyx_n_s__context, __pyx_k__context, sizeof(__pyx_k__context), 0, 0, 1, 1}, - {&__pyx_n_s__convert, __pyx_k__convert, sizeof(__pyx_k__convert), 0, 0, 1, 1}, - {&__pyx_n_s__dfas, __pyx_k__dfas, sizeof(__pyx_k__dfas), 0, 0, 1, 1}, - {&__pyx_n_s__grammar, __pyx_k__grammar, sizeof(__pyx_k__grammar), 0, 0, 1, 1}, - {&__pyx_n_s__keywords, __pyx_k__keywords, sizeof(__pyx_k__keywords), 0, 0, 1, 1}, - {&__pyx_n_s__labels, __pyx_k__labels, sizeof(__pyx_k__labels), 0, 0, 1, 1}, - {&__pyx_n_s__msg, __pyx_k__msg, sizeof(__pyx_k__msg), 0, 0, 1, 1}, - {&__pyx_n_s__number2symbol, __pyx_k__number2symbol, sizeof(__pyx_k__number2symbol), 0, 0, 1, 1}, - {&__pyx_n_s__pop, __pyx_k__pop, sizeof(__pyx_k__pop), 0, 0, 1, 1}, - {&__pyx_n_s__push, __pyx_k__push, sizeof(__pyx_k__push), 0, 0, 1, 1}, - {&__pyx_n_s__rootnode, __pyx_k__rootnode, sizeof(__pyx_k__rootnode), 0, 0, 1, 1}, - {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1}, - {&__pyx_n_s__shift, __pyx_k__shift, sizeof(__pyx_k__shift), 0, 0, 1, 1}, - {&__pyx_n_s__stack, __pyx_k__stack, sizeof(__pyx_k__stack), 0, 0, 1, 1}, - {&__pyx_n_s__start, __pyx_k__start, sizeof(__pyx_k__start), 0, 0, 1, 1}, - {&__pyx_n_s__tokens, __pyx_k__tokens, sizeof(__pyx_k__tokens), 0, 0, 1, 1}, - {&__pyx_n_s__type, __pyx_k__type, sizeof(__pyx_k__type), 0, 0, 1, 1}, - {&__pyx_n_s__used_names, __pyx_k__used_names, sizeof(__pyx_k__used_names), 0, 0, 1, 1}, - {&__pyx_n_s__value, __pyx_k__value, sizeof(__pyx_k__value), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} -}; -static int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - return 0; - __pyx_L1_error:; - return -1; -} - -static int __Pyx_InitGlobals(void) { - #if PY_VERSION_HEX < 0x02040000 - if (unlikely(__Pyx_Py23SetsImport() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - return 0; - __pyx_L1_error:; - return -1; -} - -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC initparse(void); /*proto*/ -PyMODINIT_FUNC initparse(void) -#else -PyMODINIT_FUNC PyInit_parse(void); /*proto*/ -PyMODINIT_FUNC PyInit_parse(void) -#endif -{ - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - #if CYTHON_REFNANNY - void* __pyx_refnanny = NULL; - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); - if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); - } - __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit_parse(void)", __LINE__, __FILE__); - #endif - __pyx_init_filenames(); - __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #if PY_MAJOR_VERSION < 3 - __pyx_empty_bytes = PyString_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #else - __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ - #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - #ifdef WITH_THREAD /* Python build with threading support? */ - PyEval_InitThreads(); - #endif - #endif - /*--- Module creation code ---*/ - #if PY_MAJOR_VERSION < 3 - __pyx_m = Py_InitModule4(__Pyx_NAMESTR("parse"), __pyx_methods, __Pyx_DOCSTR(__pyx_k_6), 0, PYTHON_API_VERSION); - #else - __pyx_m = PyModule_Create(&__pyx_moduledef); - #endif - if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - #if PY_MAJOR_VERSION < 3 - Py_INCREF(__pyx_m); - #endif - __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME)); - if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - /*--- Initialize various global constants etc. ---*/ - if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__pyx_module_is_main_sphinx__pycode__pgen2__parse) { - if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - } - /*--- Builtin init code ---*/ - if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Global init code ---*/ - /*--- Function export code ---*/ - /*--- Type init code ---*/ - __pyx_vtabptr_6sphinx_6pycode_5pgen2_5parse_Parser = &__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser; - #if PY_MAJOR_VERSION >= 3 - __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.classify = (int (*)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, int, PyObject *, PyObject *))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_classify; - __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.shift = (void (*)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *, PyObject *, PyObject *, PyObject *))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_shift; - __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.push = (void (*)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *, PyObject *, PyObject *, PyObject *))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_push; - __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.pop = (void (*)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_pop; - __pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.convert = (PyObject *(*)(struct __pyx_obj_6sphinx_6pycode_5pgen2_5parse_Parser *, PyObject *))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_convert; - #else - *(void(**)(void))&__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.classify = (void(*)(void))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_classify; - *(void(**)(void))&__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.shift = (void(*)(void))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_shift; - *(void(**)(void))&__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.push = (void(*)(void))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_push; - *(void(**)(void))&__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.pop = (void(*)(void))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_pop; - *(void(**)(void))&__pyx_vtable_6sphinx_6pycode_5pgen2_5parse_Parser.convert = (void(*)(void))__pyx_f_6sphinx_6pycode_5pgen2_5parse_6Parser_convert; - #endif - if (PyType_Ready(&__pyx_type_6sphinx_6pycode_5pgen2_5parse_Parser) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_SetVtable(__pyx_type_6sphinx_6pycode_5pgen2_5parse_Parser.tp_dict, __pyx_vtabptr_6sphinx_6pycode_5pgen2_5parse_Parser) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_SetAttrString(__pyx_m, "Parser", (PyObject *)&__pyx_type_6sphinx_6pycode_5pgen2_5parse_Parser) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_ptype_6sphinx_6pycode_5pgen2_5parse_Parser = &__pyx_type_6sphinx_6pycode_5pgen2_5parse_Parser; - /*--- Type import code ---*/ - /*--- Function import code ---*/ - /*--- Execution code ---*/ - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":15 - * """ - * - * from sphinx.pycode.nodes import Node, Leaf # <<<<<<<<<<<<<< - * - * DEF NAME = 1 - */ - __pyx_t_1 = PyList_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - __Pyx_INCREF(((PyObject *)__pyx_n_s__Node)); - PyList_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_n_s__Node)); - __Pyx_GIVEREF(((PyObject *)__pyx_n_s__Node)); - __Pyx_INCREF(((PyObject *)__pyx_n_s__Leaf)); - PyList_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_n_s__Leaf)); - __Pyx_GIVEREF(((PyObject *)__pyx_n_s__Leaf)); - __pyx_t_2 = __Pyx_Import(((PyObject *)__pyx_n_s_7), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; - __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Node); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Node, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Leaf); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Leaf, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":19 - * DEF NAME = 1 - * - * class ParseError(Exception): # <<<<<<<<<<<<<< - * """Exception to signal the parser is stuck.""" - * - */ - __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_builtin_Exception); - PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_builtin_Exception); - __Pyx_GIVEREF(__pyx_builtin_Exception); - if (PyDict_SetItemString(((PyObject *)__pyx_t_2), "__doc__", ((PyObject *)__pyx_kp_s_8)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_3 = __Pyx_CreateClass(__pyx_t_1, ((PyObject *)__pyx_t_2), __pyx_n_s__ParseError, "sphinx.pycode.pgen2.parse"); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":22 - * """Exception to signal the parser is stuck.""" - * - * def __init__(self, msg, type, value, context): # <<<<<<<<<<<<<< - * Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - * (msg, type, value, context)) - */ - __pyx_t_1 = PyCFunction_New(&__pyx_mdef_6sphinx_6pycode_5pgen2_5parse_10ParseError___init__, 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_4 = PyMethod_New(__pyx_t_1, 0, __pyx_t_3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (PyObject_SetAttr(__pyx_t_3, __pyx_n_s____init__, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ParseError, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; - - /* "/home/gbr/devel/sphinx/sphinx/pycode/pgen2/parse.pyx":1 - * # Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. # <<<<<<<<<<<<<< - * # Licensed to PSF under a Contributor Agreement. - * - */ - __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Parser); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyObject_GetAttr(__pyx_t_3, __pyx_n_s__addtoken); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_4, "__doc__"); - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_kp_u_9), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_2)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - if (__pyx_m) { - __Pyx_AddTraceback("init sphinx.pycode.pgen2.parse"); - Py_DECREF(__pyx_m); __pyx_m = 0; - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init sphinx.pycode.pgen2.parse"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if PY_MAJOR_VERSION < 3 - return; - #else - return __pyx_m; - #endif -} - -static const char *__pyx_filenames[] = { - "parse.pyx", -}; - -/* Runtime support code */ - -static void __pyx_init_filenames(void) { - __pyx_f = __pyx_filenames; -} - -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, - PyObject* kw_name) -{ - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION >= 3 - "%s() got multiple values for keyword argument '%U'", func_name, kw_name); - #else - "%s() got multiple values for keyword argument '%s'", func_name, - PyString_AS_STRING(kw_name)); - #endif -} - -static void __Pyx_RaiseArgtupleInvalid( - const char* func_name, - int exact, - Py_ssize_t num_min, - Py_ssize_t num_max, - Py_ssize_t num_found) -{ - Py_ssize_t num_expected; - const char *number, *more_or_less; - - if (num_found < num_min) { - num_expected = num_min; - more_or_less = "at least"; - } else { - num_expected = num_max; - more_or_less = "at most"; - } - if (exact) { - more_or_less = "exactly"; - } - number = (num_expected == 1) ? "" : "s"; - PyErr_Format(PyExc_TypeError, - #if PY_VERSION_HEX < 0x02050000 - "%s() takes %s %d positional argument%s (%d given)", - #else - "%s() takes %s %zd positional argument%s (%zd given)", - #endif - func_name, more_or_less, num_expected, number, num_found); -} - -static int __Pyx_ParseOptionalKeywords( - PyObject *kwds, - PyObject **argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - const char* function_name) -{ - PyObject *key = 0, *value = 0; - Py_ssize_t pos = 0; - PyObject*** name; - PyObject*** first_kw_arg = argnames + num_pos_args; - - while (PyDict_Next(kwds, &pos, &key, &value)) { - name = first_kw_arg; - while (*name && (**name != key)) name++; - if (*name) { - values[name-argnames] = value; - } else { - #if PY_MAJOR_VERSION < 3 - if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) { - #else - if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) { - #endif - goto invalid_keyword_type; - } else { - for (name = first_kw_arg; *name; name++) { - #if PY_MAJOR_VERSION >= 3 - if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && - PyUnicode_Compare(**name, key) == 0) break; - #else - if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && - _PyString_Eq(**name, key)) break; - #endif - } - if (*name) { - values[name-argnames] = value; - } else { - /* unexpected keyword found */ - for (name=argnames; name != first_kw_arg; name++) { - if (**name == key) goto arg_passed_twice; - #if PY_MAJOR_VERSION >= 3 - if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && - PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice; - #else - if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && - _PyString_Eq(**name, key)) goto arg_passed_twice; - #endif - } - if (kwds2) { - if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; - } else { - goto invalid_keyword; - } - } - } - } - } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, **name); - goto bad; -invalid_keyword_type: - PyErr_Format(PyExc_TypeError, - "%s() keywords must be strings", function_name); - goto bad; -invalid_keyword: - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION < 3 - "%s() got an unexpected keyword argument '%s'", - function_name, PyString_AsString(key)); - #else - "%s() got an unexpected keyword argument '%U'", - function_name, key); - #endif -bad: - return -1; -} - - -static INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { - PyErr_Format(PyExc_ValueError, - #if PY_VERSION_HEX < 0x02050000 - "need more than %d value%s to unpack", (int)index, - #else - "need more than %zd value%s to unpack", index, - #endif - (index == 1) ? "" : "s"); -} - -static INLINE void __Pyx_RaiseTooManyValuesError(void) { - PyErr_SetString(PyExc_ValueError, "too many values to unpack"); -} - -static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) { - PyObject *item; - if (!(item = PyIter_Next(iter))) { - if (!PyErr_Occurred()) { - __Pyx_RaiseNeedMoreValuesError(index); - } - } - return item; -} - -static int __Pyx_EndUnpack(PyObject *iter) { - PyObject *item; - if ((item = PyIter_Next(iter))) { - Py_DECREF(item); - __Pyx_RaiseTooManyValuesError(); - return -1; - } - else if (!PyErr_Occurred()) - return 0; - else - return -1; -} - -static INLINE void __Pyx_RaiseNoneNotIterableError(void) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); -} - - -static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) { - if (t == Py_None) { - __Pyx_RaiseNoneNotIterableError(); - } else if (PyTuple_GET_SIZE(t) < index) { - __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t)); - } else { - __Pyx_RaiseTooManyValuesError(); - } -} - -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) { - PyObject *__import__ = 0; - PyObject *empty_list = 0; - PyObject *module = 0; - PyObject *global_dict = 0; - PyObject *empty_dict = 0; - PyObject *list; - __import__ = __Pyx_GetAttrString(__pyx_b, "__import__"); - if (!__import__) - goto bad; - if (from_list) - list = from_list; - else { - empty_list = PyList_New(0); - if (!empty_list) - goto bad; - list = empty_list; - } - global_dict = PyModule_GetDict(__pyx_m); - if (!global_dict) - goto bad; - empty_dict = PyDict_New(); - if (!empty_dict) - goto bad; - module = PyObject_CallFunctionObjArgs(__import__, - name, global_dict, empty_dict, list, NULL); -bad: - Py_XDECREF(empty_list); - Py_XDECREF(__import__); - Py_XDECREF(empty_dict); - return module; -} - -static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { - PyObject *result; - result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static PyObject *__Pyx_CreateClass( - PyObject *bases, PyObject *dict, PyObject *name, const char *modname) -{ - PyObject *py_modname; - PyObject *result = 0; - - #if PY_MAJOR_VERSION < 3 - py_modname = PyString_FromString(modname); - #else - py_modname = PyUnicode_FromString(modname); - #endif - if (!py_modname) - goto bad; - if (PyDict_SetItemString(dict, "__module__", py_modname) < 0) - goto bad; - #if PY_MAJOR_VERSION < 3 - result = PyClass_New(bases, dict, name); - #else - result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL); - #endif -bad: - Py_XDECREF(py_modname); - return result; -} - -static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - PyThreadState *tstate = PyThreadState_GET(); - - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -} - -static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) { - PyThreadState *tstate = PyThreadState_GET(); - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -} - - -#if PY_MAJOR_VERSION < 3 -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - Py_XINCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); - /* First, check the traceback argument, replacing None with NULL. */ - if (tb == Py_None) { - Py_DECREF(tb); - tb = 0; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - /* Next, replace a missing value with None */ - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - #if PY_VERSION_HEX < 0x02050000 - if (!PyClass_Check(type)) - #else - if (!PyType_Check(type)) - #endif - { - /* Raising an instance. The value should be a dummy. */ - if (value != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - /* Normalize to raise , */ - Py_DECREF(value); - value = type; - #if PY_VERSION_HEX < 0x02050000 - if (PyInstance_Check(type)) { - type = (PyObject*) ((PyInstanceObject*)type)->in_class; - Py_INCREF(type); - } - else { - type = 0; - PyErr_SetString(PyExc_TypeError, - "raise: exception must be an old-style class or instance"); - goto raise_error; - } - #else - type = (PyObject*) Py_TYPE(type); - Py_INCREF(type); - if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto raise_error; - } - #endif - } - - __Pyx_ErrRestore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} - -#else /* Python 3+ */ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { - if (tb == Py_None) { - tb = 0; - } else if (tb && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto bad; - } - if (value == Py_None) - value = 0; - - if (PyExceptionInstance_Check(type)) { - if (value) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto bad; - } - value = type; - type = (PyObject*) Py_TYPE(value); - } else if (!PyExceptionClass_Check(type)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto bad; - } - - PyErr_SetObject(type, value); - - if (tb) { - PyThreadState *tstate = PyThreadState_GET(); - PyObject* tmp_tb = tstate->curexc_traceback; - if (tb != tmp_tb) { - Py_INCREF(tb); - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_tb); - } - } - -bad: - return; -} -#endif - -static INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) { - const unsigned char neg_one = (unsigned char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned char" : - "value too large to convert to unsigned char"); - } - return (unsigned char)-1; - } - return (unsigned char)val; - } - return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x); -} - -static INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) { - const unsigned short neg_one = (unsigned short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned short" : - "value too large to convert to unsigned short"); - } - return (unsigned short)-1; - } - return (unsigned short)val; - } - return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x); -} - -static INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) { - const unsigned int neg_one = (unsigned int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(unsigned int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(unsigned int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to unsigned int" : - "value too large to convert to unsigned int"); - } - return (unsigned int)-1; - } - return (unsigned int)val; - } - return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x); -} - -static INLINE char __Pyx_PyInt_AsChar(PyObject* x) { - const char neg_one = (char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to char" : - "value too large to convert to char"); - } - return (char)-1; - } - return (char)val; - } - return (char)__Pyx_PyInt_AsLong(x); -} - -static INLINE short __Pyx_PyInt_AsShort(PyObject* x) { - const short neg_one = (short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to short" : - "value too large to convert to short"); - } - return (short)-1; - } - return (short)val; - } - return (short)__Pyx_PyInt_AsLong(x); -} - -static INLINE int __Pyx_PyInt_AsInt(PyObject* x) { - const int neg_one = (int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to int" : - "value too large to convert to int"); - } - return (int)-1; - } - return (int)val; - } - return (int)__Pyx_PyInt_AsLong(x); -} - -static INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) { - const signed char neg_one = (signed char)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed char) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed char)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed char" : - "value too large to convert to signed char"); - } - return (signed char)-1; - } - return (signed char)val; - } - return (signed char)__Pyx_PyInt_AsSignedLong(x); -} - -static INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) { - const signed short neg_one = (signed short)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed short) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed short)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed short" : - "value too large to convert to signed short"); - } - return (signed short)-1; - } - return (signed short)val; - } - return (signed short)__Pyx_PyInt_AsSignedLong(x); -} - -static INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) { - const signed int neg_one = (signed int)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; - if (sizeof(signed int) < sizeof(long)) { - long val = __Pyx_PyInt_AsLong(x); - if (unlikely(val != (long)(signed int)val)) { - if (!unlikely(val == -1 && PyErr_Occurred())) { - PyErr_SetString(PyExc_OverflowError, - (is_unsigned && unlikely(val < 0)) ? - "can't convert negative value to signed int" : - "value too large to convert to signed int"); - } - return (signed int)-1; - } - return (signed int)val; - } - return (signed int)__Pyx_PyInt_AsSignedLong(x); -} - -static INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) { - const unsigned long neg_one = (unsigned long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long)-1; - } - return (unsigned long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned long"); - return (unsigned long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - unsigned long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (unsigned long)-1; - val = __Pyx_PyInt_AsUnsignedLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) { - const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned PY_LONG_LONG"); - return (unsigned PY_LONG_LONG)-1; - } - return (unsigned PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned PY_LONG_LONG"); - return (unsigned PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - unsigned PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (unsigned PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsUnsignedLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static INLINE long __Pyx_PyInt_AsLong(PyObject* x) { - const long neg_one = (long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long)-1; - } - return (long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (long)-1; - val = __Pyx_PyInt_AsLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) { - const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to PY_LONG_LONG"); - return (PY_LONG_LONG)-1; - } - return (PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to PY_LONG_LONG"); - return (PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) { - const signed long neg_one = (signed long)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed long"); - return (signed long)-1; - } - return (signed long)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed long"); - return (signed long)-1; - } - return PyLong_AsUnsignedLong(x); - } else { - return PyLong_AsLong(x); - } - } else { - signed long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (signed long)-1; - val = __Pyx_PyInt_AsSignedLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) { - const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0; - const int is_unsigned = neg_one > const_zero; -#if PY_VERSION_HEX < 0x03000000 - if (likely(PyInt_Check(x))) { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed PY_LONG_LONG"); - return (signed PY_LONG_LONG)-1; - } - return (signed PY_LONG_LONG)val; - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { - if (unlikely(Py_SIZE(x) < 0)) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to signed PY_LONG_LONG"); - return (signed PY_LONG_LONG)-1; - } - return PyLong_AsUnsignedLongLong(x); - } else { - return PyLong_AsLongLong(x); - } - } else { - signed PY_LONG_LONG val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (signed PY_LONG_LONG)-1; - val = __Pyx_PyInt_AsSignedLongLong(tmp); - Py_DECREF(tmp); - return val; - } -} - -static void __Pyx_WriteUnraisable(const char *name) { - PyObject *old_exc, *old_val, *old_tb; - PyObject *ctx; - __Pyx_ErrFetch(&old_exc, &old_val, &old_tb); - #if PY_MAJOR_VERSION < 3 - ctx = PyString_FromString(name); - #else - ctx = PyUnicode_FromString(name); - #endif - __Pyx_ErrRestore(old_exc, old_val, old_tb); - if (!ctx) { - PyErr_WriteUnraisable(Py_None); - } else { - PyErr_WriteUnraisable(ctx); - Py_DECREF(ctx); - } -} - -static int __Pyx_SetVtable(PyObject *dict, void *vtable) { -#if PY_VERSION_HEX < 0x03010000 - PyObject *ob = PyCObject_FromVoidPtr(vtable, 0); -#else - PyObject *ob = PyCapsule_New(vtable, 0, 0); -#endif - if (!ob) - goto bad; - if (PyDict_SetItemString(dict, "__pyx_vtable__", ob) < 0) - goto bad; - Py_DECREF(ob); - return 0; -bad: - Py_XDECREF(ob); - return -1; -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" - -static void __Pyx_AddTraceback(const char *funcname) { - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - PyObject *py_globals = 0; - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - - #if PY_MAJOR_VERSION < 3 - py_srcfile = PyString_FromString(__pyx_filename); - #else - py_srcfile = PyUnicode_FromString(__pyx_filename); - #endif - if (!py_srcfile) goto bad; - if (__pyx_clineno) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno); - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); - #else - py_funcname = PyUnicode_FromString(funcname); - #endif - } - if (!py_funcname) goto bad; - py_globals = PyModule_GetDict(__pyx_m); - if (!py_globals) goto bad; - py_code = PyCode_New( - 0, /*int argcount,*/ - #if PY_MAJOR_VERSION >= 3 - 0, /*int kwonlyargcount,*/ - #endif - 0, /*int nlocals,*/ - 0, /*int stacksize,*/ - 0, /*int flags,*/ - __pyx_empty_bytes, /*PyObject *code,*/ - __pyx_empty_tuple, /*PyObject *consts,*/ - __pyx_empty_tuple, /*PyObject *names,*/ - __pyx_empty_tuple, /*PyObject *varnames,*/ - __pyx_empty_tuple, /*PyObject *freevars,*/ - __pyx_empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - __pyx_lineno, /*int firstlineno,*/ - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - if (!py_code) goto bad; - py_frame = PyFrame_New( - PyThreadState_GET(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - py_globals, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = __pyx_lineno; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - #if PY_MAJOR_VERSION < 3 - if (t->is_unicode) { - *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); - } else if (t->intern) { - *t->p = PyString_InternFromString(t->s); - } else { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - } - #else /* Python 3+ has unicode identifiers */ - if (t->is_unicode | t->is_str) { - if (t->intern) { - *t->p = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); - } else { - *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - #endif - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -/* Type Conversion Functions */ - -static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - if (x == Py_True) return 1; - else if ((x == Py_False) | (x == Py_None)) return 0; - else return PyObject_IsTrue(x); -} - -static INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { - PyNumberMethods *m; - const char *name = NULL; - PyObject *res = NULL; -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(x) || PyLong_Check(x)) -#else - if (PyLong_Check(x)) -#endif - return Py_INCREF(x), x; - m = Py_TYPE(x)->tp_as_number; -#if PY_VERSION_HEX < 0x03000000 - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Int(x); - } - else if (m && m->nb_long) { - name = "long"; - res = PyNumber_Long(x); - } -#else - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Long(x); - } -#endif - if (res) { -#if PY_VERSION_HEX < 0x03000000 - if (!PyInt_Check(res) && !PyLong_Check(res)) { -#else - if (!PyLong_Check(res)) { -#endif - PyErr_Format(PyExc_TypeError, - "__%s__ returned non-%s (type %.200s)", - name, name, Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} - -static INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject* x = PyNumber_Index(b); - if (!x) return -1; - ival = PyInt_AsSsize_t(x); - Py_DECREF(x); - return ival; -} - -static INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { -#if PY_VERSION_HEX < 0x02050000 - if (ival <= LONG_MAX) - return PyInt_FromLong((long)ival); - else { - unsigned char *bytes = (unsigned char *) &ival; - int one = 1; int little = (int)*(unsigned char*)&one; - return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0); - } -#else - return PyInt_FromSize_t(ival); -#endif -} - -static INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) { - unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x); - if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) { - return (size_t)-1; - } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) { - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to size_t"); - return (size_t)-1; - } - return (size_t)val; -} - - -#endif /* Py_PYTHON_H */ diff --git a/sphinx/pycode/pgen2/parse.py b/sphinx/pycode/pgen2/parse.py deleted file mode 100644 index 660a47e68..000000000 --- a/sphinx/pycode/pgen2/parse.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Parser engine for the grammar tables generated by pgen. - -The grammar table must be loaded first. - -See Parser/parser.c in the Python distribution for additional info on -how this parsing engine works. - -""" - -# Local imports -from sphinx.pycode.pgen2 import token - -if False: - # For type annotation - from typing import Any, List, Set, Tuple # NOQA - -class ParseError(Exception): - """Exception to signal the parser is stuck.""" - - def __init__(self, msg, type, value, context): - Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - (msg, type, value, context)) - self.msg = msg - self.type = type - self.value = value - self.context = context - -class Parser(object): - """Parser engine. - - The proper usage sequence is: - - p = Parser(grammar, [converter]) # create instance - p.setup([start]) # prepare for parsing - : - if p.addtoken(...): # parse a token; may raise ParseError - break - root = p.rootnode # root of abstract syntax tree - - A Parser instance may be reused by calling setup() repeatedly. - - A Parser instance contains state pertaining to the current token - sequence, and should not be used concurrently by different threads - to parse separate token sequences. - - See driver.py for how to get input tokens by tokenizing a file or - string. - - Parsing is complete when addtoken() returns True; the root of the - abstract syntax tree can then be retrieved from the rootnode - instance variable. When a syntax error occurs, addtoken() raises - the ParseError exception. There is no error recovery; the parser - cannot be used after a syntax error was reported (but it can be - reinitialized by calling setup()). - - """ - - def __init__(self, grammar, convert=None): - """Constructor. - - The grammar argument is a grammar.Grammar instance; see the - grammar module for more information. - - The parser is not ready yet for parsing; you must call the - setup() method to get it started. - - The optional convert argument is a function mapping concrete - syntax tree nodes to abstract syntax tree nodes. If not - given, no conversion is done and the syntax tree produced is - the concrete syntax tree. If given, it must be a function of - two arguments, the first being the grammar (a grammar.Grammar - instance), and the second being the concrete syntax tree node - to be converted. The syntax tree is converted from the bottom - up. - - A concrete syntax tree node is a (type, value, context, nodes) - tuple, where type is the node type (a token or symbol number), - value is None for symbols and a string for tokens, context is - None or an opaque value used for error reporting (typically a - (lineno, offset) pair), and nodes is a list of children for - symbols, and None for tokens. - - An abstract syntax tree node may be anything; this is entirely - up to the converter function. - - """ - self.grammar = grammar - self.convert = convert or (lambda grammar, node: node) - - def setup(self, start=None): - """Prepare for parsing. - - This *must* be called before starting to parse. - - The optional argument is an alternative start symbol; it - defaults to the grammar's start symbol. - - You can use a Parser instance to parse any number of programs; - each time you call setup() the parser is reset to an initial - state determined by the (implicit or explicit) start symbol. - - """ - if start is None: - start = self.grammar.start - # Each stack entry is a tuple: (dfa, state, node). - # A node is a tuple: (type, value, context, children), - # where children is a list of nodes or None, and context may be None. - newnode = (start, None, None, []) # type: Tuple[unicode, unicode, unicode, List] - stackentry = (self.grammar.dfas[start], 0, newnode) - self.stack = [stackentry] - self.rootnode = None # type: Any - self.used_names = set() # type: Set[unicode] - # Aliased to self.rootnode.used_names in pop() - - def addtoken(self, type, value, context): - """Add a token; return True iff this is the end of the program.""" - # Map from token to label - ilabel = self.classify(type, value, context) - # Loop until the token is shifted; may raise exceptions - while True: - dfa, state, node = self.stack[-1] - states, first = dfa - arcs = states[state] - # Look for a state with this label - for i, newstate in arcs: - t, v = self.grammar.labels[i] - if ilabel == i: - # Look it up in the list of labels - assert t < 256 - # Shift a token; we're done with it - self.shift(type, value, newstate, context) - # Pop while we are in an accept-only state - state = newstate - while states[state] == [(0, state)]: - self.pop() - if not self.stack: - # Done parsing! - return True - dfa, state, node = self.stack[-1] - states, first = dfa - # Done with this token - return False - elif t >= 256: - # See if it's a symbol and if we're in its first set - itsdfa = self.grammar.dfas[t] - itsstates, itsfirst = itsdfa - if ilabel in itsfirst: - # Push a symbol - self.push(t, self.grammar.dfas[t], newstate, context) - break # To continue the outer while loop - else: - if (0, state) in arcs: - # An accepting state, pop it and try something else - self.pop() - if not self.stack: - # Done parsing, but another token is input - raise ParseError("too much input", - type, value, context) - else: - # No success finding a transition - raise ParseError("bad input", type, value, context) - - def classify(self, type, value, context): - """Turn a token into a label. (Internal)""" - if type == token.NAME: - # Keep a listing of all used names - self.used_names.add(value) - # Check for reserved words - ilabel = self.grammar.keywords.get(value) - if ilabel is not None: - return ilabel - ilabel = self.grammar.tokens.get(type) - if ilabel is None: - raise ParseError("bad token", type, value, context) - return ilabel - - def shift(self, type, value, newstate, context): - """Shift a token. (Internal)""" - dfa, state, node = self.stack[-1] - newnode = (type, value, context, None) # type: Tuple[unicode, unicode, unicode, List] - newnode = self.convert(self.grammar, newnode) - if newnode is not None: - node[-1].append(newnode) - self.stack[-1] = (dfa, newstate, node) - - def push(self, type, newdfa, newstate, context): - """Push a nonterminal. (Internal)""" - dfa, state, node = self.stack[-1] - newnode = (type, None, context, []) # type: Tuple[unicode, unicode, unicode, List] - self.stack[-1] = (dfa, newstate, node) - self.stack.append((newdfa, 0, newnode)) - - def pop(self): - """Pop a nonterminal. (Internal)""" - popdfa, popstate, popnode = self.stack.pop() - newnode = self.convert(self.grammar, popnode) - if newnode is not None: - if self.stack: - dfa, state, node = self.stack[-1] - node[-1].append(newnode) - else: - self.rootnode = newnode - self.rootnode.used_names = self.used_names diff --git a/sphinx/pycode/pgen2/parse.pyx b/sphinx/pycode/pgen2/parse.pyx deleted file mode 100644 index 9c97a4539..000000000 --- a/sphinx/pycode/pgen2/parse.pyx +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# Adapted from parse.py to be compiled with Cython by Georg Brandl. - -"""Parser engine for the grammar tables generated by pgen. - -The grammar table must be loaded first. - -See Parser/parser.c in the Python distribution for additional info on -how this parsing engine works. - -""" - -from sphinx.pycode.nodes import Node, Leaf - -DEF NAME = 1 - -class ParseError(Exception): - """Exception to signal the parser is stuck.""" - - def __init__(self, msg, type, value, context): - Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - (msg, type, value, context)) - self.msg = msg - self.type = type - self.value = value - self.context = context - - -cdef class Parser: - cdef public object grammar - cdef public object rootnode - cdef public list stack - cdef public set used_names - cdef int _grammar_start - cdef list _grammar_labels - cdef dict _grammar_dfas - cdef dict _grammar_keywords - cdef dict _grammar_tokens - cdef dict _grammar_number2symbol - - def __init__(self, grammar, convert=None): - self.grammar = grammar - #self.convert = convert or noconvert - - self._grammar_dfas = grammar.dfas - self._grammar_labels = grammar.labels - self._grammar_keywords = grammar.keywords - self._grammar_tokens = grammar.tokens - self._grammar_number2symbol = grammar.number2symbol - self._grammar_start = grammar.start - - def setup(self, start=None): - if start is None: - start = self._grammar_start - # Each stack entry is a tuple: (dfa, state, node). - # A node is a tuple: (type, value, context, children), - # where children is a list of nodes or None, and context may be None. - newnode = (start, None, None, []) - stackentry = (self._grammar_dfas[start], 0, newnode) - self.stack = [stackentry] - self.rootnode = None - self.used_names = set() # Aliased to self.rootnode.used_names in pop() - - def addtoken(self, int type, value, context): - """Add a token; return True iff this is the end of the program.""" - cdef int ilabel, i, t, state, newstate - # Map from token to label - ilabel = self.classify(type, value, context) - # Loop until the token is shifted; may raise exceptions - while True: - dfa, state, node = self.stack[-1] - states, first = dfa - arcs = states[state] - # Look for a state with this label - for i, newstate in arcs: - t, v = self._grammar_labels[i] - if ilabel == i: - # Look it up in the list of labels - ## assert t < 256 - # Shift a token; we're done with it - self.shift(type, value, newstate, context) - # Pop while we are in an accept-only state - state = newstate - while states[state] == [(0, state)]: - self.pop() - if not self.stack: - # Done parsing! - return True - dfa, state, node = self.stack[-1] - states, first = dfa - # Done with this token - return False - elif t >= 256: - # See if it's a symbol and if we're in its first set - itsdfa = self._grammar_dfas[t] - itsstates, itsfirst = itsdfa - if ilabel in itsfirst: - # Push a symbol - self.push(t, itsdfa, newstate, context) - break # To continue the outer while loop - else: - if (0, state) in arcs: - # An accepting state, pop it and try something else - self.pop() - if not self.stack: - # Done parsing, but another token is input - raise ParseError("too much input", - type, value, context) - else: - # No success finding a transition - raise ParseError("bad input", type, value, context) - - cdef int classify(self, int type, value, context): - """Turn a token into a label. (Internal)""" - if type == NAME: - # Keep a listing of all used names - self.used_names.add(value) - # Check for reserved words - if value in self._grammar_keywords: - return self._grammar_keywords[value] - if type not in self._grammar_tokens: - raise ParseError("bad token", type, value, context) - return self._grammar_tokens[type] - - cdef void shift(self, type, value, newstate, context): - """Shift a token. (Internal)""" - cdef tuple node - dfa, state, node = self.stack[-1] - newnode = (type, value, context, None) - newnode = self.convert(newnode) - if newnode is not None: - node[-1].append(newnode) - self.stack[-1] = (dfa, newstate, node) - - cdef void push(self, type, newdfa, newstate, context): - """Push a nonterminal. (Internal)""" - dfa, state, node = self.stack[-1] - newnode = (type, None, context, []) - self.stack[-1] = (dfa, newstate, node) - self.stack.append((newdfa, 0, newnode)) - - cdef void pop(self): - """Pop a nonterminal. (Internal)""" - popdfa, popstate, popnode = self.stack.pop() - newnode = self.convert(popnode) - if newnode is not None: - if self.stack: - dfa, state, node = self.stack[-1] - node[-1].append(newnode) - else: - self.rootnode = newnode - self.rootnode.used_names = self.used_names - - cdef convert(self, tuple raw_node): - type, value, context, children = raw_node - if children or type in self._grammar_number2symbol: - # If there's exactly one child, return that child instead of - # creating a new node. - if len(children) == 1: - return children[0] - return Node(type, children, context=context) - else: - return Leaf(type, value, context=context) diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py deleted file mode 100644 index 8d9cc786a..000000000 --- a/sphinx/pycode/pgen2/pgen.py +++ /dev/null @@ -1,403 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -from __future__ import print_function - -from six import iteritems -from collections import OrderedDict - -# Pgen imports -from sphinx.pycode.pgen2 import grammar, token, tokenize - -if False: - # For type annotation - from typing import Any, Dict, List, Tuple # NOQA - - -class PgenGrammar(grammar.Grammar): - pass - -class ParserGenerator(object): - - def __init__(self, filename, stream=None): - close_stream = None - if stream is None: - stream = open(filename) - close_stream = stream.close - self.filename = filename - self.stream = stream - self.generator = tokenize.generate_tokens(stream.readline) - self.gettoken() # Initialize lookahead - self.dfas, self.startsymbol = self.parse() - if close_stream is not None: - close_stream() - self.first = {} # type: Dict[unicode, List[unicode]] - # map from symbol name to set of tokens - self.addfirstsets() - - def make_grammar(self): - c = PgenGrammar() - names = list(self.dfas.keys()) - names.sort() - names.remove(self.startsymbol) - names.insert(0, self.startsymbol) - for name in names: - i = 256 + len(c.symbol2number) - c.symbol2number[name] = i - c.number2symbol[i] = name - for name in names: - dfa = self.dfas[name] - states = [] # type: List[List[Tuple[int, int]]] - for state in dfa: - arcs = [] - for label, next in iteritems(state.arcs): - arcs.append((self.make_label(c, label), dfa.index(next))) - if state.isfinal: - arcs.append((0, dfa.index(state))) - states.append(arcs) - c.states.append(states) - c.dfas[c.symbol2number[name]] = (states, self.make_first(c, name)) - c.start = c.symbol2number[self.startsymbol] - return c - - def make_first(self, c, name): - rawfirst = self.first[name] - first = {} - for label in sorted(rawfirst): - ilabel = self.make_label(c, label) - ##assert ilabel not in first # X X X failed on <> ... != - first[ilabel] = 1 - return first - - def make_label(self, c, label): - # X X X Maybe this should be a method on a subclass of converter? - ilabel = len(c.labels) - if label[0].isalpha(): - # Either a symbol name or a named token - if label in c.symbol2number: - # A symbol name (a non-terminal) - if label in c.symbol2label: - return c.symbol2label[label] - else: - c.labels.append((c.symbol2number[label], None)) - c.symbol2label[label] = ilabel - return ilabel - else: - # A named token (NAME, NUMBER, STRING) - itoken = getattr(token, label, None) - assert isinstance(itoken, int), label - assert itoken in token.tok_name, label - if itoken in c.tokens: - return c.tokens[itoken] - else: - c.labels.append((itoken, None)) - c.tokens[itoken] = ilabel - return ilabel - else: - # Either a keyword or an operator - assert label[0] in ('"', "'"), label - value = eval(label) - if value[0].isalpha(): - # A keyword - if value in c.keywords: - return c.keywords[value] - else: - c.labels.append((token.NAME, value)) - c.keywords[value] = ilabel - return ilabel - else: - # An operator (any non-numeric token) - itoken = grammar.opmap[value] # Fails if unknown token - if itoken in c.tokens: - return c.tokens[itoken] - else: - c.labels.append((itoken, None)) - c.tokens[itoken] = ilabel - return ilabel - - def addfirstsets(self): - names = list(self.dfas.keys()) - names.sort() - for name in names: - if name not in self.first: - self.calcfirst(name) - #print name, self.first[name].keys() - - def calcfirst(self, name): - dfa = self.dfas[name] - self.first[name] = None # dummy to detect left recursion - state = dfa[0] - totalset = {} # type: Dict[unicode, int] - overlapcheck = {} - for label, next in iteritems(state.arcs): - if label in self.dfas: - if label in self.first: - fset = self.first[label] - if fset is None: - raise ValueError("recursion for rule %r" % name) - else: - self.calcfirst(label) - fset = self.first[label] - totalset.update(fset) - overlapcheck[label] = fset - else: - totalset[label] = 1 - overlapcheck[label] = {label: 1} - inverse = {} # type: Dict[unicode, unicode] - for label, itsfirst in sorted(overlapcheck.items()): - for symbol in sorted(itsfirst): - if symbol in inverse: - raise ValueError("rule %s is ambiguous; %s is in the" - " first sets of %s as well as %s" % - (name, symbol, label, inverse[symbol])) - inverse[symbol] = label - self.first[name] = totalset - - def parse(self): - dfas = {} - startsymbol = None - # MSTART: (NEWLINE | RULE)* ENDMARKER - while self.type != token.ENDMARKER: - while self.type == token.NEWLINE: - self.gettoken() - # RULE: NAME ':' RHS NEWLINE - name = self.expect(token.NAME) - self.expect(token.OP, ":") - a, z = self.parse_rhs() - self.expect(token.NEWLINE) - #self.dump_nfa(name, a, z) - dfa = self.make_dfa(a, z) - #self.dump_dfa(name, dfa) - #oldlen = len(dfa) - self.simplify_dfa(dfa) - #newlen = len(dfa) - dfas[name] = dfa - #print name, oldlen, newlen - if startsymbol is None: - startsymbol = name - return dfas, startsymbol - - def make_dfa(self, start, finish): - # To turn an NFA into a DFA, we define the states of the DFA - # to correspond to *sets* of states of the NFA. Then do some - # state reduction. Let's represent sets as dicts with 1 for - # values. - assert isinstance(start, NFAState) - assert isinstance(finish, NFAState) - def closure(state): - base = {} # type: Dict - addclosure(state, base) - return base - def addclosure(state, base): - assert isinstance(state, NFAState) - if state in base: - return - base[state] = 1 - for label, next in state.arcs: - if label is None: - addclosure(next, base) - states = [DFAState(closure(start), finish)] - for state in states: # NB states grows while we're iterating - arcs = {} # type: Dict[unicode, Dict] - for nfastate in state.nfaset: - for label, next in nfastate.arcs: - if label is not None: - addclosure(next, arcs.setdefault(label, {})) - for label, nfaset in iteritems(arcs): - for st in states: - if st.nfaset == nfaset: - break - else: - st = DFAState(nfaset, finish) - states.append(st) - state.addarc(st, label) - return states # List of DFAState instances; first one is start - - def dump_nfa(self, name, start, finish): - print("Dump of NFA for", name) - todo = [start] - for i, state in enumerate(todo): - print(" State", i, state is finish and "(final)" or "") - for label, next in state.arcs: - if next in todo: - j = todo.index(next) - else: - j = len(todo) - todo.append(next) - if label is None: - print(" -> %d" % j) - else: - print(" %s -> %d" % (label, j)) - - def dump_dfa(self, name, dfa): - print("Dump of DFA for", name) - for i, state in enumerate(dfa): - print(" State", i, state.isfinal and "(final)" or "") - for label, next in iteritems(state.arcs): - print(" %s -> %d" % (label, dfa.index(next))) - - def simplify_dfa(self, dfa): - # This is not theoretically optimal, but works well enough. - # Algorithm: repeatedly look for two states that have the same - # set of arcs (same labels pointing to the same nodes) and - # unify them, until things stop changing. - - # dfa is a list of DFAState instances - changes = True - while changes: - changes = False - for i, state_i in enumerate(dfa): - for j in range(i+1, len(dfa)): - state_j = dfa[j] - if state_i == state_j: - #print " unify", i, j - del dfa[j] - for state in dfa: - state.unifystate(state_j, state_i) - changes = True - break - - def parse_rhs(self): - # RHS: ALT ('|' ALT)* - a, z = self.parse_alt() - if self.value != "|": - return a, z - else: - aa = NFAState() - zz = NFAState() - aa.addarc(a) - z.addarc(zz) - while self.value == "|": - self.gettoken() - a, z = self.parse_alt() - aa.addarc(a) - z.addarc(zz) - return aa, zz - - def parse_alt(self): - # ALT: ITEM+ - a, b = self.parse_item() - while (self.value in ("(", "[") or - self.type in (token.NAME, token.STRING)): - c, d = self.parse_item() - b.addarc(c) - b = d - return a, b - - def parse_item(self): - # ITEM: '[' RHS ']' | ATOM ['+' | '*'] - if self.value == "[": - self.gettoken() - a, z = self.parse_rhs() - self.expect(token.OP, "]") - a.addarc(z) - return a, z - else: - a, z = self.parse_atom() - value = self.value - if value not in ("+", "*"): - return a, z - self.gettoken() - z.addarc(a) - if value == "+": - return a, z - else: - return a, a - - def parse_atom(self): - # ATOM: '(' RHS ')' | NAME | STRING - if self.value == "(": - self.gettoken() - a, z = self.parse_rhs() - self.expect(token.OP, ")") - return a, z - elif self.type in (token.NAME, token.STRING): - a = NFAState() - z = NFAState() - a.addarc(z, self.value) - self.gettoken() - return a, z - else: - self.raise_error("expected (...) or NAME or STRING, got %s/%s", - self.type, self.value) - - def expect(self, type, value=None): - if self.type != type or (value is not None and self.value != value): - self.raise_error("expected %s/%s, got %s/%s", - type, value, self.type, self.value) - value = self.value - self.gettoken() - return value - - def gettoken(self): - tup = next(self.generator) - while tup[0] in (tokenize.COMMENT, tokenize.NL): - tup = next(self.generator) - self.type, self.value, self.begin, self.end, self.line = tup - #print token.tok_name[self.type], repr(self.value) - - def raise_error(self, msg, *args): - if args: - try: - msg = msg % args - except: - msg = " ".join([msg] + [str(x) for x in args]) - raise SyntaxError(msg, (self.filename, self.end[0], - self.end[1], self.line)) - -class NFAState(object): - - def __init__(self): - self.arcs = [] # type: List[Tuple[unicode, Any]] - # list of (label, NFAState) pairs - - def addarc(self, next, label=None): - assert label is None or isinstance(label, str) - assert isinstance(next, NFAState) - self.arcs.append((label, next)) - - def __hash__(self): - return hash(tuple(x[0] for x in self.arcs)) - -class DFAState(object): - - def __init__(self, nfaset, final): - assert isinstance(nfaset, dict) - assert isinstance(next(iter(nfaset)), NFAState) - assert isinstance(final, NFAState) - self.nfaset = nfaset - self.isfinal = final in nfaset - self.arcs = OrderedDict() # type: OrderedDict - # map from label to DFAState - - def __hash__(self): - return hash(tuple(self.arcs)) - - def addarc(self, next, label): - assert isinstance(label, str) - assert label not in self.arcs - assert isinstance(next, DFAState) - self.arcs[label] = next - - def unifystate(self, old, new): - for label, next in iteritems(self.arcs): - if next is old: - self.arcs[label] = new - - def __eq__(self, other): - # Equality test -- ignore the nfaset instance variable - assert isinstance(other, DFAState) - if self.isfinal != other.isfinal: - return False - # Can't just return self.arcs == other.arcs, because that - # would invoke this method recursively, with cycles... - if len(self.arcs) != len(other.arcs): - return False - for label, next in iteritems(self.arcs): - if next is not other.arcs.get(label): - return False - return True - -def generate_grammar(filename="Grammar.txt"): - p = ParserGenerator(filename) - return p.make_grammar() diff --git a/sphinx/pycode/pgen2/token.py b/sphinx/pycode/pgen2/token.py deleted file mode 100755 index 73718d166..000000000 --- a/sphinx/pycode/pgen2/token.py +++ /dev/null @@ -1,86 +0,0 @@ -#! /usr/bin/env python - -"""Token constants (from "token.h").""" - -# Taken from Python (r53757) and modified to include some tokens -# originally monkeypatched in by pgen2.tokenize - -#--start constants-- -ENDMARKER = 0 -NAME = 1 -NUMBER = 2 -STRING = 3 -NEWLINE = 4 -INDENT = 5 -DEDENT = 6 -LPAR = 7 -RPAR = 8 -LSQB = 9 -RSQB = 10 -COLON = 11 -COMMA = 12 -SEMI = 13 -PLUS = 14 -MINUS = 15 -STAR = 16 -SLASH = 17 -VBAR = 18 -AMPER = 19 -LESS = 20 -GREATER = 21 -EQUAL = 22 -DOT = 23 -PERCENT = 24 -BACKQUOTE = 25 -LBRACE = 26 -RBRACE = 27 -EQEQUAL = 28 -NOTEQUAL = 29 -LESSEQUAL = 30 -GREATEREQUAL = 31 -TILDE = 32 -CIRCUMFLEX = 33 -LEFTSHIFT = 34 -RIGHTSHIFT = 35 -DOUBLESTAR = 36 -PLUSEQUAL = 37 -MINEQUAL = 38 -STAREQUAL = 39 -SLASHEQUAL = 40 -PERCENTEQUAL = 41 -AMPEREQUAL = 42 -VBAREQUAL = 43 -CIRCUMFLEXEQUAL = 44 -LEFTSHIFTEQUAL = 45 -RIGHTSHIFTEQUAL = 46 -DOUBLESTAREQUAL = 47 -DOUBLESLASH = 48 -DOUBLESLASHEQUAL = 49 -AT = 50 -ATEQUAL = 51 -RARROW = 52 -ELLIPSIS = 53 -OP = 54 -AWAIT = 55 -ASYNC = 56 -COMMENT = 57 -NL = 58 -ERRORTOKEN = 59 -N_TOKENS = 60 -NT_OFFSET = 256 -#--end constants-- - -tok_name = {} -for _name, _value in list(globals().items()): - if type(_value) is type(0): - tok_name[_value] = _name - - -def ISTERMINAL(x): - return x < NT_OFFSET - -def ISNONTERMINAL(x): - return x >= NT_OFFSET - -def ISEOF(x): - return x == ENDMARKER diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py deleted file mode 100644 index d2820d23a..000000000 --- a/sphinx/pycode/pgen2/tokenize.py +++ /dev/null @@ -1,441 +0,0 @@ -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation. -# All rights reserved. - -"""Tokenization help for Python programs. - -generate_tokens(readline) is a generator that breaks a stream of -text into Python tokens. It accepts a readline-like method which is called -repeatedly to get the next line of input (or "" for EOF). It generates -5-tuples with these members: - - the token type (see token.py) - the token (a string) - the starting (row, column) indices of the token (a 2-tuple of ints) - the ending (row, column) indices of the token (a 2-tuple of ints) - the original line (string) - -It is designed to match the working of the Python tokenizer exactly, except -that it produces COMMENT tokens for comments and gives type OP for all -operators - -Older entry points - tokenize_loop(readline, tokeneater) - tokenize(readline, tokeneater=printtoken) -are the same, except instead of generating tokens, tokeneater is a callback -function to which the 5 fields described above are passed as 5 arguments, -each time a new token is found. -""" - -from __future__ import print_function - -__author__ = 'Ka-Ping Yee ' -__credits__ = \ - 'GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro' - -import string, re -from six import PY3 -from sphinx.pycode.pgen2.token import * -from sphinx.pycode.pgen2 import token - -if False: - # For type annotation - from typing import List # NOQA - -__all__ = [x for x in dir(token) if x[0] != '_'] + ["tokenize", - "generate_tokens", "untokenize"] -del token - -def group(*choices): return '(' + '|'.join(choices) + ')' -def any(*choices): return group(*choices) + '*' -def maybe(*choices): return group(*choices) + '?' - -Whitespace = r'[ \f\t]*' -Comment = r'#[^\r\n]*' -Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) -Name = r'[a-zA-Z_]\w*' - -Binnumber = r'0[bB][01]*' -Hexnumber = r'0[xX][\da-fA-F]*[lL]?' -Octnumber = r'0[oO]?[0-7]*[lL]?' -Decnumber = r'[1-9]\d*[lL]?' -Intnumber = group(Binnumber, Hexnumber, Octnumber, Decnumber) -Exponent = r'[eE][-+]?\d+' -Pointfloat = group(r'\d+\.\d*', r'\.\d+') + maybe(Exponent) -Expfloat = r'\d+' + Exponent -Floatnumber = group(Pointfloat, Expfloat) -Imagnumber = group(r'\d+[jJ]', Floatnumber + r'[jJ]') -Number = group(Imagnumber, Floatnumber, Intnumber) - -# Tail end of ' string. -Single = r"[^'\\]*(?:\\.[^'\\]*)*'" -# Tail end of " string. -Double = r'[^"\\]*(?:\\.[^"\\]*)*"' -# Tail end of ''' string. -Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" -# Tail end of """ string. -Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -Triple = group("[ubUB]?[rR]?'''", '[ubUB]?[rR]?"""') -# Single-line ' or " string. -String = group(r"[uU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - r'[uU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"') - -# Because of leftmost-then-longest match semantics, be sure to put the -# longest operators first (e.g., if = came before ==, == would get -# recognized as two instances of =). -Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"<>", r"!=", - r"//=?", r"->", - r"[+\-*/%&|^=<>]=?", - r"~") - -Bracket = '[][(){}]' -Special = group(r'\r?\n', r'[:;.,`@]') -if PY3: - Ellipsis_ = r'\.{3}' - Special = group(Ellipsis_, Special) -Funny = group(Operator, Bracket, Special) - -PlainToken = group(Number, Funny, String, Name) -Token = Ignore + PlainToken - -# First (or only) line of ' or " string. -ContStr = group(r"[uUbB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" + - group("'", r'\\\r?\n'), - r'[uUbB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' + - group('"', r'\\\r?\n')) -PseudoExtras = group(r'\\\r?\n', Comment, Triple) -PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) - -tokenprog, pseudoprog, single3prog, double3prog = [ - re.compile(x) for x in (Token, PseudoToken, Single3, Double3) -] -endprogs = {"'": re.compile(Single), '"': re.compile(Double), - "'''": single3prog, '"""': double3prog, - "r'''": single3prog, 'r"""': double3prog, - "u'''": single3prog, 'u"""': double3prog, - "b'''": single3prog, 'b"""': double3prog, - "ur'''": single3prog, 'ur"""': double3prog, - "br'''": single3prog, 'br"""': double3prog, - "R'''": single3prog, 'R"""': double3prog, - "U'''": single3prog, 'U"""': double3prog, - "B'''": single3prog, 'B"""': double3prog, - "uR'''": single3prog, 'uR"""': double3prog, - "Ur'''": single3prog, 'Ur"""': double3prog, - "UR'''": single3prog, 'UR"""': double3prog, - "bR'''": single3prog, 'bR"""': double3prog, - "Br'''": single3prog, 'Br"""': double3prog, - "BR'''": single3prog, 'BR"""': double3prog, - 'r': None, 'R': None, - 'u': None, 'U': None, - 'b': None, 'B': None} - -triple_quoted = {} -for t in ("'''", '"""', - "r'''", 'r"""', "R'''", 'R"""', - "u'''", 'u"""', "U'''", 'U"""', - "b'''", 'b"""', "B'''", 'B"""', - "ur'''", 'ur"""', "Ur'''", 'Ur"""', - "uR'''", 'uR"""', "UR'''", 'UR"""', - "br'''", 'br"""', "Br'''", 'Br"""', - "bR'''", 'bR"""', "BR'''", 'BR"""',): - triple_quoted[t] = t -single_quoted = {} -for t in ("'", '"', - "r'", 'r"', "R'", 'R"', - "u'", 'u"', "U'", 'U"', - "b'", 'b"', "B'", 'B"', - "ur'", 'ur"', "Ur'", 'Ur"', - "uR'", 'uR"', "UR'", 'UR"', - "br'", 'br"', "Br'", 'Br"', - "bR'", 'bR"', "BR'", 'BR"', ): - single_quoted[t] = t - -tabsize = 8 - -class TokenError(Exception): pass - -class StopTokenizing(Exception): pass - -def printtoken(type, token, scell, ecell, line): # for testing - srow, scol = scell - erow, ecol = ecell - print("%d,%d-%d,%d:\t%s\t%s" % - (srow, scol, erow, ecol, tok_name[type], repr(token))) - -def tokenize(readline, tokeneater=printtoken): - """ - The tokenize() function accepts two parameters: one representing the - input stream, and one providing an output mechanism for tokenize(). - - The first parameter, readline, must be a callable object which provides - the same interface as the readline() method of built-in file objects. - Each call to the function should return one line of input as a string. - - The second parameter, tokeneater, must also be a callable object. It is - called once for each token, with five arguments, corresponding to the - tuples generated by generate_tokens(). - """ - try: - tokenize_loop(readline, tokeneater) - except StopTokenizing: - pass - -# backwards compatible interface -def tokenize_loop(readline, tokeneater): - for token_info in generate_tokens(readline): - tokeneater(*token_info) - -class Untokenizer: - - def __init__(self): - self.tokens = [] # type: List[unicode] - self.prev_row = 1 - self.prev_col = 0 - - def add_whitespace(self, start): - row, col = start - assert row <= self.prev_row - col_offset = col - self.prev_col - if col_offset: - self.tokens.append(" " * col_offset) - - def untokenize(self, iterable): - for t in iterable: - if len(t) == 2: - self.compat(t, iterable) - break - tok_type, token, start, end, line = t - self.add_whitespace(start) - self.tokens.append(token) - self.prev_row, self.prev_col = end - if tok_type in (NEWLINE, NL): - self.prev_row += 1 - self.prev_col = 0 - return "".join(self.tokens) - - def compat(self, token, iterable): - startline = False - indents = [] - toks_append = self.tokens.append - toknum, tokval = token - if toknum in (NAME, NUMBER): - tokval += ' ' - if toknum in (NEWLINE, NL): - startline = True - for tok in iterable: - toknum, tokval = tok[:2] - - if toknum in (NAME, NUMBER): - tokval += ' ' - - if toknum == INDENT: - indents.append(tokval) - continue - elif toknum == DEDENT: - indents.pop() - continue - elif toknum in (NEWLINE, NL): - startline = True - elif startline and indents: - toks_append(indents[-1]) - startline = False - toks_append(tokval) - -def untokenize(iterable): - """Transform tokens back into Python source code. - - Each element returned by the iterable must be a token sequence - with at least two elements, a token number and token value. If - only two tokens are passed, the resulting output is poor. - - Round-trip invariant for full input: - Untokenized source will match input source exactly - - Round-trip invariant for limited intput: - # Output text will tokenize the back to the input - t1 = [tok[:2] for tok in generate_tokens(f.readline)] - newcode = untokenize(t1) - readline = iter(newcode.splitlines(1)).next - t2 = [tok[:2] for tokin generate_tokens(readline)] - assert t1 == t2 - """ - ut = Untokenizer() - return ut.untokenize(iterable) - -def generate_tokens(readline): - """ - The generate_tokens() generator requires one argment, readline, which - must be a callable object which provides the same interface as the - readline() method of built-in file objects. Each call to the function - should return one line of input as a string. Alternately, readline - can be a callable function terminating with StopIteration: - readline = open(myfile).next # Example of alternate readline - - The generator produces 5-tuples with these members: the token type; the - token string; a 2-tuple (srow, scol) of ints specifying the row and - column where the token begins in the source; a 2-tuple (erow, ecol) of - ints specifying the row and column where the token ends in the source; - and the line on which the token was found. The line passed is the - logical line; continuation lines are included. - """ - lnum = parenlev = continued = 0 - namechars, numchars = string.ascii_letters + '_', '0123456789' - contstr, needcont = '', 0 - contline = None - indents = [0] - - while 1: # loop over lines in stream - try: - line = readline() - except StopIteration: - line = '' - # if we are not at the end of the file make sure the - # line ends with a newline because the parser depends - # on that. - if line: - line = line.rstrip() + '\n' - lnum = lnum + 1 - pos, max = 0, len(line) - - if contstr: # continued string - if not line: - raise TokenError("EOF in multi-line string", strstart) # type: ignore - endmatch = endprog.match(line) # type: ignore - if endmatch: - pos = end = endmatch.end(0) - yield (STRING, contstr + line[:end], - strstart, (lnum, end), contline + line) # type: ignore - contstr, needcont = '', 0 - contline = None - elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': - yield (ERRORTOKEN, contstr + line, - strstart, (lnum, len(line)), contline) # type: ignore - contstr = '' - contline = None - continue - else: - contstr = contstr + line - contline = contline + line - continue - - elif parenlev == 0 and not continued: # new statement - if not line: break - column = 0 - while pos < max: # measure leading whitespace - if line[pos] == ' ': column = column + 1 - elif line[pos] == '\t': column = (column/tabsize + 1)*tabsize - elif line[pos] == '\f': column = 0 - else: break - pos = pos + 1 - if pos == max: break - - if line[pos] in '#\r\n': # skip comments or blank lines - if line[pos] == '#': - comment_token = line[pos:].rstrip('\r\n') - nl_pos = pos + len(comment_token) - yield (COMMENT, comment_token, - (lnum, pos), (lnum, pos + len(comment_token)), line) - yield (NL, line[nl_pos:], - (lnum, nl_pos), (lnum, len(line)), line) - else: - yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], - (lnum, pos), (lnum, len(line)), line) - continue - - if column > indents[-1]: # count indents or dedents - indents.append(column) - yield (INDENT, line[:pos], (lnum, 0), (lnum, pos), line) - while column < indents[-1]: - if column not in indents: - raise IndentationError( - "unindent does not match any outer indentation level", - ("", lnum, pos, line)) - indents = indents[:-1] - yield (DEDENT, '', (lnum, pos), (lnum, pos), line) - - else: # continued statement - if not line: - raise TokenError("EOF in multi-line statement", (lnum, 0)) - continued = 0 - - while pos < max: - pseudomatch = pseudoprog.match(line, pos) - if pseudomatch: # scan for tokens - start, end = pseudomatch.span(1) - spos, epos, pos = (lnum, start), (lnum, end), end - token, initial = line[start:end], line[start] - - if end < max: - next_pseudomatch = pseudoprog.match(line, end) - if next_pseudomatch: - n_start, n_end = next_pseudomatch.span(1) - n_token = line[n_start:n_end] - else: - n_token = None - else: - n_token = None - - if initial in numchars or ( - initial == '.' and token not in ('.', '...') - ): # ordinary number - yield (NUMBER, token, spos, epos, line) - elif initial in '\r\n': - newline = NEWLINE - if parenlev > 0: - newline = NL - yield (newline, token, spos, epos, line) - elif initial == '#': - assert not token.endswith("\n") - yield (COMMENT, token, spos, epos, line) - elif token in triple_quoted: - endprog = endprogs[token] - endmatch = endprog.match(line, pos) - if endmatch: # all on one line - pos = endmatch.end(0) - token = line[start:pos] - yield (STRING, token, spos, (lnum, pos), line) - else: - strstart = (lnum, start) # multiple lines - contstr = line[start:] - contline = line - break - elif initial in single_quoted or \ - token[:2] in single_quoted or \ - token[:3] in single_quoted: - if token[-1] == '\n': # continued string - strstart = (lnum, start) - endprog = (endprogs[initial] or endprogs[token[1]] or - endprogs[token[2]]) - contstr, needcont = line[start:], 1 - contline = line - break - else: # ordinary string - yield (STRING, token, spos, epos, line) - elif token == 'await' and n_token: - yield (AWAIT, token, spos, epos, line) - elif token == 'async' and n_token in ('def', 'for', 'with'): - yield (ASYNC, token, spos, epos, line) - elif initial in namechars: # ordinary name - yield (NAME, token, spos, epos, line) - elif token in ('...',): # ordinary name - yield (NAME, token, spos, epos, line) - elif initial == '\\': # continued stmt - # This yield is new; needed for better idempotency: - yield (NL, token, spos, (lnum, pos), line) - continued = 1 - else: - if initial in '([{': parenlev = parenlev + 1 - elif initial in ')]}': parenlev = parenlev - 1 - yield (OP, token, spos, epos, line) - else: - yield (ERRORTOKEN, line[pos], - (lnum, pos), (lnum, pos+1), line) - pos = pos + 1 - - for _ in indents[1:]: # pop remaining indent levels - yield (DEDENT, '', (lnum, 0), (lnum, 0), '') - yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '') - -if __name__ == '__main__': # testing - import sys - if len(sys.argv) > 1: tokenize(open(sys.argv[1]).readline) - else: tokenize(sys.stdin.readline) diff --git a/tests/test_pycode.py b/tests/test_pycode.py index 152a92a27..2b5ae1514 100644 --- a/tests/test_pycode.py +++ b/tests/test_pycode.py @@ -63,20 +63,30 @@ def test_ModuleAnalyzer_find_tags(): ' """function baz"""\n' ' pass\n' '\n' - '@decorator\n' + '@decorator1\n' + '@decorator2\n' 'def quux():\n' - ' pass\n') + ' pass\n' # line: 21 + '\n' + 'class Corge(object):\n' + ' @decorator1\n' + ' @decorator2\n' + ' def grault(self):\n' + ' pass\n') analyzer = ModuleAnalyzer.for_string(code, 'module') tags = analyzer.find_tags() assert set(tags.keys()) == {'Foo', 'Foo.__init__', 'Foo.bar', - 'Foo.Baz', 'Foo.Baz.__init__', 'qux', 'quux'} - assert tags['Foo'] == ('class', 1, 13) # type, start, end - assert tags['Foo.__init__'] == ('def', 3, 5) - assert tags['Foo.bar'] == ('def', 6, 9) - assert tags['Foo.Baz'] == ('class', 10, 13) - assert tags['Foo.Baz.__init__'] == ('def', 11, 13) - assert tags['qux'] == ('def', 14, 17) - assert tags['quux'] == ('def', 18, 21) # decorator + 'Foo.Baz', 'Foo.Baz.__init__', 'qux', 'quux', + 'Corge', 'Corge.grault'} + assert tags['Foo'] == ('class', 1, 12) # type, start, end + assert tags['Foo.__init__'] == ('def', 3, 4) + assert tags['Foo.bar'] == ('def', 6, 8) + assert tags['Foo.Baz'] == ('class', 10, 12) + assert tags['Foo.Baz.__init__'] == ('def', 11, 12) + assert tags['qux'] == ('def', 14, 16) + assert tags['quux'] == ('def', 18, 21) + assert tags['Corge'] == ('class', 23, 27) + assert tags['Corge.grault'] == ('def', 24, 27) def test_ModuleAnalyzer_find_attr_docs(): @@ -114,6 +124,8 @@ def test_ModuleAnalyzer_find_attr_docs(): ('Foo', 'attr3'), ('Foo', 'attr4'), ('Foo', 'attr5'), + ('Foo', 'attr6'), + ('Foo', 'attr7'), ('Foo', 'attr8'), ('Foo', 'attr9')} assert docs[('Foo', 'attr1')] == ['comment before attr1', ''] @@ -121,19 +133,23 @@ def test_ModuleAnalyzer_find_attr_docs(): assert docs[('Foo', 'attr4')] == ['long attribute comment', ''] assert docs[('Foo', 'attr4')] == ['long attribute comment', ''] assert docs[('Foo', 'attr5')] == ['attribute comment for attr5', ''] + assert docs[('Foo', 'attr6')] == ['this comment is ignored', ''] + assert docs[('Foo', 'attr7')] == ['this comment is ignored', ''] assert docs[('Foo', 'attr8')] == ['attribute comment for attr8', ''] assert docs[('Foo', 'attr9')] == ['string after attr9', ''] assert analyzer.tagorder == {'Foo': 0, - 'Foo.__init__': 6, + 'Foo.__init__': 8, 'Foo.attr1': 1, 'Foo.attr2': 2, 'Foo.attr3': 3, 'Foo.attr4': 4, 'Foo.attr5': 5, - 'Foo.attr8': 8, - 'Foo.attr9': 10, - 'Foo.bar': 11, - 'baz': 12, - 'Qux': 13, - 'Qux.attr1': 14, - 'Qux.attr2': 15} + 'Foo.attr6': 6, + 'Foo.attr7': 7, + 'Foo.attr8': 10, + 'Foo.attr9': 12, + 'Foo.bar': 13, + 'baz': 14, + 'Qux': 15, + 'Qux.attr1': 16, + 'Qux.attr2': 17} diff --git a/utils/release-checklist b/utils/release-checklist index 751be382b..f18c20710 100644 --- a/utils/release-checklist +++ b/utils/release-checklist @@ -20,7 +20,6 @@ Release checklist * Check diff by `git diff` * `git commit -am 'Bump to x.y.z final'` * `make clean` -* `python setup.py compile_grammar` * `python setup.py release bdist_wheel sdist upload --identity=[your key]` * open https://pypi.python.org/pypi/Sphinx and check there are no obvious errors * `git tag x.y.z` with version number From 79243816f14a2ea5ab47f64776328cc3feeb7c7c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 16 Jul 2017 22:59:15 +0900 Subject: [PATCH 0056/1814] Remove unused regexp --- sphinx/pycode/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index 29aa4356f..450ac575b 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -10,8 +10,6 @@ """ from __future__ import print_function -import re - from six import iteritems, BytesIO, StringIO from sphinx.errors import PycodeError @@ -22,8 +20,6 @@ if False: # For type annotation from typing import Any, Dict, IO, List, Tuple # NOQA -emptyline_re = re.compile(r'^\s*(#.*)?$') - class ModuleAnalyzer(object): # cache for analyzer objects -- caches both by module and file name From 1a48c4b9635fc4656969647edfc75cde62beb0eb Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Wed, 26 Jul 2017 17:39:12 +0100 Subject: [PATCH 0057/1814] add IDE files to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d8a75381c..11f46d9e3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ doc/_build/ tests/.coverage tests/build/ utils/regression_test.js + +# IDE +.idea From 7697683b3d6ccd81566ce092d52de16cfed872ce Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Wed, 26 Jul 2017 18:25:54 +0100 Subject: [PATCH 0058/1814] add proxy to tox, so the tests can succeed even behind a proxy network --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 530e5b941..c90732b11 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ envlist=flake8,py27,py34,py35,py36,pypy,du13,du12,du11 [testenv] +passenv = https_proxy http_proxy no_proxy deps= six pytest From 44da8f4fa744e88472d91a86fd7219f1729cae88 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Wed, 24 May 2017 23:52:56 +0200 Subject: [PATCH 0059/1814] i18n: This string is used as html_title, it needs to be capitalized. --- sphinx/locale/fr/LC_MESSAGES/sphinx.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/locale/fr/LC_MESSAGES/sphinx.po b/sphinx/locale/fr/LC_MESSAGES/sphinx.po index fd1ae6605..6f6492b53 100644 --- a/sphinx/locale/fr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fr/LC_MESSAGES/sphinx.po @@ -356,7 +356,7 @@ msgstr "précédent" #: sphinx/builders/html.py:1313 #, python-format msgid "%s %s documentation" -msgstr "documentation %s %s" +msgstr "Documentation %s %s" #: sphinx/builders/latex.py:199 sphinx/builders/texinfo.py:217 msgid " (in " From 56a47cd9b90fe18615718335b71e62d6615e3720 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jul 2017 14:59:51 +0900 Subject: [PATCH 0060/1814] Fix #3962: sphinx-apidoc does not recognize implicit namespace packages correctly --- CHANGES | 4 ++++ sphinx/apidoc.py | 9 +++++---- tests/test_apidoc.py | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index d33f5431d..6eaf62af2 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,9 @@ Incompatible changes * #3668: The arguments has changed of main functions for each command * #3893: Unknown html_theme_options throw warnings instead of errors * #3927: Python parameter/variable types should match classes, not all objects +* #3962: sphinx-apidoc now recognizes given directory as an implicit namespace + package when ``--implicit-namespaces`` option given, not subdirectories of + given directory. Deprecated ---------- @@ -60,6 +63,7 @@ Bugs fixed ---------- * #3882: Update the order of files for HTMLHelp and QTHelp +* #3962: sphinx-apidoc does not recognize implicit namespace packages correctly Testing -------- diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index b9a445c95..da908da04 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -205,17 +205,18 @@ def recurse_tree(rootpath, excludes, opts): Look for every file in the directory tree and create the corresponding ReST files. """ + followlinks = getattr(opts, 'followlinks', False) + includeprivate = getattr(opts, 'includeprivate', False) + implicit_namespaces = getattr(opts, 'implicit_namespaces', False) + # check if the base directory is a package and get its name - if INITPY in os.listdir(rootpath): + if INITPY in os.listdir(rootpath) or implicit_namespaces: root_package = rootpath.split(path.sep)[-1] else: # otherwise, the base is a directory with packages root_package = None toplevels = [] - followlinks = getattr(opts, 'followlinks', False) - includeprivate = getattr(opts, 'includeprivate', False) - implicit_namespaces = getattr(opts, 'implicit_namespaces', False) for root, subs, files in walk(rootpath, followlinks=followlinks): # document only Python module files (that aren't excluded) py_files = sorted(f for f in files diff --git a/tests/test_apidoc.py b/tests/test_apidoc.py index bef19e54d..1e0a712d5 100644 --- a/tests/test_apidoc.py +++ b/tests/test_apidoc.py @@ -60,7 +60,7 @@ def test_simple(make_app, apidoc): @pytest.mark.apidoc( - coderoot='test-apidoc-pep420', + coderoot='test-apidoc-pep420/a', options=["--implicit-namespaces"], ) def test_pep_0420_enabled(make_app, apidoc): @@ -97,7 +97,7 @@ def test_pep_0420_enabled(make_app, apidoc): assert "a.b.x namespace\n" in txt -@pytest.mark.apidoc(coderoot='test-apidoc-pep420') +@pytest.mark.apidoc(coderoot='test-apidoc-pep420/a') def test_pep_0420_disabled(make_app, apidoc): outdir = apidoc.outdir assert (outdir / 'conf.py').isfile() From ea03e27fb86ace1ca936ea603bab3c963990c7a5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jul 2017 16:49:34 +0900 Subject: [PATCH 0061/1814] Fix :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) --- CHANGES | 1 + sphinx/environment/__init__.py | 1 + sphinx/roles.py | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4d037ed60..ec2db7821 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ Bugs fixed * #3924: docname lost after dynamically parsing RST in extension * #3946: Typo in sphinx.sty (this was a bug with no effect in default context) +* Fix :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) Testing -------- diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index edec9ba2f..126a962a3 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -665,6 +665,7 @@ class BuildEnvironment(object): self.temp_data['docname'] = docname # defaults to the global default, but can be re-set in a document + self.temp_data['default_role'] = self.config.default_role self.temp_data['default_domain'] = \ self.domains.get(self.config.primary_domain) diff --git a/sphinx/roles.py b/sphinx/roles.py index dbd136fdb..ab6efc89f 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -185,7 +185,8 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[] """Role for PEP/RFC references that generate an index entry.""" env = inliner.document.settings.env if not typ: - typ = env.config.default_role + assert env.temp_data['default_role'] + typ = env.temp_data['default_role'].lower() else: typ = typ.lower() has_explicit_title, title, target = split_explicit_title(text) From 3d37aa2c87ecab7d54ae2067ffdb8b6f1cd42f76 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sat, 29 Jul 2017 21:07:09 -0400 Subject: [PATCH 0062/1814] Theme: Change for HTML5 --- sphinx/themes/basic/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index bae7db7b5..f80ca5d03 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -120,7 +120,7 @@ {%- endif %} - {%- if use_meta_charset %} + {%- if use_meta_charset or html5_doctype %} {%- else %} From fa9ad8552d92f3727264cddb70cdfe2fc87f62eb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 30 Jul 2017 23:52:39 +0900 Subject: [PATCH 0063/1814] Fix #3960: default_role = guilabel not functioning --- CHANGES | 3 ++- sphinx/roles.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ec2db7821..32e945ec3 100644 --- a/CHANGES +++ b/CHANGES @@ -21,7 +21,8 @@ Bugs fixed * #3924: docname lost after dynamically parsing RST in extension * #3946: Typo in sphinx.sty (this was a bug with no effect in default context) -* Fix :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) +* :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) +* #3960: default_role = 'guilabel' not functioning Testing -------- diff --git a/sphinx/roles.py b/sphinx/roles.py index ab6efc89f..4007b9f88 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -189,6 +189,7 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[] typ = env.temp_data['default_role'].lower() else: typ = typ.lower() + has_explicit_title, title, target = split_explicit_title(text) title = utils.unescape(title) target = utils.unescape(target) @@ -250,6 +251,13 @@ _amp_re = re.compile(r'(? Tuple[List[nodes.Node], List[nodes.Node]] # NOQA + env = inliner.document.settings.env + if not typ: + assert env.temp_data['default_role'] + typ = env.temp_data['default_role'].lower() + else: + typ = typ.lower() + text = utils.unescape(text) if typ == 'menuselection': text = text.replace('-->', u'\N{TRIANGULAR BULLET}') @@ -281,6 +289,13 @@ _litvar_re = re.compile('{([^}]+)}') def emph_literal_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA + env = inliner.document.settings.env + if not typ: + assert env.temp_data['default_role'] + typ = env.temp_data['default_role'].lower() + else: + typ = typ.lower() + text = utils.unescape(text) pos = 0 retnode = nodes.literal(role=typ.lower(), classes=[typ]) From da0fda3b0be4b4de26c4e55fdd6bece9575d70ad Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 Jul 2017 00:46:26 +0900 Subject: [PATCH 0064/1814] Add tests for default-role --- tests/roots/test-default_role/conf.py | 3 ++ tests/roots/test-default_role/foo.rst | 4 +++ tests/roots/test-default_role/index.rst | 6 ++++ tests/test_markup.py | 41 +++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 tests/roots/test-default_role/conf.py create mode 100644 tests/roots/test-default_role/foo.rst create mode 100644 tests/roots/test-default_role/index.rst diff --git a/tests/roots/test-default_role/conf.py b/tests/roots/test-default_role/conf.py new file mode 100644 index 000000000..f81c30bc4 --- /dev/null +++ b/tests/roots/test-default_role/conf.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' diff --git a/tests/roots/test-default_role/foo.rst b/tests/roots/test-default_role/foo.rst new file mode 100644 index 000000000..00e5ae59d --- /dev/null +++ b/tests/roots/test-default_role/foo.rst @@ -0,0 +1,4 @@ +foo.rst +======= + +`OK` button diff --git a/tests/roots/test-default_role/index.rst b/tests/roots/test-default_role/index.rst new file mode 100644 index 000000000..34c1855f6 --- /dev/null +++ b/tests/roots/test-default_role/index.rst @@ -0,0 +1,6 @@ +default_role +============ + +.. default-role:: pep + +`8` diff --git a/tests/test_markup.py b/tests/test_markup.py index 9690f2bf9..dfa4d74cf 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -286,3 +286,44 @@ def test_compact_refonly_bullet_list(app, status, warning): assert_node(doctree[0][4], nodes.bullet_list) assert_node(doctree[0][4][0][0], nodes.paragraph) assert doctree[0][4][0][0].astext() == 'Hello' + + +@pytest.mark.sphinx('dummy', testroot='default_role') +def test_default_role1(app, status, warning): + app.builder.build_all() + + # default-role: pep + doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes()) + assert_node(doctree[0], nodes.section) + assert_node(doctree[0][1], nodes.paragraph) + assert_node(doctree[0][1][0], addnodes.index) + assert_node(doctree[0][1][1], nodes.target) + assert_node(doctree[0][1][2], nodes.reference, classes=["pep"]) + + # no default-role + doctree = pickle.loads((app.doctreedir / 'foo.doctree').bytes()) + assert_node(doctree[0], nodes.section) + assert_node(doctree[0][1], nodes.paragraph) + assert_node(doctree[0][1][0], nodes.title_reference) + assert_node(doctree[0][1][1], nodes.Text) + + +@pytest.mark.sphinx('dummy', testroot='default_role', + confoverrides={'default_role': 'guilabel'}) +def test_default_role2(app, status, warning): + app.builder.build_all() + + # default-role directive is stronger than configratuion + doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes()) + assert_node(doctree[0], nodes.section) + assert_node(doctree[0][1], nodes.paragraph) + assert_node(doctree[0][1][0], addnodes.index) + assert_node(doctree[0][1][1], nodes.target) + assert_node(doctree[0][1][2], nodes.reference, classes=["pep"]) + + # default_role changes the default behavior + doctree = pickle.loads((app.doctreedir / 'foo.doctree').bytes()) + assert_node(doctree[0], nodes.section) + assert_node(doctree[0][1], nodes.paragraph) + assert_node(doctree[0][1][0], nodes.inline, classes=["guilabel"]) + assert_node(doctree[0][1][1], nodes.Text) From d63a6782287b797fa3924e59f2df113d73e9a909 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 Jul 2017 22:30:37 +0900 Subject: [PATCH 0065/1814] Reduce DeprecationWarning --- sphinx/builders/epub3.py | 29 +++++++++++++---------------- sphinx/builders/html.py | 4 ++-- tests/test_directive_only.py | 2 +- tests/test_environment_toctree.py | 17 +++++++++-------- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 6256b0f6d..fb2a71b34 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -85,40 +85,37 @@ class Epub3Builder(_epub_base.EpubBuilder): def validate_config_value(self): # lang attribute, dc:language if not self.app.config.epub_language: - self.app.warn( - 'conf value "epub_language" (or "language") ' - 'should not be empty for EPUB3') + logger.warning('conf value "epub_language" (or "language") ' + 'should not be empty for EPUB3') # unique-identifier attribute if not xmlname_checker().match(self.app.config.epub_uid): - self.app.warn('conf value "epub_uid" should be XML NAME for EPUB3') + logger.warning('conf value "epub_uid" should be XML NAME for EPUB3') # dc:title if not self.app.config.epub_title: - self.app.warn( - 'conf value "epub_title" (or "html_title") ' - 'should not be empty for EPUB3') + logger.warning('conf value "epub_title" (or "html_title") ' + 'should not be empty for EPUB3') # dc:creator if not self.app.config.epub_author: - self.app.warn('conf value "epub_author" should not be empty for EPUB3') + logger.warning('conf value "epub_author" should not be empty for EPUB3') # dc:contributor if not self.app.config.epub_contributor: - self.app.warn('conf value "epub_contributor" should not be empty for EPUB3') + logger.warning('conf value "epub_contributor" should not be empty for EPUB3') # dc:description if not self.app.config.epub_description: - self.app.warn('conf value "epub_description" should not be empty for EPUB3') + logger.warning('conf value "epub_description" should not be empty for EPUB3') # dc:publisher if not self.app.config.epub_publisher: - self.app.warn('conf value "epub_publisher" should not be empty for EPUB3') + logger.warning('conf value "epub_publisher" should not be empty for EPUB3') # dc:rights if not self.app.config.epub_copyright: - self.app.warn( - 'conf value "epub_copyright" (or "copyright")' - 'should not be empty for EPUB3') + logger.warning('conf value "epub_copyright" (or "copyright")' + 'should not be empty for EPUB3') # dc:identifier if not self.app.config.epub_identifier: - self.app.warn('conf value "epub_identifier" should not be empty for EPUB3') + logger.warning('conf value "epub_identifier" should not be empty for EPUB3') # meta ibooks:version if not self.app.config.version: - self.app.warn('conf value "version" should not be empty for EPUB3') + logger.warning('conf value "version" should not be empty for EPUB3') def content_metadata(self): # type: () -> Dict diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 540125b2a..0265f6a1b 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -605,7 +605,7 @@ class StandaloneHTMLBuilder(Builder): # additional pages from conf.py for pagename, template in self.config.html_additional_pages.items(): - self.info(' ' + pagename, nonl=1) + logger.info(' ' + pagename, nonl=1) self.handle_page(pagename, {}, template) # the search page @@ -1188,7 +1188,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): # additional pages from conf.py for pagename, template in self.config.html_additional_pages.items(): - self.info(' ' + pagename, nonl=1) + logger.info(' ' + pagename, nonl=1) self.handle_page(pagename, {}, template) if self.config.html_use_opensearch: diff --git a/tests/test_directive_only.py b/tests/test_directive_only.py index 35d15b391..d70585774 100644 --- a/tests/test_directive_only.py +++ b/tests/test_directive_only.py @@ -46,7 +46,7 @@ def test_sectioning(app, status, warning): app.builder.build(['only']) doctree = app.env.get_doctree('only') - process_only_nodes(doctree, app.builder.tags) + app.env.apply_post_transforms(doctree, 'only') parts = [getsects(n) for n in [_n for _n in doctree.children if isinstance(_n, nodes.section)]] diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index db07aa479..5fef9218a 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -14,6 +14,7 @@ from docutils.nodes import bullet_list, list_item, caption, comment, reference from sphinx import addnodes from sphinx.addnodes import compact_paragraph, only from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.environment.adapters.toctree import TocTree import pytest from sphinx.testing.util import assert_node @@ -138,7 +139,7 @@ def test_glob(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toc_for(app): app.build() - toctree = app.env.get_toc_for('index', app.builder) + toctree = TocTree(app.env).get_toc_for('index', app.builder) assert_node(toctree, [bullet_list, ([list_item, (compact_paragraph, # [0][0] @@ -165,7 +166,7 @@ def test_get_toc_for(app): def test_get_toc_for_only(app): app.build() builder = StandaloneHTMLBuilder(app) - toctree = app.env.get_toc_for('index', builder) + toctree = TocTree(app.env).get_toc_for('index', builder) assert_node(toctree, [bullet_list, ([list_item, (compact_paragraph, # [0][0] @@ -194,7 +195,7 @@ def test_get_toc_for_only(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toc_for_tocdepth(app): app.build() - toctree = app.env.get_toc_for('tocdepth', app.builder) + toctree = TocTree(app.env).get_toc_for('tocdepth', app.builder) assert_node(toctree, [bullet_list, list_item, (compact_paragraph, # [0][0] @@ -209,7 +210,7 @@ def test_get_toc_for_tocdepth(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for(app): app.build() - toctree = app.env.get_toctree_for('index', app.builder, collapse=False) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, @@ -246,7 +247,7 @@ def test_get_toctree_for(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for_collapse(app): app.build() - toctree = app.env.get_toctree_for('index', app.builder, collapse=True) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=True) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, @@ -274,7 +275,7 @@ def test_get_toctree_for_collapse(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for_maxdepth(app): app.build() - toctree = app.env.get_toctree_for('index', app.builder, collapse=False, maxdepth=3) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, maxdepth=3) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, @@ -316,8 +317,8 @@ def test_get_toctree_for_maxdepth(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for_includehidden(app): app.build() - toctree = app.env.get_toctree_for('index', app.builder, collapse=False, - includehidden=False) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, + includehidden=False) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, From 13be8e03ba7c52e2b471caa053c381cd3ea37f56 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 Jul 2017 22:35:56 +0900 Subject: [PATCH 0066/1814] Fix #3969: private instance attributes causes AttributeError --- CHANGES | 1 + sphinx/ext/autodoc.py | 14 ++++++++++---- tests/test_autodoc.py | 5 ++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 32e945ec3..a8cd32a16 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugs fixed * #3946: Typo in sphinx.sty (this was a bug with no effect in default context) * :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) * #3960: default_role = 'guilabel' not functioning +* #3969: private instance attributes causes AttributeError Testing -------- diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 91feb6a2a..bb5f78332 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -962,14 +962,20 @@ class Documenter(object): self.options.special_members is not ALL and \ membername in self.options.special_members: keep = has_doc or self.options.undoc_members + elif (namespace, membername) in attr_docs: + if want_all and membername.startswith('_'): + # ignore members whose name starts with _ by default + keep = self.options.private_members and \ + (has_doc or self.options.undoc_members) + else: + # keep documented attributes + keep = True + isattr = True + print(membername, keep) elif want_all and membername.startswith('_'): # ignore members whose name starts with _ by default keep = self.options.private_members and \ (has_doc or self.options.undoc_members) - elif (namespace, membername) in attr_docs: - # keep documented attributes - keep = True - isattr = True else: # ignore undocumented members if :undoc-members: is not given keep = has_doc or self.options.undoc_members diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index e04e38bb3..6eb087567 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -107,7 +107,7 @@ def process_signature(app, what, name, obj, options, args, retann): def skip_member(app, what, name, obj, skip, options): if name in ('__special1__', '__special2__'): return skip - if name.startswith('_'): + if name.startswith('__'): return True if name == 'skipmeth': return True @@ -756,6 +756,7 @@ def test_generate(): # test autodoc_member_order == 'source' directive.env.ref_context['py:module'] = 'test_autodoc' + options.private_members = True if PY3: roger_line = ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)' else: @@ -773,6 +774,7 @@ def test_generate(): ' .. py:classmethod:: Class.moore(a, e, f) -> happiness', ' .. py:attribute:: Class.inst_attr_comment', ' .. py:attribute:: Class.inst_attr_string', + ' .. py:attribute:: Class._private_inst_attr', ' .. py:method:: Class.inheritedmeth()', ], 'class', 'Class', member_order='bysource', all_members=True) @@ -989,6 +991,7 @@ class Class(Base): self.inst_attr_comment = None self.inst_attr_string = None """a documented instance attribute""" + self._private_inst_attr = None #: a private instance attribute def __special1__(self): """documented special method""" From 0c3f9851b35ace2f3605b2942d1d6973d92d0b25 Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Wed, 26 Jul 2017 20:07:25 +0100 Subject: [PATCH 0067/1814] fixes #3959 alias/rename support for classes inside inheritence diagrams --- doc/ext/inheritance.rst | 10 ++++++ sphinx/ext/inheritance_diagram.py | 36 +++++++++++-------- .../test-ext-inheritance_diagram/index.rst | 2 ++ tests/test_ext_inheritance_diagram.py | 28 ++++++++++++++- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst index bd287aa49..231b5fdaa 100644 --- a/doc/ext/inheritance.rst +++ b/doc/ext/inheritance.rst @@ -66,3 +66,13 @@ New config values are: .. confval:: inheritance_edge_attrs A dictionary of graphviz edge attributes for inheritance diagrams. + +.. confval:: inheritance_alias + + Allows mapping the full qualified name of the class to custom values + (useful when exposing the underlying path of a class is not desirable, + e.g. it's a private class and should not be instantiated by the user). + + For example:: + + inheritance_alias = {'_pytest.Magic': 'pytest.Magic'} diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index f5b0228a5..3c3e330d5 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -58,7 +58,7 @@ from sphinx.util import force_decode if False: # For type annotation - from typing import Any, Dict, List, Tuple # NOQA + from typing import Any, Dict, List, Tuple, Dict, Optional # NOQA from sphinx.application import Sphinx # NOQA from sphinx.environment import BuildEnvironment # NOQA @@ -133,8 +133,8 @@ class InheritanceGraph(object): graphviz dot graph from them. """ def __init__(self, class_names, currmodule, show_builtins=False, - private_bases=False, parts=0): - # type: (unicode, str, bool, bool, int) -> None + private_bases=False, parts=0, aliases=None): + # type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]]) -> None """*class_names* is a list of child classes to show bases from. If *show_builtins* is True, then Python builtins will be shown @@ -143,7 +143,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) + private_bases, parts, aliases) if not self.class_info: raise InheritanceException('No classes found for ' 'inheritance diagram') @@ -156,8 +156,8 @@ class InheritanceGraph(object): classes.extend(import_classes(name, currmodule)) return classes - def _class_info(self, classes, show_builtins, private_bases, parts): - # type: (List[Any], bool, bool, int) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA + 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 """Return name and bases for all classes that are ancestors of *classes*. @@ -174,8 +174,8 @@ class InheritanceGraph(object): if not private_bases and cls.__name__.startswith('_'): return - nodename = self.class_name(cls, parts) - fullname = self.class_name(cls, 0) + nodename = self.class_name(cls, parts, aliases) + fullname = self.class_name(cls, 0, aliases) # Use first line of docstring as tooltip, if available tooltip = None @@ -197,7 +197,7 @@ class InheritanceGraph(object): continue if not private_bases and base.__name__.startswith('_'): continue - baselist.append(self.class_name(base, parts)) + baselist.append(self.class_name(base, parts, aliases)) if base not in all_classes: recurse(base) @@ -206,8 +206,8 @@ class InheritanceGraph(object): return list(all_classes.values()) - def class_name(self, cls, parts=0): - # type: (Any, int) -> unicode + def class_name(self, cls, parts=0, aliases=None): + # type: (Any, int, Optional[Dict[unicode, unicode]]) -> unicode """Given a class object, return a fully-qualified name. This works for things I've tested in matplotlib so far, but may not be @@ -219,9 +219,13 @@ class InheritanceGraph(object): else: fullname = '%s.%s' % (module, cls.__name__) if parts == 0: - return fullname - name_parts = fullname.split('.') - return '.'.join(name_parts[-parts:]) + result = fullname + else: + name_parts = fullname.split('.') + result = '.'.join(name_parts[-parts:]) + if aliases is not None and result in aliases: + return aliases[result] + return result def get_all_class_names(self): # type: () -> List[unicode] @@ -339,7 +343,8 @@ class InheritanceDiagram(Directive): graph = InheritanceGraph( class_names, env.ref_context.get('py:module'), parts=node['parts'], - private_bases='private-bases' in self.options) + private_bases='private-bases' in self.options, + aliases=env.config.inheritance_alias) except InheritanceException as err: return [node.document.reporter.warning(err.args[0], line=self.lineno)] @@ -453,4 +458,5 @@ def setup(app): app.add_config_value('inheritance_graph_attrs', {}, False) app.add_config_value('inheritance_node_attrs', {}, False) app.add_config_value('inheritance_edge_attrs', {}, False) + app.add_config_value('inheritance_alias', {}, False) return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/tests/roots/test-ext-inheritance_diagram/index.rst b/tests/roots/test-ext-inheritance_diagram/index.rst index 777192bd7..8e25eee5b 100644 --- a/tests/roots/test-ext-inheritance_diagram/index.rst +++ b/tests/roots/test-ext-inheritance_diagram/index.rst @@ -6,3 +6,5 @@ test-ext-inheritance_diagram .. inheritance-diagram:: test.Foo :caption: Test Foo! + +.. inheritance-diagram:: test.Baz diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py index 6a2652514..40edfa937 100644 --- a/tests/test_ext_inheritance_diagram.py +++ b/tests/test_ext_inheritance_diagram.py @@ -11,9 +11,11 @@ import re import sys -from sphinx.ext.inheritance_diagram import InheritanceException, import_classes + import pytest +from sphinx.ext.inheritance_diagram import InheritanceException, import_classes + @pytest.mark.sphinx('html', testroot='ext-inheritance_diagram') @pytest.mark.usefixtures('if_graphviz_found') @@ -43,6 +45,30 @@ def test_inheritance_diagram_latex(app, status, warning): assert re.search(pattern, content, re.M) +@pytest.mark.sphinx('html', testroot='ext-inheritance_diagram', + srcdir='ext-inheritance_diagram-alias') +@pytest.mark.usefixtures('if_graphviz_found') +def test_inheritance_diagram_latex_alias(app, status, warning): + app.config.inheritance_alias = {'test.Foo': 'alias.Foo'} + app.builder.build_all() + + doc = app.env.get_and_resolve_doctree('index', app) + aliased_graph = doc.children[0].children[3]['graph'].class_info + assert len(aliased_graph) == 3 + assert ('test.Baz', 'test.Baz', ['test.Bar'], None) in aliased_graph + assert ('test.Bar', 'test.Bar', ['alias.Foo'], None) in aliased_graph + assert ('alias.Foo', 'alias.Foo', [], None) in aliased_graph + + content = (app.outdir / 'index.html').text() + + pattern = ('
\n' + 'Inheritance diagram of test.Foo\n

' + 'Test Foo!\xb6

') + assert re.search(pattern, content, re.M) + + def test_import_classes(rootdir): from sphinx.application import Sphinx, TemplateBridge from sphinx.util.i18n import CatalogInfo From 6413833a4fffbe766c95023bc5a065bf3143c14a Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Wed, 2 Aug 2017 00:20:49 +0200 Subject: [PATCH 0068/1814] #3751 work in feedback --- doc/man/sphinx-build.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 863f83a55..4866282d4 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -103,10 +103,14 @@ Options **latexpdfja** Build LaTeX files and run them through :program:`platex/dvipdfmx`. + We recommend using ``latexpdf`` instead. **info** Build Texinfo files and run them through :program:`makeinfo`. + .. important:: + Sphinx only recognizes the ``-M`` option if it is placed first. + .. versionadded:: 1.2.1 .. option:: -a From 55ea789d973260c23ee2c6a16dda2f099336f62e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vedran=20Mileti=C4=87?= Date: Wed, 2 Aug 2017 12:43:09 +0200 Subject: [PATCH 0069/1814] Add more EXAMPLES, remove those that use MkDocs --- EXAMPLES | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/EXAMPLES b/EXAMPLES index fc6d75d3b..d901c7ec6 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -25,6 +25,7 @@ Documentation using the alabaster theme * Invoke: http://docs.pyinvoke.org/ * Jinja: http://jinja.pocoo.org/docs/ * Lino: http://www.lino-framework.org/ (customized) +* marbl: https://getmarbl.readthedocs.io/ * MDAnalysis: http://www.mdanalysis.org/docs/ (customized) * MeshPy: https://documen.tician.de/meshpy/ * PyCUDA: https://documen.tician.de/pycuda/ @@ -34,6 +35,7 @@ Documentation using the alabaster theme * python-apt: https://apt.alioth.debian.org/python-apt-doc/ * PyVisfile: https://documen.tician.de/pyvisfile/ * Tablib: http://docs.python-tablib.org/ +* urllib3: https://urllib3.readthedocs.io/ (customized) * Werkzeug: http://werkzeug.pocoo.org/docs/ (customized) Documentation using the classic theme @@ -45,6 +47,7 @@ Documentation using the classic theme * Arb: http://arblib.org/ * Bazaar: http://doc.bazaar.canonical.com/ (customized) * Blender: https://docs.blender.org/api/current/ +* Bugzilla: https://bugzilla.readthedocs.io/ * Buildbot: https://docs.buildbot.net/latest/ * CMake: https://cmake.org/documentation/ (customized) * Chaco: http://docs.enthought.com/chaco/ (customized) @@ -65,6 +68,7 @@ Documentation using the classic theme * Leo: http://leoeditor.com/ * LEPL: http://www.acooke.org/lepl/ (customized) * Mayavi: http://docs.enthought.com/mayavi/mayavi/ (customized) +* MediaGoblin: https://mediagoblin.readthedocs.io/ (customized) * mpmath: http://mpmath.org/doc/current/ * OpenCV: http://docs.opencv.org/ (customized) * OpenEXR: http://excamera.com/articles/26/doc/index.html @@ -97,6 +101,7 @@ Documentation using the sphinxdoc theme --------------------------------------- * cartopy: http://scitools.org.uk/cartopy/docs/latest/ +* Jython: http://www.jython.org/docs/ * Matplotlib: https://matplotlib.org/ * MDAnalysis Tutorial: http://www.mdanalysis.org/MDAnalysisTutorial/ * NetworkX: https://networkx.github.io/ @@ -141,24 +146,26 @@ Documentation using sphinx_rtd_theme ------------------------------------ * Annotator: http://docs.annotatorjs.org/ -* ANNOVAR: http://annovar.openbioinformatics.org/ * Ansible: https://docs.ansible.com/ (customized) * ASE: https://wiki.fysik.dtu.dk/ase/ * Autofac: http://docs.autofac.org/ * BigchainDB: https://docs.bigchaindb.com/ +* bootstrap-datepicker: https://bootstrap-datepicker.readthedocs.io/ * Certbot: https://letsencrypt.readthedocs.io/ * CherryPy: http://docs.cherrypy.org/ * Chainer: https://docs.chainer.org/ * CodeIgniter: https://www.codeigniter.com/user_guide/ +* Conda: https://conda.io/docs/ * Corda: https://docs.corda.net/ * Dask: https://dask.pydata.org/ +* Databricks: https://docs.databricks.com/ (customized) * Dataiku DSS: https://doc.dataiku.com/ -* Drush: http://www.drush.org/ * edX: http://docs.edx.org/ * Electrum: http://docs.electrum.org/ * Elemental: http://libelemental.org/documentation/dev/ * ESWP3: https://eswp3.readthedocs.io/ * Ethereum Homestead: http://www.ethdocs.org/ +* Fidimag: https://fidimag.readthedocs.io/ * Flake8: http://flake8.pycqa.org/ * GeoNode: http://docs.geonode.org/ * Godot: https://godot.readthedocs.io/ @@ -170,9 +177,10 @@ Documentation using sphinx_rtd_theme * IdentityServer: http://docs.identityserver.io/ * Idris: http://docs.idris-lang.org/ * javasphinx: https://bronto-javasphinx.readthedocs.io/ -* Kalabox: http://docs.kalabox.io/ +* Julia: https://julia.readthedocs.io/ * Linguistica: https://linguistica-uchicago.github.io/lxa5/ * MathJax: https://docs.mathjax.org/ +* MDTraj: http://mdtraj.org/latest/ (customized) * MICrobial Community Analysis (micca): http://micca.org/docs/latest/ * MicroPython: https://docs.micropython.org/ * Mink: http://mink.behat.org/ @@ -183,6 +191,7 @@ Documentation using sphinx_rtd_theme * Nextflow: https://www.nextflow.io/docs/latest/index.html * NICOS: https://forge.frm2.tum.de/nicos/doc/nicos-master/ (customized) * Pelican: http://docs.getpelican.com/ +* picamera: https://picamera.readthedocs.io/ * Pillow: https://pillow.readthedocs.io/ * pip: https://pip.pypa.io/ * Paver: https://paver.readthedocs.io/ @@ -190,7 +199,9 @@ Documentation using sphinx_rtd_theme * Phinx: http://docs.phinx.org/ * phpMyAdmin: https://docs.phpmyadmin.net/ * Pweave: http://mpastell.com/pweave/ +* PyPy: http://doc.pypy.org/ * python-sqlparse: https://sqlparse.readthedocs.io/ +* PyVISA: https://pyvisa.readthedocs.io/ * Read The Docs: https://docs.readthedocs.io/ * Free your information from their silos (French): http://redaction-technique.org/ (customized) @@ -201,6 +212,7 @@ Documentation using sphinx_rtd_theme * Scapy: https://scapy.readthedocs.io/ * SimPy: http://simpy.readthedocs.io/ * SlamData: http://docs.slamdata.com/ +* Solidity: https://solidity.readthedocs.io/ * Sonos Controller (SoCo): http://docs.python-soco.com/ * Sphinx AutoAPI: https://sphinx-autoapi.readthedocs.io/ * sphinx-argparse: https://sphinx-argparse.readthedocs.io/ @@ -217,6 +229,7 @@ Documentation using sphinx_rtd_theme * Wagtail: http://docs.wagtail.io/ * Web Application Attack and Audit Framework (w3af): http://docs.w3af.org/ * Weblate: https://docs.weblate.org/ +* x265: https://x265.readthedocs.io/ Documentation using sphinx_bootstrap_theme ------------------------------------------ @@ -237,6 +250,7 @@ Documentation using a custom theme or integrated in a website * Apache Cassandra: https://cassandra.apache.org/doc/ * Astropy: http://docs.astropy.org/ +* Boto 3: https://boto3.readthedocs.io/ * CakePHP: https://book.cakephp.org/ * CasperJS: http://docs.casperjs.org/ * Ceph: http://docs.ceph.com/docs/master/ @@ -304,6 +318,7 @@ Homepages and other non-documentation sites https://lab.miletic.net/ (sphinx_rtd_theme) * Loyola University Chicago COMP 339-439 Distributed Systems course: http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme) +* SciPy Cookbook: https://scipy-cookbook.readthedocs.io/ (sphinx_rtd_theme) * The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc) * Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials: http://thomas-cokelaer.info/tutorials/ (standard) From 83155ddf7f3eb4fcb698c5bc38e04284f5885fd0 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 5 Aug 2017 13:50:26 +0200 Subject: [PATCH 0070/1814] #3978 fix typo --- doc/ext/autosummary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ext/autosummary.rst b/doc/ext/autosummary.rst index 7adf65c53..c35ba50a5 100644 --- a/doc/ext/autosummary.rst +++ b/doc/ext/autosummary.rst @@ -237,7 +237,7 @@ Additionally, the following filters are available .. function:: escape(s) Escape any special characters in the text to be used in formatting RST - contexts. For instance, this prevents asterisks making things bolt. This + contexts. For instance, this prevents asterisks making things bold. This replaces the builtin Jinja `escape filter`_ that does html-escaping. .. function:: underline(s, line='=') From 0fc80438e6fa806df2be71716f7844640ba0def4 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 5 Aug 2017 14:21:31 +0200 Subject: [PATCH 0071/1814] #3979 add Linux kernel doc to list of projects that use Sphinx --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index fc6d75d3b..35c705bc2 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -172,6 +172,7 @@ Documentation using sphinx_rtd_theme * javasphinx: https://bronto-javasphinx.readthedocs.io/ * Kalabox: http://docs.kalabox.io/ * Linguistica: https://linguistica-uchicago.github.io/lxa5/ +* Linux kernel: https://www.kernel.org/doc/html/latest/index.html * MathJax: https://docs.mathjax.org/ * MICrobial Community Analysis (micca): http://micca.org/docs/latest/ * MicroPython: https://docs.micropython.org/ From 0ed69442eb56fd7cf472ed5273ced6f7ddf673f7 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 5 Aug 2017 18:51:12 +0200 Subject: [PATCH 0072/1814] #3799 support ngettext in internal locale package --- sphinx/locale/__init__.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 6c77eeb8b..06a20bbec 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -227,29 +227,35 @@ pairindextypes = { translators = {} # type: Dict[unicode, Any] if PY3: - def _(message): + def _(message, *args): # type: (unicode) -> unicode try: - return translators['sphinx'].gettext(message) + if len(args) <= 1: + return translators['sphinx'].gettext(message) + else: # support pluralization + return translators['sphinx'].ngettext(message, args[0], args[1]) except KeyError: return message else: - def _(message): + def _(message, *args): # type: (unicode) -> unicode try: - return translators['sphinx'].ugettext(message) + if len(args) <= 1: + return translators['sphinx'].ugettext(message) + else: # support pluralization + return translators['sphinx'].ungettext(message, args[0], args[1]) except KeyError: return message -def __(message): +def __(message, *args): # type: (unicode) -> unicode """A dummy wrapper to i18n'ize exceptions and command line messages. In future, the messages are translated using LC_MESSAGES or any other locale settings. """ - return message + return message if len(args) <= 1 else args[0] def init(locale_dirs, language, catalog='sphinx'): From 4f3cf402f66303f52c9e39ced35008a51073ebdc Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 5 Aug 2017 18:52:09 +0200 Subject: [PATCH 0073/1814] #3799 use propper pluralization in (dummy) i18n call --- sphinx/application.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 8fb2e8d8e..209c73202 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -332,9 +332,9 @@ class Sphinx(object): status = (self.statuscode == 0 and __('succeeded') or __('finished with problems')) if self._warncount: - logger.info(bold(__('build %s, %s warning%s.') % - (status, self._warncount, - self._warncount != 1 and 's' or ''))) + logger.info(bold(__('build %s, %s warning.', + 'build %s, %s warnings.', self._warncount) % + (status, self._warncount))) else: logger.info(bold(__('build %s.') % status)) except Exception as err: From 2150634508fa905ad192e4601d34339a4c1c3a04 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 6 Aug 2017 09:55:05 +0200 Subject: [PATCH 0074/1814] #3799 specify missing type arguments --- sphinx/locale/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 06a20bbec..1b4ed02fe 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -228,7 +228,7 @@ translators = {} # type: Dict[unicode, Any] if PY3: def _(message, *args): - # type: (unicode) -> unicode + # type: (unicode, *Any) -> unicode try: if len(args) <= 1: return translators['sphinx'].gettext(message) @@ -238,7 +238,7 @@ if PY3: return message else: def _(message, *args): - # type: (unicode) -> unicode + # type: (unicode, *Any) -> unicode try: if len(args) <= 1: return translators['sphinx'].ugettext(message) @@ -249,7 +249,7 @@ else: def __(message, *args): - # type: (unicode) -> unicode + # type: (unicode, *Any) -> unicode """A dummy wrapper to i18n'ize exceptions and command line messages. In future, the messages are translated using LC_MESSAGES or any other From bd1a83c1ec5db4c99ab211acb9fa163ba8c4fd61 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 6 Aug 2017 21:46:27 +0200 Subject: [PATCH 0075/1814] #3548 clarify that Sphinx docs do not use sphinxdoc theme anymore --- doc/theming.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/theming.rst b/doc/theming.rst index c8cad2ba2..01f72fde9 100644 --- a/doc/theming.rst +++ b/doc/theming.rst @@ -171,9 +171,15 @@ These themes are: - **bodyfont** (CSS font-family): Font for normal text. - **headfont** (CSS font-family): Font for headings. -* **sphinxdoc** -- The theme used for this documentation. It features a sidebar - on the right side. There are currently no options beyond *nosidebar* and - *sidebarwidth*. +* **sphinxdoc** -- The theme originally used by this documentation. It features + a sidebar on the right side. There are currently no options beyond + *nosidebar* and *sidebarwidth*. + + .. note:: + + The Sphinx documentation now uses + `an adjusted version of the sphinxdoc theme + `_. * **scrolls** -- A more lightweight theme, based on `the Jinja documentation `_. The following color options are available: From 308dc7ad414ec493b03e410929cf30df466b0995 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Tue, 8 Aug 2017 16:08:16 +0200 Subject: [PATCH 0076/1814] Add OpenTURNS to EXAMPLES --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index fc6d75d3b..52d2cf59f 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -266,6 +266,7 @@ Documentation using a custom theme or integrated in a website * OpenERP: https://doc.odoo.com/ * OpenCV: http://docs.opencv.org/ * OpenLayers: http://docs.openlayers.org/ +* OpenTURNS: http://openturns.github.io/openturns/master/ * Open vSwitch: http://docs.openvswitch.org/ * PlatformIO: http://docs.platformio.org/ * PyEphem: http://rhodesmill.org/pyephem/ From c96b5b67b15386e2b59d1b1bd3412fadcda90dc0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 10 Aug 2017 10:36:19 +0900 Subject: [PATCH 0077/1814] Fix flake8 violation --- tests/test_environment_toctree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index 5fef9218a..f7a24d1fc 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -275,7 +275,8 @@ def test_get_toctree_for_collapse(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for_maxdepth(app): app.build() - toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, maxdepth=3) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, + collapse=False, maxdepth=3) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, From a027ee79902f0a8935b180eb5c4df56403bb33cb Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sat, 12 Aug 2017 19:42:31 +0200 Subject: [PATCH 0078/1814] #3537 set IE doc mode to Edge if not HTML5 --- sphinx/themes/basic/layout.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index f80ca5d03..56743f27e 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -120,6 +120,9 @@ {%- endif %} + {%- if not html5_doctype %} + + {%- endif %} {%- if use_meta_charset or html5_doctype %} {%- else %} From 30edc3fa866c95d3f7050d2f183a7ba5cc404c47 Mon Sep 17 00:00:00 2001 From: Gabriel Laskar Date: Thu, 13 Apr 2017 17:54:01 +0200 Subject: [PATCH 0079/1814] use templates_path for latex template instead of hardcoded path Signed-off-by: Gabriel Laskar --- sphinx/writers/latex.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 380dfab36..3fdec884a 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -883,11 +883,12 @@ class LaTeXTranslator(nodes.NodeVisitor): def render(self, template_name, variables): # type: (unicode, Dict) -> unicode - template_path = path.join(self.builder.srcdir, '_templates', template_name) - if path.exists(template_path): - return LaTeXRenderer().render(template_path, variables) - else: - return LaTeXRenderer().render(template_name, variables) + for template_path in self.builder.config.templates_path: + template = path.join(template_path, template_name) + if path.exists(template): + return LaTeXRenderer().render(template, variables) + + return LaTeXRenderer().render(template_name, variables) def visit_document(self, node): # type: (nodes.Node) -> None From 22ea6d560b5c9e971aebc4ec18b15df136cbff36 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 13 Aug 2017 16:20:25 +0200 Subject: [PATCH 0080/1814] #3996 add note: replace hyphen with underscore if build options set in setup() command --- doc/setuptools.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/setuptools.rst b/doc/setuptools.rst index dab25fc59..2aebb16ca 100644 --- a/doc/setuptools.rst +++ b/doc/setuptools.rst @@ -32,15 +32,23 @@ For instance, from ``setup.py``:: 'build_sphinx': { 'project': ('setup.py', name), 'version': ('setup.py', version), - 'release': ('setup.py', release)}}, + 'release': ('setup.py', release), + 'source_dir': ('setup.py', 'doc')}}, ) +.. note:: + + If you set Sphinx options directly in the ``setup()`` command, replace + hyphens in variable names with underscores. In the example above, + ``source-dir`` becomes ``source_dir``. + Or add this section in ``setup.cfg``:: [build_sphinx] project = 'My project' version = 1.2 release = 1.2.0 + source-dir = 'doc' Once configured, call this by calling the relevant command on ``setup.py``:: From b9e7824033728c29aa33e08f42b855255bcaf9e7 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 13 Aug 2017 17:01:16 +0200 Subject: [PATCH 0081/1814] #3987 remove alabaster-specific sidebars as default sphinx-quickstart settings --- sphinx/templates/quickstart/conf.py_t | 3 --- 1 file changed, 3 deletions(-) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 2821704f8..70683f8ee 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -114,11 +114,8 @@ html_static_path = ['{{ dot }}static'] # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ - 'about.html', - 'navigation.html', 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', - 'donate.html', ] } From 4f0de6f49ba130835dc087ca36b7e15a941aea29 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Wed, 16 Aug 2017 15:13:15 +0900 Subject: [PATCH 0082/1814] copy static files beyond symlinked directories under _static directory. This issue caused from ref #2744 --- sphinx/util/fileutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py index 04fd338b7..fe98117d2 100644 --- a/sphinx/util/fileutil.py +++ b/sphinx/util/fileutil.py @@ -77,7 +77,7 @@ def copy_asset(source, destination, excluded=lambda path: False, context=None, r copy_asset_file(source, destination, context, renderer) return - for root, dirs, files in walk(source): + for root, dirs, files in walk(source, followlinks=True): reldir = relative_path(source, root) for dir in dirs[:]: if excluded(posixpath.join(reldir, dir)): From 1b545d608281a92f4f88d5df41dc1c8541a505d0 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 16 Aug 2017 23:15:25 +0530 Subject: [PATCH 0083/1814] remove unnecessay import --- sphinx/ext/inheritance_diagram.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index f5b0228a5..a49a8add5 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -39,10 +39,7 @@ r""" import re import sys import inspect -try: - from hashlib import md5 -except ImportError: - from md5 import md5 +from hashlib import md5 from six import text_type from six.moves import builtins From 620491fcd55d4ff0b8365fddf78a2fca2659c04b Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Fri, 18 Aug 2017 10:51:24 +0200 Subject: [PATCH 0084/1814] Retireve docstirng form base classes (Closes #3140) --- doc/ext/autodoc.rst | 10 ++++ sphinx/ext/autodoc/__init__.py | 8 ++- sphinx/util/inspect.py | 96 ++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index 1f1892dbf..bfd55c81a 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -393,6 +393,16 @@ There are also new config values that you can set: If ``False`` is given, autodoc forcely suppresses the error if the imported module emits warnings. By default, ``True``. +.. confval:: autodoc_inherit_docstrings + + This value controls the docstrings inheritance. + If set to True the cocstring for classes or methods, if not explicitly set, + is inherited form parents. + + The default is ``True``. + + .. versionadded:: 1.7 + Docstring preprocessing ----------------------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 967cd9c5a..0af344751 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -35,7 +35,7 @@ from sphinx.util import logging from sphinx.util.nodes import nested_parse_with_titles from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \ safe_getattr, object_description, is_builtin_class_method, \ - isenumclass, isenumattribute + isenumclass, isenumattribute, getdoc from sphinx.util.docstrings import prepare_docstring if False: @@ -525,6 +525,8 @@ class Documenter(object): # type: (unicode, int) -> List[List[unicode]] """Decode and return lines of the docstring(s) for the object.""" docstring = self.get_attr(self.object, '__doc__', None) + if docstring is None and self.env.config.autodoc_inherit_docstrings: + docstring = getdoc(self.object) # make sure we have Unicode docstrings, then sanitize and split # into lines if isinstance(docstring, text_type): @@ -682,6 +684,9 @@ class Documenter(object): isattr = False doc = self.get_attr(member, '__doc__', None) + if doc is None and self.env.config.autodoc_inherit_docstrings: + doc = getdoc(member) + # if the member __doc__ is the same as self's __doc__, it's just # inherited and therefore not the member's doc cls = self.get_attr(member, '__class__', None) @@ -1617,6 +1622,7 @@ def setup(app): app.add_config_value('autodoc_docstring_signature', True, True) app.add_config_value('autodoc_mock_imports', [], True) app.add_config_value('autodoc_warningiserror', True, True) + app.add_config_value('autodoc_inherit_docstrings', True, True) app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 3f95dfcfe..2128ec5fe 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -11,6 +11,7 @@ from __future__ import absolute_import import re +import sys import typing import inspect from collections import OrderedDict @@ -456,3 +457,98 @@ class Signature(object): ', '.join(param_strings)) return qualified_name + + +if sys.version_info >= (3, 5): + getdoc = inspect.getdoc +else: + # code copyed from the inspect.py module of the standard library + # of Python 3.5 + + def _findclass(func): + cls = sys.modules.get(func.__module__) + if cls is None: + return None + for name in func.__qualname__.split('.')[:-1]: + cls = getattr(cls, name) + if not inspect.isclass(cls): + return None + return cls + + def _finddoc(obj): + if inspect.isclass(obj): + for base in obj.__mro__: + if base is not object: + try: + doc = base.__doc__ + except AttributeError: + continue + if doc is not None: + return doc + return None + + if inspect.ismethod(obj): + name = obj.__func__.__name__ + self = obj.__self__ + if (inspect.isclass(self) and + getattr(getattr(self, name, None), '__func__') is obj.__func__): + # classmethod + cls = self + else: + cls = self.__class__ + elif inspect.isfunction(obj): + name = obj.__name__ + cls = _findclass(obj) + if cls is None or getattr(cls, name) is not obj: + return None + elif inspect.isbuiltin(obj): + name = obj.__name__ + self = obj.__self__ + if (inspect.isclass(self) and + self.__qualname__ + '.' + name == obj.__qualname__): + # classmethod + cls = self + else: + cls = self.__class__ + # Should be tested before isdatadescriptor(). + elif isinstance(obj, property): + func = obj.fget + name = func.__name__ + cls = _findclass(func) + if cls is None or getattr(cls, name) is not obj: + return None + elif inspect.ismethoddescriptor(obj) or inspect.isdatadescriptor(obj): + name = obj.__name__ + cls = obj.__objclass__ + if getattr(cls, name) is not obj: + return None + else: + return None + + for base in cls.__mro__: + try: + doc = getattr(base, name).__doc__ + except AttributeError: + continue + if doc is not None: + return doc + return None + + def getdoc(object): + """Get the documentation string for an object. + + All tabs are expanded to spaces. To clean up docstrings that are + indented to line up with blocks of code, any whitespace than can be + uniformly removed from the second line onwards is removed.""" + try: + doc = object.__doc__ + except AttributeError: + return None + if doc is None: + try: + doc = _finddoc(object) + except (AttributeError, TypeError): + return None + if not isinstance(doc, str): + return None + return inspect.cleandoc(doc) From 23a40f88d04667bddbf6d50a6d04853bfd62a294 Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Fri, 18 Aug 2017 11:05:33 +0200 Subject: [PATCH 0085/1814] Improve fomatting (make flake8 happy) --- sphinx/util/inspect.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 2128ec5fe..390505c71 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -491,7 +491,8 @@ else: name = obj.__func__.__name__ self = obj.__self__ if (inspect.isclass(self) and - getattr(getattr(self, name, None), '__func__') is obj.__func__): + getattr(getattr(self, name, None), '__func__') + is obj.__func__): # classmethod cls = self else: @@ -505,7 +506,7 @@ else: name = obj.__name__ self = obj.__self__ if (inspect.isclass(self) and - self.__qualname__ + '.' + name == obj.__qualname__): + self.__qualname__ + '.' + name == obj.__qualname__): # classmethod cls = self else: From beac2f8647f97aa1a2dc40a5ce0426ab2d51a644 Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Fri, 18 Aug 2017 11:26:10 +0200 Subject: [PATCH 0086/1814] Update AUTHORS and CHANGES --- AUTHORS | 2 +- CHANGES | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 580feeb32..c531d5ac1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -57,7 +57,7 @@ Other contributors, listed alphabetically, are: * Stefan Seefeld -- toctree improvements * Gregory Szorc -- performance improvements * Taku Shimizu -- epub3 builder -* Antonio Valentino -- qthelp builder +* Antonio Valentino -- qthelp builder, docstring ingeritance * Filip Vavera -- napoleon todo directive * Pauli Virtanen -- autodoc improvements, autosummary extension * Stefan van der Walt -- autosummary extension diff --git a/CHANGES b/CHANGES index 6eaf62af2..bee7cbf32 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,7 @@ Features added - ``ref.python`` (ref: #3866) * #3872: Add latex key to configure literal blocks caption position in PDF output (refs #3792, #1723) +* In case of missing docstring try to retrieve doc from base classes (ref: #3140) Features removed From 5359bb8ba50e5c8e6ceefad84b74c5af237b1403 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 18 Aug 2017 11:53:37 +0200 Subject: [PATCH 0087/1814] =?UTF-8?q?Fix=20DeprecationWarning=20for=20r'?= =?UTF-8?q?=E2=80=A6(=3Fu)'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes > DeprecationWarning: Flags not at the start of the expression … --- sphinx/domains/cpp.py | 2 +- sphinx/search/__init__.py | 2 +- sphinx/search/zh.py | 2 +- utils/jssplitter_generator.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 9a4df9e74..0b4b501a2 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -294,7 +294,7 @@ logger = logging.getLogger(__name__) _integer_literal_re = re.compile(r'-?[1-9][0-9]*') _float_literal_re = re.compile(r'[+-]?[0-9]*\.[0-9]+') _identifier_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*)\b') -_whitespace_re = re.compile(r'\s+(?u)') +_whitespace_re = re.compile(r'(?u)\s+') _string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S) _visibility_re = re.compile(r'\b(public|private|protected)\b') diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index ef74d3b71..813a6dd51 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -65,7 +65,7 @@ var Stemmer = function() { } """ # type: unicode - _word_re = re.compile(r'\w+(?u)') + _word_re = re.compile(r'(?u)\w+') def __init__(self, options): # type: (Dict) -> None diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index bf01812e0..a1a7ffeb0 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -233,7 +233,7 @@ class SearchChinese(SearchLanguage): language_name = 'Chinese' js_stemmer_code = js_porter_stemmer stopwords = english_stopwords - latin1_letters = re.compile(r'\w+(?u)[\u0000-\u00ff]') + latin1_letters = re.compile(r'(?u)\w+[\u0000-\u00ff]') def init(self, options): # type: (Dict) -> None diff --git a/utils/jssplitter_generator.py b/utils/jssplitter_generator.py index 75f0353af..05b8628b3 100644 --- a/utils/jssplitter_generator.py +++ b/utils/jssplitter_generator.py @@ -5,9 +5,9 @@ import subprocess import sys import six -# find char codes they are matched with Python's \\w(?u) +# find char codes they are matched with Python's (?u)\\w -match = re.compile(r'\w(?u)') +match = re.compile(r'(?u)\w') begin = -1 ranges = [] From 5148d6953b5cb46a47f3f88554d46614cf170009 Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Fri, 18 Aug 2017 19:26:39 +0200 Subject: [PATCH 0088/1814] Typo --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index c531d5ac1..96d08788f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -57,7 +57,7 @@ Other contributors, listed alphabetically, are: * Stefan Seefeld -- toctree improvements * Gregory Szorc -- performance improvements * Taku Shimizu -- epub3 builder -* Antonio Valentino -- qthelp builder, docstring ingeritance +* Antonio Valentino -- qthelp builder, docstring inheritance * Filip Vavera -- napoleon todo directive * Pauli Virtanen -- autodoc improvements, autosummary extension * Stefan van der Walt -- autosummary extension From 04ff790139e79c9402f44d412857a351b58e55ad Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 16 Aug 2017 23:24:24 +0530 Subject: [PATCH 0089/1814] remove unnecessary else clauses in for loop --- sphinx/directives/code.py | 15 +++++++-------- sphinx/environment/__init__.py | 5 ++--- sphinx/io.py | 3 +-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 111f6b189..4d7e7a48d 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -311,11 +311,11 @@ class LiteralIncludeReader(object): self.lineno_start += lineno return lines[lineno:] + + if inclusive is True: + raise ValueError('start-after pattern not found: %s' % start) else: - if inclusive is True: - raise ValueError('start-after pattern not found: %s' % start) - else: - raise ValueError('start-at pattern not found: %s' % start) + raise ValueError('start-at pattern not found: %s' % start) return lines @@ -340,11 +340,10 @@ class LiteralIncludeReader(object): return [] else: return lines[:lineno] + if inclusive is True: + raise ValueError('end-at pattern not found: %s' % end) else: - if inclusive is True: - raise ValueError('end-at pattern not found: %s' % end) - else: - raise ValueError('end-before pattern not found: %s' % end) + raise ValueError('end-before pattern not found: %s' % end) return lines diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 53693aaf7..536aa959e 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -354,9 +354,8 @@ class BuildEnvironment(object): for suffix in self.config.source_suffix: if fnmatch.fnmatch(filename, '*' + suffix): return filename[:-len(suffix)] - else: - # the file does not have docname - return None + # the file does not have docname + return None def doc2path(self, docname, base=True, suffix=None): # type: (unicode, Union[bool, unicode], unicode) -> unicode diff --git a/sphinx/io.py b/sphinx/io.py index 8f048c7fc..8813cb3b6 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -166,8 +166,7 @@ class SphinxFileInput(FileInput): if isinstance(parser_class, string_types): parser_class = import_object(parser_class, 'source parser') # type: ignore # NOQA return parser_class.supported - else: - return ('restructuredtext',) + return ('restructuredtext',) data = FileInput.read(self) if self.app: From feab97e2939909d83fd24794efa83f6278db8d59 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 20 Aug 2017 00:27:07 +0900 Subject: [PATCH 0090/1814] Fix flake8 violation --- tests/test_environment_toctree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index 5fef9218a..f7a24d1fc 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -275,7 +275,8 @@ def test_get_toctree_for_collapse(app): @pytest.mark.test_params(shared_result='test_environment_toctree_basic') def test_get_toctree_for_maxdepth(app): app.build() - toctree = TocTree(app.env).get_toctree_for('index', app.builder, collapse=False, maxdepth=3) + toctree = TocTree(app.env).get_toctree_for('index', app.builder, + collapse=False, maxdepth=3) assert_node(toctree, [compact_paragraph, ([caption, "Table of Contents"], bullet_list, From 96ee24d7c1025e25417901b375f68731fc1c6085 Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Sat, 19 Aug 2017 21:52:30 +0200 Subject: [PATCH 0091/1814] Basic test for docstring inheritance --- tests/test_autodoc.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index caf31b7e9..af94de80e 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -431,6 +431,13 @@ def test_get_doc(): directive.env.config.autoclass_content = 'both' assert getdocl('class', I) == ['Class docstring', '', 'New docstring'] + # NOTE: inspect.getdoc seems not to work with locally defined classes + directive.env.config.autodoc_inherit_docstrings = False + assert getdocl('method', Base.inheritedmeth) == ['Inherited function.'] + assert getdocl('method', Derived.inheritedmeth) == [] + directive.env.config.autodoc_inherit_docstrings = True + assert getdocl('method', Derived.inheritedmeth) == ['Inherited function.'] + @pytest.mark.usefixtures('setup_test') def test_docstring_processing(): @@ -941,6 +948,12 @@ class Base(object): """Inherited function.""" +class Derived(Base): + def inheritedmeth(self): + # no docstring here + pass + + class Class(Base): """Class to document.""" From d454bb7472273a6106b249e353cdf83e31c8e342 Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Sun, 20 Aug 2017 11:10:35 +0200 Subject: [PATCH 0092/1814] Fix compatibility with Python 2 --- sphinx/util/inspect.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 390505c71..d75a86dc8 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -462,15 +462,18 @@ class Signature(object): if sys.version_info >= (3, 5): getdoc = inspect.getdoc else: - # code copyed from the inspect.py module of the standard library + # code copied from the inspect.py module of the standard library # of Python 3.5 def _findclass(func): cls = sys.modules.get(func.__module__) if cls is None: return None - for name in func.__qualname__.split('.')[:-1]: - cls = getattr(cls, name) + if hasattr(func, 'im_class'): + cls = func.im_class + else: + for name in func.__qualname__.split('.')[:-1]: + cls = getattr(cls, name) if not inspect.isclass(cls): return None return cls @@ -487,7 +490,7 @@ else: return doc return None - if inspect.ismethod(obj): + if inspect.ismethod(obj) and getattr(obj, '__self__' , None): name = obj.__func__.__name__ self = obj.__self__ if (inspect.isclass(self) and @@ -497,10 +500,10 @@ else: cls = self else: cls = self.__class__ - elif inspect.isfunction(obj): + elif inspect.isfunction(obj) or inspect.ismethod(obj): name = obj.__name__ cls = _findclass(obj) - if cls is None or getattr(cls, name) is not obj: + if cls is None or getattr(cls, name) != obj: return None elif inspect.isbuiltin(obj): name = obj.__name__ From 849c19c0e58d8817252aec7e8a98c5d4e554039c Mon Sep 17 00:00:00 2001 From: Antonio Valentino Date: Sun, 20 Aug 2017 11:48:13 +0200 Subject: [PATCH 0093/1814] PEP8 --- sphinx/util/inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index d75a86dc8..a2928fc7e 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -490,7 +490,7 @@ else: return doc return None - if inspect.ismethod(obj) and getattr(obj, '__self__' , None): + if inspect.ismethod(obj) and getattr(obj, '__self__', None): name = obj.__func__.__name__ self = obj.__self__ if (inspect.isclass(self) and From e7304c74e84a2535c2ba651de49faadc104a27b4 Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Fri, 23 Jun 2017 15:56:36 +0100 Subject: [PATCH 0094/1814] Update regex to fix character class range The use of a raw string literal here means that \uXXXX will not be treated as a unicode character, but rather as the string "\\uXXXX". I've adjusted this here to make this a unicode string. --- sphinx/search/zh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index a1a7ffeb0..6250c1e11 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -233,7 +233,7 @@ class SearchChinese(SearchLanguage): language_name = 'Chinese' js_stemmer_code = js_porter_stemmer stopwords = english_stopwords - latin1_letters = re.compile(r'(?u)\w+[\u0000-\u00ff]') + latin1_letters = re.compile(u'(?u)\\w+[\u0000-\u00ff]') def init(self, options): # type: (Dict) -> None From 3164e27ca0638fbe212c15d47ef9662c4b42af9c Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Tue, 1 Aug 2017 06:37:47 +0200 Subject: [PATCH 0095/1814] epub: Sort manifest entries by filename is a fixup on commit 0b7c73a98133236883f1c80afbd6acf530928e70 is required because the os.walk loop is run per directory and the ordering of directories is indeterministic --- sphinx/builders/_epub_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index b68fdbacc..1c188183d 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -513,6 +513,7 @@ class EpubBuilder(StandaloneHTMLBuilder): if not self.use_index: self.ignored_files.append('genindex' + self.out_suffix) for root, dirs, files in os.walk(outdir): + dirs.sort() for fn in sorted(files): filename = path.join(root, fn)[olen:] if filename in self.ignored_files: From 5b4761e8277b71b3341335b8cf5e9691f9866c0a Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Tue, 1 Aug 2017 07:26:06 +0200 Subject: [PATCH 0096/1814] epub: use format_date to allow to override build date to enable reproducible builds of packages like certbot in openSUSE See https://reproducible-builds.org/ for why this is good. --- sphinx/builders/_epub_base.py | 4 ++-- sphinx/builders/epub3.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index b68fdbacc..7535cecd9 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -12,8 +12,8 @@ import os import re from os import path +from sphinx.util.i18n import format_date from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile -from datetime import datetime from collections import namedtuple try: @@ -486,7 +486,7 @@ class EpubBuilder(StandaloneHTMLBuilder): metadata['copyright'] = self.esc(self.config.epub_copyright) metadata['scheme'] = self.esc(self.config.epub_scheme) metadata['id'] = self.esc(self.config.epub_identifier) - metadata['date'] = self.esc(datetime.utcnow().strftime("%Y-%m-%d")) + metadata['date'] = self.esc(format_date("%Y-%m-%d")) metadata['manifest_items'] = [] metadata['spines'] = [] metadata['guides'] = [] diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index ac85342e5..f94c9ff3c 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -11,7 +11,6 @@ """ from os import path -from datetime import datetime from collections import namedtuple from sphinx import package_dir @@ -19,6 +18,7 @@ from sphinx.config import string_classes, ENUM from sphinx.builders import _epub_base from sphinx.util import logging, xmlname_checker from sphinx.util.fileutil import copy_asset_file +from sphinx.util.i18n import format_date from sphinx.util.osutil import make_filename if False: @@ -133,7 +133,7 @@ class Epub3Builder(_epub_base.EpubBuilder): metadata['contributor'] = self.esc(self.config.epub_contributor) metadata['page_progression_direction'] = PAGE_PROGRESSION_DIRECTIONS.get(writing_mode) metadata['ibook_scroll_axis'] = IBOOK_SCROLL_AXIS.get(writing_mode) - metadata['date'] = self.esc(datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")) + metadata['date'] = self.esc(format_date("%Y-%m-%dT%H:%M:%SZ")) metadata['version'] = self.esc(self.config.version) return metadata From dd8c3211bea1cb53a84959dbd34aad51e072202e Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Tue, 22 Aug 2017 11:02:51 +0900 Subject: [PATCH 0097/1814] fix: missing ``texinputs_win/Makefile`` to be used in latexpdf builder on windows. --- CHANGES | 1 + MANIFEST.in | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 32e945ec3..d2a764f0d 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugs fixed * #3946: Typo in sphinx.sty (this was a bug with no effect in default context) * :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) * #3960: default_role = 'guilabel' not functioning +* Missing ``texinputs_win/Makefile`` to be used in latexpdf builder on windows. Testing -------- diff --git a/MANIFEST.in b/MANIFEST.in index 6fe5c7d6d..d478724e7 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -18,6 +18,7 @@ include sphinx/locale/.tx/config recursive-include sphinx/templates * recursive-include sphinx/texinputs * +recursive-include sphinx/texinputs_win * recursive-include sphinx/themes * recursive-include sphinx/pycode/pgen2 *.c *.pyx recursive-include sphinx/locale *.js *.pot *.po *.mo From ec9f373bfad744c170aa1b57d156c33054780549 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Wed, 23 Aug 2017 00:05:56 +0200 Subject: [PATCH 0098/1814] #3751 use double back ticks --- doc/man/sphinx-quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index 62b3a89b7..c4bbc531b 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -121,7 +121,7 @@ Options .. option:: --use-make-mode, --no-use-make-mode :file:`Makefile/make.bat` uses (or doesn't use) :ref:`make-mode `. - Default is `use`, which generates a more concise :file:`Makefile/make.bat`. + Default is ``use``, which generates a more concise :file:`Makefile/make.bat`. .. versionchanged:: 1.5 make-mode is default. From 16cbf658a247b94ce02e4942f794f408ba492a67 Mon Sep 17 00:00:00 2001 From: Atlas Date: Wed, 23 Aug 2017 11:56:35 +0200 Subject: [PATCH 0099/1814] Update tutorial.rst --- doc/tutorial.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index ffabbd93e..4dcee9e1d 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -153,9 +153,9 @@ very general sense) in any :dfn:`domain`. A domain is a collection of object types that belong together, complete with markup to create and reference descriptions of these objects. -The most prominent domain is the Python domain. To e.g. document the Python -built-in function ``enumerate()``, you would add this to one of your source -files:: +The most prominent domain is the Python domain. For example, to document +Python's built-in function ``enumerate()``, you would add this to one of your +source files:: .. py:function:: enumerate(sequence[, start=0]) From 14e39adb82c65db7cf94e6fa4bee98d69154498e Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Wed, 23 Aug 2017 20:55:54 +0200 Subject: [PATCH 0100/1814] #1618 make search results reader friendly request results as HTML instead of source files retrieve preview snippet text from HTML --- sphinx/themes/basic/static/searchtools.js_t | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sphinx/themes/basic/static/searchtools.js_t b/sphinx/themes/basic/static/searchtools.js_t index 149d1624d..130cd81e2 100644 --- a/sphinx/themes/basic/static/searchtools.js_t +++ b/sphinx/themes/basic/static/searchtools.js_t @@ -64,6 +64,14 @@ var Search = { _queued_query : null, _pulse_status : -1, + htmlToText : function(htmlString) { + var htmlElement = document.createElement('span'); + htmlElement.innerHTML = htmlString; + $(htmlElement).find('.headerlink').remove(); + docContent = $(htmlElement).find('[role=main]')[0]; + return docContent.textContent || docContent.innerText; + }, + init : function() { var params = $.getQueryParameters(); if (params.q) { @@ -268,8 +276,7 @@ var Search = { displayNextItem(); }); } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { - var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX; - $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix), + $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + '.html', dataType: "text", complete: function(jqxhr, textstatus) { var data = jqxhr.responseText; @@ -462,7 +469,8 @@ var Search = { * words. the first one is used to find the occurrence, the * latter for highlighting it. */ - makeSearchSummary : function(text, keywords, hlwords) { + makeSearchSummary : function(htmlText, keywords, hlwords) { + var text = Search.htmlToText(htmlText); var textLower = text.toLowerCase(); var start = 0; $.each(keywords, function() { From 65aa87c6e932039b9bbe703d3c5eb975f76ce857 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 23 Aug 2017 14:56:15 -0700 Subject: [PATCH 0101/1814] Clarify error message when any role has more than one target. (by including the full names of the candidate targets) --- sphinx/transforms/post_transforms/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 4c4e094d1..a3f742e53 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -134,7 +134,8 @@ class ReferencesResolver(SphinxTransform): if not results: return None if len(results) > 1: - nice_results = ' or '.join(':%s:' % r[0] for r in results) + nice_results = ' or '.join(':%s:`%s`' % (name, role["reftitle"]) + for name, role in results) logger.warning(__('more than one target found for \'any\' cross-' 'reference %r: could be %s'), target, nice_results, location=node) From 63c15998f66eeb42f3fcfef6087a7264645bee6b Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Fri, 25 Aug 2017 23:37:06 +0900 Subject: [PATCH 0102/1814] closes #4017: some web site house cleaning --- EXAMPLES | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/EXAMPLES b/EXAMPLES index 805f0edba..01c414016 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -37,7 +37,6 @@ Documentation using the classic theme * mpmath: http://mpmath.org/doc/current/ * OpenEXR: http://excamera.com/articles/26/doc/index.html * OpenGDA: http://www.opengda.org/gdadoc/html/ -* openWNS: http://docs.openwns.org/ * Pioneers and Prominent Men of Utah: http://pioneers.rstebbing.com/ * PyCantonese: http://pycantonese.org/ * Pyevolve: http://pyevolve.sourceforge.net/ @@ -64,9 +63,7 @@ Documentation using a customized version of the classic theme * CakePHP: http://book.cakephp.org/2.0/en/index.html * Chaco: http://docs.enthought.com/chaco/ * Chef: https://docs.chef.io/index.html -* Djagios: http://djagios.org/ * EZ-Draw: http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html -* GetFEM++: http://home.gna.org/getfem/ * Google or-tools: https://or-tools.googlecode.com/svn/trunk/documentation/user_manual/index.html * GPAW: https://wiki.fysik.dtu.dk/gpaw/ @@ -132,11 +129,10 @@ Documentation using another builtin theme http://docs.pylonsproject.org/projects/pyramid/en/latest/ (pyramid) * Quex: http://quex.sourceforge.net/doc/html/main.html * Satchmo: http://docs.satchmoproject.com/en/latest/ (sphinx_rtd_theme) -* Setuptools: http://pythonhosted.org/setuptools/ (nature) +* Setuptools: https://setuptools.readthedocs.io/en/latest/ (nature) * SimPy: http://simpy.readthedocs.org/en/latest/ * Spring Python: http://docs.spring.io/spring-python/1.2.x/sphinx/html/ (nature) -* sqlparse: http://python-sqlparse.googlecode.com/svn/docs/api/index.html - (agogo) +* sqlparse: https://sqlparse.readthedocs.io/en/latest/ (sphinx_rtd_theme) * Sylli: http://sylli.sourceforge.net/ (nature) * Tuleap Open ALM: https://tuleap.net/doc/en/ (nature) * Valence: http://docs.valence.desire2learn.com/ (haiku) @@ -161,15 +157,12 @@ Documentation using a custom theme/integrated in a site * GeoServer: http://docs.geoserver.org/ * gevent: http://www.gevent.org/ * GHC - Glasgow Haskell Compiler: http://downloads.haskell.org/~ghc/master/users-guide/ -* Glashammer: http://glashammer.org/ -* Istihza (Turkish Python documentation project): http://belgeler.istihza.com/py2/ * Lasso: http://lassoguide.com/ * Manage documentation such as source code (fr): http://redaction-technique.org/ * MathJax: http://docs.mathjax.org/en/latest/ * MirrorBrain: http://mirrorbrain.org/docs/ * MyHDL: http://docs.myhdl.org/en/latest/ * nose: http://nose.readthedocs.org/en/latest/ -* NoTex: https://www.notex.ch/overview/ * ObjectListView: http://objectlistview.sourceforge.net/python/ * Open ERP: https://doc.odoo.com/ * OpenCV: http://docs.opencv.org/ @@ -189,7 +182,6 @@ Documentation using a custom theme/integrated in a site * Selenium: http://docs.seleniumhq.org/docs/ * Self: http://www.selflanguage.org/ * Substance D: http://docs.pylonsproject.org/projects/substanced/en/latest/ -* Tablib: http://tablib.org/ * SQLAlchemy: http://www.sqlalchemy.org/docs/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ * Ubuntu packaging guide: http://packaging.ubuntu.com/html/ @@ -204,11 +196,9 @@ Homepages and other non-documentation sites * A personal page: http://www.dehlia.in/ * Benoit Boissinot: http://bboissin.appspot.com/ -* lunarsite: http://lunaryorn.de/ * The Wine Cellar Book: http://www.thewinecellarbook.com/doc/en/ * UC Berkeley Advanced Control Systems course: http://msc.berkeley.edu/tomizuka/me233spring13/ -* VOR: http://www.vor-cycling.be/ Books produced using Sphinx @@ -227,7 +217,7 @@ Books produced using Sphinx http://www.amazon.co.jp/dp/4048689525/ * "Python Professional Programming" (in Japanese): http://www.amazon.co.jp/dp/4798032948/ -* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski": +* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kie?lowski": http://www.hasecke.eu/Dekalog/ * The "Varnish Book": http://book.varnish-software.com/4.0/ From e451b80cfb74462eb78ce4d39f51de3c48d7b35a Mon Sep 17 00:00:00 2001 From: Robin Neatherway Date: Mon, 28 Aug 2017 11:34:19 +0100 Subject: [PATCH 0103/1814] Remove unused 'type: ignore' comment flagged by mypy --- sphinx/search/zh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index 6250c1e11..5d4f87b88 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -250,7 +250,7 @@ class SearchChinese(SearchLanguage): if JIEBA: chinese = list(jieba.cut_for_search(input)) - latin1 = self.latin1_letters.findall(input) # type: ignore + latin1 = self.latin1_letters.findall(input) return chinese + latin1 def word_filter(self, stemmed_word): From e34019ecbbe534e8ba834aeee31dd0a1ee7d44a1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 28 Aug 2017 20:55:48 +0900 Subject: [PATCH 0104/1814] Update CHANGES for PR #4023 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index bee7cbf32..76ebbef70 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,7 @@ Features added * #3872: Add latex key to configure literal blocks caption position in PDF output (refs #3792, #1723) * In case of missing docstring try to retrieve doc from base classes (ref: #3140) +* #4023: Clarify error message when any role has more than one target. Features removed From 852d96eb3de00f06c802cd76205891a7badef5fa Mon Sep 17 00:00:00 2001 From: James Clarke Date: Sun, 27 Aug 2017 00:14:06 +0100 Subject: [PATCH 0105/1814] nature: Fix macOS Safari scrollbar color macOS scrollbars overlap the contents, and the color is either black or white, depending on the color of the body. Therefore having a black body causes the scrollbar to appear white, and since the theme itself is light, the scrollbar is barely visible. Fix this by setting body to have a white background-color, matching the visible color coming from div.body. --- sphinx/themes/nature/static/nature.css_t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index 4c86f9e7d..bb0c83bac 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -16,7 +16,7 @@ body { font-family: Arial, sans-serif; font-size: 100%; - background-color: #111; + background-color: #fff; color: #555; margin: 0; padding: 0; From 6fdea58b7f75fa7b69a934264838c219abaca308 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 28 Aug 2017 21:00:55 +0900 Subject: [PATCH 0106/1814] Update CHANGES for PR #3973 --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 76ebbef70..4a463e85c 100644 --- a/CHANGES +++ b/CHANGES @@ -30,7 +30,7 @@ Features added output (refs #3792, #1723) * In case of missing docstring try to retrieve doc from base classes (ref: #3140) * #4023: Clarify error message when any role has more than one target. - +* #3973: epub: allow to override build date Features removed ---------------- From 79e90d6cdbaf63ec05ab10f093de6257033a6a33 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 28 Aug 2017 22:47:07 +0900 Subject: [PATCH 0107/1814] Update CHANGES for PR #4026 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index d2a764f0d..d1411007a 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,7 @@ Bugs fixed * :pep: and :rfc: does not supports ``default-role`` directive (refs: #3960) * #3960: default_role = 'guilabel' not functioning * Missing ``texinputs_win/Makefile`` to be used in latexpdf builder on windows. +* #4026: nature: Fix macOS Safari scrollbar color Testing -------- From ff06cb837b0d1b9632ccdb38a6df122a36cb60fa Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 31 Aug 2017 17:01:58 +0200 Subject: [PATCH 0108/1814] Fix C++ multiline signatures Fixes sphinx-doc/sphinx#3877 --- CHANGES | 1 + sphinx/domains/cpp.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index d1411007a..7298df297 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,7 @@ Bugs fixed * #3960: default_role = 'guilabel' not functioning * Missing ``texinputs_win/Makefile`` to be used in latexpdf builder on windows. * #4026: nature: Fix macOS Safari scrollbar color +* #3877: Fix for C++ multiline signatures. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index ece1eba3a..1425fe447 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4582,8 +4582,11 @@ class CPPObject(ObjectDescription): if ast.objectType == 'enumerator': self._add_enumerator_to_parent(ast) - self.options['tparam-line-spec'] = 'tparam-line-spec' in self.options - self.describe_signature(signode, ast, self.options) + # note: handle_signature may be called multiple time per directive, + # if it has multiple signatures, so don't mess with the original options. + options = dict(self.options) + options['tparam-line-spec'] = 'tparam-line-spec' in self.options + self.describe_signature(signode, ast, options) return ast def before_content(self): From cfa03b9771f368797a3119969f39bbfd9965ab6f Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 1 Sep 2017 22:28:49 -0700 Subject: [PATCH 0109/1814] Fix documented default values for setuptools integration. The defaults were obtained by reading the implementation in `setup_command.py`, notably `_guess_source_dir` and `finalize_options`. --- doc/setuptools.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/setuptools.rst b/doc/setuptools.rst index 2aebb16ca..8d759f985 100644 --- a/doc/setuptools.rst +++ b/doc/setuptools.rst @@ -82,7 +82,9 @@ Options for setuptools integration .. confval:: source-dir The target source directory. This can be relative to the ``setup.py`` or - ``setup.cfg`` file, or it can be absolute. Default is ``''``. + ``setup.cfg`` file, or it can be absolute. It defaults to ``./doc`` or + ``./docs`` if either contains a file named ``conf.py`` (checking ``./doc`` + first); otherwise it defaults to the current directory. This can also be set by passing the `-s` flag to ``setup.py``: @@ -93,13 +95,13 @@ Options for setuptools integration .. confval:: build-dir The target build directory. This can be relative to the ``setup.py`` or - ``setup.cfg`` file, or it can be absolute. Default is ``''``. + ``setup.cfg`` file, or it can be absolute. Default is ``./build/sphinx``. .. confval:: config-dir Location of the configuration directory. This can be relative to the - ``setup.py`` or ``setup.cfg`` file, or it can be absolute. Default is - ``''``. + ``setup.py`` or ``setup.cfg`` file, or it can be absolute. Default is to use + `source-dir`. This can also be set by passing the `-c` flag to ``setup.py``: From ad41e0b25e07b4d7aac35cb43130b18dae8be02e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 4 Sep 2017 22:46:05 +0900 Subject: [PATCH 0110/1814] Update CHANGES for PR #3972 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 4a463e85c..fb0227ee7 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,7 @@ Features added * In case of missing docstring try to retrieve doc from base classes (ref: #3140) * #4023: Clarify error message when any role has more than one target. * #3973: epub: allow to override build date +* #3972: epub: Sort manifest entries by filename Features removed ---------------- From 0cb57f19a099be2809a8fb5dc9274f7411e1caac Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 5 Sep 2017 01:37:33 +0900 Subject: [PATCH 0111/1814] Fix #4006: Fix crash on parallel build --- CHANGES | 1 + sphinx/util/parallel.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 7298df297..e850b3910 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,7 @@ Bugs fixed * Missing ``texinputs_win/Makefile`` to be used in latexpdf builder on windows. * #4026: nature: Fix macOS Safari scrollbar color * #3877: Fix for C++ multiline signatures. +* #4006: Fix crash on parallel build Testing -------- diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py index 7ca4e94e6..9bc3c36e1 100644 --- a/sphinx/util/parallel.py +++ b/sphinx/util/parallel.py @@ -122,6 +122,7 @@ class ParallelTasks(object): logger.handle(log) self._result_funcs.pop(tid)(self._args.pop(tid), result) self._procs[tid].join() + self._precvs.pop(tid) self._pworking -= 1 break else: From eb9c18b1bc6d7b870d05f92355f9c7b8218254a0 Mon Sep 17 00:00:00 2001 From: Daniel Pizetta Date: Mon, 4 Sep 2017 16:14:30 -0300 Subject: [PATCH 0112/1814] Fix #4019: exception treatment for NoneType group attibute. --- sphinx/ext/inheritance_diagram.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index f5b0228a5..f7cf34111 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -80,14 +80,18 @@ def try_import(objname): __import__(objname) return sys.modules.get(objname) # type: ignore except ImportError: - modname, attrname = module_sig_re.match(objname).groups() # type: ignore - if modname is None: - return None try: - __import__(modname) - return getattr(sys.modules.get(modname), attrname, None) - except ImportError: + modname, attrname = module_sig_re.match(objname).groups() # type: ignore + except AttributeError: return None + else: + if modname is None: + return None + try: + __import__(modname) + return getattr(sys.modules.get(modname), attrname, None) + except ImportError: + return None def import_classes(name, currmodule): From 8797ff51b39b94487623efb5ee1154444ef2c538 Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Wed, 6 Sep 2017 15:29:41 -0700 Subject: [PATCH 0113/1814] Properties can have types documented with :type: --- sphinx/ext/napoleon/docstring.py | 10 ++++++++-- sphinx/util/docfields.py | 29 ++++++++++++++++++++++------ tests/test_ext_napoleon_docstring.py | 20 ++++++++++++++----- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index c77598ef1..330813f8a 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -553,7 +553,10 @@ class GoogleDocstring(UnicodeMixin): def _parse_attribute_docstring(self): # type: () -> List[unicode] _type, _desc = self._consume_inline_attribute() - return self._format_field('', _type, _desc) + lines = self._format_field('', '', _desc) + if _type: + lines.extend(['', ':type: %s' % _type]) + return lines def _parse_attributes_section(self, section): # type: (unicode) -> List[unicode] @@ -566,8 +569,11 @@ class GoogleDocstring(UnicodeMixin): lines.append(':vartype %s: %s' % (_name, _type)) else: lines.extend(['.. attribute:: ' + _name, '']) - fields = self._format_field('', _type, _desc) + fields = self._format_field('', '', _desc) lines.extend(self._indent(fields, 3)) + if _type: + lines.append('') + lines.extend(self._indent([':type: %s' % _type], 3)) lines.append('') if self._config.napoleon_use_ivar: lines.append('') diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 4bce071c0..b20f4f98e 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -288,6 +288,12 @@ class DocFieldTransformer(object): fieldtype, fieldarg = fieldname.astext(), '' typedesc, is_typefield = typemap.get(fieldtype, (None, None)) + # collect the content, trying not to keep unnecessary paragraphs + if _is_single_paragraph(fieldbody): + content = fieldbody.children[0].children + else: + content = fieldbody.children + # sort out unknown fields if typedesc is None or typedesc.has_arg != bool(fieldarg): # either the field name is unknown, or the argument doesn't @@ -297,16 +303,27 @@ class DocFieldTransformer(object): new_fieldname += ' ' + fieldarg fieldname[0] = nodes.Text(new_fieldname) entries.append(field) + + # but if this has a type then we can at least link it + if typedesc and is_typefield and content: + target = content[0].astext() + xrefs = typedesc.make_xrefs( + typedesc.typerolename, + self.directive.domain, + target, + contnode=content[0], + ) + if _is_single_paragraph(fieldbody): + fieldbody.children[0].clear() + fieldbody.children[0].extend(xrefs) + else: + fieldbody.clear() + fieldbody.extend(xrefs) + continue typename = typedesc.name - # collect the content, trying not to keep unnecessary paragraphs - if _is_single_paragraph(fieldbody): - content = fieldbody.children[0].children - else: - content = fieldbody.children - # if the field specifies a type, put it in the types collection if is_typefield: # filter out only inline nodes; others will result in invalid diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index e71d517fe..c1e92f023 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -58,15 +58,21 @@ Sample namedtuple subclass .. attribute:: attr1 - *Arbitrary type* -- Quick description of attr1 + Quick description of attr1 + + :type: Arbitrary type .. attribute:: attr2 - *Another arbitrary type* -- Quick description of attr2 + Quick description of attr2 + + :type: Another arbitrary type .. attribute:: attr3 - *Type* -- Adds a newline after the type + Adds a newline after the type + + :type: Type """ self.assertEqual(expected, actual) @@ -323,7 +329,9 @@ Attributes: expected = """\ .. attribute:: in_attr - :class:`numpy.ndarray` -- super-dooper attribute + super-dooper attribute + + :type: :class:`numpy.ndarray` """ self.assertEqual(expected, actual) @@ -336,7 +344,9 @@ Attributes: expected = """\ .. attribute:: in_attr - *numpy.ndarray* -- super-dooper attribute + super-dooper attribute + + :type: numpy.ndarray """ self.assertEqual(expected, actual) From c0f84295b685a6b7f12024ea64721708480dc227 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 7 Sep 2017 13:20:31 +0200 Subject: [PATCH 0114/1814] C++, fix linking in function pointers. Fixes sphinx-doc/sphinx#4041 --- CHANGES | 1 + sphinx/domains/cpp.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index c7c273390..f2b422107 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,7 @@ Bugs fixed * #3877: Fix for C++ multiline signatures. * #4006: Fix crash on parallel build * #3969: private instance attributes causes AttributeError +* #4041: C++, remove extra name linking in function pointers. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 1425fe447..f8a77cee8 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -2408,6 +2408,10 @@ class ASTType(ASTBase): if (self.decl.require_space_after_declSpecs() and len(text_type(self.declSpecs)) > 0): signode += nodes.Text(' ') + # for paramters that don't really declare new names we get 'markType', + # this should not be propagated, but be 'noneIsName'. + if mode == 'markType': + mode = 'noneIsName' self.decl.describe_signature(signode, mode, env, symbol) From c43c781a03e7acc97eb1ba705b07a490792a94a4 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 7 Sep 2017 21:24:44 +0200 Subject: [PATCH 0115/1814] Docs, add missing ``member`` role for C domain Fixes sphinx-doc/sphinx#4038 --- CHANGES | 1 + doc/domains.rst | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index f2b422107..d9d950824 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,7 @@ Bugs fixed * #4006: Fix crash on parallel build * #3969: private instance attributes causes AttributeError * #4041: C++, remove extra name linking in function pointers. +* #4038: C, add missing documentation of ``member`` role. Testing -------- diff --git a/doc/domains.rst b/doc/domains.rst index 838f40870..2dc01c0b9 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -473,7 +473,7 @@ The C Domain The C domain (name **c**) is suited for documentation of C API. -.. rst:directive:: .. c:function:: type name(signature) +.. rst:directive:: .. c:function:: function prototype Describes a C function. The signature should be given as in C, e.g.:: @@ -485,7 +485,7 @@ The C domain (name **c**) is suited for documentation of C API. Note that you don't have to backslash-escape asterisks in the signature, as it is not parsed by the reST inliner. -.. rst:directive:: .. c:member:: type name +.. rst:directive:: .. c:member:: declaration Describes a C struct member. Example signature:: @@ -508,7 +508,7 @@ The C domain (name **c**) is suited for documentation of C API. Describes a C type (whether defined by a typedef or struct). The signature should just be the type name. -.. rst:directive:: .. c:var:: type name +.. rst:directive:: .. c:var:: declaration Describes a global C variable. The signature should include the type, such as:: @@ -524,14 +524,14 @@ Cross-referencing C constructs The following roles create cross-references to C-language constructs if they are defined in the documentation: -.. rst:role:: c:data - - Reference a C-language variable. - .. rst:role:: c:func Reference a C-language function. Should include trailing parentheses. +.. rst:role:: c:member + + Reference a C-language member of a struct. + .. rst:role:: c:macro Reference a "simple" C macro, as defined above. @@ -540,6 +540,10 @@ defined in the documentation: Reference a C-language type. +.. rst:role:: c:data + + Reference a C-language variable. + The C++ Domain -------------- From f4c8115a7e5f1a5d9ba10279b5a7634f63c18526 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 8 Sep 2017 11:42:35 +0200 Subject: [PATCH 0116/1814] Turn any environment unpickling error into IOError --- sphinx/environment/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 536aa959e..a3a3e3a3b 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -110,7 +110,12 @@ class BuildEnvironment(object): @staticmethod def load(f, app=None): # type: (IO, Sphinx) -> BuildEnvironment - env = pickle.load(f) + try: + env = pickle.load(f) + except Exception as exc: + # This can happen for example when the pickle is from a + # different version of Sphinx. + raise IOError(exc) if env.version != ENV_VERSION: raise IOError('build environment version not current') if app: From ddd23d31f19efd442c104b6c70f62aeb8fd3b88b Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 8 Sep 2017 22:56:39 -0700 Subject: [PATCH 0117/1814] Fix typo in output of sphinx-build -h. --- sphinx/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 0558239d3..54e4dcb78 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -169,7 +169,7 @@ def main(argv=sys.argv[1:]): # type: ignore help='Do emit colored output (default: auto-detect)') group.add_option('-N', '--no-color', dest='color', action='store_const', const='no', - help='Do not emit colored output (default: auot-detect)') + help='Do not emit colored output (default: auto-detect)') group.add_option('-w', metavar='FILE', dest='warnfile', help='write warnings (and errors) to given file') group.add_option('-W', action='store_true', dest='warningiserror', From 3e94878871ccaa2db4134d5021d8212b298eb1c6 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 10 Sep 2017 09:23:09 +0900 Subject: [PATCH 0118/1814] Add support for docutils 0.14 --- .appveyor.yml | 8 ++++---- .travis.yml | 12 ++++++------ CHANGES | 2 ++ tox.ini | 7 ++++++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3012267c2..deaf503b7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,15 +6,15 @@ environment: matrix: - PYTHON: 27 - DOCUTILS: 0.12 + DOCUTILS: 0.13.1 TEST_IGNORE: --ignore py35 - PYTHON: 27 - DOCUTILS: 0.13.1 + DOCUTILS: 0.14 TEST_IGNORE: --ignore py35 - PYTHON: 36 - DOCUTILS: 0.13.1 + DOCUTILS: 0.14 - PYTHON: 36-x64 - DOCUTILS: 0.13.1 + DOCUTILS: 0.14 install: - C:\Python%PYTHON%\python.exe -m pip install -U pip setuptools diff --git a/.travis.yml b/.travis.yml index c78db3d4e..f271fd4a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,20 +18,20 @@ env: - PYTHONWARNINGS=all - SKIP_LATEX_BUILD=1 matrix: - - DOCUTILS=0.12 - DOCUTILS=0.13.1 + - DOCUTILS=0.14 matrix: exclude: - python: "3.4" - env: DOCUTILS=0.12 + env: DOCUTILS=0.13.1 - python: "3.5" - env: DOCUTILS=0.12 + env: DOCUTILS=0.13.1 - python: "3.6" - env: DOCUTILS=0.12 + env: DOCUTILS=0.13.1 - python: nightly - env: DOCUTILS=0.12 + env: DOCUTILS=0.13.1 - python: "pypy-5.4.1" - env: DOCUTILS=0.12 + env: DOCUTILS=0.13.1 addons: apt: packages: diff --git a/CHANGES b/CHANGES index fb0227ee7..37ef1d428 100644 --- a/CHANGES +++ b/CHANGES @@ -71,6 +71,8 @@ Bugs fixed Testing -------- +* Add support for docutils 0.14 + Release 1.6.4 (in development) ============================== diff --git a/tox.ini b/tox.ini index c90732b11..b7d4feb98 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=flake8,py27,py34,py35,py36,pypy,du13,du12,du11 +envlist=flake8,py27,py34,py35,py36,pypy,du14,du13,du12,du11 [testenv] passenv = https_proxy http_proxy no_proxy @@ -37,6 +37,11 @@ deps= docutils==0.13.1 {[testenv]deps} +[testenv:du14] +deps= + docutils==0.14 + {[testenv]deps} + [testenv:flake8] deps=flake8 commands=flake8 From 0e39d92c9237d944009aa6ca9d741de2e55a53f1 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Sun, 10 Sep 2017 12:13:05 +0900 Subject: [PATCH 0119/1814] ignore 'doc/locale' directory to avoid mis-committing --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4472af150..023b12a00 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ doc/_build/ tests/.coverage tests/build/ utils/regression_test.js +doc/locale/ From f453fe7bf0748ab5da9980846325c11a833b989d Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Sep 2017 20:17:09 +0200 Subject: [PATCH 0120/1814] Fix #4044 (extra row height in PDF output from empty multicell) --- CHANGES | 1 + sphinx/writers/latex.py | 2 +- .../test-latex-table/expects/complex_spanning_cell.tex | 10 +++++----- tests/roots/test-latex-table/expects/gridtable.tex | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index d9d950824..ecc711a03 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,7 @@ Bugs fixed * #3969: private instance attributes causes AttributeError * #4041: C++, remove extra name linking in function pointers. * #4038: C, add missing documentation of ``member`` role. +* #4044: An empty multicolumn cell causes extra row height in PDF output Testing -------- diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index e4e6159c0..855822335 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1463,7 +1463,7 @@ class LaTeXTranslator(nodes.NodeVisitor): if cell.width > 1 or cell.height > 1: self.body.append('\\begin{varwidth}[t]{\\sphinxcolwidth{%d}{%d}}\n' % (cell.width, self.table.colcount)) - context = ('\\par\n\\vskip-\\baselineskip\\strut\\end{varwidth}%\n') + context + context = ('\\par\n\\vskip-\\baselineskip\\vbox{\\hbox{\\strut}}\\end{varwidth}%\n') + context self.needs_linetrimming = 1 if len(node) > 2 and len(node.astext().split('\n')) > 2: self.needs_linetrimming = 1 diff --git a/tests/roots/test-latex-table/expects/complex_spanning_cell.tex b/tests/roots/test-latex-table/expects/complex_spanning_cell.tex index cc434f0fe..3d9e5cae1 100644 --- a/tests/roots/test-latex-table/expects/complex_spanning_cell.tex +++ b/tests/roots/test-latex-table/expects/complex_spanning_cell.tex @@ -18,13 +18,13 @@ consecutive multirow at end of row (1-4 and 1-5) \begin{varwidth}[t]{\sphinxcolwidth{1}{5}} cell1-1 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% &\sphinxmultirow{3}{2}{% \begin{varwidth}[t]{\sphinxcolwidth{1}{5}} cell1-2 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% & cell1-3 @@ -32,20 +32,20 @@ cell1-3 \begin{varwidth}[t]{\sphinxcolwidth{1}{5}} cell1-4 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% &\sphinxmultirow{2}{5}{% \begin{varwidth}[t]{\sphinxcolwidth{1}{5}} cell1-5 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% \\ \cline{3-3}\sphinxtablestrut{1}&\sphinxtablestrut{2}&\sphinxmultirow{2}{6}{% \begin{varwidth}[t]{\sphinxcolwidth{1}{5}} cell2-3 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% &\sphinxtablestrut{4}&\sphinxtablestrut{5}\\ \cline{5-5}\sphinxtablestrut{1}&\sphinxtablestrut{2}&\sphinxtablestrut{6}&\sphinxtablestrut{4}& diff --git a/tests/roots/test-latex-table/expects/gridtable.tex b/tests/roots/test-latex-table/expects/gridtable.tex index e6bbbda6b..6f1fc0b91 100644 --- a/tests/roots/test-latex-table/expects/gridtable.tex +++ b/tests/roots/test-latex-table/expects/gridtable.tex @@ -17,7 +17,7 @@ cell1-1 \begin{varwidth}[t]{\sphinxcolwidth{1}{3}} cell1-2 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% & cell1-3 @@ -26,7 +26,7 @@ cell1-3 \begin{varwidth}[t]{\sphinxcolwidth{1}{3}} cell2-1 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% &\sphinxtablestrut{5}& cell2-3 @@ -36,7 +36,7 @@ cell2-3 \begin{varwidth}[t]{\sphinxcolwidth{2}{3}} cell3-2 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% }% \sphinxstopmulticolumn \\ @@ -47,7 +47,7 @@ cell4-1 \begin{varwidth}[t]{\sphinxcolwidth{3}{3}} cell5-1 \par -\vskip-\baselineskip\strut\end{varwidth}% +\vskip-\baselineskip\vbox{\hbox{\strut}}\end{varwidth}% \sphinxstopmulticolumn \\ \hline From 8542e29b40787676630fd1b77258826c0aa747a6 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Sep 2017 20:35:25 +0200 Subject: [PATCH 0121/1814] Fix flake8 line too long violation in latex.py --- sphinx/writers/latex.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 855822335..8c87302d9 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1463,7 +1463,8 @@ class LaTeXTranslator(nodes.NodeVisitor): if cell.width > 1 or cell.height > 1: self.body.append('\\begin{varwidth}[t]{\\sphinxcolwidth{%d}{%d}}\n' % (cell.width, self.table.colcount)) - context = ('\\par\n\\vskip-\\baselineskip\\vbox{\\hbox{\\strut}}\\end{varwidth}%\n') + context + context = ('\\par\n\\vskip-\\baselineskip' + '\\vbox{\\hbox{\\strut}}\\end{varwidth}%\n') + context self.needs_linetrimming = 1 if len(node) > 2 and len(node.astext().split('\n')) > 2: self.needs_linetrimming = 1 From 99503bdb6cca2be4d06772cef4cf79eed8d2eb19 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Tue, 12 Sep 2017 14:59:08 +0100 Subject: [PATCH 0122/1814] Sort modules for highlighting With this change the output will be in a predictable order on older versions of Python (where the dictionary is not sorted by default). This is helpful for debugging and interpreting the progress from the terminal. --- sphinx/ext/viewcode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 25e5fe82a..68655146a 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -146,7 +146,7 @@ def collect_pages(app): # app.builder.info(' (%d module code pages)' % # len(env._viewcode_modules), nonl=1) - for modname, entry in status_iterator(iteritems(env._viewcode_modules), # type: ignore + for modname, entry in status_iterator(sorted(iteritems(env._viewcode_modules)), # type: ignore 'highlighting module code... ', "blue", len(env._viewcode_modules), # type: ignore app.verbosity, lambda x: x[0]): From 7bda952e4a64fd4947f23e497ea6367556069217 Mon Sep 17 00:00:00 2001 From: Takayuki SHIMIZUKAWA Date: Wed, 13 Sep 2017 17:39:31 +0900 Subject: [PATCH 0123/1814] add Sylius to EXAMPLES https://groups.google.com/d/msg/sphinx-users/MACgWve2r9M/e2RUk2z2AwAJ --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index 01c414016..682c05c07 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -183,6 +183,7 @@ Documentation using a custom theme/integrated in a site * Self: http://www.selflanguage.org/ * Substance D: http://docs.pylonsproject.org/projects/substanced/en/latest/ * SQLAlchemy: http://www.sqlalchemy.org/docs/ +* Sylius: http://docs.sylius.org/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ * Ubuntu packaging guide: http://packaging.ubuntu.com/html/ * Werkzeug: http://werkzeug.pocoo.org/docs/ From 8b28cf4728f1fb3c54fcdba6553e1b112132d03c Mon Sep 17 00:00:00 2001 From: Craig Rodrigues Date: Fri, 15 Sep 2017 14:45:56 -0700 Subject: [PATCH 0124/1814] hashlib.sha1() must take bytes, not unicode --- sphinx/transforms/post_transforms/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index 9f07a391f..788684e40 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -70,7 +70,7 @@ class ImageDownloader(BaseImageConverter): if '?' in basename: basename = basename.split('?')[0] if basename == '': - basename = sha1(node['uri']).hexdigest() + basename = sha1(node['uri'].encode("utf-8")).hexdigest() dirname = node['uri'].replace('://', '/').translate({ord("?"): u"/", ord("&"): u"/"}) ensuredir(os.path.join(self.imagedir, dirname)) From 6e6a573cba5fc0c9fa05287935cf39478bfae4a2 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 8 Sep 2017 22:56:39 -0700 Subject: [PATCH 0125/1814] Fix typo in output of sphinx-build -h. --- sphinx/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 7b6cf0860..79a69cd7b 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -169,7 +169,7 @@ def main(argv): help='Do emit colored output (default: auto-detect)') group.add_option('-N', '--no-color', dest='color', action='store_const', const='no', - help='Do not emit colored output (default: auot-detect)') + help='Do not emit colored output (default: auto-detect)') group.add_option('-w', metavar='FILE', dest='warnfile', help='write warnings (and errors) to given file') group.add_option('-W', action='store_true', dest='warningiserror', From c31b9121036888ecd630eba09c6430f6eee2b6ae Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Sep 2017 22:48:38 +0900 Subject: [PATCH 0126/1814] Update CHANGES for PR #4049 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index ecc711a03..70901fac7 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,7 @@ Bugs fixed * #4041: C++, remove extra name linking in function pointers. * #4038: C, add missing documentation of ``member`` role. * #4044: An empty multicolumn cell causes extra row height in PDF output +* #4049: Fix typo in output of sphinx-build -h Testing -------- From 9f889932815dea46f8e97c732aaa8216e4b37c08 Mon Sep 17 00:00:00 2001 From: Craig Rodrigues Date: Fri, 15 Sep 2017 14:45:56 -0700 Subject: [PATCH 0127/1814] hashlib.sha1() must take bytes, not unicode --- sphinx/transforms/post_transforms/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index c57355774..df207f8ad 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -70,7 +70,7 @@ class ImageDownloader(BaseImageConverter): if '?' in basename: basename = basename.split('?')[0] if basename == '': - basename = sha1(node['uri']).hexdigest() + basename = sha1(node['uri'].encode("utf-8")).hexdigest() dirname = node['uri'].replace('://', '/').translate({ord("?"): u"/", ord("&"): u"/"}) ensuredir(os.path.join(self.imagedir, dirname)) From 666a69b286f13132073ad6a02addbf1baa94d487 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Sep 2017 22:50:07 +0900 Subject: [PATCH 0128/1814] Update CHANGES for PR #4062 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 70901fac7..c8fdc389d 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,8 @@ Bugs fixed * #4038: C, add missing documentation of ``member`` role. * #4044: An empty multicolumn cell causes extra row height in PDF output * #4049: Fix typo in output of sphinx-build -h +* #4062: hashlib.sha1() must take bytes, not unicode on Python 3 + Testing -------- From e47b30d5660535cb8af33e91ff947e01c657a50c Mon Sep 17 00:00:00 2001 From: Oliver Sanders Date: Mon, 18 Sep 2017 11:09:48 +0100 Subject: [PATCH 0129/1814] Fix ext.graphviz alignment. --- sphinx/ext/graphviz.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index a1565a1a7..2a83474ce 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -246,14 +246,14 @@ def render_dot_html(self, node, code, options, prefix='graphviz', if alt is None: alt = node.get('alt', self.encode(code).strip()) imgcss = imgcls and 'class="%s"' % imgcls or '' + if 'align' in node: + self.body.append('
' % + (node['align'], node['align'])) if format == 'svg': svgtag = '''

%s

\n''' % (fname, alt) self.body.append(svgtag) else: - if 'align' in node: - self.body.append('
' % - (node['align'], node['align'])) with open(outfn + '.map', 'rb') as mapfile: imgmap = mapfile.readlines() if len(imgmap) == 2: @@ -266,8 +266,8 @@ def render_dot_html(self, node, code, options, prefix='graphviz', self.body.append('%s\n' % (fname, alt, mapname, imgcss)) self.body.extend([item.decode('utf-8') for item in imgmap]) - if 'align' in node: - self.body.append('
\n') + if 'align' in node: + self.body.append('
\n') raise nodes.SkipNode @@ -286,24 +286,26 @@ def render_dot_latex(self, node, code, options, prefix='graphviz'): raise nodes.SkipNode is_inline = self.is_inline(node) - if is_inline: - para_separator = '' - else: - para_separator = '\n' - if fname is not None: - post = None # type: unicode - if not is_inline and 'align' in node: + if not is_inline: + pre = '' + post = '' + if 'align' in node: if node['align'] == 'left': - self.body.append('{') - post = '\\hspace*{\\fill}}' + pre = '{' + post = r'\hspace*{\fill}}' elif node['align'] == 'right': - self.body.append('{\\hspace*{\\fill}') + pre = r'{\hspace*{\fill}' post = '}' - self.body.append('%s\\includegraphics{%s}%s' % - (para_separator, fname, para_separator)) - if post: - self.body.append(post) + elif node['align'] == 'center': + pre = r'{\hfill' + post = r'\hspace*{\fill}}' + self.body.append('\n%s' % pre) + + self.body.append(r'\includegraphics{%s}' % fname) + + if not is_inline: + self.body.append('%s\n' % post) raise nodes.SkipNode From 447582724de08fafb1f954a3c50c953382352d49 Mon Sep 17 00:00:00 2001 From: Oliver Sanders Date: Mon, 18 Sep 2017 11:10:19 +0100 Subject: [PATCH 0130/1814] Add test for ext.graphviz alignment. --- tests/roots/test-ext-graphviz/index.rst | 5 +++ tests/test_ext_graphviz.py | 52 ++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/roots/test-ext-graphviz/index.rst b/tests/roots/test-ext-graphviz/index.rst index ab86e2a5a..930ec656d 100644 --- a/tests/roots/test-ext-graphviz/index.rst +++ b/tests/roots/test-ext-graphviz/index.rst @@ -25,3 +25,8 @@ Hello |graph| graphviz world :caption: on right foo -> bar + +.. digraph:: foo + :align: center + + centered diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py index 6affda7ab..1d2a3ab2f 100644 --- a/tests/test_ext_graphviz.py +++ b/tests/test_ext_graphviz.py @@ -16,7 +16,7 @@ import pytest @pytest.mark.sphinx('html', testroot='ext-graphviz') @pytest.mark.usefixtures('if_graphviz_found') -def test_graphviz_html(app, status, warning): +def test_graphviz_png_html(app, status, warning): app.builder.build_all() content = (app.outdir / 'index.html').text() @@ -34,6 +34,51 @@ def test_graphviz_html(app, status, warning): r'on right.*

\s*
') assert re.search(html, content, re.S) + html = (r'
' + r'\"digraph\n
') + assert re.search(html, content, re.S) + +@pytest.mark.sphinx('html', testroot='ext-graphviz', + confoverrides={'graphviz_output_format': 'svg'}) +@pytest.mark.usefixtures('if_graphviz_found') +def test_graphviz_svg_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'index.html').text() + + html = (r'
\n' + r'\n' + r'\s+

digraph foo {\n' + r'bar -> baz\n' + r'}

\n' + r'

' + r'caption of graph.*

\n
') + assert re.search(html, content, re.S) + + html = (r'Hello \n' + r'\s+

graph

\n' + r' graphviz world') + assert re.search(html, content, re.S) + + html = (r'
\n' + r'\n' + r'\s+

digraph bar {\n' + r'foo -> bar\n' + r'}

\n' + r'

' + r'on right.*

\n' + r'
') + assert re.search(html, content, re.S) + + html = (r'
' + r'\n' + r'\s+

digraph foo {\n' + r'centered\n' + r'}

\n' + r'
') + assert re.search(html, content, re.S) @pytest.mark.sphinx('latex', testroot='ext-graphviz') @pytest.mark.usefixtures('if_graphviz_found') @@ -54,6 +99,11 @@ def test_graphviz_latex(app, status, warning): '\\\\caption{on right}\\\\label{.*}\\\\end{wrapfigure}') assert re.search(macro, content, re.S) + macro = (r'\{\\hfill' + r'\\includegraphics{graphviz-.*}' + r'\\hspace\*{\\fill}}') + assert re.search(macro, content, re.S) + @pytest.mark.sphinx('html', testroot='ext-graphviz', confoverrides={'language': 'xx'}) @pytest.mark.usefixtures('if_graphviz_found') From 4475fc80c5a301db63e61fbca99f05f287d4137b Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Mon, 18 Sep 2017 15:42:57 +0300 Subject: [PATCH 0131/1814] Return non-zero exit status when make subprocess fails For example, when latexmk is not installed. --- sphinx/make_mode.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py index 9fe7ecebf..e7962db2e 100644 --- a/sphinx/make_mode.py +++ b/sphinx/make_mode.py @@ -18,6 +18,7 @@ from __future__ import print_function import os import sys +import subprocess from os import path import sphinx @@ -196,16 +197,14 @@ class Make(object): if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): - os.system('%s all-pdf' % self.makecmd) - return 0 + return subprocess.call([self.makecmd, 'all-pdf']) def build_latexpdfja(self): # type: () -> int if self.run_generic_build('latex') > 0: return 1 with cd(self.builddir_join('latex')): - os.system('%s all-pdf-ja' % self.makecmd) - return 0 + return subprocess.call([self.makecmd, 'all-pdf-ja']) def build_text(self): # type: () -> int @@ -231,8 +230,7 @@ class Make(object): if self.run_generic_build('texinfo') > 0: return 1 with cd(self.builddir_join('texinfo')): - os.system('%s info' % self.makecmd) - return 0 + return subprocess.call([self.makecmd, 'info']) def build_gettext(self): # type: () -> int From 0e82661b63f0ef2678bcb121b7877348b6bd0c4e Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Mon, 18 Sep 2017 23:57:08 +0900 Subject: [PATCH 0132/1814] #4068: Update linkcheck docs to use requests --- doc/builders.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/builders.rst b/doc/builders.rst index 9aad16a5f..534428732 100644 --- a/doc/builders.rst +++ b/doc/builders.rst @@ -423,8 +423,8 @@ instructions. .. class:: CheckExternalLinksBuilder This builder scans all documents for external links, tries to open them with - :mod:`urllib2`, and writes an overview which ones are broken and redirected - to standard output and to :file:`output.txt` in the output directory. + ``requests``, and writes an overview which ones are broken and redirected to + standard output and to :file:`output.txt` in the output directory. .. autoattribute:: name @@ -432,6 +432,10 @@ instructions. .. autoattribute:: supported_image_types + .. versionchanged:: 1.5 + + Since Sphinx-1.5, the linkcheck builder comes to use requests module. + .. module:: sphinx.builders.xml .. class:: XMLBuilder From 774f9d953a2b086e577349c7e3a170d52dd5028f Mon Sep 17 00:00:00 2001 From: aszekMosek Date: Mon, 18 Sep 2017 13:45:01 +0200 Subject: [PATCH 0133/1814] Avoiding indent after index entries in latex --- sphinx/writers/latex.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 8c87302d9..a25056826 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2006,6 +2006,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append(r'\index{%s|see{%s}}' % (p1, p2)) else: logger.warning('unknown index entry type %s found', type) + self.body.append('%\n') except ValueError as err: logger.warning(str(err)) raise nodes.SkipNode From 2ff6434b6adf9bc1d96c523f2ee1d9319a889822 Mon Sep 17 00:00:00 2001 From: aszek Date: Tue, 19 Sep 2017 09:39:58 +0200 Subject: [PATCH 0134/1814] Update fix as per discussion --- sphinx/writers/latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index a25056826..1c3242c92 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2006,7 +2006,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append(r'\index{%s|see{%s}}' % (p1, p2)) else: logger.warning('unknown index entry type %s found', type) - self.body.append('%\n') + self.body.append('\\ignorespaces ') except ValueError as err: logger.warning(str(err)) raise nodes.SkipNode From 444b1998d835af2526acc7eaa1510f92ecd0278e Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Sep 2017 09:56:06 +0200 Subject: [PATCH 0135/1814] Produce less ``\ignorespaces `` in latex output --- sphinx/writers/latex.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 1c3242c92..0e2a7261f 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2006,9 +2006,10 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append(r'\index{%s|see{%s}}' % (p1, p2)) else: logger.warning('unknown index entry type %s found', type) - self.body.append('\\ignorespaces ') except ValueError as err: logger.warning(str(err)) + if not node.get('inline', True): + self.body.append('\\ignorespaces ') raise nodes.SkipNode def visit_raw(self, node): From d0418f912943b5fa436ea27dedd730191b99114f Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Sep 2017 10:20:43 +0200 Subject: [PATCH 0136/1814] Add test for #4066 latex `\index` indent fix --- tests/roots/test-latex-index/conf.py | 3 +++ tests/roots/test-latex-index/index.rst | 12 ++++++++++++ tests/test_build_latex.py | 9 +++++++++ 3 files changed, 24 insertions(+) create mode 100644 tests/roots/test-latex-index/conf.py create mode 100644 tests/roots/test-latex-index/index.rst diff --git a/tests/roots/test-latex-index/conf.py b/tests/roots/test-latex-index/conf.py new file mode 100644 index 000000000..f81c30bc4 --- /dev/null +++ b/tests/roots/test-latex-index/conf.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' diff --git a/tests/roots/test-latex-index/index.rst b/tests/roots/test-latex-index/index.rst new file mode 100644 index 000000000..3c1bb46f9 --- /dev/null +++ b/tests/roots/test-latex-index/index.rst @@ -0,0 +1,12 @@ +test-latex-index +================ + +A :index:`famous` :index:`equation`: + +.. math:: + + E = m c^2 + +.. index:: Einstein, relativity + +and some text. diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 55f48cd22..a53c146a8 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1020,3 +1020,12 @@ def test_latex_remote_images(app, status, warning): assert '\\sphinxincludegraphics{{NOT_EXIST}.PNG}' not in result assert ('WARNING: Could not fetch remote image: ' 'http://example.com/NOT_EXIST.PNG [404]' in warning.getvalue()) + + +@pytest.mark.sphinx('latex', testroot='latex-index') +def test_latex_index(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'Python.tex').text(encoding='utf8') + assert 'A \\index{famous}famous \\index{equation}equation:\n' in result + assert '\n\\index{Einstein}\\index{relativity}\\ignorespaces \nand' in result From 6b7e33a33245f8a7acf3f3b0936bfcde2674bbaf Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Sep 2017 10:44:31 +0200 Subject: [PATCH 0137/1814] Update CHANGES for PR #4066 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index c8fdc389d..ab05011d8 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,7 @@ Bugs fixed * #4044: An empty multicolumn cell causes extra row height in PDF output * #4049: Fix typo in output of sphinx-build -h * #4062: hashlib.sha1() must take bytes, not unicode on Python 3 +* Avoid indent after index entries in latex (refs: #4066) Testing From 96cf498c9e63f0469279ff142a90d2e8de695a85 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 11 Jul 2017 16:24:07 +0100 Subject: [PATCH 0138/1814] apidoc: Move apidoc to ext/apidoc The 'sphinx-apidoc' tool is no longer the only kid on the block when it comes to automatic documentation of Python projects, with the likes of 'sphinx-autoapi' in development [1], and is not really maintained. Given the fact that the tool is tangential to Sphinx's main goal, there isn't really anything that warrants its continue existence as a core module. Signify this by moving the feature to 'ext'. This allows the feature to continue to exist in the package, but indicates that stability might be worse than one would expect from the core library. To avoid breaking packages that are using this feature directly, such as pbr [3], aliases for the old 'main' method are included. This is based on what Django does and, like Django, will allow us to safely remove the old modules in Sphinx 2.0. [1] https://github.com/rtfd/sphinx-autoapi [2] https://github.com/sphinx-doc/sphinx/pull/3485#issuecomment-288081223 [3] https://github.com/django/django/blob/1.11/django/test/runner.py#L688-L695 Signed-off-by: Stephen Finucane --- setup.py | 2 +- sphinx-apidoc.py | 2 +- sphinx/apidoc.py | 437 +----------------- sphinx/ext/apidoc.py | 440 +++++++++++++++++++ tests/{test_apidoc.py => test_ext_apidoc.py} | 2 +- 5 files changed, 459 insertions(+), 424 deletions(-) create mode 100644 sphinx/ext/apidoc.py rename tests/{test_apidoc.py => test_ext_apidoc.py} (99%) diff --git a/setup.py b/setup.py index e5453f645..8a0ab0776 100644 --- a/setup.py +++ b/setup.py @@ -241,7 +241,7 @@ setup( 'console_scripts': [ 'sphinx-build = sphinx:main', 'sphinx-quickstart = sphinx.quickstart:main', - 'sphinx-apidoc = sphinx.apidoc:main', + 'sphinx-apidoc = sphinx.ext.apidoc:main', 'sphinx-autogen = sphinx.ext.autosummary.generate:main', ], 'distutils.commands': [ diff --git a/sphinx-apidoc.py b/sphinx-apidoc.py index c9f7b4f48..eb86e0b12 100755 --- a/sphinx-apidoc.py +++ b/sphinx-apidoc.py @@ -11,5 +11,5 @@ import sys if __name__ == '__main__': - from sphinx.apidoc import main + from sphinx.ext.apidoc import main sys.exit(main(sys.argv[1:])) diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index da908da04..0a924b31d 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -3,437 +3,32 @@ sphinx.apidoc ~~~~~~~~~~~~~ - Parses a directory tree looking for Python modules and packages and creates - ReST files appropriately to create code documentation with Sphinx. It also - creates a modules index (named modules.). - - This is derived from the "sphinx-autopackage" script, which is: - Copyright 2008 Société des arts technologiques (SAT), - http://www.sat.qc.ca/ + This file has moved to :py:mod:`sphinx.ext.apidoc`. :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from __future__ import print_function -import os -import sys -import optparse -from os import path -from six import binary_type -from fnmatch import fnmatch +import warnings -from sphinx import __display_version__ -from sphinx.quickstart import EXTENSIONS -from sphinx.util import rst -from sphinx.util.osutil import FileAvoidWrite, walk - -if False: - # For type annotation - from typing import Any, List, Tuple # NOQA - -# automodule options -if 'SPHINX_APIDOC_OPTIONS' in os.environ: - OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',') -else: - OPTIONS = [ - 'members', - 'undoc-members', - # 'inherited-members', # disabled because there's a bug in sphinx - 'show-inheritance', - ] - -INITPY = '__init__.py' -PY_SUFFIXES = set(['.py', '.pyx']) +from sphinx.deprecation import RemovedInSphinx20Warning +from sphinx.ext.apidoc import main as _main -def makename(package, module): - # type: (unicode, unicode) -> unicode - """Join package and module with a dot.""" - # Both package and module can be None/empty. - if package: - name = package - if module: - name += '.' + module - else: - name = module - return name - - -def write_file(name, text, opts): - # type: (unicode, unicode, Any) -> None - """Write the output file for module/package .""" - fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix)) - if opts.dryrun: - print('Would create file %s.' % fname) - return - if not opts.force and path.isfile(fname): - print('File %s already exists, skipping.' % fname) - else: - print('Creating file %s.' % fname) - with FileAvoidWrite(fname) as f: - f.write(text) - - -def format_heading(level, text, escape=True): - # type: (int, unicode, bool) -> unicode - """Create a heading of [1, 2 or 3 supported].""" - if escape: - text = rst.escape(text) - underlining = ['=', '-', '~', ][level - 1] * len(text) - return '%s\n%s\n\n' % (text, underlining) - - -def format_directive(module, package=None): - # type: (unicode, unicode) -> unicode - """Create the automodule directive and add the options.""" - directive = '.. automodule:: %s\n' % makename(package, module) - for option in OPTIONS: - directive += ' :%s:\n' % option - return directive - - -def create_module_file(package, module, opts): - # type: (unicode, unicode, Any) -> None - """Build the text of the file and write the file.""" - if not opts.noheadings: - text = format_heading(1, '%s module' % module) - else: - text = '' - # text += format_heading(2, ':mod:`%s` Module' % module) - text += format_directive(module, package) - write_file(makename(package, module), text, opts) - - -def create_package_file(root, master_package, subroot, py_files, opts, subs, is_namespace): - # type: (unicode, unicode, unicode, List[unicode], Any, List[unicode], bool) -> None - """Build the text of the file and write the file.""" - text = format_heading(1, ('%s package' if not is_namespace else "%s namespace") - % makename(master_package, subroot)) - - if opts.modulefirst and not is_namespace: - text += format_directive(subroot, master_package) - text += '\n' - - # build a list of directories that are szvpackages (contain an INITPY file) - subs = [sub for sub in subs if path.isfile(path.join(root, sub, INITPY))] - # if there are some package directories, add a TOC for theses subpackages - if subs: - text += format_heading(2, 'Subpackages') - text += '.. toctree::\n\n' - for sub in subs: - text += ' %s.%s\n' % (makename(master_package, subroot), sub) - text += '\n' - - submods = [path.splitext(sub)[0] for sub in py_files - if not shall_skip(path.join(root, sub), opts) and - sub != INITPY] - if submods: - text += format_heading(2, 'Submodules') - if opts.separatemodules: - text += '.. toctree::\n\n' - for submod in submods: - modfile = makename(master_package, makename(subroot, submod)) - text += ' %s\n' % modfile - - # generate separate file for this module - if not opts.noheadings: - filetext = format_heading(1, '%s module' % modfile) - else: - filetext = '' - filetext += format_directive(makename(subroot, submod), - master_package) - write_file(modfile, filetext, opts) - else: - for submod in submods: - modfile = makename(master_package, makename(subroot, submod)) - if not opts.noheadings: - text += format_heading(2, '%s module' % modfile) - text += format_directive(makename(subroot, submod), - master_package) - text += '\n' - text += '\n' - - if not opts.modulefirst and not is_namespace: - text += format_heading(2, 'Module contents') - text += format_directive(subroot, master_package) - - write_file(makename(master_package, subroot), text, opts) - - -def create_modules_toc_file(modules, opts, name='modules'): - # type: (List[unicode], Any, unicode) -> None - """Create the module's index.""" - text = format_heading(1, '%s' % opts.header, escape=False) - text += '.. toctree::\n' - text += ' :maxdepth: %s\n\n' % opts.maxdepth - - modules.sort() - prev_module = '' # type: unicode - for module in modules: - # look if the module is a subpackage and, if yes, ignore it - if module.startswith(prev_module + '.'): - continue - prev_module = module - text += ' %s\n' % module - - write_file(name, text, opts) - - -def shall_skip(module, opts): - # type: (unicode, Any) -> bool - """Check if we want to skip this module.""" - # skip if the file doesn't exist and not using implicit namespaces - if not opts.implicit_namespaces and not path.exists(module): - return True - - # skip it if there is nothing (or just \n or \r\n) in the file - if path.exists(module) and path.getsize(module) <= 2: - return True - - # skip if it has a "private" name and this is selected - filename = path.basename(module) - if filename != '__init__.py' and filename.startswith('_') and \ - not opts.includeprivate: - return True - return False - - -def recurse_tree(rootpath, excludes, opts): - # type: (unicode, List[unicode], Any) -> List[unicode] - """ - Look for every file in the directory tree and create the corresponding - ReST files. - """ - followlinks = getattr(opts, 'followlinks', False) - includeprivate = getattr(opts, 'includeprivate', False) - implicit_namespaces = getattr(opts, 'implicit_namespaces', False) - - # check if the base directory is a package and get its name - if INITPY in os.listdir(rootpath) or implicit_namespaces: - root_package = rootpath.split(path.sep)[-1] - else: - # otherwise, the base is a directory with packages - root_package = None - - toplevels = [] - for root, subs, files in walk(rootpath, followlinks=followlinks): - # document only Python module files (that aren't excluded) - py_files = sorted(f for f in files - if path.splitext(f)[1] in PY_SUFFIXES and - not is_excluded(path.join(root, f), excludes)) - is_pkg = INITPY in py_files - is_namespace = INITPY not in py_files and implicit_namespaces - if is_pkg: - py_files.remove(INITPY) - py_files.insert(0, INITPY) - elif root != rootpath: - # only accept non-package at toplevel unless using implicit namespaces - if not implicit_namespaces: - del subs[:] - continue - # remove hidden ('.') and private ('_') directories, as well as - # excluded dirs - if includeprivate: - exclude_prefixes = ('.',) # type: Tuple[unicode, ...] - else: - exclude_prefixes = ('.', '_') - subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and - not is_excluded(path.join(root, sub), excludes)) - - if is_pkg or is_namespace: - # we are in a package with something to document - if subs or len(py_files) > 1 or not shall_skip(path.join(root, INITPY), opts): - subpackage = root[len(rootpath):].lstrip(path.sep).\ - replace(path.sep, '.') - # if this is not a namespace or - # a namespace and there is something there to document - if not is_namespace or len(py_files) > 0: - create_package_file(root, root_package, subpackage, - py_files, opts, subs, is_namespace) - toplevels.append(makename(root_package, subpackage)) - else: - # if we are at the root level, we don't require it to be a package - assert root == rootpath and root_package is None - for py_file in py_files: - if not shall_skip(path.join(rootpath, py_file), opts): - module = path.splitext(py_file)[0] - create_module_file(root_package, module, opts) - toplevels.append(module) - - return toplevels - - -def normalize_excludes(rootpath, excludes): - # type: (unicode, List[unicode]) -> List[unicode] - """Normalize the excluded directory list.""" - return [path.abspath(exclude) for exclude in excludes] - - -def is_excluded(root, excludes): - # type: (unicode, List[unicode]) -> bool - """Check if the directory is in the exclude list. - - Note: by having trailing slashes, we avoid common prefix issues, like - e.g. an exlude "foo" also accidentally excluding "foobar". - """ - for exclude in excludes: - if fnmatch(root, exclude): - return True - return False - - -def main(argv=sys.argv[1:]): - # type: (List[str]) -> int - """Parse and check the command line arguments.""" - parser = optparse.OptionParser( - usage="""\ -usage: %prog [options] -o [exclude_pattern, ...] - -Look recursively in for Python modules and packages and create -one reST file with automodule directives per package in the . - -The s can be file and/or directory patterns that will be -excluded from generation. - -Note: By default this script will not overwrite already created files.""") - - parser.add_option('-o', '--output-dir', action='store', dest='destdir', - help='Directory to place all output', default='') - parser.add_option('-d', '--maxdepth', action='store', dest='maxdepth', - help='Maximum depth of submodules to show in the TOC ' - '(default: 4)', type='int', default=4) - parser.add_option('-f', '--force', action='store_true', dest='force', - help='Overwrite existing files') - parser.add_option('-l', '--follow-links', action='store_true', - dest='followlinks', default=False, - help='Follow symbolic links. Powerful when combined ' - 'with collective.recipe.omelette.') - parser.add_option('-n', '--dry-run', action='store_true', dest='dryrun', - help='Run the script without creating files') - parser.add_option('-e', '--separate', action='store_true', - dest='separatemodules', - help='Put documentation for each module on its own page') - parser.add_option('-P', '--private', action='store_true', - dest='includeprivate', - help='Include "_private" modules') - parser.add_option('-T', '--no-toc', action='store_true', dest='notoc', - help='Don\'t create a table of contents file') - parser.add_option('-E', '--no-headings', action='store_true', - dest='noheadings', - help='Don\'t create headings for the module/package ' - 'packages (e.g. when the docstrings already contain ' - 'them)') - parser.add_option('-M', '--module-first', action='store_true', - dest='modulefirst', - help='Put module documentation before submodule ' - 'documentation') - parser.add_option('--implicit-namespaces', action='store_true', - dest='implicit_namespaces', - help='Interpret module paths according to PEP-0420 ' - 'implicit namespaces specification') - parser.add_option('-s', '--suffix', action='store', dest='suffix', - help='file suffix (default: rst)', default='rst') - parser.add_option('-F', '--full', action='store_true', dest='full', - help='Generate a full project with sphinx-quickstart') - parser.add_option('-a', '--append-syspath', action='store_true', - dest='append_syspath', - help='Append module_path to sys.path, used when --full is given') - parser.add_option('-H', '--doc-project', action='store', dest='header', - help='Project name (default: root module name)') - parser.add_option('-A', '--doc-author', action='store', dest='author', - type='str', - help='Project author(s), used when --full is given') - parser.add_option('-V', '--doc-version', action='store', dest='version', - help='Project version, used when --full is given') - parser.add_option('-R', '--doc-release', action='store', dest='release', - help='Project release, used when --full is given, ' - 'defaults to --doc-version') - parser.add_option('--version', action='store_true', dest='show_version', - help='Show version information and exit') - group = parser.add_option_group('Extension options') - for ext in EXTENSIONS: - group.add_option('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, - help='enable %s extension' % ext) - - (opts, args) = parser.parse_args(argv) - - if opts.show_version: - print('Sphinx (sphinx-apidoc) %s' % __display_version__) - return 0 - - if not args: - parser.error('A package path is required.') - - rootpath, excludes = args[0], args[1:] - if not opts.destdir: - parser.error('An output directory is required.') - if opts.header is None: - opts.header = path.abspath(rootpath).split(path.sep)[-1] - if opts.suffix.startswith('.'): - opts.suffix = opts.suffix[1:] - if not path.isdir(rootpath): - print('%s is not a directory.' % rootpath, file=sys.stderr) - sys.exit(1) - if not path.isdir(opts.destdir): - if not opts.dryrun: - os.makedirs(opts.destdir) - rootpath = path.abspath(rootpath) - excludes = normalize_excludes(rootpath, excludes) - modules = recurse_tree(rootpath, excludes, opts) - if opts.full: - from sphinx import quickstart as qs - modules.sort() - prev_module = '' # type: unicode - text = '' - for module in modules: - if module.startswith(prev_module + '.'): - continue - prev_module = module - text += ' %s\n' % module - d = dict( - path = opts.destdir, - sep = False, - dot = '_', - project = opts.header, - author = opts.author or 'Author', - version = opts.version or '', - release = opts.release or opts.version or '', - suffix = '.' + opts.suffix, - master = 'index', - epub = True, - ext_autodoc = True, - ext_viewcode = True, - ext_todo = True, - makefile = True, - batchfile = True, - mastertocmaxdepth = opts.maxdepth, - mastertoctree = text, - language = 'en', - module_path = rootpath, - append_syspath = opts.append_syspath, - ) - enabled_exts = {'ext_' + ext: getattr(opts, 'ext_' + ext) - for ext in EXTENSIONS if getattr(opts, 'ext_' + ext)} - d.update(enabled_exts) - - if isinstance(opts.header, binary_type): - d['project'] = d['project'].decode('utf-8') - if isinstance(opts.author, binary_type): - d['author'] = d['author'].decode('utf-8') - if isinstance(opts.version, binary_type): - d['version'] = d['version'].decode('utf-8') - if isinstance(opts.release, binary_type): - d['release'] = d['release'].decode('utf-8') - - if not opts.dryrun: - qs.generate(d, silent=True, overwrite=opts.force) - elif not opts.notoc: - create_modules_toc_file(modules, opts) - return 0 +def main(*args, **kwargs): + warnings.warn( + '`sphinx.apidoc.main()` has moved to `sphinx.ext.apidoc.main()`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) + _main(*args, **kwargs) # So program can be started with "python -m sphinx.apidoc ..." if __name__ == "__main__": + warnings.warn( + '`sphinx.apidoc` has moved to `sphinx.ext.apidoc`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) main() diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py new file mode 100644 index 000000000..9061d801e --- /dev/null +++ b/sphinx/ext/apidoc.py @@ -0,0 +1,440 @@ +# -*- coding: utf-8 -*- +""" + sphinx.ext.apidoc + ~~~~~~~~~~~~~~~~~ + + Parses a directory tree looking for Python modules and packages and creates + ReST files appropriately to create code documentation with Sphinx. It also + creates a modules index (named modules.). + + This is derived from the "sphinx-autopackage" script, which is: + Copyright 2008 Société des arts technologiques (SAT), + http://www.sat.qc.ca/ + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from __future__ import print_function + +import os +import sys +import optparse +from os import path +from six import binary_type +from fnmatch import fnmatch + +from sphinx import __display_version__ +from sphinx.quickstart import EXTENSIONS +from sphinx.util import rst +from sphinx.util.osutil import FileAvoidWrite, walk + +if False: + # For type annotation + from typing import Any, List, Tuple # NOQA + +# automodule options +if 'SPHINX_APIDOC_OPTIONS' in os.environ: + OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',') +else: + OPTIONS = [ + 'members', + 'undoc-members', + # 'inherited-members', # disabled because there's a bug in sphinx + 'show-inheritance', + ] + +INITPY = '__init__.py' +PY_SUFFIXES = set(['.py', '.pyx']) + + +def makename(package, module): + # type: (unicode, unicode) -> unicode + """Join package and module with a dot.""" + # Both package and module can be None/empty. + if package: + name = package + if module: + name += '.' + module + else: + name = module + return name + + +def write_file(name, text, opts): + # type: (unicode, unicode, Any) -> None + """Write the output file for module/package .""" + fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix)) + if opts.dryrun: + print('Would create file %s.' % fname) + return + if not opts.force and path.isfile(fname): + print('File %s already exists, skipping.' % fname) + else: + print('Creating file %s.' % fname) + with FileAvoidWrite(fname) as f: + f.write(text) + + +def format_heading(level, text, escape=True): + # type: (int, unicode, bool) -> unicode + """Create a heading of [1, 2 or 3 supported].""" + if escape: + text = rst.escape(text) + underlining = ['=', '-', '~', ][level - 1] * len(text) + return '%s\n%s\n\n' % (text, underlining) + + +def format_directive(module, package=None): + # type: (unicode, unicode) -> unicode + """Create the automodule directive and add the options.""" + directive = '.. automodule:: %s\n' % makename(package, module) + for option in OPTIONS: + directive += ' :%s:\n' % option + return directive + + +def create_module_file(package, module, opts): + # type: (unicode, unicode, Any) -> None + """Build the text of the file and write the file.""" + if not opts.noheadings: + text = format_heading(1, '%s module' % module) + else: + text = '' + # text += format_heading(2, ':mod:`%s` Module' % module) + text += format_directive(module, package) + write_file(makename(package, module), text, opts) + + +def create_package_file(root, master_package, subroot, py_files, opts, subs, is_namespace): + # type: (unicode, unicode, unicode, List[unicode], Any, List[unicode], bool) -> None + """Build the text of the file and write the file.""" + text = format_heading(1, ('%s package' if not is_namespace else "%s namespace") + % makename(master_package, subroot)) + + if opts.modulefirst and not is_namespace: + text += format_directive(subroot, master_package) + text += '\n' + + # build a list of directories that are szvpackages (contain an INITPY file) + subs = [sub for sub in subs if path.isfile(path.join(root, sub, INITPY))] + # if there are some package directories, add a TOC for theses subpackages + if subs: + text += format_heading(2, 'Subpackages') + text += '.. toctree::\n\n' + for sub in subs: + text += ' %s.%s\n' % (makename(master_package, subroot), sub) + text += '\n' + + submods = [path.splitext(sub)[0] for sub in py_files + if not shall_skip(path.join(root, sub), opts) and + sub != INITPY] + if submods: + text += format_heading(2, 'Submodules') + if opts.separatemodules: + text += '.. toctree::\n\n' + for submod in submods: + modfile = makename(master_package, makename(subroot, submod)) + text += ' %s\n' % modfile + + # generate separate file for this module + if not opts.noheadings: + filetext = format_heading(1, '%s module' % modfile) + else: + filetext = '' + filetext += format_directive(makename(subroot, submod), + master_package) + write_file(modfile, filetext, opts) + else: + for submod in submods: + modfile = makename(master_package, makename(subroot, submod)) + if not opts.noheadings: + text += format_heading(2, '%s module' % modfile) + text += format_directive(makename(subroot, submod), + master_package) + text += '\n' + text += '\n' + + if not opts.modulefirst and not is_namespace: + text += format_heading(2, 'Module contents') + text += format_directive(subroot, master_package) + + write_file(makename(master_package, subroot), text, opts) + + +def create_modules_toc_file(modules, opts, name='modules'): + # type: (List[unicode], Any, unicode) -> None + """Create the module's index.""" + text = format_heading(1, '%s' % opts.header, escape=False) + text += '.. toctree::\n' + text += ' :maxdepth: %s\n\n' % opts.maxdepth + + modules.sort() + prev_module = '' # type: unicode + for module in modules: + # look if the module is a subpackage and, if yes, ignore it + if module.startswith(prev_module + '.'): + continue + prev_module = module + text += ' %s\n' % module + + write_file(name, text, opts) + + +def shall_skip(module, opts): + # type: (unicode, Any) -> bool + """Check if we want to skip this module.""" + # skip if the file doesn't exist and not using implicit namespaces + if not opts.implicit_namespaces and not path.exists(module): + return True + + # skip it if there is nothing (or just \n or \r\n) in the file + if path.exists(module) and path.getsize(module) <= 2: + return True + + # skip if it has a "private" name and this is selected + filename = path.basename(module) + if filename != '__init__.py' and filename.startswith('_') and \ + not opts.includeprivate: + return True + return False + + +def recurse_tree(rootpath, excludes, opts): + # type: (unicode, List[unicode], Any) -> List[unicode] + """ + Look for every file in the directory tree and create the corresponding + ReST files. + """ + followlinks = getattr(opts, 'followlinks', False) + includeprivate = getattr(opts, 'includeprivate', False) + implicit_namespaces = getattr(opts, 'implicit_namespaces', False) + + # check if the base directory is a package and get its name + if INITPY in os.listdir(rootpath) or implicit_namespaces: + root_package = rootpath.split(path.sep)[-1] + else: + # otherwise, the base is a directory with packages + root_package = None + + toplevels = [] + for root, subs, files in walk(rootpath, followlinks=followlinks): + # document only Python module files (that aren't excluded) + py_files = sorted(f for f in files + if path.splitext(f)[1] in PY_SUFFIXES and + not is_excluded(path.join(root, f), excludes)) + is_pkg = INITPY in py_files + is_namespace = INITPY not in py_files and implicit_namespaces + if is_pkg: + py_files.remove(INITPY) + py_files.insert(0, INITPY) + elif root != rootpath: + # only accept non-package at toplevel unless using implicit namespaces + if not implicit_namespaces: + del subs[:] + continue + # remove hidden ('.') and private ('_') directories, as well as + # excluded dirs + if includeprivate: + exclude_prefixes = ('.',) # type: Tuple[unicode, ...] + else: + exclude_prefixes = ('.', '_') + subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and + not is_excluded(path.join(root, sub), excludes)) + + if is_pkg or is_namespace: + # we are in a package with something to document + if subs or len(py_files) > 1 or not shall_skip(path.join(root, INITPY), opts): + subpackage = root[len(rootpath):].lstrip(path.sep).\ + replace(path.sep, '.') + # if this is not a namespace or + # a namespace and there is something there to document + if not is_namespace or len(py_files) > 0: + create_package_file(root, root_package, subpackage, + py_files, opts, subs, is_namespace) + toplevels.append(makename(root_package, subpackage)) + else: + # if we are at the root level, we don't require it to be a package + assert root == rootpath and root_package is None + for py_file in py_files: + if not shall_skip(path.join(rootpath, py_file), opts): + module = path.splitext(py_file)[0] + create_module_file(root_package, module, opts) + toplevels.append(module) + + return toplevels + + +def normalize_excludes(rootpath, excludes): + # type: (unicode, List[unicode]) -> List[unicode] + """Normalize the excluded directory list.""" + return [path.abspath(exclude) for exclude in excludes] + + +def is_excluded(root, excludes): + # type: (unicode, List[unicode]) -> bool + """Check if the directory is in the exclude list. + + Note: by having trailing slashes, we avoid common prefix issues, like + e.g. an exlude "foo" also accidentally excluding "foobar". + """ + for exclude in excludes: + if fnmatch(root, exclude): + return True + return False + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> int + """Parse and check the command line arguments.""" + parser = optparse.OptionParser( + usage="""\ +usage: %prog [options] -o [exclude_pattern, ...] + +Look recursively in for Python modules and packages and create +one reST file with automodule directives per package in the . + +The s can be file and/or directory patterns that will be +excluded from generation. + +Note: By default this script will not overwrite already created files.""") + + parser.add_option('-o', '--output-dir', action='store', dest='destdir', + help='Directory to place all output', default='') + parser.add_option('-d', '--maxdepth', action='store', dest='maxdepth', + help='Maximum depth of submodules to show in the TOC ' + '(default: 4)', type='int', default=4) + parser.add_option('-f', '--force', action='store_true', dest='force', + help='Overwrite existing files') + parser.add_option('-l', '--follow-links', action='store_true', + dest='followlinks', default=False, + help='Follow symbolic links. Powerful when combined ' + 'with collective.recipe.omelette.') + parser.add_option('-n', '--dry-run', action='store_true', dest='dryrun', + help='Run the script without creating files') + parser.add_option('-e', '--separate', action='store_true', + dest='separatemodules', + help='Put documentation for each module on its own page') + parser.add_option('-P', '--private', action='store_true', + dest='includeprivate', + help='Include "_private" modules') + parser.add_option('-T', '--no-toc', action='store_true', dest='notoc', + help='Don\'t create a table of contents file') + parser.add_option('-E', '--no-headings', action='store_true', + dest='noheadings', + help='Don\'t create headings for the module/package ' + 'packages (e.g. when the docstrings already contain ' + 'them)') + parser.add_option('-M', '--module-first', action='store_true', + dest='modulefirst', + help='Put module documentation before submodule ' + 'documentation') + parser.add_option('--implicit-namespaces', action='store_true', + dest='implicit_namespaces', + help='Interpret module paths according to PEP-0420 ' + 'implicit namespaces specification') + parser.add_option('-s', '--suffix', action='store', dest='suffix', + help='file suffix (default: rst)', default='rst') + parser.add_option('-F', '--full', action='store_true', dest='full', + help='Generate a full project with sphinx-quickstart') + parser.add_option('-a', '--append-syspath', action='store_true', + dest='append_syspath', + help='Append module_path to sys.path, used when --full is given') + parser.add_option('-H', '--doc-project', action='store', dest='header', + help='Project name (default: root module name)') + parser.add_option('-A', '--doc-author', action='store', dest='author', + type='str', + help='Project author(s), used when --full is given') + parser.add_option('-V', '--doc-version', action='store', dest='version', + help='Project version, used when --full is given') + parser.add_option('-R', '--doc-release', action='store', dest='release', + help='Project release, used when --full is given, ' + 'defaults to --doc-version') + parser.add_option('--version', action='store_true', dest='show_version', + help='Show version information and exit') + group = parser.add_option_group('Extension options') + for ext in EXTENSIONS: + group.add_option('--ext-' + ext, action='store_true', + dest='ext_' + ext, default=False, + help='enable %s extension' % ext) + + (opts, args) = parser.parse_args(argv) + + if opts.show_version: + print('Sphinx (sphinx-apidoc) %s' % __display_version__) + return 0 + + if not args: + parser.error('A package path is required.') + + rootpath, excludes = args[0], args[1:] + if not opts.destdir: + parser.error('An output directory is required.') + if opts.header is None: + opts.header = path.abspath(rootpath).split(path.sep)[-1] + if opts.suffix.startswith('.'): + opts.suffix = opts.suffix[1:] + if not path.isdir(rootpath): + print('%s is not a directory.' % rootpath, file=sys.stderr) + sys.exit(1) + if not path.isdir(opts.destdir): + if not opts.dryrun: + os.makedirs(opts.destdir) + rootpath = path.abspath(rootpath) + excludes = normalize_excludes(rootpath, excludes) + modules = recurse_tree(rootpath, excludes, opts) + if opts.full: + from sphinx import quickstart as qs + modules.sort() + prev_module = '' # type: unicode + text = '' + for module in modules: + if module.startswith(prev_module + '.'): + continue + prev_module = module + text += ' %s\n' % module + d = dict( + path = opts.destdir, + sep = False, + dot = '_', + project = opts.header, + author = opts.author or 'Author', + version = opts.version or '', + release = opts.release or opts.version or '', + suffix = '.' + opts.suffix, + master = 'index', + epub = True, + ext_autodoc = True, + ext_viewcode = True, + ext_todo = True, + makefile = True, + batchfile = True, + mastertocmaxdepth = opts.maxdepth, + mastertoctree = text, + language = 'en', + module_path = rootpath, + append_syspath = opts.append_syspath, + ) + enabled_exts = {'ext_' + ext: getattr(opts, 'ext_' + ext) + for ext in EXTENSIONS if getattr(opts, 'ext_' + ext)} + d.update(enabled_exts) + + if isinstance(opts.header, binary_type): + d['project'] = d['project'].decode('utf-8') + if isinstance(opts.author, binary_type): + d['author'] = d['author'].decode('utf-8') + if isinstance(opts.version, binary_type): + d['version'] = d['version'].decode('utf-8') + if isinstance(opts.release, binary_type): + d['release'] = d['release'].decode('utf-8') + + if not opts.dryrun: + qs.generate(d, silent=True, overwrite=opts.force) + elif not opts.notoc: + create_modules_toc_file(modules, opts) + return 0 + + +# So program can be started with "python -m sphinx.apidoc ..." +if __name__ == "__main__": + main() diff --git a/tests/test_apidoc.py b/tests/test_ext_apidoc.py similarity index 99% rename from tests/test_apidoc.py rename to tests/test_ext_apidoc.py index 1e0a712d5..794591aa6 100644 --- a/tests/test_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -15,7 +15,7 @@ from collections import namedtuple import pytest -from sphinx.apidoc import main as apidoc_main +from sphinx.ext.apidoc import main as apidoc_main from sphinx.testing.util import remove_unicode_literals From 4d2cd03879af3eff859fc2be06cfacd33ea05ce0 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Wed, 20 Sep 2017 14:47:46 +0100 Subject: [PATCH 0139/1814] Reformat to avoid overly long line flake8 E501 --- sphinx/ext/viewcode.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 68655146a..ce67081d3 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -146,10 +146,11 @@ def collect_pages(app): # app.builder.info(' (%d module code pages)' % # len(env._viewcode_modules), nonl=1) - for modname, entry in status_iterator(sorted(iteritems(env._viewcode_modules)), # type: ignore - 'highlighting module code... ', "blue", - len(env._viewcode_modules), # type: ignore - app.verbosity, lambda x: x[0]): + for modname, entry in status_iterator( + sorted(iteritems(env._viewcode_modules)), # type: ignore + 'highlighting module code... ', "blue", + len(env._viewcode_modules), # type: ignore + app.verbosity, lambda x: x[0]): if not entry: continue code, tags, used, refname = entry From a455ffcce18d346cc4f77a9d51ebfe432eb40e38 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 13:52:59 +0900 Subject: [PATCH 0140/1814] Fix #4070: crashes when the warning message contains format strings --- CHANGES | 1 + sphinx/util/logging.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index ab05011d8..9119dc18c 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ Bugs fixed * #4049: Fix typo in output of sphinx-build -h * #4062: hashlib.sha1() must take bytes, not unicode on Python 3 * Avoid indent after index entries in latex (refs: #4066) +* #4070: crashes when the warning message contains format strings Testing diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 04cb5fcab..2cdac6c40 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -356,10 +356,11 @@ class WarningIsErrorFilter(logging.Filter): return True elif self.app.warningiserror: location = getattr(record, 'location', '') + message = record.msg.replace('%', '%%') if location: - raise SphinxWarning(location + ":" + record.msg % record.args) + raise SphinxWarning(location + ":" + message % record.args) else: - raise SphinxWarning(record.msg % record.args) + raise SphinxWarning(message % record.args) else: return True From 0f22fcdfb6c39c4d118fd920d6b1b335ad7dcae7 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 16:43:46 +0900 Subject: [PATCH 0141/1814] Update CHANGES for PR #4067 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 9119dc18c..5d371a9f8 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,7 @@ Bugs fixed * #4062: hashlib.sha1() must take bytes, not unicode on Python 3 * Avoid indent after index entries in latex (refs: #4066) * #4070: crashes when the warning message contains format strings +* #4067: Return non-zero exit status when make subprocess fails Testing From 395f4d4ca8aa7ffa0962fe636615c44c341d4db7 Mon Sep 17 00:00:00 2001 From: Oliver Sanders Date: Mon, 18 Sep 2017 11:09:48 +0100 Subject: [PATCH 0142/1814] Fix ext.graphviz alignment. --- sphinx/ext/graphviz.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index a1565a1a7..2a83474ce 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -246,14 +246,14 @@ def render_dot_html(self, node, code, options, prefix='graphviz', if alt is None: alt = node.get('alt', self.encode(code).strip()) imgcss = imgcls and 'class="%s"' % imgcls or '' + if 'align' in node: + self.body.append('
' % + (node['align'], node['align'])) if format == 'svg': svgtag = '''

%s

\n''' % (fname, alt) self.body.append(svgtag) else: - if 'align' in node: - self.body.append('
' % - (node['align'], node['align'])) with open(outfn + '.map', 'rb') as mapfile: imgmap = mapfile.readlines() if len(imgmap) == 2: @@ -266,8 +266,8 @@ def render_dot_html(self, node, code, options, prefix='graphviz', self.body.append('%s\n' % (fname, alt, mapname, imgcss)) self.body.extend([item.decode('utf-8') for item in imgmap]) - if 'align' in node: - self.body.append('
\n') + if 'align' in node: + self.body.append('
\n') raise nodes.SkipNode @@ -286,24 +286,26 @@ def render_dot_latex(self, node, code, options, prefix='graphviz'): raise nodes.SkipNode is_inline = self.is_inline(node) - if is_inline: - para_separator = '' - else: - para_separator = '\n' - if fname is not None: - post = None # type: unicode - if not is_inline and 'align' in node: + if not is_inline: + pre = '' + post = '' + if 'align' in node: if node['align'] == 'left': - self.body.append('{') - post = '\\hspace*{\\fill}}' + pre = '{' + post = r'\hspace*{\fill}}' elif node['align'] == 'right': - self.body.append('{\\hspace*{\\fill}') + pre = r'{\hspace*{\fill}' post = '}' - self.body.append('%s\\includegraphics{%s}%s' % - (para_separator, fname, para_separator)) - if post: - self.body.append(post) + elif node['align'] == 'center': + pre = r'{\hfill' + post = r'\hspace*{\fill}}' + self.body.append('\n%s' % pre) + + self.body.append(r'\includegraphics{%s}' % fname) + + if not is_inline: + self.body.append('%s\n' % post) raise nodes.SkipNode From 261f74bc7a903981e28b6363ad7c19747c781ffa Mon Sep 17 00:00:00 2001 From: Oliver Sanders Date: Mon, 18 Sep 2017 11:10:19 +0100 Subject: [PATCH 0143/1814] Add test for ext.graphviz alignment. --- tests/roots/test-ext-graphviz/index.rst | 5 +++ tests/test_ext_graphviz.py | 52 ++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/roots/test-ext-graphviz/index.rst b/tests/roots/test-ext-graphviz/index.rst index ab86e2a5a..930ec656d 100644 --- a/tests/roots/test-ext-graphviz/index.rst +++ b/tests/roots/test-ext-graphviz/index.rst @@ -25,3 +25,8 @@ Hello |graph| graphviz world :caption: on right foo -> bar + +.. digraph:: foo + :align: center + + centered diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py index 6affda7ab..1d2a3ab2f 100644 --- a/tests/test_ext_graphviz.py +++ b/tests/test_ext_graphviz.py @@ -16,7 +16,7 @@ import pytest @pytest.mark.sphinx('html', testroot='ext-graphviz') @pytest.mark.usefixtures('if_graphviz_found') -def test_graphviz_html(app, status, warning): +def test_graphviz_png_html(app, status, warning): app.builder.build_all() content = (app.outdir / 'index.html').text() @@ -34,6 +34,51 @@ def test_graphviz_html(app, status, warning): r'on right.*

\s*') assert re.search(html, content, re.S) + html = (r'
' + r'\"digraph\n
') + assert re.search(html, content, re.S) + +@pytest.mark.sphinx('html', testroot='ext-graphviz', + confoverrides={'graphviz_output_format': 'svg'}) +@pytest.mark.usefixtures('if_graphviz_found') +def test_graphviz_svg_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'index.html').text() + + html = (r'
\n' + r'\n' + r'\s+

digraph foo {\n' + r'bar -> baz\n' + r'}

\n' + r'

' + r'caption of graph.*

\n
') + assert re.search(html, content, re.S) + + html = (r'Hello \n' + r'\s+

graph

\n' + r' graphviz world') + assert re.search(html, content, re.S) + + html = (r'
\n' + r'\n' + r'\s+

digraph bar {\n' + r'foo -> bar\n' + r'}

\n' + r'

' + r'on right.*

\n' + r'
') + assert re.search(html, content, re.S) + + html = (r'
' + r'\n' + r'\s+

digraph foo {\n' + r'centered\n' + r'}

\n' + r'
') + assert re.search(html, content, re.S) @pytest.mark.sphinx('latex', testroot='ext-graphviz') @pytest.mark.usefixtures('if_graphviz_found') @@ -54,6 +99,11 @@ def test_graphviz_latex(app, status, warning): '\\\\caption{on right}\\\\label{.*}\\\\end{wrapfigure}') assert re.search(macro, content, re.S) + macro = (r'\{\\hfill' + r'\\includegraphics{graphviz-.*}' + r'\\hspace\*{\\fill}}') + assert re.search(macro, content, re.S) + @pytest.mark.sphinx('html', testroot='ext-graphviz', confoverrides={'language': 'xx'}) @pytest.mark.usefixtures('if_graphviz_found') From 7ecc2531f9a11a8d70b850b1f9a4ae80d6891fe1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 17:05:47 +0900 Subject: [PATCH 0144/1814] Update CHANGES for PR #4055 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 5d371a9f8..bceb672d0 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,9 @@ Bugs fixed * Avoid indent after index entries in latex (refs: #4066) * #4070: crashes when the warning message contains format strings * #4067: Return non-zero exit status when make subprocess fails +* #4055: graphviz: the :align: option does not work for SVG output +* #4055: graphviz: the :align: center option does not work for latex output + Testing From 4d58347c7dbe8f12558683b414e4880f9a4eddc3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 20:51:56 +0900 Subject: [PATCH 0145/1814] Update CHANGES for PR #4052 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 37ef1d428..548ffc737 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,8 @@ Features added * #4023: Clarify error message when any role has more than one target. * #3973: epub: allow to override build date * #3972: epub: Sort manifest entries by filename +* #4052: viewcode: Sort before highlighting module code + Features removed ---------------- From 9eec5fa8d7cfaeaece565330244489e9a2328bcd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 21:19:21 +0900 Subject: [PATCH 0146/1814] Reorder .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 023b12a00..8ba227c7a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ build/ dist/ Sphinx.egg-info/ doc/_build/ +doc/locale/ tests/.coverage tests/build/ utils/regression_test.js -doc/locale/ From 5e6da322378289dd15966808ed16edeb9d7b4221 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 21:19:51 +0900 Subject: [PATCH 0147/1814] Reorder .gitignore --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 11f46d9e3..f3ff8aba7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .dir-locals.el .cache/ +.idea .mypy_cache/ .ropeproject/ TAGS @@ -23,6 +24,3 @@ doc/_build/ tests/.coverage tests/build/ utils/regression_test.js - -# IDE -.idea From 617bb43cae3c8a620c2e57f84fc6fbe3ed0b4d34 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 24 Sep 2017 23:46:31 +0900 Subject: [PATCH 0148/1814] Comment out broken test cases temporarily --- tests/test_ext_intersphinx.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 96210dc6c..76f4cef0a 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -232,12 +232,12 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): ' href="https://docs.python.org/index.html#cpp_foo_bar"' ' title="(in foo v2.0)">' 'Bar' in html) - assert ('std' in html) - assert ('uint8_t' in html) + # assert ('std' in html) + # assert ('uint8_t' in html) def test_missing_reference_jsdomain(tempdir, app, status, warning): From f9250e198b5dab4ab9ff9a489ffdf723d873451c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 24 Sep 2017 14:02:53 -0400 Subject: [PATCH 0149/1814] Switched stylesheet for font to HTTPS to avoid mixed content issues --- doc/_themes/sphinx13/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_themes/sphinx13/layout.html b/doc/_themes/sphinx13/layout.html index fdac6d0a2..911d1287c 100644 --- a/doc/_themes/sphinx13/layout.html +++ b/doc/_themes/sphinx13/layout.html @@ -14,7 +14,7 @@ {% block sidebar2 %}{% endblock %} {% block extrahead %} - {{ super() }} {%- if not embedded %} From ec2e60674f4964b65044a154a5cb8736801d33f5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 26 Sep 2017 00:55:42 +0900 Subject: [PATCH 0150/1814] Fix #4051: warn() function for HTML theme outputs 'None' string --- CHANGES | 2 +- sphinx/builders/html.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index bceb672d0..8b698ebf0 100644 --- a/CHANGES +++ b/CHANGES @@ -38,7 +38,7 @@ Bugs fixed * #4067: Return non-zero exit status when make subprocess fails * #4055: graphviz: the :align: option does not work for SVG output * #4055: graphviz: the :align: center option does not work for latex output - +* #4051: ``warn()`` function for HTML theme outputs 'None' string Testing diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 0265f6a1b..90e4574cc 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -898,7 +898,6 @@ class StandaloneHTMLBuilder(Builder): outfilename=None, event_arg=None): # type: (unicode, Dict, unicode, unicode, Any) -> None ctx = self.globalcontext.copy() - ctx['warn'] = self.warn # current_page_name is backwards compatibility ctx['pagename'] = ctx['current_page_name'] = pagename ctx['encoding'] = self.config.html_output_encoding @@ -931,6 +930,13 @@ class StandaloneHTMLBuilder(Builder): return False ctx['hasdoc'] = hasdoc + def warn(*args, **kwargs): + # type: (Any, Any) -> unicode + """Simple warn() wrapper for themes.""" + self.warn(*args, **kwargs) + return '' # return empty string + ctx['warn'] = warn + ctx['toctree'] = lambda **kw: self._get_local_toctree(pagename, **kw) self.add_sidebars(pagename, ctx) ctx.update(addctx) From cc5a1542c78aa65077b8f9aeb24bb802ccac03d6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 26 Sep 2017 00:55:42 +0900 Subject: [PATCH 0151/1814] Fix #4051: warn() function for HTML theme outputs 'None' string --- CHANGES | 2 +- sphinx/builders/html.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index bceb672d0..8b698ebf0 100644 --- a/CHANGES +++ b/CHANGES @@ -38,7 +38,7 @@ Bugs fixed * #4067: Return non-zero exit status when make subprocess fails * #4055: graphviz: the :align: option does not work for SVG output * #4055: graphviz: the :align: center option does not work for latex output - +* #4051: ``warn()`` function for HTML theme outputs 'None' string Testing diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 0265f6a1b..90e4574cc 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -898,7 +898,6 @@ class StandaloneHTMLBuilder(Builder): outfilename=None, event_arg=None): # type: (unicode, Dict, unicode, unicode, Any) -> None ctx = self.globalcontext.copy() - ctx['warn'] = self.warn # current_page_name is backwards compatibility ctx['pagename'] = ctx['current_page_name'] = pagename ctx['encoding'] = self.config.html_output_encoding @@ -931,6 +930,13 @@ class StandaloneHTMLBuilder(Builder): return False ctx['hasdoc'] = hasdoc + def warn(*args, **kwargs): + # type: (Any, Any) -> unicode + """Simple warn() wrapper for themes.""" + self.warn(*args, **kwargs) + return '' # return empty string + ctx['warn'] = warn + ctx['toctree'] = lambda **kw: self._get_local_toctree(pagename, **kw) self.add_sidebars(pagename, ctx) ctx.update(addctx) From c6fe6a3bf23d3c61a9a05c9a2ab58ce17d594a62 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 26 Sep 2017 09:45:14 +0900 Subject: [PATCH 0152/1814] Bump to 1.6.4 final --- CHANGES | 17 ++--------------- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index 8b698ebf0..25f6363fc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,5 @@ -Release 1.6.4 (in development) -============================== - -Dependencies ------------- - -Incompatible changes --------------------- - -Deprecated ----------- +Release 1.6.4 (released Sep 26, 2017) +===================================== Features added -------------- @@ -40,10 +31,6 @@ Bugs fixed * #4055: graphviz: the :align: center option does not work for latex output * #4051: ``warn()`` function for HTML theme outputs 'None' string - -Testing --------- - Release 1.6.3 (released Jul 02, 2017) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index e574ffe6c..be114cf02 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.4+' +__version__ = '1.6.4' __released__ = '1.6.4' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 4, 'beta', 0) +version_info = (1, 6, 4, 'final', 0) package_dir = path.abspath(path.dirname(__file__)) From 0ba56553e342edb91f757608a646bcb798b03efd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 26 Sep 2017 09:48:09 +0900 Subject: [PATCH 0153/1814] Bump version --- CHANGES | 21 +++++++++++++++++++++ sphinx/__init__.py | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 25f6363fc..29cf96116 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Release 1.6.5 (in development) +============================== + +Dependencies +------------ + +Incompatible changes +-------------------- + +Deprecated +---------- + +Features added +-------------- + +Bugs fixed +---------- + +Testing +-------- + Release 1.6.4 (released Sep 26, 2017) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index be114cf02..1d7bcc2ba 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.4' -__released__ = '1.6.4' # used when Sphinx builds its own docs +__version__ = '1.6.5+' +__released__ = '1.6.5' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 4, 'final', 0) +version_info = (1, 6, 5, 'beta', 0) package_dir = path.abspath(path.dirname(__file__)) From 5cfefdf2c14e405d706fcdd09c36c2afabb5207c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 26 Sep 2017 15:47:20 +0900 Subject: [PATCH 0154/1814] Update CHANGES for PR #3929 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 037743bd2..1c011ec76 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,7 @@ Incompatible changes * #3962: sphinx-apidoc now recognizes given directory as an implicit namespace package when ``--implicit-namespaces`` option given, not subdirectories of given directory. +* #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc Deprecated ---------- From e15e9a79b404b2f6c2c3267b5f980e8400cc4130 Mon Sep 17 00:00:00 2001 From: Takayuki SHIMIZUKAWA Date: Tue, 26 Sep 2017 22:49:23 +0900 Subject: [PATCH 0155/1814] fix a glitch --- EXAMPLES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES b/EXAMPLES index 682c05c07..fa91b206e 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -218,7 +218,7 @@ Books produced using Sphinx http://www.amazon.co.jp/dp/4048689525/ * "Python Professional Programming" (in Japanese): http://www.amazon.co.jp/dp/4798032948/ -* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kie?lowski": +* "Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski": http://www.hasecke.eu/Dekalog/ * The "Varnish Book": http://book.varnish-software.com/4.0/ From 5e1af8df773f09f2abb93129ca9b48d59e0a4a38 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 21 Sep 2017 10:55:40 +0100 Subject: [PATCH 0156/1814] setup.cfg: Ignore .venv We started ignoring this file from Git in commit 75154196b. Now do the same for flake8. Signed-off-by: Stephen Finucane --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index e0312ce00..90c531bf6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,7 +26,7 @@ universal = 1 [flake8] max-line-length = 95 ignore = E116,E241,E251 -exclude = .git,.tox,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py +exclude = .git,.tox,.venv,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py [build_sphinx] warning-is-error = 1 From 384ccf78133cb149cea47e31488285e228d129a4 Mon Sep 17 00:00:00 2001 From: Sumana Harihareswara Date: Tue, 26 Sep 2017 12:55:51 -0400 Subject: [PATCH 0157/1814] Fix grammar in exclude_patterns explanation comment --- sphinx/templates/quickstart/conf.py_t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 70683f8ee..8300e626f 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -79,7 +79,7 @@ language = {{ language | repr }} # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path +# This pattern also affects html_static_path and html_extra_path . exclude_patterns = [{{ exclude_patterns }}] # The name of the Pygments (syntax highlighting) style to use. From dc129e0532e3cfba4add790861e03872101dbe9b Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 27 Sep 2017 09:54:18 +0200 Subject: [PATCH 0158/1814] Fix #4085 Failed PDF build from image in parsed-literal --- CHANGES | 2 ++ sphinx/writers/latex.py | 6 +++--- tests/roots/test-image-in-parsed-literal/conf.py | 13 +++++++++++++ .../roots/test-image-in-parsed-literal/index.rst | 9 +++++++++ tests/roots/test-image-in-parsed-literal/pic.png | Bin 0 -> 120 bytes tests/test_build_latex.py | 10 ++++++++++ 6 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/roots/test-image-in-parsed-literal/conf.py create mode 100644 tests/roots/test-image-in-parsed-literal/index.rst create mode 100644 tests/roots/test-image-in-parsed-literal/pic.png diff --git a/CHANGES b/CHANGES index 29cf96116..86baa9421 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,8 @@ Features added Bugs fixed ---------- +* #4085: Failed PDF build from image in parsed-literal using ``:align:`` option + Testing -------- diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 0e2a7261f..3512f781f 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1702,9 +1702,6 @@ class LaTeXTranslator(nodes.NodeVisitor): pre = [] # type: List[unicode] # in reverse order post = [] # type: List[unicode] - if self.in_parsed_literal: - pre = ['\\begingroup\\sphinxunactivateextrasandspace\\relax '] - post = ['\\endgroup '] include_graphics_options = [] is_inline = self.is_inline(node) if 'width' in attrs: @@ -1744,6 +1741,9 @@ class LaTeXTranslator(nodes.NodeVisitor): post.append(align_prepost[is_inline, attrs['align']][1]) except KeyError: pass + if self.in_parsed_literal: + pre.append('\\begingroup\\sphinxunactivateextrasandspace\\relax ') + post.append('\\endgroup ') if not is_inline: pre.append('\n\\noindent') post.append('\n') diff --git a/tests/roots/test-image-in-parsed-literal/conf.py b/tests/roots/test-image-in-parsed-literal/conf.py new file mode 100644 index 000000000..c2daf654f --- /dev/null +++ b/tests/roots/test-image-in-parsed-literal/conf.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' +exclude_patterns = ['_build'] + +rst_epilog = ''' +.. |picture| image:: pic.png + :width: 15pt + :scale: 200% + :align: middle + :alt: alternative_text +''' + diff --git a/tests/roots/test-image-in-parsed-literal/index.rst b/tests/roots/test-image-in-parsed-literal/index.rst new file mode 100644 index 000000000..147a111dc --- /dev/null +++ b/tests/roots/test-image-in-parsed-literal/index.rst @@ -0,0 +1,9 @@ +test-image-in-parsed-literal +============================ + +Dummy text + +.. parsed-literal:: + + |picture| + diff --git a/tests/roots/test-image-in-parsed-literal/pic.png b/tests/roots/test-image-in-parsed-literal/pic.png new file mode 100644 index 0000000000000000000000000000000000000000..fda6cd29ede1be6168ce8b5e02d099ea9055ccfb GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI|!2~2VCcCc%QudxMjv*C{TfG{24>0g7{2zat zIm@i@&@2&y-PR1xY$qjFM{J&XU;25XW1{_&{(Ldr+IaofPcAOcp2zd*+4*{gj8%&M U)(>{V3jhEB literal 0 HcmV?d00001 diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index a53c146a8..4133f3699 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1029,3 +1029,13 @@ def test_latex_index(app, status, warning): result = (app.outdir / 'Python.tex').text(encoding='utf8') assert 'A \\index{famous}famous \\index{equation}equation:\n' in result assert '\n\\index{Einstein}\\index{relativity}\\ignorespaces \nand' in result + + +@pytest.mark.sphinx('latex', testroot='image-in-parsed-literal') +def test_latex_image_in_parsed_literal(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'Python.tex').text(encoding='utf8') + assert (r'\begingroup\sphinxunactivateextrasandspace\relax \raisebox{-0.5\height}' + r'{\scalebox{2.000000}{\sphinxincludegraphics[width=15bp]{{pic}.png}}}' + r'\endgroup ') in result From db36b42e5549b1b1e38b6163016c6458afc2a5c5 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 27 Sep 2017 12:43:28 +0200 Subject: [PATCH 0159/1814] Avoid extra space in PDF after image in parsed-literal (refs: Fix #4085) --- sphinx/writers/latex.py | 4 ++-- tests/roots/test-image-in-parsed-literal/conf.py | 2 +- tests/roots/test-image-in-parsed-literal/index.rst | 2 +- tests/test_build_latex.py | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 3512f781f..83ccd54de 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1742,8 +1742,8 @@ class LaTeXTranslator(nodes.NodeVisitor): except KeyError: pass if self.in_parsed_literal: - pre.append('\\begingroup\\sphinxunactivateextrasandspace\\relax ') - post.append('\\endgroup ') + pre.append('{\\sphinxunactivateextrasandspace ') + post.append('}') if not is_inline: pre.append('\n\\noindent') post.append('\n') diff --git a/tests/roots/test-image-in-parsed-literal/conf.py b/tests/roots/test-image-in-parsed-literal/conf.py index c2daf654f..d208b8385 100644 --- a/tests/roots/test-image-in-parsed-literal/conf.py +++ b/tests/roots/test-image-in-parsed-literal/conf.py @@ -5,7 +5,7 @@ exclude_patterns = ['_build'] rst_epilog = ''' .. |picture| image:: pic.png - :width: 15pt + :height: 1cm :scale: 200% :align: middle :alt: alternative_text diff --git a/tests/roots/test-image-in-parsed-literal/index.rst b/tests/roots/test-image-in-parsed-literal/index.rst index 147a111dc..80e1008e1 100644 --- a/tests/roots/test-image-in-parsed-literal/index.rst +++ b/tests/roots/test-image-in-parsed-literal/index.rst @@ -5,5 +5,5 @@ Dummy text .. parsed-literal:: - |picture| + |picture|\ AFTER diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 4133f3699..f36aa355b 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1036,6 +1036,6 @@ def test_latex_image_in_parsed_literal(app, status, warning): app.builder.build_all() result = (app.outdir / 'Python.tex').text(encoding='utf8') - assert (r'\begingroup\sphinxunactivateextrasandspace\relax \raisebox{-0.5\height}' - r'{\scalebox{2.000000}{\sphinxincludegraphics[width=15bp]{{pic}.png}}}' - r'\endgroup ') in result + assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\height}' + '{\\scalebox{2.000000}{\\sphinxincludegraphics[height=1cm]{{pic}.png}}}' + '}AFTER') in result From 447c54ae92e69a33c2357adea5cceee1a5a73282 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 28 Sep 2017 20:10:07 +0200 Subject: [PATCH 0160/1814] C++, adapt sphinx-doc/sphinx#3894 after merge to master Fixes sphinx-doc/sphinx#4082 --- sphinx/domains/cpp.py | 10 +++++----- tests/test_ext_intersphinx.py | 6 ------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 20c0f0074..9e8624df8 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -5469,12 +5469,12 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(l_('class'), 'class', 'type', 'typeOrConcept'), - 'function': ObjType(l_('function'), 'function', 'func', 'type', 'typeOrConcept'), + 'class': ObjType(l_('class'), 'class', 'type', 'identifier'), + 'function': ObjType(l_('function'), 'function', 'func', 'type', 'identifier'), 'member': ObjType(l_('member'), 'member', 'var'), - 'type': ObjType(l_('type'), 'type', 'typeOrConcept'), - 'concept': ObjType(l_('concept'), 'concept', 'typeOrConcept'), - 'enum': ObjType(l_('enum'), 'enum', 'type', 'typeOrConcept'), + 'type': ObjType(l_('type'), 'type', 'identifier'), + 'concept': ObjType(l_('concept'), 'concept', 'identifier'), + 'enum': ObjType(l_('enum'), 'enum', 'type', 'identifier'), 'enumerator': ObjType(l_('enumerator'), 'enumerator') } diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 76f4cef0a..4965108ef 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -232,12 +232,6 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): ' href="https://docs.python.org/index.html#cpp_foo_bar"' ' title="(in foo v2.0)">' 'Bar' in html) - # assert ('std' in html) - # assert ('uint8_t' in html) def test_missing_reference_jsdomain(tempdir, app, status, warning): From 3a0c050af0ab106ac3316a747a3ca8418a2129df Mon Sep 17 00:00:00 2001 From: Andy Neebel Date: Thu, 28 Sep 2017 13:43:46 -0500 Subject: [PATCH 0161/1814] Some cleanup to avoid using the std:: namespace --- tests/roots/test-ext-intersphinx-cppdomain/index.rst | 2 +- tests/test_ext_intersphinx.py | 7 +++++++ tests/test_util_inventory.py | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/roots/test-ext-intersphinx-cppdomain/index.rst b/tests/roots/test-ext-intersphinx-cppdomain/index.rst index 06c954b99..bf67d52d2 100644 --- a/tests/roots/test-ext-intersphinx-cppdomain/index.rst +++ b/tests/roots/test-ext-intersphinx-cppdomain/index.rst @@ -5,4 +5,4 @@ test-ext-intersphinx-cppdomain :cpp:class:`Bar` -.. cpp:function:: std::uint8_t FooBarBaz() +.. cpp:function:: foons::bartype FooBarBaz() diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 4965108ef..594aa81b8 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -232,6 +232,13 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): ' href="https://docs.python.org/index.html#cpp_foo_bar"' ' title="(in foo v2.0)">' 'Bar' in html) + assert ('foons' in html) + assert ('bartype' in html) + def test_missing_reference_jsdomain(tempdir, app, status, warning): diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py index 1a5be431b..3829de9ef 100644 --- a/tests/test_util_inventory.py +++ b/tests/test_util_inventory.py @@ -38,6 +38,8 @@ std cpp:type 1 index.html#std - std::uint8_t cpp:type 1 index.html#std_uint8_t - foo::Bar cpp:class 1 index.html#cpp_foo_bar - foo::Bar::baz cpp:function 1 index.html#cpp_foo_bar_baz - +foons cpp:type 1 index.html#foons - +foons::bartype cpp:type 1 index.html#foons_bartype - a term std:term -1 glossary.html#term-a-term - ls.-l std:cmdoption 1 index.html#cmdoption-ls-l - docname std:doc -1 docname.html - From b85ea529b88c6b38494523654b3b57552727648b Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 28 Sep 2017 20:46:34 +0200 Subject: [PATCH 0162/1814] C++, allow empty template argument lists See sphinx-doc/sphinx#4094 --- CHANGES | 1 + sphinx/domains/cpp.py | 5 +++-- tests/test_domain_cpp.py | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 1c011ec76..116857e81 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ Features added * C++, handle ``decltype(auto)``. * #2406: C++, add proper parsing of expressions, including linking of identifiers. * C++, add a ``cpp:expr`` role for inserting inline C++ expressions or types. +* #4094: C++, allow empty template argument lists. * #3638: Allow to change a label of reference to equation using ``math_eqref_format`` diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 9e8624df8..95ebcf165 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1603,7 +1603,6 @@ class ASTTemplateArgs(ASTBase): def __init__(self, args): # type: (List[Any]) -> None assert args is not None - assert len(args) > 0 self.args = args def get_id(self, version): @@ -4120,8 +4119,10 @@ class DefinitionParser(object): def _parse_template_argument_list(self): # type: () -> ASTTemplateArgs self.skip_ws() - if not self.skip_string('<'): + if not self.skip_string_and_ws('<'): return None + if self.skip_string('>'): + return ASTTemplateArgs([]) prevErrors = [] templateArgs = [] # type: List while 1: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 8fa5405bc..1229e550d 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -495,6 +495,8 @@ def test_templates(): check('class', "template A", {2:"I_iE1A"}) check('class', "template A", {2:"I_iE1A"}) + check('class', "template<> A>", {2:"IE1AIN2NS1BIEEE"}) + # from #2058 check('function', "template " From fd0a56bd37a2ca2cbc58053e9c5ea0f50b865d7d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 1 Oct 2017 00:55:04 +0900 Subject: [PATCH 0163/1814] Fix #4100: Remove debug print from autodoc extension --- CHANGES | 1 + sphinx/ext/autodoc.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 86baa9421..d972aa21e 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Bugs fixed ---------- * #4085: Failed PDF build from image in parsed-literal using ``:align:`` option +* #4100: Remove debug print from autodoc extension Testing -------- diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index bb5f78332..0f28ecb3f 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -971,7 +971,6 @@ class Documenter(object): # keep documented attributes keep = True isattr = True - print(membername, keep) elif want_all and membername.startswith('_'): # ignore members whose name starts with _ by default keep = self.options.private_members and \ From e2633a81a4896d478efdc1b083e05c09f4b3f5d4 Mon Sep 17 00:00:00 2001 From: Timotheus Kampik Date: Sun, 13 Aug 2017 17:01:16 +0200 Subject: [PATCH 0164/1814] #3987 remove alabaster-specific sidebars as default sphinx-quickstart settings --- sphinx/templates/quickstart/conf.py_t | 3 --- 1 file changed, 3 deletions(-) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 2821704f8..70683f8ee 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -114,11 +114,8 @@ html_static_path = ['{{ dot }}static'] # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ - 'about.html', - 'navigation.html', 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', - 'donate.html', ] } From 3ec2a649b40a678a41ed539a50389cfe560f03f2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 1 Oct 2017 22:04:38 +0900 Subject: [PATCH 0165/1814] Update CHANGES for PR #4002 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index d972aa21e..ada1a5190 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,7 @@ Bugs fixed * #4085: Failed PDF build from image in parsed-literal using ``:align:`` option * #4100: Remove debug print from autodoc extension +* #3987: Changing theme from alabaster causes HTML build to fail Testing -------- From b01de08e19c918fddd8645c431c071725a623042 Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Thu, 28 Sep 2017 21:48:22 +0300 Subject: [PATCH 0166/1814] C++: Do not assert False if type and declType mismatch Revert to 1.6.4 behavior where a warning was raised instead. --- sphinx/domains/cpp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index f8a77cee8..f55018b47 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4963,8 +4963,8 @@ class CPPDomain(Domain): if declTyp == 'templateParam': return True objtypes = self.objtypes_for_role(typ) - if objtypes and declTyp in objtypes: - return True + if objtypes: + return declTyp in objtypes print("Type is %s, declType is %s" % (typ, declTyp)) assert False if not checkType(): From d736efbdabfe1b76297357a75eafdf7267c6c58d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 13:33:40 +0100 Subject: [PATCH 0167/1814] Stop handling package issues from 'sphinx-build' There were a number of package error handlers run as part of the 'sphinx-build' command/executable: - Unsupported Python version (it should be 2.7 or 3.4+) - Missing packages (missing docutils, jinja2, and roman, which is part of docutils, packages) - Out-of-date packages (docutils) This code is mostly unchanged since Sphinx was first released. Python, and in particular Python's packaging options, have come a long way since then. Today, all of the above checks are provided by setuptools and the 'setup.py' script, meaning we should never actually get to the point of triggering any of these checks. This is further reinforced by the fact that none of the other executables carry out these checks: either this is a bug that no one has reported in ~8 years or, more likely, the checks are useless and we don't need them anywhere. In all, we can happily remove these checks, greatly simplify a piece of code that's otherwise rarely touched, and trust that setuptools is up to the job it's designed for. Signed-off-by: Stephen Finucane --- sphinx/__init__.py | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 69b379cd3..7a5684c85 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -74,42 +74,7 @@ def main(argv=sys.argv[1:]): def build_main(argv=sys.argv[1:]): # type: (List[str]) -> int """Sphinx build "main" command-line entry.""" - if (sys.version_info[:3] < (2, 7, 0) or - (3, 0, 0) <= sys.version_info[:3] < (3, 4, 0)): - sys.stderr.write('Error: Sphinx requires at least Python 2.7 or 3.4 to run.\n') - return 1 - try: - from sphinx import cmdline - except ImportError: - err = sys.exc_info()[1] - errstr = str(err) - if errstr.lower().startswith('no module named'): - whichmod = errstr[16:] - hint = '' - if whichmod.startswith('docutils'): - whichmod = 'Docutils library' - elif whichmod.startswith('jinja'): - whichmod = 'Jinja2 library' - elif whichmod == 'roman': - whichmod = 'roman module (which is distributed with Docutils)' - hint = ('This can happen if you upgraded docutils using\n' - 'easy_install without uninstalling the old version' - 'first.\n') - else: - whichmod += ' module' - sys.stderr.write('Error: The %s cannot be found. ' - 'Did you install Sphinx and its dependencies ' - 'correctly?\n' % whichmod) - if hint: - sys.stderr.write(hint) - return 1 - raise - - import sphinx.util.docutils - if sphinx.util.docutils.__version_info__ < (0, 10): - sys.stderr.write('Error: Sphinx requires at least Docutils 0.10 to ' - 'run.\n') - return 1 + from sphinx import cmdline return cmdline.main(argv) # type: ignore From 89f9c7cab74298a243ac409c26d25eb2b137bf03 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 21 Sep 2017 10:28:44 +0100 Subject: [PATCH 0168/1814] sphinx-build: Move code out of 'sphinx.__init__' We have multiple executables in tree and, while 'sphinx-build' is arguably the most important of these, there's no reason its importance should warrant inclusion at the package level. Create a new module, 'sphinx.cmd', and move the code from 'sphinx.__init__' into a 'build' submodule within. This name might be a bit disingenuous at present, given the availability of 'make-mode' here too, but that's an artifact of the current executable design and can be cleaned up later. To avoid breaking packages that are using this feature directly, aliases for the old 'main' method are included. This is based on what Django does [1] and, like Django, will allow us to safely remove the old modules in Sphinx 2.0. [1] https://github.com/django/django/blob/1.11/django/test/runner.py#L688-L695 Signed-off-by: Stephen Finucane --- setup.py | 2 +- sphinx/__init__.py | 41 +++++++++++++++-------------------------- sphinx/cmd/__init__.py | 10 ++++++++++ sphinx/cmd/build.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 sphinx/cmd/__init__.py create mode 100644 sphinx/cmd/build.py diff --git a/setup.py b/setup.py index 8a0ab0776..d55fa2a64 100644 --- a/setup.py +++ b/setup.py @@ -239,7 +239,7 @@ setup( include_package_data=True, entry_points={ 'console_scripts': [ - 'sphinx-build = sphinx:main', + 'sphinx-build = sphinx.cmd.build:main', 'sphinx-quickstart = sphinx.quickstart:main', 'sphinx-apidoc = sphinx.ext.apidoc:main', 'sphinx-autogen = sphinx.ext.autosummary.generate:main', diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 7a5684c85..9f0a295c6 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -15,15 +15,12 @@ from __future__ import absolute_import import os -import sys import warnings from os import path +from .cmd import build from .deprecation import RemovedInNextVersionWarning - -if False: - # For type annotation - from typing import List # NOQA +from .deprecation import RemovedInSphinx20Warning # by default, all DeprecationWarning under sphinx package will be emit. # Users can avoid this by using environment variable: PYTHONWARNINGS= @@ -63,27 +60,19 @@ if __version__.endswith('+'): pass -def main(argv=sys.argv[1:]): - # type: (List[str]) -> int - if sys.argv[1:2] == ['-M']: - return make_main(argv) - else: - return build_main(argv) - - -def build_main(argv=sys.argv[1:]): - # type: (List[str]) -> int - """Sphinx build "main" command-line entry.""" - from sphinx import cmdline - return cmdline.main(argv) # type: ignore - - -def make_main(argv=sys.argv[1:]): - # type: (List[str]) -> int - """Sphinx build "make mode" entry.""" - from sphinx import make_mode - return make_mode.run_make_mode(argv[1:]) # type: ignore +def main(*args, **kwargs): + warnings.warn( + '`sphinx.main()` has moved to `sphinx.cmd.build.main()`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) + build.main(*args, **kwargs) if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + warnings.warn( + '`sphinx` has moved to `sphinx.build`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) + build.main() diff --git a/sphinx/cmd/__init__.py b/sphinx/cmd/__init__.py new file mode 100644 index 000000000..9ffb9e612 --- /dev/null +++ b/sphinx/cmd/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" + sphinx.cmd + ~~~~~~~~~~ + + Modules for command line executables. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" diff --git a/sphinx/cmd/build.py b/sphinx/cmd/build.py new file mode 100644 index 000000000..6c9d6e3e9 --- /dev/null +++ b/sphinx/cmd/build.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" + sphinx.cmd.build + ~~~~~~~~~~~~~~~~ + + Build documentation from a provided source. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys + +if False: + # For type annotation + from typing import List # NOQA + + +def build_main(argv=sys.argv[1:]): + # type: (List[str]) -> int + """Sphinx build "main" command-line entry.""" + from sphinx import cmdline + return cmdline.main(argv) # type: ignore + + +def make_main(argv=sys.argv[1:]): + # type: (List[str]) -> int + """Sphinx build "make mode" entry.""" + from sphinx import make_mode + return make_mode.run_make_mode(argv[1:]) # type: ignore + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> int + if sys.argv[1:2] == ['-M']: + return make_main(argv) + else: + return build_main(argv) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) From 1f5ed022252066900c4ed982184e3d26885ca33d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 14:45:41 +0100 Subject: [PATCH 0169/1814] sphinx-quickstart: Move code to 'sphinx.cmd' We're going to move the executable's here (or at least those that part of the core library). The 'sphinx-build' executable was already moved, so lets do 'sphinx-quickstart' next. To avoid breaking packages that are using this feature directly, aliases for the old 'main' method are included. This is based on what Django does [1] and, like Django, will allow us to safely remove the old modules in Sphinx 2.0. [1] https://github.com/django/django/blob/1.11/django/test/runner.py#L688-L695 Signed-off-by: Stephen Finucane --- setup.py | 2 +- sphinx-quickstart.py | 2 +- sphinx/cmd/quickstart.py | 715 ++++++++++++++++++++++++++++++++++++++ sphinx/ext/apidoc.py | 4 +- sphinx/quickstart.py | 720 ++------------------------------------- tests/test_quickstart.py | 2 +- 6 files changed, 740 insertions(+), 705 deletions(-) create mode 100644 sphinx/cmd/quickstart.py diff --git a/setup.py b/setup.py index d55fa2a64..c8c300667 100644 --- a/setup.py +++ b/setup.py @@ -240,7 +240,7 @@ setup( entry_points={ 'console_scripts': [ 'sphinx-build = sphinx.cmd.build:main', - 'sphinx-quickstart = sphinx.quickstart:main', + 'sphinx-quickstart = sphinx.cmd.quickstart:main', 'sphinx-apidoc = sphinx.ext.apidoc:main', 'sphinx-autogen = sphinx.ext.autosummary.generate:main', ], diff --git a/sphinx-quickstart.py b/sphinx-quickstart.py index 7e17beb27..3caa6590f 100755 --- a/sphinx-quickstart.py +++ b/sphinx-quickstart.py @@ -11,5 +11,5 @@ import sys if __name__ == '__main__': - from sphinx.quickstart import main + from sphinx.cmd.quickstart import main sys.exit(main(sys.argv[1:])) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py new file mode 100644 index 000000000..cdd0295e4 --- /dev/null +++ b/sphinx/cmd/quickstart.py @@ -0,0 +1,715 @@ +# -*- coding: utf-8 -*- +""" + sphinx.cmd.quickstart + ~~~~~~~~~~~~~~~~~~~~~ + + Quickly setup documentation source to work with Sphinx. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from __future__ import print_function +from __future__ import absolute_import + +import re +import os +import sys +import optparse +import time +from os import path +from io import open + +# try to import readline, unix specific enhancement +try: + import readline + if readline.__doc__ and 'libedit' in readline.__doc__: + readline.parse_and_bind("bind ^I rl_complete") + else: + readline.parse_and_bind("tab: complete") +except ImportError: + pass + +from six import PY2, PY3, text_type, binary_type +from six.moves import input +from six.moves.urllib.parse import quote as urlquote +from docutils.utils import column_width + +from sphinx import __display_version__, package_dir +from sphinx.util.osutil import make_filename +from sphinx.util.console import ( # type: ignore + purple, bold, red, turquoise, nocolor, color_terminal +) +from sphinx.util.template import SphinxRenderer +from sphinx.util import texescape + +if False: + # For type annotation + from typing import Any, Callable, Dict, List, Pattern # NOQA + +TERM_ENCODING = getattr(sys.stdin, 'encoding', None) + +DEFAULT_VALUE = { + 'path': '.', + 'sep': False, + 'dot': '_', + 'language': None, + 'suffix': '.rst', + 'master': 'index', + 'epub': False, + 'ext_autodoc': False, + 'ext_doctest': False, + 'ext_todo': False, + 'makefile': True, + 'batchfile': True, +} + +EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage', + 'imgmath', 'mathjax', 'ifconfig', 'viewcode', 'githubpages') + +PROMPT_PREFIX = '> ' + + +def mkdir_p(dir): + # type: (unicode) -> None + if path.isdir(dir): + return + os.makedirs(dir) + + +# function to get input from terminal -- overridden by the test suite +def term_input(prompt): + # type: (unicode) -> unicode + print(prompt, end='') + return input('') + + +class ValidationError(Exception): + """Raised for validation errors.""" + + +def is_path(x): + # type: (unicode) -> unicode + x = path.expanduser(x) + if path.exists(x) and not path.isdir(x): + raise ValidationError("Please enter a valid path name.") + return x + + +def allow_empty(x): + # type: (unicode) -> unicode + return x + + +def nonempty(x): + # type: (unicode) -> unicode + if not x: + raise ValidationError("Please enter some text.") + return x + + +def choice(*l): + # type: (unicode) -> Callable[[unicode], unicode] + def val(x): + # type: (unicode) -> unicode + if x not in l: + raise ValidationError('Please enter one of %s.' % ', '.join(l)) + return x + return val + + +def boolean(x): + # type: (unicode) -> bool + if x.upper() not in ('Y', 'YES', 'N', 'NO'): + raise ValidationError("Please enter either 'y' or 'n'.") + return x.upper() in ('Y', 'YES') + + +def suffix(x): + # type: (unicode) -> unicode + if not (x[0:1] == '.' and len(x) > 1): + raise ValidationError("Please enter a file suffix, " + "e.g. '.rst' or '.txt'.") + return x + + +def ok(x): + # type: (unicode) -> unicode + return x + + +def term_decode(text): + # type: (unicode) -> unicode + if isinstance(text, text_type): + return text + + # for Python 2.x, try to get a Unicode string out of it + if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: + return text + + if TERM_ENCODING: + text = text.decode(TERM_ENCODING) + else: + print(turquoise('* Note: non-ASCII characters entered ' + 'and terminal encoding unknown -- assuming ' + 'UTF-8 or Latin-1.')) + try: + text = text.decode('utf-8') + except UnicodeDecodeError: + text = text.decode('latin1') + return text + + +def do_prompt(d, key, text, default=None, validator=nonempty): + # type: (Dict, unicode, unicode, unicode, Callable[[unicode], Any]) -> None + while True: + if default is not None: + prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode + else: + prompt = PROMPT_PREFIX + text + ': ' + if PY2: + # for Python 2.x, try to get a Unicode string out of it + if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \ + != prompt: + if TERM_ENCODING: + prompt = prompt.encode(TERM_ENCODING) + else: + print(turquoise('* Note: non-ASCII default value provided ' + 'and terminal encoding unknown -- assuming ' + 'UTF-8 or Latin-1.')) + try: + prompt = prompt.encode('utf-8') + except UnicodeEncodeError: + prompt = prompt.encode('latin1') + prompt = purple(prompt) + x = term_input(prompt).strip() + if default and not x: + x = default + x = term_decode(x) + try: + x = validator(x) + except ValidationError as err: + print(red('* ' + str(err))) + continue + break + d[key] = x + + +def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")): + # type: (unicode, Pattern) -> unicode + # remove Unicode literal prefixes + if PY3: + return rex.sub('\\1', source) + else: + return source + + +class QuickstartRenderer(SphinxRenderer): + def __init__(self, templatedir): + # type: (unicode) -> None + self.templatedir = templatedir or '' + super(QuickstartRenderer, self).__init__() + + def render(self, template_name, context): + # type: (unicode, Dict) -> unicode + user_template = path.join(self.templatedir, path.basename(template_name)) + if self.templatedir and path.exists(user_template): + return self.render_from_file(user_template, context) + else: + return super(QuickstartRenderer, self).render(template_name, context) + + +def ask_user(d): + # type: (Dict) -> None + """Ask the user for quickstart values missing from *d*. + + Values are: + + * path: root path + * sep: separate source and build dirs (bool) + * dot: replacement for dot in _templates etc. + * project: project name + * author: author names + * version: version of project + * release: release of project + * language: document language + * suffix: source file suffix + * master: master document name + * epub: use epub (bool) + * ext_*: extensions to use (bools) + * makefile: make Makefile + * batchfile: make command file + """ + + print(bold('Welcome to the Sphinx %s quickstart utility.') % __display_version__) + print(''' +Please enter values for the following settings (just press Enter to +accept a default value, if one is given in brackets).''') + + if 'path' in d: + print(bold(''' +Selected root path: %s''' % d['path'])) + else: + print(''' +Enter the root path for documentation.''') + do_prompt(d, 'path', 'Root path for the documentation', '.', is_path) + + while path.isfile(path.join(d['path'], 'conf.py')) or \ + path.isfile(path.join(d['path'], 'source', 'conf.py')): + print() + print(bold('Error: an existing conf.py has been found in the ' + 'selected root path.')) + print('sphinx-quickstart will not overwrite existing Sphinx projects.') + print() + do_prompt(d, 'path', 'Please enter a new root path (or just Enter ' + 'to exit)', '', is_path) + if not d['path']: + sys.exit(1) + + if 'sep' not in d: + print(''' +You have two options for placing the build directory for Sphinx output. +Either, you use a directory "_build" within the root path, or you separate +"source" and "build" directories within the root path.''') + do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n', + boolean) + + if 'dot' not in d: + print(''' +Inside the root directory, two more directories will be created; "_templates" +for custom HTML templates and "_static" for custom stylesheets and other static +files. You can enter another prefix (such as ".") to replace the underscore.''') + do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok) + + if 'project' not in d: + print(''' +The project name will occur in several places in the built documentation.''') + do_prompt(d, 'project', 'Project name') + if 'author' not in d: + do_prompt(d, 'author', 'Author name(s)') + + if 'version' not in d: + print(''' +Sphinx has the notion of a "version" and a "release" for the +software. Each version can have multiple releases. For example, for +Python the version is something like 2.5 or 3.0, while the release is +something like 2.5.1 or 3.0a1. If you don't need this dual structure, +just set both to the same value.''') + do_prompt(d, 'version', 'Project version', '', allow_empty) + if 'release' not in d: + do_prompt(d, 'release', 'Project release', d['version'], allow_empty) + + if 'language' not in d: + print(''' +If the documents are to be written in a language other than English, +you can select a language here by its language code. Sphinx will then +translate text that it generates into that language. + +For a list of supported codes, see +http://sphinx-doc.org/config.html#confval-language.''') + do_prompt(d, 'language', 'Project language', 'en') + if d['language'] == 'en': + d['language'] = None + + if 'suffix' not in d: + print(''' +The file name suffix for source files. Commonly, this is either ".txt" +or ".rst". Only files with this suffix are considered documents.''') + do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix) + + if 'master' not in d: + print(''' +One document is special in that it is considered the top node of the +"contents tree", that is, it is the root of the hierarchical structure +of the documents. Normally, this is "index", but if your "index" +document is a custom template, you can also set this to another filename.''') + do_prompt(d, 'master', 'Name of your master document (without suffix)', + 'index') + + while path.isfile(path.join(d['path'], d['master'] + d['suffix'])) or \ + path.isfile(path.join(d['path'], 'source', d['master'] + d['suffix'])): + print() + print(bold('Error: the master file %s has already been found in the ' + 'selected root path.' % (d['master'] + d['suffix']))) + print('sphinx-quickstart will not overwrite the existing file.') + print() + do_prompt(d, 'master', 'Please enter a new file name, or rename the ' + 'existing file and press Enter', d['master']) + + if 'epub' not in d: + print(''' +Sphinx can also add configuration for epub output:''') + do_prompt(d, 'epub', 'Do you want to use the epub builder (y/n)', + 'n', boolean) + + if 'ext_autodoc' not in d: + print(''' +Please indicate if you want to use one of the following Sphinx extensions:''') + do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings ' + 'from modules (y/n)', 'n', boolean) + if 'ext_doctest' not in d: + do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets ' + 'in doctest blocks (y/n)', 'n', boolean) + if 'ext_intersphinx' not in d: + do_prompt(d, 'ext_intersphinx', 'intersphinx: link between Sphinx ' + 'documentation of different projects (y/n)', 'n', boolean) + if 'ext_todo' not in d: + do_prompt(d, 'ext_todo', 'todo: write "todo" entries ' + 'that can be shown or hidden on build (y/n)', 'n', boolean) + if 'ext_coverage' not in d: + do_prompt(d, 'ext_coverage', 'coverage: checks for documentation ' + 'coverage (y/n)', 'n', boolean) + if 'ext_imgmath' not in d: + do_prompt(d, 'ext_imgmath', 'imgmath: include math, rendered ' + 'as PNG or SVG images (y/n)', 'n', boolean) + if 'ext_mathjax' not in d: + do_prompt(d, 'ext_mathjax', 'mathjax: include math, rendered in the ' + 'browser by MathJax (y/n)', 'n', boolean) + if d['ext_imgmath'] and d['ext_mathjax']: + print('''Note: imgmath and mathjax cannot be enabled at the same time. +imgmath has been deselected.''') + d['ext_imgmath'] = False + if 'ext_ifconfig' not in d: + do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of ' + 'content based on config values (y/n)', 'n', boolean) + if 'ext_viewcode' not in d: + do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source ' + 'code of documented Python objects (y/n)', 'n', boolean) + if 'ext_githubpages' not in d: + do_prompt(d, 'ext_githubpages', 'githubpages: create .nojekyll file ' + 'to publish the document on GitHub pages (y/n)', 'n', boolean) + + if 'no_makefile' in d: + d['makefile'] = False + elif 'makefile' not in d: + print(''' +A Makefile and a Windows command file can be generated for you so that you +only have to run e.g. `make html' instead of invoking sphinx-build +directly.''') + do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean) + if 'no_batchfile' in d: + d['batchfile'] = False + elif 'batchfile' not in d: + do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)', + 'y', boolean) + print() + + +def generate(d, overwrite=True, silent=False, templatedir=None): + # type: (Dict, bool, bool, unicode) -> None + """Generate project based on values in *d*.""" + template = QuickstartRenderer(templatedir=templatedir) + + texescape.init() + indent = ' ' * 4 + + if 'mastertoctree' not in d: + d['mastertoctree'] = '' + if 'mastertocmaxdepth' not in d: + d['mastertocmaxdepth'] = 2 + + d['PY3'] = PY3 + d['project_fn'] = make_filename(d['project']) + d['project_url'] = urlquote(d['project'].encode('idna')) + d['project_manpage'] = d['project_fn'].lower() + d['now'] = time.asctime() + d['project_underline'] = column_width(d['project']) * '=' + d.setdefault('extensions', []) + for name in EXTENSIONS: + if d.get('ext_' + name): + d['extensions'].append('sphinx.ext.' + name) + d['extensions'] = (',\n' + indent).join(repr(name) for name in d['extensions']) + d['copyright'] = time.strftime('%Y') + ', ' + d['author'] + d['author_texescaped'] = text_type(d['author']).\ + translate(texescape.tex_escape_map) + d['project_doc'] = d['project'] + ' Documentation' + d['project_doc_texescaped'] = text_type(d['project'] + ' Documentation').\ + translate(texescape.tex_escape_map) + + # escape backslashes and single quotes in strings that are put into + # a Python string literal + for key in ('project', 'project_doc', 'project_doc_texescaped', + 'author', 'author_texescaped', 'copyright', + 'version', 'release', 'master'): + d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'") + + if not path.isdir(d['path']): + mkdir_p(d['path']) + + srcdir = d['sep'] and path.join(d['path'], 'source') or d['path'] + + mkdir_p(srcdir) + if d['sep']: + builddir = path.join(d['path'], 'build') + d['exclude_patterns'] = '' + else: + builddir = path.join(srcdir, d['dot'] + 'build') + exclude_patterns = map(repr, [ + d['dot'] + 'build', + 'Thumbs.db', '.DS_Store', + ]) + d['exclude_patterns'] = ', '.join(exclude_patterns) + mkdir_p(builddir) + mkdir_p(path.join(srcdir, d['dot'] + 'templates')) + mkdir_p(path.join(srcdir, d['dot'] + 'static')) + + def write_file(fpath, content, newline=None): + # type: (unicode, unicode, unicode) -> None + if overwrite or not path.isfile(fpath): + print('Creating file %s.' % fpath) + with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: + f.write(content) + else: + print('File %s already exists, skipping.' % fpath) + + conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None + if not conf_path or not path.isfile(conf_path): + conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t') + with open(conf_path) as f: + conf_text = convert_python_source(f.read()) + + write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d)) + + masterfile = path.join(srcdir, d['master'] + d['suffix']) + write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) + + if d.get('make_mode') is True: + makefile_template = 'quickstart/Makefile.new_t' + batchfile_template = 'quickstart/make.bat.new_t' + else: + makefile_template = 'quickstart/Makefile_t' + batchfile_template = 'quickstart/make.bat_t' + + if d['makefile'] is True: + d['rsrcdir'] = d['sep'] and 'source' or '.' + d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' + # use binary mode, to avoid writing \r\n on Windows + write_file(path.join(d['path'], 'Makefile'), + template.render(makefile_template, d), u'\n') + + if d['batchfile'] is True: + d['rsrcdir'] = d['sep'] and 'source' or '.' + d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' + write_file(path.join(d['path'], 'make.bat'), + template.render(batchfile_template, d), u'\r\n') + + if silent: + return + print() + print(bold('Finished: An initial directory structure has been created.')) + print(''' +You should now populate your master file %s and create other documentation +source files. ''' % masterfile + ((d['makefile'] or d['batchfile']) and '''\ +Use the Makefile to build the docs, like so: + make builder +''' or '''\ +Use the sphinx-build command to build the docs, like so: + sphinx-build -b builder %s %s +''' % (srcdir, builddir)) + '''\ +where "builder" is one of the supported builders, e.g. html, latex or linkcheck. +''') + + +def usage(argv, msg=None): + # type: (List[unicode], unicode) -> None + if msg: + print(msg, file=sys.stderr) + print(file=sys.stderr) + + +USAGE = """\ +Sphinx v%s +Usage: %%prog [options] [projectdir] +""" % __display_version__ + +EPILOG = """\ +For more information, visit . +""" + + +def valid_dir(d): + # type: (Dict) -> bool + dir = d['path'] + if not path.exists(dir): + return True + if not path.isdir(dir): + return False + + if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): + return False + + if d['sep']: + dir = os.path.join('source', dir) + if not path.exists(dir): + return True + if not path.isdir(dir): + return False + + reserved_names = [ + 'conf.py', + d['dot'] + 'static', + d['dot'] + 'templates', + d['master'] + d['suffix'], + ] + if set(reserved_names) & set(os.listdir(dir)): + return False + + return True + + +class MyFormatter(optparse.IndentedHelpFormatter): + def format_usage(self, usage): # type: ignore + # type: (str) -> str + return usage + + def format_help(self, formatter): + result = [] + if self.description: + result.append(self.format_description(formatter)) + if self.option_list: + result.append(self.format_option_help(formatter)) + return "\n".join(result) + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> int + if not color_terminal(): + nocolor() + + parser = optparse.OptionParser(USAGE, epilog=EPILOG, + version='Sphinx v%s' % __display_version__, + formatter=MyFormatter()) + parser.add_option('-q', '--quiet', action='store_true', dest='quiet', + default=False, + help='quiet mode') + + group = parser.add_option_group('Structure options') + group.add_option('--sep', action='store_true', dest='sep', + help='if specified, separate source and build dirs') + group.add_option('--dot', metavar='DOT', dest='dot', + help='replacement for dot in _templates etc.') + + group = parser.add_option_group('Project basic options') + group.add_option('-p', '--project', metavar='PROJECT', dest='project', + help='project name') + group.add_option('-a', '--author', metavar='AUTHOR', dest='author', + help='author names') + group.add_option('-v', metavar='VERSION', dest='version', + help='version of project') + group.add_option('-r', '--release', metavar='RELEASE', dest='release', + help='release of project') + group.add_option('-l', '--language', metavar='LANGUAGE', dest='language', + help='document language') + group.add_option('--suffix', metavar='SUFFIX', dest='suffix', + help='source file suffix') + group.add_option('--master', metavar='MASTER', dest='master', + help='master document name') + group.add_option('--epub', action='store_true', dest='epub', + default=False, + help='use epub') + + group = parser.add_option_group('Extension options') + for ext in EXTENSIONS: + group.add_option('--ext-' + ext, action='store_true', + dest='ext_' + ext, default=False, + help='enable %s extension' % ext) + group.add_option('--extensions', metavar='EXTENSIONS', dest='extensions', + action='append', help='enable extensions') + + group = parser.add_option_group('Makefile and Batchfile creation') + group.add_option('--makefile', action='store_true', dest='makefile', + default=False, + help='create makefile') + group.add_option('--no-makefile', action='store_true', dest='no_makefile', + default=False, + help='not create makefile') + group.add_option('--batchfile', action='store_true', dest='batchfile', + default=False, + help='create batchfile') + group.add_option('--no-batchfile', action='store_true', dest='no_batchfile', + default=False, + help='not create batchfile') + group.add_option('-M', '--no-use-make-mode', action='store_false', dest='make_mode', + help='not use make-mode for Makefile/make.bat') + group.add_option('-m', '--use-make-mode', action='store_true', dest='make_mode', + default=True, + help='use make-mode for Makefile/make.bat') + + group = parser.add_option_group('Project templating') + group.add_option('-t', '--templatedir', metavar='TEMPLATEDIR', dest='templatedir', + help='template directory for template files') + group.add_option('-d', metavar='NAME=VALUE', action='append', dest='variables', + help='define a template variable') + + # parse options + try: + opts, args = parser.parse_args(argv) + except SystemExit as err: + return err.code + + if len(args) > 0: + opts.ensure_value('path', args[0]) + + d = vars(opts) + # delete None or False value + d = dict((k, v) for k, v in d.items() if not (v is None or v is False)) + + try: + if 'quiet' in d: + if not set(['project', 'author']).issubset(d): + print('''"quiet" is specified, but any of "project" or \ +"author" is not specified.''') + return 1 + + if set(['quiet', 'project', 'author']).issubset(d): + # quiet mode with all required params satisfied, use default + d.setdefault('version', '') + d.setdefault('release', d['version']) + d2 = DEFAULT_VALUE.copy() + d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS)) + d2.update(d) + d = d2 + if 'no_makefile' in d: + d['makefile'] = False + if 'no_batchfile' in d: + d['batchfile'] = False + + if not valid_dir(d): + print() + print(bold('Error: specified path is not a directory, or sphinx' + ' files already exist.')) + print('sphinx-quickstart only generate into a empty directory.' + ' Please specify a new root path.') + return 1 + else: + ask_user(d) + except (KeyboardInterrupt, EOFError): + print() + print('[Interrupted.]') + return 130 # 128 + SIGINT + + # decode values in d if value is a Python string literal + for key, value in d.items(): + if isinstance(value, binary_type): + d[key] = term_decode(value) + + # parse extensions list + d.setdefault('extensions', []) + for ext in d['extensions'][:]: + if ',' in ext: + d['extensions'].remove(ext) + for modname in ext.split(','): + d['extensions'].append(modname) + + for variable in d.get('variables', []): + try: + name, value = variable.split('=') + d[name] = value + except ValueError: + print('Invalid template variable: %s' % variable) + + generate(d, templatedir=opts.templatedir) + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 9061d801e..4a5c56850 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -25,7 +25,7 @@ from six import binary_type from fnmatch import fnmatch from sphinx import __display_version__ -from sphinx.quickstart import EXTENSIONS +from sphinx.cmd.quickstart import EXTENSIONS from sphinx.util import rst from sphinx.util.osutil import FileAvoidWrite, walk @@ -384,7 +384,7 @@ Note: By default this script will not overwrite already created files.""") excludes = normalize_excludes(rootpath, excludes) modules = recurse_tree(rootpath, excludes, opts) if opts.full: - from sphinx import quickstart as qs + from sphinx.cmd import quickstart as qs modules.sort() prev_module = '' # type: unicode text = '' diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 04e83d7a2..75c244c8e 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -3,713 +3,33 @@ sphinx.quickstart ~~~~~~~~~~~~~~~~~ - Quickly setup documentation source to work with Sphinx. + This file has moved to :py:mod:`sphinx.cmd.quickstart`. :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from __future__ import print_function -from __future__ import absolute_import -import re -import os -import sys -import optparse -import time -from os import path -from io import open +import warnings -# try to import readline, unix specific enhancement -try: - import readline - if readline.__doc__ and 'libedit' in readline.__doc__: - readline.parse_and_bind("bind ^I rl_complete") - else: - readline.parse_and_bind("tab: complete") -except ImportError: - pass +from sphinx.deprecation import RemovedInSphinx20Warning +from sphinx.cmd.quickstart import main as _main -from six import PY2, PY3, text_type, binary_type -from six.moves import input -from six.moves.urllib.parse import quote as urlquote -from docutils.utils import column_width -from sphinx import __display_version__, package_dir -from sphinx.util.osutil import make_filename -from sphinx.util.console import ( # type: ignore - purple, bold, red, turquoise, nocolor, color_terminal -) -from sphinx.util.template import SphinxRenderer -from sphinx.util import texescape +def main(*args, **kwargs): + warnings.warn( + '`sphinx.quickstart.main()` has moved to `sphinx.cmd.quickstart.' + 'main()`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) + _main(*args, **kwargs) -if False: - # For type annotation - from typing import Any, Callable, Dict, List, Pattern # NOQA -TERM_ENCODING = getattr(sys.stdin, 'encoding', None) - -DEFAULT_VALUE = { - 'path': '.', - 'sep': False, - 'dot': '_', - 'language': None, - 'suffix': '.rst', - 'master': 'index', - 'epub': False, - 'ext_autodoc': False, - 'ext_doctest': False, - 'ext_todo': False, - 'makefile': True, - 'batchfile': True, -} - -EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage', - 'imgmath', 'mathjax', 'ifconfig', 'viewcode', 'githubpages') - -PROMPT_PREFIX = '> ' - - -def mkdir_p(dir): - # type: (unicode) -> None - if path.isdir(dir): - return - os.makedirs(dir) - - -# function to get input from terminal -- overridden by the test suite -def term_input(prompt): - # type: (unicode) -> unicode - print(prompt, end='') - return input('') - - -class ValidationError(Exception): - """Raised for validation errors.""" - - -def is_path(x): - # type: (unicode) -> unicode - x = path.expanduser(x) - if path.exists(x) and not path.isdir(x): - raise ValidationError("Please enter a valid path name.") - return x - - -def allow_empty(x): - # type: (unicode) -> unicode - return x - - -def nonempty(x): - # type: (unicode) -> unicode - if not x: - raise ValidationError("Please enter some text.") - return x - - -def choice(*l): - # type: (unicode) -> Callable[[unicode], unicode] - def val(x): - # type: (unicode) -> unicode - if x not in l: - raise ValidationError('Please enter one of %s.' % ', '.join(l)) - return x - return val - - -def boolean(x): - # type: (unicode) -> bool - if x.upper() not in ('Y', 'YES', 'N', 'NO'): - raise ValidationError("Please enter either 'y' or 'n'.") - return x.upper() in ('Y', 'YES') - - -def suffix(x): - # type: (unicode) -> unicode - if not (x[0:1] == '.' and len(x) > 1): - raise ValidationError("Please enter a file suffix, " - "e.g. '.rst' or '.txt'.") - return x - - -def ok(x): - # type: (unicode) -> unicode - return x - - -def term_decode(text): - # type: (unicode) -> unicode - if isinstance(text, text_type): - return text - - # for Python 2.x, try to get a Unicode string out of it - if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: - return text - - if TERM_ENCODING: - text = text.decode(TERM_ENCODING) - else: - print(turquoise('* Note: non-ASCII characters entered ' - 'and terminal encoding unknown -- assuming ' - 'UTF-8 or Latin-1.')) - try: - text = text.decode('utf-8') - except UnicodeDecodeError: - text = text.decode('latin1') - return text - - -def do_prompt(d, key, text, default=None, validator=nonempty): - # type: (Dict, unicode, unicode, unicode, Callable[[unicode], Any]) -> None - while True: - if default is not None: - prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode - else: - prompt = PROMPT_PREFIX + text + ': ' - if PY2: - # for Python 2.x, try to get a Unicode string out of it - if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \ - != prompt: - if TERM_ENCODING: - prompt = prompt.encode(TERM_ENCODING) - else: - print(turquoise('* Note: non-ASCII default value provided ' - 'and terminal encoding unknown -- assuming ' - 'UTF-8 or Latin-1.')) - try: - prompt = prompt.encode('utf-8') - except UnicodeEncodeError: - prompt = prompt.encode('latin1') - prompt = purple(prompt) - x = term_input(prompt).strip() - if default and not x: - x = default - x = term_decode(x) - try: - x = validator(x) - except ValidationError as err: - print(red('* ' + str(err))) - continue - break - d[key] = x - - -def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")): - # type: (unicode, Pattern) -> unicode - # remove Unicode literal prefixes - if PY3: - return rex.sub('\\1', source) - else: - return source - - -class QuickstartRenderer(SphinxRenderer): - def __init__(self, templatedir): - # type: (unicode) -> None - self.templatedir = templatedir or '' - super(QuickstartRenderer, self).__init__() - - def render(self, template_name, context): - # type: (unicode, Dict) -> unicode - user_template = path.join(self.templatedir, path.basename(template_name)) - if self.templatedir and path.exists(user_template): - return self.render_from_file(user_template, context) - else: - return super(QuickstartRenderer, self).render(template_name, context) - - -def ask_user(d): - # type: (Dict) -> None - """Ask the user for quickstart values missing from *d*. - - Values are: - - * path: root path - * sep: separate source and build dirs (bool) - * dot: replacement for dot in _templates etc. - * project: project name - * author: author names - * version: version of project - * release: release of project - * language: document language - * suffix: source file suffix - * master: master document name - * epub: use epub (bool) - * ext_*: extensions to use (bools) - * makefile: make Makefile - * batchfile: make command file - """ - - print(bold('Welcome to the Sphinx %s quickstart utility.') % __display_version__) - print(''' -Please enter values for the following settings (just press Enter to -accept a default value, if one is given in brackets).''') - - if 'path' in d: - print(bold(''' -Selected root path: %s''' % d['path'])) - else: - print(''' -Enter the root path for documentation.''') - do_prompt(d, 'path', 'Root path for the documentation', '.', is_path) - - while path.isfile(path.join(d['path'], 'conf.py')) or \ - path.isfile(path.join(d['path'], 'source', 'conf.py')): - print() - print(bold('Error: an existing conf.py has been found in the ' - 'selected root path.')) - print('sphinx-quickstart will not overwrite existing Sphinx projects.') - print() - do_prompt(d, 'path', 'Please enter a new root path (or just Enter ' - 'to exit)', '', is_path) - if not d['path']: - sys.exit(1) - - if 'sep' not in d: - print(''' -You have two options for placing the build directory for Sphinx output. -Either, you use a directory "_build" within the root path, or you separate -"source" and "build" directories within the root path.''') - do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n', - boolean) - - if 'dot' not in d: - print(''' -Inside the root directory, two more directories will be created; "_templates" -for custom HTML templates and "_static" for custom stylesheets and other static -files. You can enter another prefix (such as ".") to replace the underscore.''') - do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok) - - if 'project' not in d: - print(''' -The project name will occur in several places in the built documentation.''') - do_prompt(d, 'project', 'Project name') - if 'author' not in d: - do_prompt(d, 'author', 'Author name(s)') - - if 'version' not in d: - print(''' -Sphinx has the notion of a "version" and a "release" for the -software. Each version can have multiple releases. For example, for -Python the version is something like 2.5 or 3.0, while the release is -something like 2.5.1 or 3.0a1. If you don't need this dual structure, -just set both to the same value.''') - do_prompt(d, 'version', 'Project version', '', allow_empty) - if 'release' not in d: - do_prompt(d, 'release', 'Project release', d['version'], allow_empty) - - if 'language' not in d: - print(''' -If the documents are to be written in a language other than English, -you can select a language here by its language code. Sphinx will then -translate text that it generates into that language. - -For a list of supported codes, see -http://sphinx-doc.org/config.html#confval-language.''') - do_prompt(d, 'language', 'Project language', 'en') - if d['language'] == 'en': - d['language'] = None - - if 'suffix' not in d: - print(''' -The file name suffix for source files. Commonly, this is either ".txt" -or ".rst". Only files with this suffix are considered documents.''') - do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix) - - if 'master' not in d: - print(''' -One document is special in that it is considered the top node of the -"contents tree", that is, it is the root of the hierarchical structure -of the documents. Normally, this is "index", but if your "index" -document is a custom template, you can also set this to another filename.''') - do_prompt(d, 'master', 'Name of your master document (without suffix)', - 'index') - - while path.isfile(path.join(d['path'], d['master'] + d['suffix'])) or \ - path.isfile(path.join(d['path'], 'source', d['master'] + d['suffix'])): - print() - print(bold('Error: the master file %s has already been found in the ' - 'selected root path.' % (d['master'] + d['suffix']))) - print('sphinx-quickstart will not overwrite the existing file.') - print() - do_prompt(d, 'master', 'Please enter a new file name, or rename the ' - 'existing file and press Enter', d['master']) - - if 'epub' not in d: - print(''' -Sphinx can also add configuration for epub output:''') - do_prompt(d, 'epub', 'Do you want to use the epub builder (y/n)', - 'n', boolean) - - if 'ext_autodoc' not in d: - print(''' -Please indicate if you want to use one of the following Sphinx extensions:''') - do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings ' - 'from modules (y/n)', 'n', boolean) - if 'ext_doctest' not in d: - do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets ' - 'in doctest blocks (y/n)', 'n', boolean) - if 'ext_intersphinx' not in d: - do_prompt(d, 'ext_intersphinx', 'intersphinx: link between Sphinx ' - 'documentation of different projects (y/n)', 'n', boolean) - if 'ext_todo' not in d: - do_prompt(d, 'ext_todo', 'todo: write "todo" entries ' - 'that can be shown or hidden on build (y/n)', 'n', boolean) - if 'ext_coverage' not in d: - do_prompt(d, 'ext_coverage', 'coverage: checks for documentation ' - 'coverage (y/n)', 'n', boolean) - if 'ext_imgmath' not in d: - do_prompt(d, 'ext_imgmath', 'imgmath: include math, rendered ' - 'as PNG or SVG images (y/n)', 'n', boolean) - if 'ext_mathjax' not in d: - do_prompt(d, 'ext_mathjax', 'mathjax: include math, rendered in the ' - 'browser by MathJax (y/n)', 'n', boolean) - if d['ext_imgmath'] and d['ext_mathjax']: - print('''Note: imgmath and mathjax cannot be enabled at the same time. -imgmath has been deselected.''') - d['ext_imgmath'] = False - if 'ext_ifconfig' not in d: - do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of ' - 'content based on config values (y/n)', 'n', boolean) - if 'ext_viewcode' not in d: - do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source ' - 'code of documented Python objects (y/n)', 'n', boolean) - if 'ext_githubpages' not in d: - do_prompt(d, 'ext_githubpages', 'githubpages: create .nojekyll file ' - 'to publish the document on GitHub pages (y/n)', 'n', boolean) - - if 'no_makefile' in d: - d['makefile'] = False - elif 'makefile' not in d: - print(''' -A Makefile and a Windows command file can be generated for you so that you -only have to run e.g. `make html' instead of invoking sphinx-build -directly.''') - do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean) - if 'no_batchfile' in d: - d['batchfile'] = False - elif 'batchfile' not in d: - do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)', - 'y', boolean) - print() - - -def generate(d, overwrite=True, silent=False, templatedir=None): - # type: (Dict, bool, bool, unicode) -> None - """Generate project based on values in *d*.""" - template = QuickstartRenderer(templatedir=templatedir) - - texescape.init() - indent = ' ' * 4 - - if 'mastertoctree' not in d: - d['mastertoctree'] = '' - if 'mastertocmaxdepth' not in d: - d['mastertocmaxdepth'] = 2 - - d['PY3'] = PY3 - d['project_fn'] = make_filename(d['project']) - d['project_url'] = urlquote(d['project'].encode('idna')) - d['project_manpage'] = d['project_fn'].lower() - d['now'] = time.asctime() - d['project_underline'] = column_width(d['project']) * '=' - d.setdefault('extensions', []) - for name in EXTENSIONS: - if d.get('ext_' + name): - d['extensions'].append('sphinx.ext.' + name) - d['extensions'] = (',\n' + indent).join(repr(name) for name in d['extensions']) - d['copyright'] = time.strftime('%Y') + ', ' + d['author'] - d['author_texescaped'] = text_type(d['author']).\ - translate(texescape.tex_escape_map) - d['project_doc'] = d['project'] + ' Documentation' - d['project_doc_texescaped'] = text_type(d['project'] + ' Documentation').\ - translate(texescape.tex_escape_map) - - # escape backslashes and single quotes in strings that are put into - # a Python string literal - for key in ('project', 'project_doc', 'project_doc_texescaped', - 'author', 'author_texescaped', 'copyright', - 'version', 'release', 'master'): - d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'") - - if not path.isdir(d['path']): - mkdir_p(d['path']) - - srcdir = d['sep'] and path.join(d['path'], 'source') or d['path'] - - mkdir_p(srcdir) - if d['sep']: - builddir = path.join(d['path'], 'build') - d['exclude_patterns'] = '' - else: - builddir = path.join(srcdir, d['dot'] + 'build') - exclude_patterns = map(repr, [ - d['dot'] + 'build', - 'Thumbs.db', '.DS_Store', - ]) - d['exclude_patterns'] = ', '.join(exclude_patterns) - mkdir_p(builddir) - mkdir_p(path.join(srcdir, d['dot'] + 'templates')) - mkdir_p(path.join(srcdir, d['dot'] + 'static')) - - def write_file(fpath, content, newline=None): - # type: (unicode, unicode, unicode) -> None - if overwrite or not path.isfile(fpath): - print('Creating file %s.' % fpath) - with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: - f.write(content) - else: - print('File %s already exists, skipping.' % fpath) - - conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None - if not conf_path or not path.isfile(conf_path): - conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t') - with open(conf_path) as f: - conf_text = convert_python_source(f.read()) - - write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d)) - - masterfile = path.join(srcdir, d['master'] + d['suffix']) - write_file(masterfile, template.render('quickstart/master_doc.rst_t', d)) - - if d.get('make_mode') is True: - makefile_template = 'quickstart/Makefile.new_t' - batchfile_template = 'quickstart/make.bat.new_t' - else: - makefile_template = 'quickstart/Makefile_t' - batchfile_template = 'quickstart/make.bat_t' - - if d['makefile'] is True: - d['rsrcdir'] = d['sep'] and 'source' or '.' - d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' - # use binary mode, to avoid writing \r\n on Windows - write_file(path.join(d['path'], 'Makefile'), - template.render(makefile_template, d), u'\n') - - if d['batchfile'] is True: - d['rsrcdir'] = d['sep'] and 'source' or '.' - d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' - write_file(path.join(d['path'], 'make.bat'), - template.render(batchfile_template, d), u'\r\n') - - if silent: - return - print() - print(bold('Finished: An initial directory structure has been created.')) - print(''' -You should now populate your master file %s and create other documentation -source files. ''' % masterfile + ((d['makefile'] or d['batchfile']) and '''\ -Use the Makefile to build the docs, like so: - make builder -''' or '''\ -Use the sphinx-build command to build the docs, like so: - sphinx-build -b builder %s %s -''' % (srcdir, builddir)) + '''\ -where "builder" is one of the supported builders, e.g. html, latex or linkcheck. -''') - - -def usage(argv, msg=None): - # type: (List[unicode], unicode) -> None - if msg: - print(msg, file=sys.stderr) - print(file=sys.stderr) - - -USAGE = """\ -Sphinx v%s -Usage: %%prog [options] [projectdir] -""" % __display_version__ - -EPILOG = """\ -For more information, visit . -""" - - -def valid_dir(d): - # type: (Dict) -> bool - dir = d['path'] - if not path.exists(dir): - return True - if not path.isdir(dir): - return False - - if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): - return False - - if d['sep']: - dir = os.path.join('source', dir) - if not path.exists(dir): - return True - if not path.isdir(dir): - return False - - reserved_names = [ - 'conf.py', - d['dot'] + 'static', - d['dot'] + 'templates', - d['master'] + d['suffix'], - ] - if set(reserved_names) & set(os.listdir(dir)): - return False - - return True - - -class MyFormatter(optparse.IndentedHelpFormatter): - def format_usage(self, usage): # type: ignore - # type: (str) -> str - return usage - - def format_help(self, formatter): - result = [] - if self.description: - result.append(self.format_description(formatter)) - if self.option_list: - result.append(self.format_option_help(formatter)) - return "\n".join(result) - - -def main(argv=sys.argv[1:]): - # type: (List[str]) -> int - if not color_terminal(): - nocolor() - - parser = optparse.OptionParser(USAGE, epilog=EPILOG, - version='Sphinx v%s' % __display_version__, - formatter=MyFormatter()) - parser.add_option('-q', '--quiet', action='store_true', dest='quiet', - default=False, - help='quiet mode') - - group = parser.add_option_group('Structure options') - group.add_option('--sep', action='store_true', dest='sep', - help='if specified, separate source and build dirs') - group.add_option('--dot', metavar='DOT', dest='dot', - help='replacement for dot in _templates etc.') - - group = parser.add_option_group('Project basic options') - group.add_option('-p', '--project', metavar='PROJECT', dest='project', - help='project name') - group.add_option('-a', '--author', metavar='AUTHOR', dest='author', - help='author names') - group.add_option('-v', metavar='VERSION', dest='version', - help='version of project') - group.add_option('-r', '--release', metavar='RELEASE', dest='release', - help='release of project') - group.add_option('-l', '--language', metavar='LANGUAGE', dest='language', - help='document language') - group.add_option('--suffix', metavar='SUFFIX', dest='suffix', - help='source file suffix') - group.add_option('--master', metavar='MASTER', dest='master', - help='master document name') - group.add_option('--epub', action='store_true', dest='epub', - default=False, - help='use epub') - - group = parser.add_option_group('Extension options') - for ext in EXTENSIONS: - group.add_option('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, - help='enable %s extension' % ext) - group.add_option('--extensions', metavar='EXTENSIONS', dest='extensions', - action='append', help='enable extensions') - - group = parser.add_option_group('Makefile and Batchfile creation') - group.add_option('--makefile', action='store_true', dest='makefile', - default=False, - help='create makefile') - group.add_option('--no-makefile', action='store_true', dest='no_makefile', - default=False, - help='not create makefile') - group.add_option('--batchfile', action='store_true', dest='batchfile', - default=False, - help='create batchfile') - group.add_option('--no-batchfile', action='store_true', dest='no_batchfile', - default=False, - help='not create batchfile') - group.add_option('-M', '--no-use-make-mode', action='store_false', dest='make_mode', - help='not use make-mode for Makefile/make.bat') - group.add_option('-m', '--use-make-mode', action='store_true', dest='make_mode', - default=True, - help='use make-mode for Makefile/make.bat') - - group = parser.add_option_group('Project templating') - group.add_option('-t', '--templatedir', metavar='TEMPLATEDIR', dest='templatedir', - help='template directory for template files') - group.add_option('-d', metavar='NAME=VALUE', action='append', dest='variables', - help='define a template variable') - - # parse options - try: - opts, args = parser.parse_args(argv) - except SystemExit as err: - return err.code - - if len(args) > 0: - opts.ensure_value('path', args[0]) - - d = vars(opts) - # delete None or False value - d = dict((k, v) for k, v in d.items() if not (v is None or v is False)) - - try: - if 'quiet' in d: - if not set(['project', 'author']).issubset(d): - print('''"quiet" is specified, but any of "project" or \ -"author" is not specified.''') - return 1 - - if set(['quiet', 'project', 'author']).issubset(d): - # quiet mode with all required params satisfied, use default - d.setdefault('version', '') - d.setdefault('release', d['version']) - d2 = DEFAULT_VALUE.copy() - d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS)) - d2.update(d) - d = d2 - if 'no_makefile' in d: - d['makefile'] = False - if 'no_batchfile' in d: - d['batchfile'] = False - - if not valid_dir(d): - print() - print(bold('Error: specified path is not a directory, or sphinx' - ' files already exist.')) - print('sphinx-quickstart only generate into a empty directory.' - ' Please specify a new root path.') - return 1 - else: - ask_user(d) - except (KeyboardInterrupt, EOFError): - print() - print('[Interrupted.]') - return 130 # 128 + SIGINT - - # decode values in d if value is a Python string literal - for key, value in d.items(): - if isinstance(value, binary_type): - d[key] = term_decode(value) - - # parse extensions list - d.setdefault('extensions', []) - for ext in d['extensions'][:]: - if ',' in ext: - d['extensions'].remove(ext) - for modname in ext.split(','): - d['extensions'].append(modname) - - for variable in d.get('variables', []): - try: - name, value = variable.split('=') - d[name] = value - except ValueError: - print('Invalid template variable: %s' % variable) - - generate(d, templatedir=opts.templatedir) - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) +# So program can be started with "python -m sphinx.quickstart ..." +if __name__ == "__main__": + warnings.warn( + '`sphinx.quickstart` has moved to `sphinx.cmd.quickstart`.', + RemovedInSphinx20Warning, + stacklevel=2, + ) + main() diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 21f836f44..46ed3a0c1 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -17,7 +17,7 @@ from six.moves import input import pytest from sphinx import application -from sphinx import quickstart as qs +from sphinx.cmd import quickstart as qs from sphinx.util.console import nocolor, coloron from sphinx.util.pycompat import execfile_ From 21ec11e1a7f0e397bc9561f5afe0fc1537637e4d Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Mon, 2 Oct 2017 17:26:21 +0200 Subject: [PATCH 0170/1814] Document qthelp configuration --- doc/config.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/config.rst b/doc/config.rst index 3751139cf..01aea96dd 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -2062,6 +2062,29 @@ These options influence Texinfo output. .. versionadded:: 1.1 +.. _qthelp-options: + +Options for QtHelp output +-------------------------- + +These options influence QtHelp output. + +.. confval:: qthelp_basename + + The basename for the qthelp file. It defaults to the :confval:`project` name. + +.. confval:: qthelp_theme + + The HTML theme for the qthelp output. + This defaults to ``'nonav'``. + +.. confval:: qthelp_theme_options + + A dictionary of options that influence the look and feel of the selected + theme. These are theme-specific. For the options understood by the builtin + themes, see :ref:`this section `. + + Options for the linkcheck builder --------------------------------- From 6d610980583f26247504058790c00be93ca901f3 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 3 Oct 2017 14:35:10 +0200 Subject: [PATCH 0171/1814] C++, add test case for sphinx-doc/sphinx#4096 --- CHANGES | 1 + tests/roots/test-domain-cpp/roles2.rst | 5 +++++ tests/test_domain_cpp.py | 7 +++++++ 3 files changed, 13 insertions(+) create mode 100644 tests/roots/test-domain-cpp/roles2.rst diff --git a/CHANGES b/CHANGES index ada1a5190..293e90604 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,7 @@ Bugs fixed * #4085: Failed PDF build from image in parsed-literal using ``:align:`` option * #4100: Remove debug print from autodoc extension * #3987: Changing theme from alabaster causes HTML build to fail +* #4096: C++, don't crash when using the wrong role type. Thanks to mitya57. Testing -------- diff --git a/tests/roots/test-domain-cpp/roles2.rst b/tests/roots/test-domain-cpp/roles2.rst new file mode 100644 index 000000000..644b827ca --- /dev/null +++ b/tests/roots/test-domain-cpp/roles2.rst @@ -0,0 +1,5 @@ +Check that we don't crash just because we misuse a role. + +.. cpp:class:: A + +:cpp:func:`A` diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 08ca6f962..2932f356f 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -508,6 +508,13 @@ def test_attributes(): # raise DefinitionError("") +@pytest.mark.sphinx(testroot='domain-cpp') +def test_build_domain_cpp_misuse_of_roles(app, status, warning): + app.builder.build_all() + + # TODO: properly check for the warnings we expect + + @pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'add_function_parentheses': True}) def test_build_domain_cpp_with_add_function_parentheses_is_True(app, status, warning): app.builder.build_all() From 9da3bf93ff58e6f9fe4ab503f6e849c45fc05f9f Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Tue, 3 Oct 2017 18:42:06 +0700 Subject: [PATCH 0172/1814] Make searchtools.js compatible with pre-Sphinx1.5 templates There are still plenty of projects which use custom templates where DOCUMENTATION_OPTIONS does not define SOURCELINK_SUFFIX. Currently search does not work in these projects. Make suffix fall back to .txt since that is the default value of configuration option. --- sphinx/themes/basic/static/searchtools.js_t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sphinx/themes/basic/static/searchtools.js_t b/sphinx/themes/basic/static/searchtools.js_t index 149d1624d..306fdf55f 100644 --- a/sphinx/themes/basic/static/searchtools.js_t +++ b/sphinx/themes/basic/static/searchtools.js_t @@ -269,6 +269,9 @@ var Search = { }); } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX; + if (suffix === undefined) { + suffix = '.txt'; + } $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix), dataType: "text", complete: function(jqxhr, textstatus) { From 4dc46350a70605684d25e9b97465d3357ae5d241 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 4 Oct 2017 01:51:37 +0900 Subject: [PATCH 0173/1814] Update CHANGES for PR #4107 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 293e90604..5c984819c 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,8 @@ Deprecated Features added -------------- +* #4107: Make searchtools.js compatible with pre-Sphinx1.5 templates + Bugs fixed ---------- From 50640b700b4cbc9b141a72765378d9a1e416bd22 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 5 Oct 2017 00:00:48 +0900 Subject: [PATCH 0174/1814] Fix #4070, #4111: crashes when the warning message contains format strings (again) --- CHANGES | 1 + sphinx/util/logging.py | 10 +++++++--- tests/test_util_logging.py | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 5c984819c..d90b29cb7 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ Bugs fixed * #4100: Remove debug print from autodoc extension * #3987: Changing theme from alabaster causes HTML build to fail * #4096: C++, don't crash when using the wrong role type. Thanks to mitya57. +* #4070, #4111: crashes when the warning message contains format strings (again) Testing -------- diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 2cdac6c40..7fb5c5894 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -356,11 +356,15 @@ class WarningIsErrorFilter(logging.Filter): return True elif self.app.warningiserror: location = getattr(record, 'location', '') - message = record.msg.replace('%', '%%') + try: + message = record.msg % record.args + except TypeError: + message = record.msg # use record.msg itself + if location: - raise SphinxWarning(location + ":" + message % record.args) + raise SphinxWarning(location + ":" + message) else: - raise SphinxWarning(message % record.args) + raise SphinxWarning(message) else: return True diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py index 717aa6cd4..7ae086872 100644 --- a/tests/test_util_logging.py +++ b/tests/test_util_logging.py @@ -165,7 +165,11 @@ def test_warningiserror(app, status, warning): # if True, warning raises SphinxWarning exception app.warningiserror = True with pytest.raises(SphinxWarning): - logger.warning('message') + logger.warning('message: %s', 'arg') + + # message contains format string (refs: #4070) + with pytest.raises(SphinxWarning): + logger.warning('%s') def test_warning_location(app, status, warning): From ee52c7cd4f5e0a300c8fdd897c9529f5c633c7ed Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 3 Oct 2017 20:59:44 -0400 Subject: [PATCH 0175/1814] Don't override the smart_quotes setting if it was already set This is needed to fix: https://github.com/sphinx-contrib/spelling/issues/1 --- sphinx/environment/__init__.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 126a962a3..f522bd576 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -676,19 +676,20 @@ class BuildEnvironment(object): language = self.config.language or 'en' self.settings['language_code'] = language - self.settings['smart_quotes'] = True - if self.config.html_use_smartypants is not None: - warnings.warn("html_use_smartypants option is deprecated. Smart " - "quotes are on by default; if you want to disable " - "or customize them, use the smart_quotes option in " - "docutils.conf.", - RemovedInSphinx17Warning) - self.settings['smart_quotes'] = self.config.html_use_smartypants - for tag in normalize_language_tag(language): - if tag in smartchars.quotes: - break - else: - self.settings['smart_quotes'] = False + if 'smart_quotes' not in self.settings: + self.settings['smart_quotes'] = True + if self.config.html_use_smartypants is not None: + warnings.warn("html_use_smartypants option is deprecated. Smart " + "quotes are on by default; if you want to disable " + "or customize them, use the smart_quotes option in " + "docutils.conf.", + RemovedInSphinx17Warning) + self.settings['smart_quotes'] = self.config.html_use_smartypants + for tag in normalize_language_tag(language): + if tag in smartchars.quotes: + break + else: + self.settings['smart_quotes'] = False docutilsconf = path.join(self.srcdir, 'docutils.conf') # read docutils.conf from source dir, not from current dir From a7bc29f1bd31b5a3b2aefdc580d91a18851e268a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 5 Oct 2017 00:47:34 +0900 Subject: [PATCH 0176/1814] Update CHANGES for PR #4112 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index d90b29cb7..96e8c4764 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,7 @@ Features added -------------- * #4107: Make searchtools.js compatible with pre-Sphinx1.5 templates +* #4112: Don't override the smart_quotes setting if it was already set Bugs fixed ---------- From c5dec1b6a97c627602df62e22cd134bad7db363e Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 5 Oct 2017 09:16:05 +0100 Subject: [PATCH 0177/1814] tox: Add pylint target to tox This isn't enabled by default because it throws so many damn errors. Perhaps we should simply remove this? Signed-off-by: Stephen Finucane --- tox.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tox.ini b/tox.ini index b7d4feb98..04c23580d 100644 --- a/tox.ini +++ b/tox.ini @@ -46,6 +46,13 @@ deps= deps=flake8 commands=flake8 +[testenv:pylint] +deps= + pylint + {[testenv]deps} +commands= + pylint --rcfile utils/pylintrc sphinx + [testenv:py27] deps= {[testenv]deps} From 6d6d3a40f1ccfc666a85de96936e78615ce3704c Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 2 Oct 2017 20:22:35 +0100 Subject: [PATCH 0178/1814] tox: Always run coverage There is value in examining coverage for something like Sphinx. Start doing this by default, in anticipation of increasing coverage over time. Signed-off-by: Stephen Finucane --- .gitignore | 1 + tox.ini | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c49070f13..f1dc3167c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ TAGS .tags .tox .venv +.coverage .DS_Store sphinx/pycode/Grammar*pickle distribute-* diff --git a/tox.ini b/tox.ini index 04c23580d..411c85ba3 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ passenv = https_proxy http_proxy no_proxy deps= six pytest + pytest-cov html5lib mock enum34 @@ -14,7 +15,7 @@ setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild PYTHONDONTWRITEBYTECODE = true commands= - {envpython} -Wall tests/run.py --ignore tests/py35 {posargs} + {envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html [testenv:pypy] @@ -63,7 +64,7 @@ deps= typed_ast {[testenv]deps} commands= - {envpython} -Wall tests/run.py {posargs} + {envpython} -Wall tests/run.py --cov=sphinx {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html [testenv:mypy] From 017f124be5f357fcda7ec254b63c6559a8259956 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 2 Oct 2017 19:23:59 +0100 Subject: [PATCH 0179/1814] mypy: Move configuration to 'setup.cfg' Less top-level files = winning [1]. [1] https://mypy.readthedocs.io/en/stable/config_file.html Signed-off-by: Stephen Finucane --- mypy.ini | 7 ------- setup.cfg | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index ec12ea587..000000000 --- a/mypy.ini +++ /dev/null @@ -1,7 +0,0 @@ -[mypy] -python_version = 2.7 -ignore_missing_imports = True -follow_imports = skip -incremental = True -check_untyped_defs = True -warn_unused_ignores = True diff --git a/setup.cfg b/setup.cfg index 90c531bf6..be10f3e15 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,5 +28,13 @@ max-line-length = 95 ignore = E116,E241,E251 exclude = .git,.tox,.venv,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py +[mypy] +python_version = 2.7 +ignore_missing_imports = True +follow_imports = skip +incremental = True +check_untyped_defs = True +warn_unused_ignores = True + [build_sphinx] warning-is-error = 1 From 9d114577dc0a611ccdf8ef872b126294ea5d3b43 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 15:15:53 +0100 Subject: [PATCH 0180/1814] Fix typo in doc It's 'py:mod', not 'py:module'. I don't know why this wasn't caught by Sphinx itself. Signed-off-by: Stephen Finucane --- doc/man/sphinx-autogen.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/sphinx-autogen.rst b/doc/man/sphinx-autogen.rst index dcab68d76..49a8220d0 100644 --- a/doc/man/sphinx-autogen.rst +++ b/doc/man/sphinx-autogen.rst @@ -15,7 +15,7 @@ that, using the :rst:dir:`autodoc` extension, document items included in *sourcefile* is the path to one or more reStructuredText documents containing :rst:dir:`autosummary` entries with the ``:toctree::`` option set. *sourcefile* -can be an :py:module:`fnmatch`-style pattern. +can be an :py:mod:`fnmatch`-style pattern. Options ------- From 71a5ec18bebb8dbcc888a2bcf0069a94486cbdd1 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 5 Oct 2017 09:57:58 +0100 Subject: [PATCH 0181/1814] tox: Always show 25 slowest tests pytest supports this natively [1] and this is what is currently used by Travis. There's value in seeing similar data locally. [1] https://docs.pytest.org/en/latest/usage.html#profiling-test-execution-duration Signed-off-by: Stephen Finucane --- tox.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 411c85ba3..e53175df0 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,8 @@ setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild PYTHONDONTWRITEBYTECODE = true commands= - {envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx {posargs} + {envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx \ + --durations 25 {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html [testenv:pypy] @@ -64,7 +65,7 @@ deps= typed_ast {[testenv]deps} commands= - {envpython} -Wall tests/run.py --cov=sphinx {posargs} + {envpython} -Wall tests/run.py --cov=sphinx --durations 25 {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html [testenv:mypy] From 40c8f661ef0c6680e3f3aed321ebded56a3207b6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 10:04:08 +0100 Subject: [PATCH 0182/1814] tox: Ensure 'mypy' targets runs with Python 3.x Turns out this requires Python 3.2 at a minimum. Who knew? We don't support Python 3.1 so simply fix to 'python3'. Signed-off-by: Stephen Finucane --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index e53175df0..5a108a700 100644 --- a/tox.ini +++ b/tox.ini @@ -69,6 +69,7 @@ commands= sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html [testenv:mypy] +basepython=python3 deps= mypy commands= From e023c296e87772ebff1b36ad3ca49b4283c4a8e9 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 10:25:10 +0100 Subject: [PATCH 0183/1814] tox: Pass posargs to docs This allows us to do something like the following: tox -e docs -- -b man Signed-off-by: Stephen Finucane --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5a108a700..d5f401a7a 100644 --- a/tox.ini +++ b/tox.ini @@ -77,4 +77,4 @@ commands= [testenv:docs] commands= - python setup.py build_sphinx + python setup.py build_sphinx {posargs} From 6086d7b608a365dc3ccfcb37d8bac7f02de338fe Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 10:36:07 +0100 Subject: [PATCH 0184/1814] tox: Don't bother setting 'PYTHONDONTWRITEBYTECODE' As I've previously discovered [1], this doesn't actually do anything in modern tox. Simply remove it. [1] https://review.openstack.org/#/c/369986/ Signed-off-by: Stephen Finucane --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index d5f401a7a..519020f98 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,6 @@ deps= typing setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild - PYTHONDONTWRITEBYTECODE = true commands= {envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx \ --durations 25 {posargs} From 36912a581525bdf6931019990b9fe73c70839d88 Mon Sep 17 00:00:00 2001 From: Yoshiki Shibukawa Date: Tue, 3 Oct 2017 23:47:00 +0900 Subject: [PATCH 0185/1814] fix: #4108 - Search word highlight breaks SVG --- CHANGES | 1 + sphinx/themes/basic/static/basic.css_t | 6 ++- sphinx/themes/basic/static/doctools.js_t | 52 +++++++++++++++++------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index d90b29cb7..0d5eecd2d 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugs fixed * #3987: Changing theme from alabaster causes HTML build to fail * #4096: C++, don't crash when using the wrong role type. Thanks to mitya57. * #4070, #4111: crashes when the warning message contains format strings (again) +* #4108: Search word highlighting breaks SVG images Testing -------- diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 1cbc649f9..d16c760cb 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -445,10 +445,14 @@ dd { margin-left: 30px; } -dt:target, .highlighted { +dt:target, span.highlighted { background-color: #fbe54e; } +rect.highlighted { + fill: #fbe54e; +} + dl.glossary dt { font-weight: bold; font-size: 1.1em; diff --git a/sphinx/themes/basic/static/doctools.js_t b/sphinx/themes/basic/static/doctools.js_t index 41830e44f..9ceecef79 100644 --- a/sphinx/themes/basic/static/doctools.js_t +++ b/sphinx/themes/basic/static/doctools.js_t @@ -45,7 +45,7 @@ jQuery.urlencode = encodeURIComponent; * it will always return arrays of strings for the value parts. */ jQuery.getQueryParameters = function(s) { - if (typeof s == 'undefined') + if (typeof s === 'undefined') s = document.location.search; var parts = s.substr(s.indexOf('?') + 1).split('&'); var result = {}; @@ -66,29 +66,53 @@ jQuery.getQueryParameters = function(s) { * span elements with the given class name. */ jQuery.fn.highlightText = function(text, className) { - function highlight(node) { - if (node.nodeType == 3) { + function highlight(node, addItems) { + if (node.nodeType === 3) { var val = node.nodeValue; var pos = val.toLowerCase().indexOf(text); if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { - var span = document.createElement("span"); - span.className = className; + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } span.appendChild(document.createTextNode(val.substr(pos, text.length))); node.parentNode.insertBefore(span, node.parentNode.insertBefore( document.createTextNode(val.substr(pos + text.length)), node.nextSibling)); node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } } } else if (!jQuery(node).is("button, select, textarea")) { jQuery.each(node.childNodes, function() { - highlight(this); + highlight(this, addItems); }); } } - return this.each(function() { - highlight(this); + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; }; /* @@ -133,21 +157,21 @@ var Documentation = { * i18n support */ TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, LOCALE : 'unknown', // gettext and ngettext don't access this so that the functions // can safely bound to a different name (_ = Documentation.gettext) gettext : function(string) { var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated == 'undefined') + if (typeof translated === 'undefined') return string; - return (typeof translated == 'string') ? translated : translated[0]; + return (typeof translated === 'string') ? translated : translated[0]; }, ngettext : function(singular, plural, n) { var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated == 'undefined') + if (typeof translated === 'undefined') return (n == 1) ? singular : plural; return translated[Documentation.PLURALEXPR(n)]; }, @@ -218,7 +242,7 @@ var Documentation = { var src = $(this).attr('src'); var idnum = $(this).attr('id').substr(7); $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) == 'minus.png') + if (src.substr(-9) === 'minus.png') $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); else $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); @@ -250,7 +274,7 @@ var Documentation = { var path = document.location.pathname; var parts = path.split(/\//); $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this == '..') + if (this === '..') parts.pop(); }); var url = parts.join('/'); From 8f1905c4aef0e30595145e70676afc0a23f7b4ff Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 10:53:06 +0100 Subject: [PATCH 0186/1814] mypy: Make output a little friendlier Two default-disabled options are enabled: - show_column_numbers - Shows context notes before errors - show_error_context - Shows column numbers in error messages This should make the output of mypy a little easier to parse. Signed-off-by: Stephen Finucane --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index be10f3e15..517e00702 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,8 @@ exclude = .git,.tox,.venv,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*, [mypy] python_version = 2.7 +show_column_numbers = True +show_error_context = True ignore_missing_imports = True follow_imports = skip incremental = True From b90e58809fdb59d28ddded19d165fe38d57d5427 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 16:31:32 +0100 Subject: [PATCH 0187/1814] utils: Remove the 'reindent' tool Nobody seems to be using this, probably because of the 'flake8' target, and it hasn't been touched, some Python/flake8 updates aside in years. Just remove it. The Make target is not removed to both give us time to warn users that the target is gone and, more importantly, to prevent merge conflicts with other patches being submitted at the same time. Signed-off-by: Stephen Finucane --- Makefile | 2 +- utils/reindent.py | 320 ---------------------------------------------- 2 files changed, 1 insertion(+), 321 deletions(-) delete mode 100755 utils/reindent.py diff --git a/Makefile b/Makefile index a20df8f39..879b10e7b 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ pylint: @pylint --rcfile utils/pylintrc sphinx reindent: - @$(PYTHON) utils/reindent.py -r -n . + @echo "This target no longer does anything and will be removed imminently" test: @cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST) diff --git a/utils/reindent.py b/utils/reindent.py deleted file mode 100755 index b79657636..000000000 --- a/utils/reindent.py +++ /dev/null @@ -1,320 +0,0 @@ -#! /usr/bin/env python - -# Released to the public domain, by Tim Peters, 03 October 2000. - -"""reindent [-d][-r][-v] [ path ... ] - --d (--dryrun) Dry run. Analyze, but don't make any changes to, files. --r (--recurse) Recurse. Search for all .py files in subdirectories too. --n (--nobackup) No backup. Does not make a ".bak" file before reindenting. --v (--verbose) Verbose. Print informative msgs; else no output. --h (--help) Help. Print this usage information and exit. - -Change Python (.py) files to use 4-space indents and no hard tab characters. -Also trim excess spaces and tabs from ends of lines, and remove empty lines -at the end of files. Also ensure the last line ends with a newline. - -If no paths are given on the command line, reindent operates as a filter, -reading a single source file from standard input and writing the transformed -source to standard output. In this case, the -d, -r and -v flags are -ignored. - -You can pass one or more file and/or directory paths. When a directory -path, all .py files within the directory will be examined, and, if the -r -option is given, likewise recursively for subdirectories. - -If output is not to standard output, reindent overwrites files in place, -renaming the originals with a .bak extension. If it finds nothing to -change, the file is left alone. If reindent does change a file, the changed -file is a fixed-point for future runs (i.e., running reindent on the -resulting .py file won't change it again). - -The hard part of reindenting is figuring out what to do with comment -lines. So long as the input files get a clean bill of health from -tabnanny.py, reindent should do a good job. - -The backup file is a copy of the one that is being reindented. The ".bak" -file is generated with shutil.copy(), but some corner cases regarding -user/group and permissions could leave the backup file more readable that -you'd prefer. You can always use the --nobackup option to prevent this. -""" -from __future__ import print_function - -import os -import sys -import shutil -import tokenize -from six.ranges import range - -__version__ = "1" - -if sys.version_info >= (3, 0): - def tokens(readline, tokeneater): - for token in tokenize.tokenize(readline): - yield tokeneater(*token) -else: - tokens = tokenize.tokenize - -verbose = 0 -recurse = 0 -dryrun = 0 -makebackup = True - - -def usage(msg=None): - if msg is not None: - print(msg, file=sys.stderr) - print(__doc__, file=sys.stderr) - - -def errprint(*args): - sep = "" - for arg in args: - sys.stderr.write(sep + str(arg)) - sep = " " - sys.stderr.write("\n") - - -def main(): - import getopt - global verbose, recurse, dryrun, makebackup - try: - opts, args = getopt.getopt(sys.argv[1:], "drnvh", - ["dryrun", "recurse", "nobackup", "verbose", "help"]) - except getopt.error as msg: - usage(msg) - return - for o, a in opts: - if o in ('-d', '--dryrun'): - dryrun += 1 - elif o in ('-r', '--recurse'): - recurse += 1 - elif o in ('-n', '--nobackup'): - makebackup = False - elif o in ('-v', '--verbose'): - verbose += 1 - elif o in ('-h', '--help'): - usage() - return - if not args: - r = Reindenter(sys.stdin) - r.run() - r.write(sys.stdout) - return - for arg in args: - check(arg) - - -def check(file): - if os.path.isdir(file) and not os.path.islink(file): - if verbose: - print("listing directory", file) - names = os.listdir(file) - for name in names: - fullname = os.path.join(file, name) - if ((recurse and os.path.isdir(fullname) and - not os.path.islink(fullname) and - not os.path.split(fullname)[1].startswith(".")) or - name.lower().endswith(".py")): - check(fullname) - return - - if verbose: - print("checking", file, "...", end=' ') - try: - f = open(file) - except IOError as msg: - errprint("%s: I/O Error: %s" % (file, str(msg))) - return - - with f: - r = Reindenter(f) - if r.run(): - if verbose: - print("changed.") - if dryrun: - print("But this is a dry run, so leaving it alone.") - if not dryrun: - bak = file + ".bak" - if makebackup: - shutil.copyfile(file, bak) - if verbose: - print("backed up", file, "to", bak) - with open(file, "w") as f: - r.write(f) - if verbose: - print("wrote new", file) - return True - else: - if verbose: - print("unchanged.") - return False - - -def _rstrip(line, JUNK='\n \t'): - """Return line stripped of trailing spaces, tabs, newlines. - - Note that line.rstrip() instead also strips sundry control characters, - but at least one known Emacs user expects to keep junk like that, not - mentioning Barry by name or anything . - """ - - i = len(line) - while i > 0 and line[i - 1] in JUNK: - i -= 1 - return line[:i] - - -class Reindenter: - def __init__(self, f): - self.find_stmt = 1 # next token begins a fresh stmt? - self.level = 0 # current indent level - - # Raw file lines. - self.raw = f.readlines() - - # File lines, rstripped & tab-expanded. Dummy at start is so - # that we can use tokenize's 1-based line numbering easily. - # Note that a line is all-blank iff it's "\n". - self.lines = [_rstrip(line).expandtabs() + "\n" - for line in self.raw] - self.lines.insert(0, None) - self.index = 1 # index into self.lines of next line - - # List of (lineno, indentlevel) pairs, one for each stmt and - # comment line. indentlevel is -1 for comment lines, as a - # signal that tokenize doesn't know what to do about them; - # indeed, they're our headache! - self.stats = [] - - def run(self): - tokens(self.getline, self.tokeneater) - # Remove trailing empty lines. - lines = self.lines - while lines and lines[-1] == "\n": - lines.pop() - # Sentinel. - stats = self.stats - stats.append((len(lines), 0)) - # Map count of leading spaces to # we want. - have2want = {} - # Program after transformation. - after = self.after = [] - # Copy over initial empty lines -- there's nothing to do until - # we see a line with *something* on it. - i = stats[0][0] - after.extend(lines[1:i]) - for i in range(len(stats) - 1): - thisstmt, thislevel = stats[i] - nextstmt = stats[i + 1][0] - have = getlspace(lines[thisstmt]) - want = thislevel * 4 - if want < 0: - # A comment line. - if have: - # An indented comment line. If we saw the same - # indentation before, reuse what it most recently - # mapped to. - want = have2want.get(have, -1) - if want < 0: - # Then it probably belongs to the next real stmt. - for j in range(i + 1, len(stats) - 1): - jline, jlevel = stats[j] - if jlevel >= 0: - if have == getlspace(lines[jline]): - want = jlevel * 4 - break - if want < 0: # Maybe it's a hanging - # comment like this one, - # in which case we should shift it like its base - # line got shifted. - for j in range(i - 1, -1, -1): - jline, jlevel = stats[j] - if jlevel >= 0: - want = (have + getlspace(after[jline - 1]) - - getlspace(lines[jline])) - break - if want < 0: - # Still no luck -- leave it alone. - want = have - else: - want = 0 - assert want >= 0 - have2want[have] = want - diff = want - have - if diff == 0 or have == 0: - after.extend(lines[thisstmt:nextstmt]) - else: - for line in lines[thisstmt:nextstmt]: - if diff > 0: - if line == "\n": - after.append(line) - else: - after.append(" " * diff + line) - else: - remove = min(getlspace(line), -diff) - after.append(line[remove:]) - return self.raw != self.after - - def write(self, f): - f.writelines(self.after) - - # Line-getter for tokenize. - def getline(self): - if self.index >= len(self.lines): - line = "" - else: - line = self.lines[self.index] - self.index += 1 - return line - - # Line-eater for tokenize. - def tokeneater(self, type, token, position, end, line, - INDENT=tokenize.INDENT, - DEDENT=tokenize.DEDENT, - NEWLINE=tokenize.NEWLINE, - COMMENT=tokenize.COMMENT, - NL=tokenize.NL): - - if type == NEWLINE: - # A program statement, or ENDMARKER, will eventually follow, - # after some (possibly empty) run of tokens of the form - # (NL | COMMENT)* (INDENT | DEDENT+)? - self.find_stmt = 1 - - elif type == INDENT: - self.find_stmt = 1 - self.level += 1 - - elif type == DEDENT: - self.find_stmt = 1 - self.level -= 1 - - elif type == COMMENT: - if self.find_stmt: - self.stats.append((position[0], -1)) - # but we're still looking for a new stmt, so leave - # find_stmt alone - - elif type == NL: - pass - - elif self.find_stmt: - # This is the first "real token" following a NEWLINE, so it - # must be the first token of the next program statement, or an - # ENDMARKER. - self.find_stmt = 0 - if line: # not endmarker - self.stats.append((position[0], self.level)) - - -# Count number of leading blanks. -def getlspace(line): - i, n = 0, len(line) - while i < n and line[i] == " ": - i += 1 - return i - - -if __name__ == '__main__': - main() From 64b4d7c686e58dfc369a89285718ac988698f34b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 2 Oct 2017 19:24:13 +0100 Subject: [PATCH 0188/1814] utils: Use better variable names in check_fileheader We're going to be doing some surgery on this function, so first clean it up before we do anything else. Signed-off-by: Stephen Finucane --- utils/check_sources.py | 47 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/utils/check_sources.py b/utils/check_sources.py index 59b380e45..2e8105487 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -98,47 +98,46 @@ def check_style(fn, lines): @checker('.py', only_pkg=True) def check_fileheader(fn, lines): # line number correction - c = 1 + offset = 1 if lines[0:1] == ['#!/usr/bin/env python\n']: lines = lines[1:] - c = 2 + offset = 2 llist = [] - docopen = False - for lno, l in enumerate(lines): - llist.append(l) + doc_open = False + for lno, line in enumerate(lines): + llist.append(line) if lno == 0: - if l != '# -*- coding: utf-8 -*-\n': + if line != '# -*- coding: utf-8 -*-\n': yield 1, "missing coding declaration" elif lno == 1: - if l != '"""\n' and l != 'r"""\n': + if line != '"""\n' and line != 'r"""\n': yield 2, 'missing docstring begin (""")' else: - docopen = True - elif docopen: - if l == '"""\n': + doc_open = True + elif doc_open: + if line == '"""\n': # end of docstring if lno <= 4: - yield lno + c, "missing module name in docstring" + yield lno + offset, "missing module name in docstring" break - if l != '\n' and l[:4] != ' ' and docopen: - yield lno + c, "missing correct docstring indentation" + if line != '\n' and line[:4] != ' ' and doc_open: + yield lno + offset, "missing correct docstring indentation" if lno == 2: # if not in package, don't check the module name - modname = fn[:-3].replace('/', '.').replace('.__init__', '') - while modname: - if l.lower()[4:-1] == modname: + mod_name = fn[:-3].replace('/', '.').replace('.__init__', '') + while mod_name: + if line.lower()[4:-1] == mod_name: break - modname = '.'.join(modname.split('.')[1:]) + mod_name = '.'.join(mod_name.split('.')[1:]) else: yield 3, "wrong module name in docstring heading" - modnamelen = len(l.strip()) + mod_name_len = len(line.strip()) elif lno == 3: - if l.strip() != modnamelen * '~': + if line.strip() != mod_name_len * '~': yield 4, "wrong module name underline, should be ~~~...~" - else: yield 0, "missing end and/or start of docstring..." @@ -147,11 +146,11 @@ def check_fileheader(fn, lines): if not license or not license_re.match(license[0]): yield 0, "no correct license info" - ci = -3 - copyright = llist[ci:ci + 1] + offset = -3 + copyright = llist[offset:offset + 1] while copyright and copyright_2_re.match(copyright[0]): - ci -= 1 - copyright = llist[ci:ci + 1] + offset -= 1 + copyright = llist[offset:offset + 1] if not copyright or not copyright_re.match(copyright[0]): yield 0, "no correct copyright info" From f5c0d646589ba0da03c4afc1487b0d28751fe774 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 21:57:23 +0100 Subject: [PATCH 0189/1814] utils: Move "header check" to a flake8 plugin If we want to check style, we run 'tox -e flake8': it shouldn't be necessary to run some obscure 'make' command too. Make this possible by moving the sole useful test from the target of this make command to a flake8 plugin. This includes a fix for a header that was previously excluded from checks, but is now included. Signed-off-by: Stephen Finucane --- setup.cfg | 2 +- setup.py | 7 +++ utils/__init__.py | 0 utils/check_sources.py | 67 ------------------------- utils/checks.py | 111 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 68 deletions(-) create mode 100644 utils/__init__.py create mode 100644 utils/checks.py diff --git a/setup.cfg b/setup.cfg index 517e00702..48045a292 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,7 +26,7 @@ universal = 1 [flake8] max-line-length = 95 ignore = E116,E241,E251 -exclude = .git,.tox,.venv,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py +exclude = .git,.tox,.venv,tests/*,build/*,doc/_build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py [mypy] python_version = 2.7 diff --git a/setup.py b/setup.py index c8c300667..af21f3938 100644 --- a/setup.py +++ b/setup.py @@ -247,6 +247,13 @@ setup( 'distutils.commands': [ 'build_sphinx = sphinx.setup_command:BuildDoc', ], + # consider moving this to 'flake8:local-plugins' once flake8 3.5.0 is + # in the wild: + # http://flake8.pycqa.org/en/latest/user/configuration.html\ + # #using-local-plugins + 'flake8.extension': [ + 'X101 = utils.checks:sphinx_has_header', + ], }, install_requires=requires, extras_require=extras_require, diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/utils/check_sources.py b/utils/check_sources.py index 2e8105487..ace691449 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -37,13 +37,6 @@ def checker(*suffixes, **kwds): coding_re = re.compile(br'coding[:=]\s*([-\w.]+)') uni_coding_re = re.compile(r'^#.*coding[:=]\s*([-\w.]+).*') -name_mail_re = r'[\w ]+(<.*?>)?' -copyright_re = re.compile(r'^ :copyright: Copyright 200\d(-20\d\d)? ' - r'by %s(, %s)*[,.]$' % - (name_mail_re, name_mail_re)) -license_re = re.compile(r" :license: (.*?).\n") -copyright_2_re = re.compile(r'^ %s(, %s)*[,.]$' % - (name_mail_re, name_mail_re)) not_ix_re = re.compile(r'\bnot\s+\S+?\s+i[sn]\s\S+') is_const_re = re.compile(r'if.*?==\s+(None|False|True)\b') noqa_re = re.compile(r'#\s+NOQA\s*$', re.I) @@ -95,66 +88,6 @@ def check_style(fn, lines): yield lno + 1, 'using == None/True/False' -@checker('.py', only_pkg=True) -def check_fileheader(fn, lines): - # line number correction - offset = 1 - if lines[0:1] == ['#!/usr/bin/env python\n']: - lines = lines[1:] - offset = 2 - - llist = [] - doc_open = False - for lno, line in enumerate(lines): - llist.append(line) - if lno == 0: - if line != '# -*- coding: utf-8 -*-\n': - yield 1, "missing coding declaration" - elif lno == 1: - if line != '"""\n' and line != 'r"""\n': - yield 2, 'missing docstring begin (""")' - else: - doc_open = True - elif doc_open: - if line == '"""\n': - # end of docstring - if lno <= 4: - yield lno + offset, "missing module name in docstring" - break - - if line != '\n' and line[:4] != ' ' and doc_open: - yield lno + offset, "missing correct docstring indentation" - - if lno == 2: - # if not in package, don't check the module name - mod_name = fn[:-3].replace('/', '.').replace('.__init__', '') - while mod_name: - if line.lower()[4:-1] == mod_name: - break - mod_name = '.'.join(mod_name.split('.')[1:]) - else: - yield 3, "wrong module name in docstring heading" - mod_name_len = len(line.strip()) - elif lno == 3: - if line.strip() != mod_name_len * '~': - yield 4, "wrong module name underline, should be ~~~...~" - else: - yield 0, "missing end and/or start of docstring..." - - # check for copyright and license fields - license = llist[-2:-1] - if not license or not license_re.match(license[0]): - yield 0, "no correct license info" - - offset = -3 - copyright = llist[offset:offset + 1] - while copyright and copyright_2_re.match(copyright[0]): - offset -= 1 - copyright = llist[offset:offset + 1] - if not copyright or not copyright_re.match(copyright[0]): - yield 0, "no correct copyright info" - - @checker('.py', '.html', '.rst') def check_whitespace_and_spelling(fn, lines): for lno, line in enumerate(lines): diff --git a/utils/checks.py b/utils/checks.py new file mode 100644 index 000000000..03104d78a --- /dev/null +++ b/utils/checks.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +""" + utils.checks + ~~~~~~~~~~~~ + + Custom, Sphinx-only flake8 plugins. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import os +import re +import sphinx + +name_mail_re = r'[\w ]+(<.*?>)?' +copyright_re = re.compile(r'^ :copyright: Copyright 200\d(-20\d\d)? ' + r'by %s(, %s)*[,.]$' % (name_mail_re, name_mail_re)) +copyright_2_re = re.compile(r'^ %s(, %s)*[,.]$' % + (name_mail_re, name_mail_re)) +license_re = re.compile(r' :license: (.*?).\n') + + +def flake8ext(_func): + """Decorate flake8_asserts functions""" + _func.name = _func.__name__ + _func.version = sphinx.__version__ + _func.code = _func.__name__.upper() + + return _func + + +@flake8ext +def sphinx_has_header(physical_line, filename, lines, line_number): + """Check for correct headers. + + Make sure each Python file has a correct file header including + copyright and license information. + + X101 invalid header found + """ + # we have a state machine of sorts so we need to start on line 1. Also, + # there's no point checking really short files + if line_number != 1 or len(lines) < 10: + return + + # this file uses a funky license but unfortunately it's not possible to + # ignore specific errors on a file-level basis yet [1]. Simply skip it. + # + # [1] https://gitlab.com/pycqa/flake8/issues/347 + if os.path.samefile(filename, './sphinx/util/smartypants.py'): + return + + # if the top-level package or not inside the package, ignore + mod_name = os.path.splitext(filename)[0].strip('./\\').replace( + '/', '.').replace('.__init__', '') + if mod_name == 'sphinx' or not mod_name.startswith('sphinx.'): + return + + # line number correction + offset = 1 + if lines[0:1] == ['#!/usr/bin/env python\n']: + lines = lines[1:] + offset = 2 + + llist = [] + doc_open = False + + for lno, line in enumerate(lines): + llist.append(line) + if lno == 0: + if line != '# -*- coding: utf-8 -*-\n': + return 0, 'X101 missing coding declaration' + elif lno == 1: + if line != '"""\n' and line != 'r"""\n': + return 0, 'X101 missing docstring begin (""")' + else: + doc_open = True + elif doc_open: + if line == '"""\n': + # end of docstring + if lno <= 4: + return 0, 'X101 missing module name in docstring' + break + + if line != '\n' and line[:4] != ' ' and doc_open: + return 0, 'X101 missing correct docstring indentation' + + if lno == 2: + mod_name_len = len(line.strip()) + if line.strip() != mod_name: + return 4, 'X101 wrong module name in docstring heading' + elif lno == 3: + if line.strip() != mod_name_len * '~': + return (4, 'X101 wrong module name underline, should be ' + '~~~...~') + else: + return 0, 'X101 missing end and/or start of docstring...' + + # check for copyright and license fields + license = llist[-2:-1] + if not license or not license_re.match(license[0]): + return 0, 'X101 no correct license info' + + offset = -3 + copyright = llist[offset:offset + 1] + while copyright and copyright_2_re.match(copyright[0]): + offset -= 1 + copyright = llist[offset:offset + 1] + if not copyright or not copyright_re.match(copyright[0]): + return 0, 'X101 no correct copyright info' From 160e27e20f059a8dffad9e6454ea6763a51feb70 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 1 Oct 2017 16:26:40 +0100 Subject: [PATCH 0190/1814] utils: Remove 'check_sources' There are still a couple of checks here but all of them can be removed now: - Check if using valid Python syntax - Check if line length too long - Check if using 'x == None/True/False' - Check if using old HTML 3 tags The first three are already handled by default by the 'flake8' tool. The last one isn't replaced by anything, but it really isn't worth worrying about now because the tags it checks for have been dead for a really long time and would not be used by anyone writing HTML in the last 10 years. Combined, it means we can remove the entire file. The 'style-check' target is updated to simply alias 'flake8'. It can be removed in a future release. This allows us to stop using this target in the Travis jobs, seeing as we already run flake8. Signed-off-by: Stephen Finucane --- .travis.yml | 2 +- Makefile | 34 +------- utils/check_sources.py | 191 ----------------------------------------- 3 files changed, 2 insertions(+), 225 deletions(-) delete mode 100755 utils/check_sources.py diff --git a/.travis.yml b/.travis.yml index f271fd4a0..6df4f7cfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,5 +44,5 @@ install: - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi script: - flake8 - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make style-check type-check test-async; fi + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test-async; fi - if [[ $TRAVIS_PYTHON_VERSION != '3.6' ]]; then make test; fi diff --git a/Makefile b/Makefile index a20df8f39..ce5bf096a 100644 --- a/Makefile +++ b/Makefile @@ -3,42 +3,10 @@ PYTHON ?= python .PHONY: all style-check type-check clean clean-pyc clean-patchfiles clean-backupfiles \ clean-generated pylint reindent test covertest build -DONT_CHECK = -i .ropeproject \ - -i .tox \ - -i build \ - -i dist \ - -i doc/_build \ - -i sphinx/pycode/pgen2 \ - -i sphinx/search/da.py \ - -i sphinx/search/de.py \ - -i sphinx/search/en.py \ - -i sphinx/search/es.py \ - -i sphinx/search/fi.py \ - -i sphinx/search/fr.py \ - -i sphinx/search/hu.py \ - -i sphinx/search/it.py \ - -i sphinx/search/ja.py \ - -i sphinx/search/nl.py \ - -i sphinx/search/no.py \ - -i sphinx/search/pt.py \ - -i sphinx/search/ro.py \ - -i sphinx/search/ru.py \ - -i sphinx/search/sv.py \ - -i sphinx/search/tr.py \ - -i sphinx/style/jquery.js \ - -i sphinx/util/smartypants.py \ - -i tests/build \ - -i tests/path.py \ - -i tests/roots/test-directive-code/target.py \ - -i tests/roots/test-warnings/undecodable.rst \ - -i tests/test_autodoc_py35.py \ - -i tests/typing_test_data.py \ - -i utils/convert.py - all: clean-pyc clean-backupfiles style-check type-check test style-check: - @PYTHONWARNINGS=all $(PYTHON) utils/check_sources.py $(DONT_CHECK) . + @flake8 type-check: mypy sphinx/ diff --git a/utils/check_sources.py b/utils/check_sources.py deleted file mode 100755 index ace691449..000000000 --- a/utils/check_sources.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Checker for file headers - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Make sure each Python file has a correct file header - including copyright and license information. - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" -from __future__ import print_function - -import os -import re -import sys -from optparse import OptionParser -from os.path import join, splitext, abspath - - -checkers = {} - - -def checker(*suffixes, **kwds): - only_pkg = kwds.pop('only_pkg', False) - - def deco(func): - for suffix in suffixes: - checkers.setdefault(suffix, []).append(func) - func.only_pkg = only_pkg - return func - return deco - - -# this one is a byte regex since it is applied before decoding -coding_re = re.compile(br'coding[:=]\s*([-\w.]+)') - -uni_coding_re = re.compile(r'^#.*coding[:=]\s*([-\w.]+).*') -not_ix_re = re.compile(r'\bnot\s+\S+?\s+i[sn]\s\S+') -is_const_re = re.compile(r'if.*?==\s+(None|False|True)\b') -noqa_re = re.compile(r'#\s+NOQA\s*$', re.I) - -misspellings = ["developement", "adress", # ALLOW-MISSPELLING - "verificate", "informations"] # ALLOW-MISSPELLING - - -def decode_source(fn, lines): - encoding = 'ascii' if fn.endswith('.py') else 'utf-8' - decoded_lines = [] - for lno, line in enumerate(lines): - if lno < 2: - co = coding_re.search(line) - if co: - encoding = co.group(1).decode() - try: - decoded_lines.append(line.decode(encoding)) - except UnicodeDecodeError as err: - raise UnicodeError("%s:%d: not decodable: %s\n Line: %r" % - (fn, lno + 1, err, line)) - except LookupError as err: - raise LookupError("unknown encoding: %s" % encoding) - return decoded_lines - - -@checker('.py') -def check_syntax(fn, lines): - lines = [uni_coding_re.sub('', line) for line in lines] - try: - compile(''.join(lines), fn, "exec") - except SyntaxError as err: - yield 0, "not compilable: %s" % err - - -@checker('.py') -def check_style(fn, lines): - for lno, line in enumerate(lines): - if noqa_re.search(line): - continue - if len(line.rstrip('\n')) > 95: - yield lno + 1, "line too long" - if line.strip().startswith('#'): - continue - # m = not_ix_re.search(line) - # if m: - # yield lno+1, '"' + m.group() + '"' - if is_const_re.search(line): - yield lno + 1, 'using == None/True/False' - - -@checker('.py', '.html', '.rst') -def check_whitespace_and_spelling(fn, lines): - for lno, line in enumerate(lines): - if '\t' in line: - yield lno + 1, "OMG TABS!!!1 " - if line[:-1].rstrip(' \t') != line[:-1]: - yield lno + 1, "trailing whitespace" - for word in misspellings: - if word in line and 'ALLOW-MISSPELLING' not in line: - yield lno + 1, '"%s" used' % word - - -bad_tags = ['', '', '', '
', ' 1 and "s" or "")) - return int(num > 0) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) From 1f0c3ce87567711090714f3070099b341af6d573 Mon Sep 17 00:00:00 2001 From: cocoatomo Date: Fri, 6 Oct 2017 00:35:05 +0900 Subject: [PATCH 0191/1814] Re-arrange WARNING messages about reference inconsistencies --- sphinx/transforms/i18n.py | 31 ++++---------------- tests/roots/test-intl/refs_inconsistency.po | 8 ++--- tests/roots/test-intl/refs_inconsistency.txt | 4 +-- tests/test_intl.py | 8 +++-- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 2618c7246..daaa2a595 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -258,11 +258,10 @@ class Locale(SphinxTransform): (nodes.paragraph,) + LITERAL_TYPE_NODES + IMAGE_TYPE_NODES): continue # skip for now - # auto-numbered foot note reference should use original 'ids'. - def is_autonumber_footnote_ref(node): + # foot note reference should use original 'ids'. + def is_footnote_ref(node): # type: (nodes.Node) -> bool - return isinstance(node, nodes.footnote_reference) and \ - node.get('auto') == 1 + return isinstance(node, nodes.footnote_reference) def list_replace_or_append(lst, old, new): # type: (List, Any, Any) -> None @@ -270,8 +269,8 @@ class Locale(SphinxTransform): lst[lst.index(old)] = new else: lst.append(new) - old_foot_refs = node.traverse(is_autonumber_footnote_ref) - new_foot_refs = patch.traverse(is_autonumber_footnote_ref) + old_foot_refs = node.traverse(is_footnote_ref) + new_foot_refs = patch.traverse(is_footnote_ref) if len(old_foot_refs) != len(new_foot_refs): logger.warning('inconsistent footnote references in translated message', location=node) @@ -327,26 +326,6 @@ class Locale(SphinxTransform): self.document.note_refname(new) - # refnamed footnote and citation should use original 'ids'. - def is_refnamed_footnote_ref(node): - # type: (nodes.Node) -> bool - footnote_ref_classes = (nodes.footnote_reference, - nodes.citation_reference) - return isinstance(node, footnote_ref_classes) and \ - 'refname' in node - old_refs = node.traverse(is_refnamed_footnote_ref) - new_refs = patch.traverse(is_refnamed_footnote_ref) - refname_ids_map = {} - if len(old_refs) != len(new_refs): - logger.warning('inconsistent references in translated message', - location=node) - for old in old_refs: - refname_ids_map[old["refname"]] = old["ids"] - for new in new_refs: - refname = new["refname"] - if refname in refname_ids_map: - new["ids"] = refname_ids_map[refname] - # Original pending_xref['reftarget'] contain not-translated # target name, new pending_xref must use original one. # This code restricts to change ref-targets in the translation. diff --git a/tests/roots/test-intl/refs_inconsistency.po b/tests/roots/test-intl/refs_inconsistency.po index cb2de9ad8..9d8d13f61 100644 --- a/tests/roots/test-intl/refs_inconsistency.po +++ b/tests/roots/test-intl/refs_inconsistency.po @@ -19,8 +19,8 @@ msgstr "" msgid "i18n with refs inconsistency" msgstr "I18N WITH REFS INCONSISTENCY" -msgid "[100]_ for [#]_ footnote [ref2]_." -msgstr "FOR FOOTNOTE [ref2]_." +msgid "[100]_ for [#]_ citation [ref2]_." +msgstr "FOR CITATION [ref3]_." msgid "for reference_." msgstr "reference_ FOR reference_." @@ -31,8 +31,8 @@ msgstr "ORPHAN REFERENCE: `I18N WITH REFS INCONSISTENCY`_." msgid "This is a auto numbered footnote." msgstr "THIS IS A AUTO NUMBERED FOOTNOTE." -msgid "This is a named footnote." -msgstr "THIS IS A NAMED FOOTNOTE." +msgid "This is a citation." +msgstr "THIS IS A CITATION." msgid "This is a numbered footnote." msgstr "THIS IS A NUMBERED FOOTNOTE." diff --git a/tests/roots/test-intl/refs_inconsistency.txt b/tests/roots/test-intl/refs_inconsistency.txt index c65c5b458..b16623a28 100644 --- a/tests/roots/test-intl/refs_inconsistency.txt +++ b/tests/roots/test-intl/refs_inconsistency.txt @@ -3,11 +3,11 @@ i18n with refs inconsistency ============================= -* [100]_ for [#]_ footnote [ref2]_. +* [100]_ for [#]_ citation [ref2]_. * for reference_. * normal text. .. [#] This is a auto numbered footnote. -.. [ref2] This is a named footnote. +.. [ref2] This is a citation. .. [100] This is a numbered footnote. .. _reference: http://www.example.com diff --git a/tests/test_intl.py b/tests/test_intl.py index 413276e44..f4f1ecc1e 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -182,11 +182,11 @@ def test_text_inconsistency_warnings(app, warning): result = (app.outdir / 'refs_inconsistency.txt').text(encoding='utf-8') expect = (u"I18N WITH REFS INCONSISTENCY" u"\n****************************\n" - u"\n* FOR FOOTNOTE [ref2].\n" + u"\n* FOR CITATION [ref3].\n" u"\n* reference FOR reference.\n" u"\n* ORPHAN REFERENCE: I18N WITH REFS INCONSISTENCY.\n" u"\n[1] THIS IS A AUTO NUMBERED FOOTNOTE.\n" - u"\n[ref2] THIS IS A NAMED FOOTNOTE.\n" + u"\n[ref2] THIS IS A CITATION.\n" u"\n[100] THIS IS A NUMBERED FOOTNOTE.\n") assert result == expect @@ -199,6 +199,10 @@ def test_text_inconsistency_warnings(app, warning): warning_fmt % 'references') assert_re_search(expected_warning_expr, warnings) + expected_citation_warning_expr = ( + u'.*/refs_inconsistency.txt:\\d+: WARNING: Citation \[ref2\] is not referenced.\n' + + u'.*/refs_inconsistency.txt:\\d+: WARNING: citation not found: ref3') + assert_re_search(expected_citation_warning_expr, warnings) @sphinx_intl @pytest.mark.sphinx('text') From aad52ebd095f6c1c4be9ae2245bc3f462037d2e8 Mon Sep 17 00:00:00 2001 From: cocoatomo Date: Sat, 7 Oct 2017 10:42:46 +0900 Subject: [PATCH 0192/1814] Divide validation code between refnamed footnote and citation --- sphinx/transforms/i18n.py | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index daaa2a595..aa0e2b942 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -258,10 +258,11 @@ class Locale(SphinxTransform): (nodes.paragraph,) + LITERAL_TYPE_NODES + IMAGE_TYPE_NODES): continue # skip for now - # foot note reference should use original 'ids'. - def is_footnote_ref(node): + # auto-numbered foot note reference should use original 'ids'. + def is_autonumber_footnote_ref(node): # type: (nodes.Node) -> bool - return isinstance(node, nodes.footnote_reference) + return isinstance(node, nodes.footnote_reference) and \ + node.get('auto') == 1 def list_replace_or_append(lst, old, new): # type: (List, Any, Any) -> None @@ -269,8 +270,8 @@ class Locale(SphinxTransform): lst[lst.index(old)] = new else: lst.append(new) - old_foot_refs = node.traverse(is_footnote_ref) - new_foot_refs = patch.traverse(is_footnote_ref) + old_foot_refs = node.traverse(is_autonumber_footnote_ref) + new_foot_refs = patch.traverse(is_autonumber_footnote_ref) if len(old_foot_refs) != len(new_foot_refs): logger.warning('inconsistent footnote references in translated message', location=node) @@ -326,6 +327,42 @@ class Locale(SphinxTransform): self.document.note_refname(new) + # refnamed footnote should use original 'ids'. + def is_refnamed_footnote_ref(node): + # type: (nodes.Node) -> bool + return isinstance(node, nodes.footnote_reference) and \ + 'refname' in node + old_foot_refs = node.traverse(is_refnamed_footnote_ref) + new_foot_refs = patch.traverse(is_refnamed_footnote_ref) + refname_ids_map = {} + if len(old_foot_refs) != len(new_foot_refs): + logger.warning('inconsistent footnote references in translated message', + location=node) + for old in old_foot_refs: + refname_ids_map[old["refname"]] = old["ids"] + for new in new_foot_refs: + refname = new["refname"] + if refname in refname_ids_map: + new["ids"] = refname_ids_map[refname] + + # citation should use original 'ids'. + def is_citation_ref(node): + # type: (nodes.Node) -> bool + return isinstance(node, nodes.citation_reference) and \ + 'refname' in node + old_cite_refs = node.traverse(is_citation_ref) + new_cite_refs = patch.traverse(is_citation_ref) + refname_ids_map = {} + if len(old_cite_refs) != len(new_cite_refs): + logger.warning('inconsistent citation references in translated message', + location=node) + for old in old_cite_refs: + refname_ids_map[old["refname"]] = old["ids"] + for new in new_cite_refs: + refname = new["refname"] + if refname in refname_ids_map: + new["ids"] = refname_ids_map[refname] + # Original pending_xref['reftarget'] contain not-translated # target name, new pending_xref must use original one. # This code restricts to change ref-targets in the translation. From 95f0f4d6a000033da6373185065be66b66496916 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 5 Oct 2017 00:47:34 +0900 Subject: [PATCH 0193/1814] Update CHANGES for PR #4112 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 0d5eecd2d..d1ef85171 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,7 @@ Features added -------------- * #4107: Make searchtools.js compatible with pre-Sphinx1.5 templates +* #4112: Don't override the smart_quotes setting if it was already set Bugs fixed ---------- From 7d4dab69286110d8e5257d2cd421c7a9c016b98b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 7 Oct 2017 15:29:29 +0900 Subject: [PATCH 0194/1814] Fix mypy violations --- sphinx/ext/autodoc.py | 2 +- sphinx/quickstart.py | 4 ++-- sphinx/util/logging.py | 6 +++--- sphinx/util/matching.py | 2 +- sphinx/util/pycompat.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 0f28ecb3f..d6e61b241 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -368,7 +368,7 @@ def format_annotation(annotation): Displaying complex types from ``typing`` relies on its private API. """ - if typing and isinstance(annotation, typing.TypeVar): # type: ignore + if typing and isinstance(annotation, typing.TypeVar): return annotation.__name__ if annotation == Ellipsis: return '...' diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index e70de64b6..67a59b059 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -534,7 +534,7 @@ def valid_dir(d): if not path.isdir(dir): return False - if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): + if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): # type: ignore return False if d['sep']: @@ -550,7 +550,7 @@ def valid_dir(d): d['dot'] + 'templates', d['master'] + d['suffix'], ] - if set(reserved_names) & set(os.listdir(dir)): + if set(reserved_names) & set(os.listdir(dir)): # type: ignore return False return True diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 7fb5c5894..17ee88a01 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -136,13 +136,13 @@ class NewLineStreamHandlerPY2(logging.StreamHandler): # type: (logging.LogRecord) -> None try: self.acquire() - stream = self.stream # type: ignore + stream = self.stream if getattr(record, 'nonl', False): # remove return code forcely when nonl=True self.stream = StringIO() super(NewLineStreamHandlerPY2, self).emit(record) - stream.write(self.stream.getvalue()[:-1]) - stream.flush() + stream.write(self.stream.getvalue()[:-1]) # type: ignore + stream.flush() # type: ignore else: super(NewLineStreamHandlerPY2, self).emit(record) finally: diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index 3990e0e4b..401f5f002 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -96,7 +96,7 @@ _pat_cache = {} # type: Dict[unicode, Pattern] def patmatch(name, pat): - # type: (unicode, unicode) -> re.Match + # type: (unicode, unicode) -> Match[unicode] """Return if name matches pat. Adapted from fnmatch module.""" if pat not in _pat_cache: _pat_cache[pat] = re.compile(_translate_pattern(pat)) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 6122c1697..7f7ee4e9b 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -36,7 +36,7 @@ if PY3: from io import TextIOWrapper else: def TextIOWrapper(stream, encoding): - # type: (file, str) -> unicode + # type: (file, str) -> Any return codecs.lookup(encoding or 'ascii')[2](stream) From bd7d5abf8a72624813b11aa4c991ed093a6fe44f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 7 Oct 2017 15:47:35 +0900 Subject: [PATCH 0195/1814] Fix mypy violations --- sphinx/cmd/quickstart.py | 4 ++-- sphinx/domains/cpp.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index cdd0295e4..ac0859c31 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -534,7 +534,7 @@ def valid_dir(d): if not path.isdir(dir): return False - if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): + if set(['Makefile', 'make.bat']) & set(os.listdir(dir)): # type: ignore return False if d['sep']: @@ -550,7 +550,7 @@ def valid_dir(d): d['dot'] + 'templates', d['master'] + d['suffix'], ] - if set(reserved_names) & set(os.listdir(dir)): + if set(reserved_names) & set(os.listdir(dir)): # type: ignore return False return True diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index bdda12473..95b0451ba 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -5494,7 +5494,7 @@ class CPPDomain(Domain): 'namespace-push': CPPNamespacePushObject, 'namespace-pop': CPPNamespacePopObject } - roles = { # type: ignore + roles = { 'any': CPPXRefRole(), 'class': CPPXRefRole(), 'func': CPPXRefRole(fix_parens=True), From 46bf9ab4a036935c941e342233f685706fba4dea Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 7 Oct 2017 23:37:33 +0900 Subject: [PATCH 0196/1814] Fix #3692: Unable to build HTML if writing .buildinfo failed --- CHANGES | 1 + sphinx/builders/html.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index d1ef85171..19461bfdd 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,7 @@ Bugs fixed * #4096: C++, don't crash when using the wrong role type. Thanks to mitya57. * #4070, #4111: crashes when the warning message contains format strings (again) * #4108: Search word highlighting breaks SVG images +* #3692: Unable to build HTML if writing .buildinfo failed Testing -------- diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 90e4574cc..ead51a983 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -776,12 +776,15 @@ class StandaloneHTMLBuilder(Builder): def write_buildinfo(self): # type: () -> None # write build info file - with open(path.join(self.outdir, '.buildinfo'), 'w') as fp: - fp.write('# Sphinx build info version 1\n' - '# This file hashes the configuration used when building' - ' these files. When it is not found, a full rebuild will' - ' be done.\nconfig: %s\ntags: %s\n' % - (self.config_hash, self.tags_hash)) + try: + with open(path.join(self.outdir, '.buildinfo'), 'w') as fp: + fp.write('# Sphinx build info version 1\n' + '# This file hashes the configuration used when building' + ' these files. When it is not found, a full rebuild will' + ' be done.\nconfig: %s\ntags: %s\n' % + (self.config_hash, self.tags_hash)) + except IOError as exc: + logger.warning('Failed to write build info file: %r', exc) def cleanup(self): # type: () -> None From ff88c8b73041fa409f0af9dc6913c5e5c8e9a747 Mon Sep 17 00:00:00 2001 From: cocoatomo Date: Sun, 8 Oct 2017 00:06:00 +0900 Subject: [PATCH 0197/1814] Display reference texts of original and translated messages --- sphinx/transforms/i18n.py | 30 +++++++++++++++++++++++++----- tests/test_intl.py | 29 ++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index aa0e2b942..4c1fbc2a7 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -273,7 +273,11 @@ class Locale(SphinxTransform): old_foot_refs = node.traverse(is_autonumber_footnote_ref) new_foot_refs = patch.traverse(is_autonumber_footnote_ref) if len(old_foot_refs) != len(new_foot_refs): - logger.warning('inconsistent footnote references in translated message', + old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs] + new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs] + logger.warning('inconsistent footnote references in translated message.' + + ' original: {0}, translated: {1}' + .format(old_foot_ref_rawsources, new_foot_ref_rawsources), location=node) old_foot_namerefs = {} # type: Dict[unicode, List[nodes.footnote_reference]] for r in old_foot_refs: @@ -309,7 +313,11 @@ class Locale(SphinxTransform): old_refs = node.traverse(is_refnamed_ref) new_refs = patch.traverse(is_refnamed_ref) if len(old_refs) != len(new_refs): - logger.warning('inconsistent references in translated message', + old_ref_rawsources = [ref.rawsource for ref in old_refs] + new_ref_rawsources = [ref.rawsource for ref in new_refs] + logger.warning('inconsistent references in translated message.' + + ' original: {0}, translated: {1}' + .format(old_ref_rawsources, new_ref_rawsources), location=node) old_ref_names = [r['refname'] for r in old_refs] new_ref_names = [r['refname'] for r in new_refs] @@ -336,7 +344,11 @@ class Locale(SphinxTransform): new_foot_refs = patch.traverse(is_refnamed_footnote_ref) refname_ids_map = {} if len(old_foot_refs) != len(new_foot_refs): - logger.warning('inconsistent footnote references in translated message', + old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs] + new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs] + logger.warning('inconsistent footnote references in translated message.' + + ' original: {0}, translated: {1}' + .format(old_foot_ref_rawsources, new_foot_ref_rawsources), location=node) for old in old_foot_refs: refname_ids_map[old["refname"]] = old["ids"] @@ -354,7 +366,11 @@ class Locale(SphinxTransform): new_cite_refs = patch.traverse(is_citation_ref) refname_ids_map = {} if len(old_cite_refs) != len(new_cite_refs): - logger.warning('inconsistent citation references in translated message', + old_cite_ref_rawsources = [ref.rawsource for ref in old_cite_refs] + new_cite_ref_rawsources = [ref.rawsource for ref in new_cite_refs] + logger.warning('inconsistent citation references in translated message.' + + ' original: {0}, translated: {1}' + .format(old_cite_ref_rawsources, new_cite_ref_rawsources), location=node) for old in old_cite_refs: refname_ids_map[old["refname"]] = old["ids"] @@ -370,7 +386,11 @@ class Locale(SphinxTransform): new_refs = patch.traverse(addnodes.pending_xref) xref_reftarget_map = {} if len(old_refs) != len(new_refs): - logger.warning('inconsistent term references in translated message', + old_ref_rawsources = [ref.rawsource for ref in old_refs] + new_ref_rawsources = [ref.rawsource for ref in new_refs] + logger.warning('inconsistent term references in translated message.' + + ' original: {0}, translated: {1}' + .format(old_ref_rawsources, new_ref_rawsources), location=node) def get_ref_key(node): diff --git a/tests/test_intl.py b/tests/test_intl.py index f4f1ecc1e..49fc59c00 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -192,11 +192,29 @@ def test_text_inconsistency_warnings(app, warning): warnings = getwarning(warning) warning_fmt = u'.*/refs_inconsistency.txt:\\d+: ' \ - u'WARNING: inconsistent %s in translated message\n' + u'WARNING: inconsistent %(reftype)s in translated message.' \ + u' original: %(original)s, translated: %(translated)s\n' expected_warning_expr = ( - warning_fmt % 'footnote references' + - warning_fmt % 'references' + - warning_fmt % 'references') + warning_fmt % { + u'reftype': u'footnote references', + u'original': u"\['\[#\]_'\]", + u'translated': u"\[\]" + } + + warning_fmt % { + u'reftype': u'footnote references', + u'original': u"\['\[100\]_'\]", + u'translated': u"\[\]" + } + + warning_fmt % { + u'reftype': u'references', + u'original': u"\['reference_'\]", + u'translated': u"\['reference_', 'reference_'\]" + } + + warning_fmt % { + u'reftype': u'references', + u'original': u"\[\]", + u'translated': u"\['`I18N WITH REFS INCONSISTENCY`_'\]" + }) assert_re_search(expected_warning_expr, warnings) expected_citation_warning_expr = ( @@ -281,7 +299,8 @@ def test_text_glossary_term_inconsistencies(app, warning): warnings = getwarning(warning) expected_warning_expr = ( u'.*/glossary_terms_inconsistency.txt:\\d+: ' - u'WARNING: inconsistent term references in translated message\n') + u'WARNING: inconsistent term references in translated message.' + u" original: \[':term:`Some term`', ':term:`Some other term`'\], translated: \[':term:`SOME NEW TERM`'\]\n") assert_re_search(expected_warning_expr, warnings) From 73fd3f90bfa6d94417d5c8b444793ecbddb35f37 Mon Sep 17 00:00:00 2001 From: cocoatomo Date: Sun, 8 Oct 2017 01:29:07 +0900 Subject: [PATCH 0198/1814] Wrap the line too long --- tests/test_intl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_intl.py b/tests/test_intl.py index 49fc59c00..a4ac29e91 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -300,7 +300,8 @@ def test_text_glossary_term_inconsistencies(app, warning): expected_warning_expr = ( u'.*/glossary_terms_inconsistency.txt:\\d+: ' u'WARNING: inconsistent term references in translated message.' - u" original: \[':term:`Some term`', ':term:`Some other term`'\], translated: \[':term:`SOME NEW TERM`'\]\n") + u" original: \[':term:`Some term`', ':term:`Some other term`'\]," + u" translated: \[':term:`SOME NEW TERM`'\]\n") assert_re_search(expected_warning_expr, warnings) From 35d10033c2f1d330d0b8f53cde8c92e36e8ac063 Mon Sep 17 00:00:00 2001 From: cocoatomo Date: Sun, 8 Oct 2017 01:55:53 +0900 Subject: [PATCH 0199/1814] Add (optional) u prefixes for Python 2.7 --- tests/test_intl.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_intl.py b/tests/test_intl.py index a4ac29e91..f3952e9a1 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -197,23 +197,23 @@ def test_text_inconsistency_warnings(app, warning): expected_warning_expr = ( warning_fmt % { u'reftype': u'footnote references', - u'original': u"\['\[#\]_'\]", + u'original': u"\[u?'\[#\]_'\]", u'translated': u"\[\]" } + warning_fmt % { u'reftype': u'footnote references', - u'original': u"\['\[100\]_'\]", + u'original': u"\[u?'\[100\]_'\]", u'translated': u"\[\]" } + warning_fmt % { u'reftype': u'references', - u'original': u"\['reference_'\]", - u'translated': u"\['reference_', 'reference_'\]" + u'original': u"\[u?'reference_'\]", + u'translated': u"\[u?'reference_', u?'reference_'\]" } + warning_fmt % { u'reftype': u'references', u'original': u"\[\]", - u'translated': u"\['`I18N WITH REFS INCONSISTENCY`_'\]" + u'translated': u"\[u?'`I18N WITH REFS INCONSISTENCY`_'\]" }) assert_re_search(expected_warning_expr, warnings) @@ -300,8 +300,8 @@ def test_text_glossary_term_inconsistencies(app, warning): expected_warning_expr = ( u'.*/glossary_terms_inconsistency.txt:\\d+: ' u'WARNING: inconsistent term references in translated message.' - u" original: \[':term:`Some term`', ':term:`Some other term`'\]," - u" translated: \[':term:`SOME NEW TERM`'\]\n") + u" original: \[u?':term:`Some term`', u?':term:`Some other term`'\]," + u" translated: \[u?':term:`SOME NEW TERM`'\]\n") assert_re_search(expected_warning_expr, warnings) From 2839fc5f68b3e173c5ec6fe14d02f841ca58ad3e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 8 Oct 2017 13:15:43 +0900 Subject: [PATCH 0200/1814] Update docs (refs: #1448) --- doc/config.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/config.rst b/doc/config.rst index 01aea96dd..1762c84ec 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -2067,7 +2067,8 @@ These options influence Texinfo output. Options for QtHelp output -------------------------- -These options influence QtHelp output. +These options influence qthelp output. As this builder derives from the HTML +builder, the HTML options also apply where appropriate. .. confval:: qthelp_basename From 12920892550a0fa0e50d876630175fd100291532 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 8 Oct 2017 23:22:56 +0900 Subject: [PATCH 0201/1814] Close #1448: qthelp: Add new config value; qthelp_namespace --- CHANGES | 1 + doc/config.rst | 5 +++++ sphinx/builders/qthelp.py | 8 +++++++- tests/test_build_qthelp.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/test_build_qthelp.py diff --git a/CHANGES b/CHANGES index 064808952..ad6fe5759 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,7 @@ Features added * #3973: epub: allow to override build date * #3972: epub: Sort manifest entries by filename * #4052: viewcode: Sort before highlighting module code +* #1448: qthelp: Add new config value; :confval:`qthelp_namespace` Features removed diff --git a/doc/config.rst b/doc/config.rst index 1762c84ec..9499c6276 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -2074,6 +2074,11 @@ builder, the HTML options also apply where appropriate. The basename for the qthelp file. It defaults to the :confval:`project` name. +.. confval:: qthelp_namespace + + The namespace for the qthelp file. It defaults to + ``org.sphinx..``. + .. confval:: qthelp_theme The HTML theme for the qthelp output. diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 14979fe4b..12c28b1a3 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -21,6 +21,7 @@ from docutils import nodes from sphinx import addnodes from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.config import string_classes from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.util import force_decode, logging from sphinx.util.osutil import make_filename @@ -199,7 +200,11 @@ class QtHelpBuilder(StandaloneHTMLBuilder): # it seems that the "namespace" may not contain non-alphanumeric # characters, and more than one successive dot, or leading/trailing # dots, are also forbidden - nspace = 'org.sphinx.%s.%s' % (outname, self.config.version) + if self.config.qthelp_namespace: + nspace = self.config.qthelp_namespace + else: + nspace = 'org.sphinx.%s.%s' % (outname, self.config.version) + nspace = re.sub('[^a-zA-Z0-9.]', '', nspace) nspace = re.sub(r'\.+', '.', nspace).strip('.') nspace = nspace.lower() @@ -328,6 +333,7 @@ def setup(app): app.add_builder(QtHelpBuilder) app.add_config_value('qthelp_basename', lambda self: make_filename(self.project), None) + app.add_config_value('qthelp_namespace', None, 'html', string_classes) app.add_config_value('qthelp_theme', 'nonav', 'html') app.add_config_value('qthelp_theme_options', {}, 'html') diff --git a/tests/test_build_qthelp.py b/tests/test_build_qthelp.py new file mode 100644 index 000000000..3e4815fbe --- /dev/null +++ b/tests/test_build_qthelp.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +""" + test_build_qthelp + ~~~~~~~~~~~~~~~~~ + + Test the Qt Help builder and check its output. We don't need to + test the HTML itself; that's already handled by + :file:`test_build_html.py`. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import pytest + + +@pytest.mark.sphinx('qthelp', testroot='basic') +def test_qthelp_namespace(app, status, warning): + # default namespace + app.builder.build_all() + qhp = (app.outdir / 'Python.qhp').text() + assert 'org.sphinx.python' in qhp + + # give a namespace + app.config.qthelp_namespace = 'org.sphinx-doc.sphinx' + app.builder.build_all() + qhp = (app.outdir / 'Python.qhp').text() + assert 'org.sphinxdoc.sphinx' in qhp From bdaab9ef1be3e0d9ee594e659842cb162e147bfe Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 4 Jun 2017 11:02:31 +0100 Subject: [PATCH 0202/1814] Remove static scripts Executable scripts without the '.py' extension are already created and installed by setuptools, by way of the 'console_scripts' section. These scripts are unnecessary noise. If people want to test this behavior locally, use a virtualenv. Signed-off-by: Stephen Finucane --- doc/Makefile | 2 +- sphinx-apidoc.py | 15 --------------- sphinx-autogen.py | 15 --------------- sphinx-build.py | 15 --------------- sphinx-quickstart.py | 15 --------------- 5 files changed, 1 insertion(+), 61 deletions(-) delete mode 100755 sphinx-apidoc.py delete mode 100755 sphinx-autogen.py delete mode 100755 sphinx-build.py delete mode 100755 sphinx-quickstart.py diff --git a/doc/Makefile b/doc/Makefile index d0e4e297b..c54236be0 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = python ../sphinx-build.py +SPHINXBUILD = python ../sphinx/cmd/build.py SPHINXPROJ = sphinx SOURCEDIR = . BUILDDIR = _build diff --git a/sphinx-apidoc.py b/sphinx-apidoc.py deleted file mode 100755 index eb86e0b12..000000000 --- a/sphinx-apidoc.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Sphinx - Python documentation toolchain - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -if __name__ == '__main__': - from sphinx.ext.apidoc import main - sys.exit(main(sys.argv[1:])) diff --git a/sphinx-autogen.py b/sphinx-autogen.py deleted file mode 100755 index c9a78d158..000000000 --- a/sphinx-autogen.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Sphinx - Python documentation toolchain - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -if __name__ == '__main__': - from sphinx.ext.autosummary.generate import main - sys.exit(main(sys.argv[1:])) diff --git a/sphinx-build.py b/sphinx-build.py deleted file mode 100755 index e8116fefc..000000000 --- a/sphinx-build.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Sphinx - Python documentation toolchain - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -if __name__ == '__main__': - from sphinx import main - sys.exit(main(sys.argv[1:])) diff --git a/sphinx-quickstart.py b/sphinx-quickstart.py deleted file mode 100755 index 3caa6590f..000000000 --- a/sphinx-quickstart.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Sphinx - Python documentation toolchain - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -if __name__ == '__main__': - from sphinx.cmd.quickstart import main - sys.exit(main(sys.argv[1:])) From 87630c8ae8bff8c0e23187676e6343d8903003a6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 4 Jun 2017 11:38:58 +0100 Subject: [PATCH 0203/1814] sphinx-apidoc: Convert to argparse This is pretty self-explanatory, with most changes coming about as a side-effect of argparse vs. optparse API differences. Lowercase characters are used in help strings, per argparse conventions. Some tests are converted because argparse natively supports unicode. Signed-off-by: Stephen Finucane --- sphinx/ext/apidoc.py | 211 ++++++++++++++++++++------------------- tests/test_ext_apidoc.py | 8 +- 2 files changed, 112 insertions(+), 107 deletions(-) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 4a5c56850..1a3fc0c4e 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -17,9 +17,9 @@ from __future__ import print_function +import argparse import os import sys -import optparse from os import path from six import binary_type from fnmatch import fnmatch @@ -287,103 +287,107 @@ def is_excluded(root, excludes): def main(argv=sys.argv[1:]): # type: (List[str]) -> int """Parse and check the command line arguments.""" - parser = optparse.OptionParser( - usage="""\ -usage: %prog [options] -o [exclude_pattern, ...] + parser = argparse.ArgumentParser( + usage='usage: %(prog)s [OPTIONS] -o ' + '[EXCLUDE_PATTERN, ...]', + epilog='For more information, visit .', + description=""" +Look recursively in for Python modules and packages and create +one reST file with automodule directives per package in the . -Look recursively in for Python modules and packages and create -one reST file with automodule directives per package in the . - -The s can be file and/or directory patterns that will be +The s can be file and/or directory patterns that will be excluded from generation. Note: By default this script will not overwrite already created files.""") - parser.add_option('-o', '--output-dir', action='store', dest='destdir', - help='Directory to place all output', default='') - parser.add_option('-d', '--maxdepth', action='store', dest='maxdepth', - help='Maximum depth of submodules to show in the TOC ' - '(default: 4)', type='int', default=4) - parser.add_option('-f', '--force', action='store_true', dest='force', - help='Overwrite existing files') - parser.add_option('-l', '--follow-links', action='store_true', - dest='followlinks', default=False, - help='Follow symbolic links. Powerful when combined ' - 'with collective.recipe.omelette.') - parser.add_option('-n', '--dry-run', action='store_true', dest='dryrun', - help='Run the script without creating files') - parser.add_option('-e', '--separate', action='store_true', - dest='separatemodules', - help='Put documentation for each module on its own page') - parser.add_option('-P', '--private', action='store_true', - dest='includeprivate', - help='Include "_private" modules') - parser.add_option('-T', '--no-toc', action='store_true', dest='notoc', - help='Don\'t create a table of contents file') - parser.add_option('-E', '--no-headings', action='store_true', - dest='noheadings', - help='Don\'t create headings for the module/package ' - 'packages (e.g. when the docstrings already contain ' - 'them)') - parser.add_option('-M', '--module-first', action='store_true', - dest='modulefirst', - help='Put module documentation before submodule ' - 'documentation') - parser.add_option('--implicit-namespaces', action='store_true', - dest='implicit_namespaces', - help='Interpret module paths according to PEP-0420 ' - 'implicit namespaces specification') - parser.add_option('-s', '--suffix', action='store', dest='suffix', - help='file suffix (default: rst)', default='rst') - parser.add_option('-F', '--full', action='store_true', dest='full', - help='Generate a full project with sphinx-quickstart') - parser.add_option('-a', '--append-syspath', action='store_true', - dest='append_syspath', - help='Append module_path to sys.path, used when --full is given') - parser.add_option('-H', '--doc-project', action='store', dest='header', - help='Project name (default: root module name)') - parser.add_option('-A', '--doc-author', action='store', dest='author', - type='str', - help='Project author(s), used when --full is given') - parser.add_option('-V', '--doc-version', action='store', dest='version', - help='Project version, used when --full is given') - parser.add_option('-R', '--doc-release', action='store', dest='release', - help='Project release, used when --full is given, ' - 'defaults to --doc-version') - parser.add_option('--version', action='store_true', dest='show_version', - help='Show version information and exit') - group = parser.add_option_group('Extension options') + parser.add_argument('--version', action='version', dest='show_version', + version='%%(prog)s %s' % __display_version__) + + parser.add_argument('module_path', + help='path to module to document') + parser.add_argument('exclude_pattern', nargs='*', + help='fnmatch-style file and/or directory patterns ' + 'to exclude from generation') + + parser.add_argument('-o', '--output-dir', action='store', dest='destdir', + required=True, + help='directory to place all output') + parser.add_argument('-d', '--maxdepth', action='store', dest='maxdepth', + type=int, default=4, + help='maximum depth of submodules to show in the TOC ' + '(default: 4)') + parser.add_argument('-f', '--force', action='store_true', dest='force', + help='overwrite existing files') + parser.add_argument('-l', '--follow-links', action='store_true', + dest='followlinks', default=False, + help='follow symbolic links. Powerful when combined ' + 'with collective.recipe.omelette.') + parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun', + help='run the script without creating files') + parser.add_argument('-e', '--separate', action='store_true', + dest='separatemodules', + help='put documentation for each module on its own page') + parser.add_argument('-P', '--private', action='store_true', + dest='includeprivate', + help='include "_private" modules') + parser.add_argument('-T', '--no-toc', action='store_true', dest='notoc', + help="don't create a table of contents file") + parser.add_argument('-E', '--no-headings', action='store_true', + dest='noheadings', + help="don't create headings for the module/package " + "packages (e.g. when the docstrings already " + "contain them)") + parser.add_argument('-M', '--module-first', action='store_true', + dest='modulefirst', + help='put module documentation before submodule ' + 'documentation') + parser.add_argument('--implicit-namespaces', action='store_true', + dest='implicit_namespaces', + help='interpret module paths according to PEP-0420 ' + 'implicit namespaces specification') + parser.add_argument('-s', '--suffix', action='store', dest='suffix', + default='rst', + help='file suffix (default: rst)') + parser.add_argument('-F', '--full', action='store_true', dest='full', + help='generate a full project with sphinx-quickstart') + parser.add_argument('-a', '--append-syspath', action='store_true', + dest='append_syspath', + help='append module_path to sys.path, used when --full is given') + parser.add_argument('-H', '--doc-project', action='store', dest='header', + help='project name (default: root module name)') + parser.add_argument('-A', '--doc-author', action='store', dest='author', + help='project author(s), used when --full is given') + parser.add_argument('-V', '--doc-version', action='store', dest='version', + help='project version, used when --full is given') + parser.add_argument('-R', '--doc-release', action='store', dest='release', + help='project release, used when --full is given, ' + 'defaults to --doc-version') + + group = parser.add_argument_group('extension options') for ext in EXTENSIONS: - group.add_option('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, - help='enable %s extension' % ext) + group.add_argument('--ext-' + ext, action='store_true', + dest='ext_' + ext, default=False, + help='enable %s extension' % ext) - (opts, args) = parser.parse_args(argv) + args = parser.parse_args(argv) - if opts.show_version: - print('Sphinx (sphinx-apidoc) %s' % __display_version__) - return 0 + rootpath = path.abspath(args.module_path) - if not args: - parser.error('A package path is required.') + # normalize opts - rootpath, excludes = args[0], args[1:] - if not opts.destdir: - parser.error('An output directory is required.') - if opts.header is None: - opts.header = path.abspath(rootpath).split(path.sep)[-1] - if opts.suffix.startswith('.'): - opts.suffix = opts.suffix[1:] + if args.header is None: + args.header = rootpath.split(path.sep)[-1] + if args.suffix.startswith('.'): + args.suffix = args.suffix[1:] if not path.isdir(rootpath): print('%s is not a directory.' % rootpath, file=sys.stderr) sys.exit(1) - if not path.isdir(opts.destdir): - if not opts.dryrun: - os.makedirs(opts.destdir) - rootpath = path.abspath(rootpath) - excludes = normalize_excludes(rootpath, excludes) - modules = recurse_tree(rootpath, excludes, opts) - if opts.full: + if not path.isdir(args.destdir) and not args.dryrun: + os.makedirs(args.destdir) + excludes = normalize_excludes(rootpath, args.exclude_pattern) + modules = recurse_tree(rootpath, excludes, args) + + if args.full: from sphinx.cmd import quickstart as qs modules.sort() prev_module = '' # type: unicode @@ -394,14 +398,14 @@ Note: By default this script will not overwrite already created files.""") prev_module = module text += ' %s\n' % module d = dict( - path = opts.destdir, + path = args.destdir, sep = False, dot = '_', - project = opts.header, - author = opts.author or 'Author', - version = opts.version or '', - release = opts.release or opts.version or '', - suffix = '.' + opts.suffix, + project = args.header, + author = args.author or 'Author', + version = args.version or '', + release = args.release or args.version or '', + suffix = '.' + args.suffix, master = 'index', epub = True, ext_autodoc = True, @@ -409,29 +413,30 @@ Note: By default this script will not overwrite already created files.""") ext_todo = True, makefile = True, batchfile = True, - mastertocmaxdepth = opts.maxdepth, + mastertocmaxdepth = args.maxdepth, mastertoctree = text, language = 'en', module_path = rootpath, - append_syspath = opts.append_syspath, + append_syspath = args.append_syspath, ) - enabled_exts = {'ext_' + ext: getattr(opts, 'ext_' + ext) - for ext in EXTENSIONS if getattr(opts, 'ext_' + ext)} + enabled_exts = {'ext_' + ext: getattr(args, 'ext_' + ext) + for ext in EXTENSIONS if getattr(args, 'ext_' + ext)} d.update(enabled_exts) - if isinstance(opts.header, binary_type): + if isinstance(args.header, binary_type): d['project'] = d['project'].decode('utf-8') - if isinstance(opts.author, binary_type): + if isinstance(args.author, binary_type): d['author'] = d['author'].decode('utf-8') - if isinstance(opts.version, binary_type): + if isinstance(args.version, binary_type): d['version'] = d['version'].decode('utf-8') - if isinstance(opts.release, binary_type): + if isinstance(args.release, binary_type): d['release'] = d['release'].decode('utf-8') - if not opts.dryrun: - qs.generate(d, silent=True, overwrite=opts.force) - elif not opts.notoc: - create_modules_toc_file(modules, opts) + if not args.dryrun: + qs.generate(d, silent=True, overwrite=args.force) + elif not args.notoc: + create_modules_toc_file(modules, args) + return 0 diff --git a/tests/test_ext_apidoc.py b/tests/test_ext_apidoc.py index 794591aa6..d98dbabb6 100644 --- a/tests/test_ext_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -152,10 +152,10 @@ def test_trailing_underscore(make_app, apidoc): @pytest.mark.apidoc( coderoot='test-root', options=[ - '--doc-project', u'プロジェクトå'.encode('utf-8'), - '--doc-author', u'著者å'.encode('utf-8'), - '--doc-version', u'ãƒãƒ¼ã‚¸ãƒ§ãƒ³'.encode('utf-8'), - '--doc-release', u'リリース'.encode('utf-8'), + '--doc-project', u'プロジェクトå', + '--doc-author', u'著者å', + '--doc-version', u'ãƒãƒ¼ã‚¸ãƒ§ãƒ³', + '--doc-release', u'リリース', ], ) def test_multibyte_parameters(make_app, apidoc): From fa74085afdb717aea83e8766734a65481d4f6f8d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 19:11:02 +0100 Subject: [PATCH 0204/1814] sphinx-apidoc: Move parser to a separate function This lets us better reason about what the parser is doing and use tools like 'sphinx-contrib.autoprogram' in our own documentation in the future. Signed-off-by: Stephen Finucane --- sphinx/ext/apidoc.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 1a3fc0c4e..73d3027a3 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -284,9 +284,8 @@ def is_excluded(root, excludes): return False -def main(argv=sys.argv[1:]): - # type: (List[str]) -> int - """Parse and check the command line arguments.""" +def get_parser(): + # type: () -> argparse.ArgumentParser parser = argparse.ArgumentParser( usage='usage: %(prog)s [OPTIONS] -o ' '[EXCLUDE_PATTERN, ...]', @@ -369,6 +368,13 @@ Note: By default this script will not overwrite already created files.""") dest='ext_' + ext, default=False, help='enable %s extension' % ext) + return parser + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> int + """Parse and check the command line arguments.""" + parser = get_parser() args = parser.parse_args(argv) rootpath = path.abspath(args.module_path) From a3f1489544ad1b66c034e1a7edb009a916b4141f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 4 Jun 2017 11:44:23 +0100 Subject: [PATCH 0205/1814] sphinx-apidoc: Remove 'normalize_excludes' function This is a one-liner that really doesn't need to be split out, so don't do it. Signed-off-by: Stephen Finucane --- sphinx/ext/apidoc.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 73d3027a3..cb020aba2 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -265,12 +265,6 @@ def recurse_tree(rootpath, excludes, opts): return toplevels -def normalize_excludes(rootpath, excludes): - # type: (unicode, List[unicode]) -> List[unicode] - """Normalize the excluded directory list.""" - return [path.abspath(exclude) for exclude in excludes] - - def is_excluded(root, excludes): # type: (unicode, List[unicode]) -> bool """Check if the directory is in the exclude list. @@ -390,7 +384,7 @@ def main(argv=sys.argv[1:]): sys.exit(1) if not path.isdir(args.destdir) and not args.dryrun: os.makedirs(args.destdir) - excludes = normalize_excludes(rootpath, args.exclude_pattern) + excludes = [path.abspath(exclude) for exclude in args.exclude_pattern] modules = recurse_tree(rootpath, excludes, args) if args.full: From fcf0c1247fba23ef86d6b6eb0f1b41f22106bb59 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 4 Jun 2017 12:02:04 +0100 Subject: [PATCH 0206/1814] sphinx-autogen: Convert to argparse Another mostly trivial conversion. The only odd thing here is that we add a '--version' parameter to keep things in line with the other applications. Signed-off-by: Stephen Finucane --- sphinx/ext/autosummary/generate.py | 55 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 13b463e87..2eaeb6530 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -19,16 +19,17 @@ """ from __future__ import print_function +import argparse +import codecs import os +import pydoc import re import sys -import pydoc -import optparse -import codecs from jinja2 import FileSystemLoader, TemplateNotFound from jinja2.sandbox import SandboxedEnvironment +from sphinx import __display_version__ from sphinx import package_dir from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader @@ -61,29 +62,35 @@ if False: def main(argv=sys.argv[1:]): # type: (List[str]) -> None - usage = """%prog [OPTIONS] SOURCEFILE ...""" - p = optparse.OptionParser(usage.strip()) - p.add_option("-o", "--output-dir", action="store", type="string", - dest="output_dir", default=None, - help="Directory to place all output in") - p.add_option("-s", "--suffix", action="store", type="string", - dest="suffix", default="rst", - help="Default suffix for files (default: %default)") - p.add_option("-t", "--templates", action="store", type="string", - dest="templates", default=None, - help="Custom template directory (default: %default)") - p.add_option("-i", "--imported-members", action="store_true", - dest="imported_members", default=False, - help="Document imported members (default: %default)") - options, args = p.parse_args(argv) + parser = argparse.ArgumentParser( + usage='%(prog)s [OPTIONS] ...') - if len(args) < 1: - p.error('no input files given') + parser.add_argument('--version', action='version', dest='show_version', + version='%%(prog)s %s' % __display_version__) - generate_autosummary_docs(args, options.output_dir, - "." + options.suffix, - template_dir=options.templates, - imported_members=options.imported_members) + parser.add_argument('source_file', nargs='+', + help='source files to generate rST files for') + parser.add_argument('-o', '--output-dir', action='store', + dest='output_dir', + help='directory to place all output in') + parser.add_argument('-s', '--suffix', action='store', dest='suffix', + default='rst', + help='default suffix for files (default: ' + '%(default)s)') + parser.add_argument('-t', '--templates', action='store', dest='templates', + default=None, + help='custom template directory (default: ' + '%(default)s)') + parser.add_argument('-i', '--imported-members', action='store_true', + dest='imported_members', default=False, + help='document imported members (default: ' + '%(default)s)') + + args = parser.parse_args(argv) + generate_autosummary_docs(args.source_file, args.output_dir, + '.' + args.suffix, + template_dir=args.templates, + imported_members=args.imported_members) def _simple_info(msg): From 6a88b5a6c27718aeaaecb124d7ecfdfd8c08e736 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 19:15:58 +0100 Subject: [PATCH 0207/1814] sphinx-autogen: Move parser to a separate function For the same reasons as the 'sphinx-apidoc' move. We also take the opportunity to add a help string and epilog while we're at it. Signed-off-by: Stephen Finucane --- sphinx/ext/autosummary/generate.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 2eaeb6530..731586430 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -60,16 +60,30 @@ if False: from sphinx.environment import BuildEnvironment # NOQA -def main(argv=sys.argv[1:]): - # type: (List[str]) -> None +def get_parser(): + # type: () -> argparse.ArgumentParser parser = argparse.ArgumentParser( - usage='%(prog)s [OPTIONS] ...') + usage='%(prog)s [OPTIONS] ...', + epilog='For more information, visit .', + description=""" +Generate ReStructuredText using autosummary directives. + +sphinx-autogen is a frontend to sphinx.ext.autosummary.generate. It generates +the reStructuredText files from the autosummary directives contained in the +given input files. + +The format of the autosummary directive is documented in the +``sphinx.ext.autosummary`` Python module and can be read using:: + + pydoc sphinx.ext.autosummary +""") parser.add_argument('--version', action='version', dest='show_version', version='%%(prog)s %s' % __display_version__) parser.add_argument('source_file', nargs='+', help='source files to generate rST files for') + parser.add_argument('-o', '--output-dir', action='store', dest='output_dir', help='directory to place all output in') @@ -86,7 +100,12 @@ def main(argv=sys.argv[1:]): help='document imported members (default: ' '%(default)s)') - args = parser.parse_args(argv) + return parser + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> None + args = get_parser().parse_args(argv) generate_autosummary_docs(args.source_file, args.output_dir, '.' + args.suffix, template_dir=args.templates, From b506d872927893f668292cbb7be290a93cfd5687 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 4 Jun 2017 12:03:08 +0100 Subject: [PATCH 0208/1814] sphinx-autogen: Move main to end of file Per Python customs. Signed-off-by: Stephen Finucane --- sphinx/ext/autosummary/generate.py | 104 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 731586430..f02c50692 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -60,58 +60,6 @@ if False: from sphinx.environment import BuildEnvironment # NOQA -def get_parser(): - # type: () -> argparse.ArgumentParser - parser = argparse.ArgumentParser( - usage='%(prog)s [OPTIONS] ...', - epilog='For more information, visit .', - description=""" -Generate ReStructuredText using autosummary directives. - -sphinx-autogen is a frontend to sphinx.ext.autosummary.generate. It generates -the reStructuredText files from the autosummary directives contained in the -given input files. - -The format of the autosummary directive is documented in the -``sphinx.ext.autosummary`` Python module and can be read using:: - - pydoc sphinx.ext.autosummary -""") - - parser.add_argument('--version', action='version', dest='show_version', - version='%%(prog)s %s' % __display_version__) - - parser.add_argument('source_file', nargs='+', - help='source files to generate rST files for') - - parser.add_argument('-o', '--output-dir', action='store', - dest='output_dir', - help='directory to place all output in') - parser.add_argument('-s', '--suffix', action='store', dest='suffix', - default='rst', - help='default suffix for files (default: ' - '%(default)s)') - parser.add_argument('-t', '--templates', action='store', dest='templates', - default=None, - help='custom template directory (default: ' - '%(default)s)') - parser.add_argument('-i', '--imported-members', action='store_true', - dest='imported_members', default=False, - help='document imported members (default: ' - '%(default)s)') - - return parser - - -def main(argv=sys.argv[1:]): - # type: (List[str]) -> None - args = get_parser().parse_args(argv) - generate_autosummary_docs(args.source_file, args.output_dir, - '.' + args.suffix, - template_dir=args.templates, - imported_members=args.imported_members) - - def _simple_info(msg): # type: (unicode) -> None print(msg) @@ -399,5 +347,57 @@ def find_autosummary_in_lines(lines, module=None, filename=None): return documented +def get_parser(): + # type: () -> argparse.ArgumentParser + parser = argparse.ArgumentParser( + usage='%(prog)s [OPTIONS] ...', + epilog='For more information, visit .', + description=""" +Generate ReStructuredText using autosummary directives. + +sphinx-autogen is a frontend to sphinx.ext.autosummary.generate. It generates +the reStructuredText files from the autosummary directives contained in the +given input files. + +The format of the autosummary directive is documented in the +``sphinx.ext.autosummary`` Python module and can be read using:: + + pydoc sphinx.ext.autosummary +""") + + parser.add_argument('--version', action='version', dest='show_version', + version='%%(prog)s %s' % __display_version__) + + parser.add_argument('source_file', nargs='+', + help='source files to generate rST files for') + + parser.add_argument('-o', '--output-dir', action='store', + dest='output_dir', + help='directory to place all output in') + parser.add_argument('-s', '--suffix', action='store', dest='suffix', + default='rst', + help='default suffix for files (default: ' + '%(default)s)') + parser.add_argument('-t', '--templates', action='store', dest='templates', + default=None, + help='custom template directory (default: ' + '%(default)s)') + parser.add_argument('-i', '--imported-members', action='store_true', + dest='imported_members', default=False, + help='document imported members (default: ' + '%(default)s)') + + return parser + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> None + args = get_parser().parse_args(argv) + generate_autosummary_docs(args.source_file, args.output_dir, + '.' + args.suffix, + template_dir=args.templates, + imported_members=args.imported_members) + + if __name__ == '__main__': main() From bca566244ab65e26b854818efa5e9f2d509b58c9 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 18:48:54 +0100 Subject: [PATCH 0209/1814] sphinx-quickstart: Convert to argparse Nothing unusual to see here. Signed-off-by: Stephen Finucane --- sphinx/cmd/quickstart.py | 167 ++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 98 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index cdd0295e4..5bd0faa39 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -11,13 +11,13 @@ from __future__ import print_function from __future__ import absolute_import -import re +import argparse import os +import re import sys -import optparse import time -from os import path from io import open +from os import path # try to import readline, unix specific enhancement try: @@ -509,23 +509,6 @@ where "builder" is one of the supported builders, e.g. html, latex or linkcheck. ''') -def usage(argv, msg=None): - # type: (List[unicode], unicode) -> None - if msg: - print(msg, file=sys.stderr) - print(file=sys.stderr) - - -USAGE = """\ -Sphinx v%s -Usage: %%prog [options] [projectdir] -""" % __display_version__ - -EPILOG = """\ -For more information, visit . -""" - - def valid_dir(d): # type: (Dict) -> bool dir = d['path'] @@ -556,100 +539,88 @@ def valid_dir(d): return True -class MyFormatter(optparse.IndentedHelpFormatter): - def format_usage(self, usage): # type: ignore - # type: (str) -> str - return usage - - def format_help(self, formatter): - result = [] - if self.description: - result.append(self.format_description(formatter)) - if self.option_list: - result.append(self.format_option_help(formatter)) - return "\n".join(result) - - def main(argv=sys.argv[1:]): # type: (List[str]) -> int if not color_terminal(): nocolor() - parser = optparse.OptionParser(USAGE, epilog=EPILOG, - version='Sphinx v%s' % __display_version__, - formatter=MyFormatter()) - parser.add_option('-q', '--quiet', action='store_true', dest='quiet', - default=False, - help='quiet mode') + parser = argparse.ArgumentParser( + usage='%(prog)s [OPTIONS] ', + epilog='For more information, visit .') - group = parser.add_option_group('Structure options') - group.add_option('--sep', action='store_true', dest='sep', - help='if specified, separate source and build dirs') - group.add_option('--dot', metavar='DOT', dest='dot', - help='replacement for dot in _templates etc.') + parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', + default=False, + help='quiet mode') + parser.add_argument('--version', action='version', dest='show_version', + version='%%(prog)s %s' % __display_version__) - group = parser.add_option_group('Project basic options') - group.add_option('-p', '--project', metavar='PROJECT', dest='project', - help='project name') - group.add_option('-a', '--author', metavar='AUTHOR', dest='author', - help='author names') - group.add_option('-v', metavar='VERSION', dest='version', - help='version of project') - group.add_option('-r', '--release', metavar='RELEASE', dest='release', - help='release of project') - group.add_option('-l', '--language', metavar='LANGUAGE', dest='language', - help='document language') - group.add_option('--suffix', metavar='SUFFIX', dest='suffix', - help='source file suffix') - group.add_option('--master', metavar='MASTER', dest='master', - help='master document name') - group.add_option('--epub', action='store_true', dest='epub', - default=False, - help='use epub') + parser.add_argument('path', metavar='PROJECT_DIR', default='.', + help='output path') - group = parser.add_option_group('Extension options') + group = parser.add_argument_group('Structure options') + group.add_argument('--sep', action='store_true', + help='if specified, separate source and build dirs') + group.add_argument('--dot', metavar='DOT', + help='replacement for dot in _templates etc.') + + group = parser.add_argument_group('Project basic options') + group.add_argument('-p', '--project', metavar='PROJECT', dest='project', + help='project name') + group.add_argument('-a', '--author', metavar='AUTHOR', dest='author', + help='author names') + group.add_argument('-v', metavar='VERSION', dest='version', default='', + help='version of project') + group.add_argument('-r', '--release', metavar='RELEASE', dest='release', + help='release of project') + group.add_argument('-l', '--language', metavar='LANGUAGE', dest='language', + help='document language') + group.add_argument('--suffix', metavar='SUFFIX', + help='source file suffix') + group.add_argument('--master', metavar='MASTER', + help='master document name') + group.add_argument('--epub', action='store_true', default=False, + help='use epub') + + group = parser.add_argument_group('Extension options') for ext in EXTENSIONS: - group.add_option('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, - help='enable %s extension' % ext) - group.add_option('--extensions', metavar='EXTENSIONS', dest='extensions', - action='append', help='enable extensions') + group.add_argument('--ext-' + ext, action='store_true', + dest='ext_' + ext, default=False, + help='enable %s extension' % ext) + group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions', + action='append', help='enable extensions') - group = parser.add_option_group('Makefile and Batchfile creation') - group.add_option('--makefile', action='store_true', dest='makefile', - default=False, - help='create makefile') - group.add_option('--no-makefile', action='store_true', dest='no_makefile', - default=False, - help='not create makefile') - group.add_option('--batchfile', action='store_true', dest='batchfile', - default=False, - help='create batchfile') - group.add_option('--no-batchfile', action='store_true', dest='no_batchfile', - default=False, - help='not create batchfile') - group.add_option('-M', '--no-use-make-mode', action='store_false', dest='make_mode', - help='not use make-mode for Makefile/make.bat') - group.add_option('-m', '--use-make-mode', action='store_true', dest='make_mode', - default=True, - help='use make-mode for Makefile/make.bat') + # TODO(stephenfin): Consider using mutually exclusive groups here + group = parser.add_argument_group('Makefile and Batchfile creation') + group.add_argument('--makefile', action='store_true', default=False, + help='create makefile') + group.add_argument('--no-makefile', action='store_true', default=False, + help='not create makefile') + group.add_argument('--batchfile', action='store_true', default=False, + help='create batchfile') + group.add_argument('--no-batchfile', action='store_true', default=False, + help='not create batchfile') + group.add_argument('-M', '--no-use-make-mode', action='store_false', + dest='make_mode', default=False, + help='not use make-mode for Makefile/make.bat') + group.add_argument('-m', '--use-make-mode', action='store_true', + dest='make_mode', default=True, + help='use make-mode for Makefile/make.bat') - group = parser.add_option_group('Project templating') - group.add_option('-t', '--templatedir', metavar='TEMPLATEDIR', dest='templatedir', - help='template directory for template files') - group.add_option('-d', metavar='NAME=VALUE', action='append', dest='variables', - help='define a template variable') + group = parser.add_argument_group('Project templating') + group.add_argument('-t', '--templatedir', metavar='TEMPLATEDIR', + dest='templatedir', + help='template directory for template files') + group.add_argument('-d', metavar='NAME=VALUE', action='append', + dest='variables', + help='define a template variable') # parse options try: - opts, args = parser.parse_args(argv) + args = parser.parse_args(argv) except SystemExit as err: return err.code - if len(args) > 0: - opts.ensure_value('path', args[0]) - - d = vars(opts) + d = vars(args) # delete None or False value d = dict((k, v) for k, v in d.items() if not (v is None or v is False)) @@ -707,7 +678,7 @@ def main(argv=sys.argv[1:]): except ValueError: print('Invalid template variable: %s' % variable) - generate(d, templatedir=opts.templatedir) + generate(d, templatedir=args.templatedir) return 0 From c68381bd6597f50e085b96d7f69a982db8baabda Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 19:23:25 +0100 Subject: [PATCH 0210/1814] sphinx-quickstart: Move parser to a separate function For the same reasons as the 'sphinx-apidoc' and 'sphinx-autogen' moves. As before, we also take the opportunity to add a help string. Signed-off-by: Stephen Finucane --- sphinx/cmd/quickstart.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 5bd0faa39..a616b263e 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -539,14 +539,18 @@ def valid_dir(d): return True -def main(argv=sys.argv[1:]): - # type: (List[str]) -> int - if not color_terminal(): - nocolor() - +def get_parser(): + # type: () -> argparse.ArgumentParser parser = argparse.ArgumentParser( usage='%(prog)s [OPTIONS] ', - epilog='For more information, visit .') + epilog="For more information, visit .", + description=""" +Generate required files for a Sphinx project. + +sphinx-quickstart is an interactive tool that asks some questions about your +project and then generates a complete documentation directory and sample +Makefile to be used with sphinx-build. +""") parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', default=False, @@ -614,7 +618,16 @@ def main(argv=sys.argv[1:]): dest='variables', help='define a template variable') + return parser + + +def main(argv=sys.argv[1:]): + # type: (List[str]) -> int + if not color_terminal(): + nocolor() + # parse options + parser = get_parser() try: args = parser.parse_args(argv) except SystemExit as err: From b778cfe2999930d812c5e6f16142dc5d2311996d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 20:00:57 +0100 Subject: [PATCH 0211/1814] sphinx-build: Convert to argparse Once again, not much different to the previous conversions. We make best use of the argparse module, allowing us to remove some funky workarounds. Signed-off-by: Stephen Finucane --- sphinx/cmdline.py | 224 ++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 126 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 54e4dcb78..30bef6674 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -10,14 +10,13 @@ """ from __future__ import print_function +import argparse import sys -import optparse import traceback from os import path -from six import text_type, binary_type - from docutils.utils import SystemMessage +from six import text_type, binary_type from sphinx import __display_version__ from sphinx.errors import SphinxError @@ -33,39 +32,9 @@ if False: from typing import Any, IO, List, Union # NOQA -USAGE = """\ -Sphinx v%s -Usage: %%prog [options] sourcedir outdir [filenames...] - -Filename arguments: - without -a and without filenames, write new and changed files. - with -a, write all files. - with filenames, write these. -""" % __display_version__ - -EPILOG = """\ -For more information, visit . -""" - - -class MyFormatter(optparse.IndentedHelpFormatter): - def format_usage(self, usage): - # type: (Any) -> Any - return usage - - def format_help(self, formatter): - # type: (Any) -> unicode - result = [] # type: List[unicode] - if self.description: # type: ignore - result.append(self.format_description(formatter)) - if self.option_list: # type: ignore - result.append(self.format_option_help(formatter)) # type: ignore - return "\n".join(result) - - -def handle_exception(app, opts, exception, stderr=sys.stderr): +def handle_exception(app, args, exception, stderr=sys.stderr): # type: (Sphinx, Any, Union[Exception, KeyboardInterrupt], IO) -> None - if opts.pdb: + if args.pdb: import pdb print(red('Exception occurred while building, starting debugger:'), file=stderr) @@ -73,7 +42,7 @@ def handle_exception(app, opts, exception, stderr=sys.stderr): pdb.post_mortem(sys.exc_info()[2]) else: print(file=stderr) - if opts.verbosity or opts.traceback: + if args.verbosity or args.traceback: traceback.print_exc(None, stderr) print(file=stderr) if isinstance(exception, KeyboardInterrupt): @@ -116,102 +85,105 @@ def handle_exception(app, opts, exception, stderr=sys.stderr): def main(argv=sys.argv[1:]): # type: ignore # type: (List[unicode]) -> int - parser = optparse.OptionParser(USAGE, epilog=EPILOG, formatter=MyFormatter()) - parser.add_option('--version', action='store_true', dest='version', - help='show version information and exit') + parser = argparse.ArgumentParser( + usage='usage: %(prog)s [OPTIONS] SOURCEDIR OUTDIR [FILENAMES...]', + epilog='For more information, visit .') - group = parser.add_option_group('General options') - group.add_option('-b', metavar='BUILDER', dest='builder', default='html', - help='builder to use; default is html') - group.add_option('-a', action='store_true', dest='force_all', - help='write all files; default is to only write new and ' - 'changed files') - group.add_option('-E', action='store_true', dest='freshenv', - help='don\'t use a saved environment, always read ' - 'all files') - group.add_option('-d', metavar='PATH', default=None, dest='doctreedir', - help='path for the cached environment and doctree files ' - '(default: outdir/.doctrees)') - group.add_option('-j', metavar='N', default=1, type='int', dest='jobs', - help='build in parallel with N processes where possible') - # this option never gets through to this point (it is intercepted earlier) - # group.add_option('-M', metavar='BUILDER', dest='make_mode', - # help='"make" mode -- as used by Makefile, like ' - # '"sphinx-build -M html"') + parser.add_argument('--version', action='version', dest='show_version', + version='%%(prog)s %s' % __display_version__) - group = parser.add_option_group('Build configuration options') - group.add_option('-c', metavar='PATH', dest='confdir', - help='path where configuration file (conf.py) is located ' - '(default: same as sourcedir)') - group.add_option('-C', action='store_true', dest='noconfig', - help='use no config file at all, only -D options') - group.add_option('-D', metavar='setting=value', action='append', - dest='define', default=[], - help='override a setting in configuration file') - group.add_option('-A', metavar='name=value', action='append', - dest='htmldefine', default=[], - help='pass a value into HTML templates') - group.add_option('-t', metavar='TAG', action='append', - dest='tags', default=[], - help='define tag: include "only" blocks with TAG') - group.add_option('-n', action='store_true', dest='nitpicky', - help='nit-picky mode, warn about all missing references') + parser.add_argument('sourcedir', + help='path to documentation source files') + parser.add_argument('outputdir', + help='path to output directory') + parser.add_argument('filenames', nargs='*', + help='a list of specific files to rebuild. Ignored ' + 'if -a is specified') - group = parser.add_option_group('Console output options') - group.add_option('-v', action='count', dest='verbosity', default=0, - help='increase verbosity (can be repeated)') - group.add_option('-q', action='store_true', dest='quiet', - help='no output on stdout, just warnings on stderr') - group.add_option('-Q', action='store_true', dest='really_quiet', - help='no output at all, not even warnings') - group.add_option('--color', dest='color', - action='store_const', const='yes', default='auto', - help='Do emit colored output (default: auto-detect)') - group.add_option('-N', '--no-color', dest='color', - action='store_const', const='no', - help='Do not emit colored output (default: auto-detect)') - group.add_option('-w', metavar='FILE', dest='warnfile', - help='write warnings (and errors) to given file') - group.add_option('-W', action='store_true', dest='warningiserror', - help='turn warnings into errors') - group.add_option('-T', action='store_true', dest='traceback', - help='show full traceback on exception') - group.add_option('-P', action='store_true', dest='pdb', - help='run Pdb on exception') + group = parser.add_argument_group('general options') + group.add_argument('-b', metavar='BUILDER', dest='builder', + default='html', + help='builder to use (default: html)') + group.add_argument('-a', action='store_true', dest='force_all', + help='write all files (default: only write new and ' + 'changed files)') + group.add_argument('-E', action='store_true', dest='freshenv', + help='don\'t use a saved environment, always read ' + 'all files') + group.add_argument('-d', metavar='PATH', dest='doctreedir', + help='path for the cached environment and doctree ' + 'files (default: outdir/.doctrees)') + group.add_argument('-j', metavar='N', default=1, type=int, dest='jobs', + help='build in parallel with N processes where ' + 'possible') + + group = parser.add_argument_group('build configuration options') + group.add_argument('-c', metavar='PATH', dest='confdir', + help='path where configuration file (conf.py) is ' + 'located (default: same as sourcedir)') + group.add_argument('-C', action='store_true', dest='noconfig', + help='use no config file at all, only -D options') + group.add_argument('-D', metavar='setting=value', action='append', + dest='define', default=[], + help='override a setting in configuration file') + group.add_argument('-A', metavar='name=value', action='append', + dest='htmldefine', default=[], + help='pass a value into HTML templates') + group.add_argument('-t', metavar='TAG', action='append', + dest='tags', default=[], + help='define tag: include "only" blocks with TAG') + group.add_argument('-n', action='store_true', dest='nitpicky', + help='nit-picky mode, warn about all missing ' + 'references') + + group = parser.add_argument_group('console output options') + group.add_argument('-v', action='count', dest='verbosity', default=0, + help='increase verbosity (can be repeated)') + group.add_argument('-q', action='store_true', dest='quiet', + help='no output on stdout, just warnings on stderr') + group.add_argument('-Q', action='store_true', dest='really_quiet', + help='no output at all, not even warnings') + group.add_argument('--color', action='store_const', const='yes', + default='auto', + help='do emit colored output (default: auto-detect)') + group.add_argument('-N', '--no-color', dest='color', action='store_const', + const='no', + help='do not emit colored output (default: ' + 'auto-detect)') + group.add_argument('-w', metavar='FILE', dest='warnfile', + help='write warnings (and errors) to given file') + group.add_argument('-W', action='store_true', dest='warningiserror', + help='turn warnings into errors') + group.add_argument('-T', action='store_true', dest='traceback', + help='show full traceback on exception') + group.add_argument('-P', action='store_true', dest='pdb', + help='run Pdb on exception') # parse options try: - opts, args = parser.parse_args(argv) + args = parser.parse_args(argv) except SystemExit as err: return err.code - # handle basic options - if opts.version: - print('Sphinx (sphinx-build) %s' % __display_version__) - return 0 - # get paths (first and second positional argument) try: - srcdir = abspath(args[0]) - confdir = abspath(opts.confdir or srcdir) - if opts.noconfig: + srcdir = abspath(args.sourcedir) + confdir = abspath(args.confdir or srcdir) + if args.noconfig: confdir = None if not path.isdir(srcdir): print('Error: Cannot find source directory `%s\'.' % srcdir, file=sys.stderr) return 1 - if not opts.noconfig and not path.isfile(path.join(confdir, 'conf.py')): + if not args.noconfig and not path.isfile(path.join(confdir, 'conf.py')): print('Error: Config directory doesn\'t contain a conf.py file.', file=sys.stderr) return 1 - outdir = abspath(args[1]) + outdir = abspath(args.outputdir) if srcdir == outdir: print('Error: source directory and destination directory are same.', file=sys.stderr) return 1 - except IndexError: - parser.print_help() - return 1 except UnicodeError: print( 'Error: Multibyte filename not supported on this filesystem ' @@ -219,7 +191,7 @@ def main(argv=sys.argv[1:]): # type: ignore return 1 # handle remaining filename arguments - filenames = args[2:] + filenames = args.filenames errored = False for filename in filenames: if not path.isfile(filename): @@ -235,35 +207,35 @@ def main(argv=sys.argv[1:]): # type: ignore except Exception: likely_encoding = None - if opts.force_all and filenames: + if args.force_all and filenames: print('Error: Cannot combine -a option and filenames.', file=sys.stderr) return 1 - if opts.color == 'no' or (opts.color == 'auto' and not color_terminal()): + if args.color == 'no' or (args.color == 'auto' and not color_terminal()): nocolor() - doctreedir = abspath(opts.doctreedir or path.join(outdir, '.doctrees')) + doctreedir = abspath(args.doctreedir or path.join(outdir, '.doctrees')) status = sys.stdout warning = sys.stderr error = sys.stderr - if opts.quiet: + if args.quiet: status = None - if opts.really_quiet: + if args.really_quiet: status = warning = None - if warning and opts.warnfile: + if warning and args.warnfile: try: - warnfp = open(opts.warnfile, 'w') + warnfp = open(args.warnfile, 'w') except Exception as exc: print('Error: Cannot open warning file %r: %s' % - (opts.warnfile, exc), file=sys.stderr) + (args.warnfile, exc), file=sys.stderr) sys.exit(1) warning = Tee(warning, warnfp) # type: ignore error = warning confoverrides = {} - for val in opts.define: + for val in args.define: try: key, val = val.split('=', 1) except ValueError: @@ -277,7 +249,7 @@ def main(argv=sys.argv[1:]): # type: ignore pass confoverrides[key] = val - for val in opts.htmldefine: + for val in args.htmldefine: try: key, val = val.split('=') except ValueError: @@ -294,17 +266,17 @@ def main(argv=sys.argv[1:]): # type: ignore pass confoverrides['html_context.%s' % key] = val - if opts.nitpicky: + if args.nitpicky: confoverrides['nitpicky'] = True app = None try: with patch_docutils(), docutils_namespace(): - app = Sphinx(srcdir, confdir, outdir, doctreedir, opts.builder, - confoverrides, status, warning, opts.freshenv, - opts.warningiserror, opts.tags, opts.verbosity, opts.jobs) - app.build(opts.force_all, filenames) + app = Sphinx(srcdir, confdir, outdir, doctreedir, args.builder, + confoverrides, status, warning, args.freshenv, + args.warningiserror, args.tags, args.verbosity, args.jobs) + app.build(args.force_all, filenames) return app.statuscode except (Exception, KeyboardInterrupt) as exc: - handle_exception(app, opts, exc, error) + handle_exception(app, args, exc, error) return 1 From aedeb2160ad07d387c9657345e42166d56d268b6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Sep 2017 20:10:32 +0100 Subject: [PATCH 0212/1814] sphinx-build: Move parser to a separate function This should be becoming passe at this point. Signed-off-by: Stephen Finucane --- sphinx/cmdline.py | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 30bef6674..11f1861d8 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -83,11 +83,27 @@ def handle_exception(app, args, exception, stderr=sys.stderr): file=stderr) -def main(argv=sys.argv[1:]): # type: ignore - # type: (List[unicode]) -> int +def get_parser(): + # type: () -> argparse.ArgumentParser parser = argparse.ArgumentParser( - usage='usage: %(prog)s [OPTIONS] SOURCEDIR OUTDIR [FILENAMES...]', - epilog='For more information, visit .') + usage='usage: %(prog)s [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]', + epilog='For more information, visit .', + description=""" +Generate documentation from source files. + +sphinx-build generates documentation from the files in SOURCEDIR and places it +in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration +settings. The 'sphinx-quickstart' tool may be used to generate template files, +including 'conf.py' + +sphinx-build can create documentation in different formats. A format is +selected by specifying the builder name on the command line; it defaults to +HTML. Builders can also perform other tasks related to documentation +processing. + +By default, everything that is outdated is built. Output only for selected +files can be built by specifying individual filenames. +""") parser.add_argument('--version', action='version', dest='show_version', version='%%(prog)s %s' % __display_version__) @@ -112,7 +128,7 @@ def main(argv=sys.argv[1:]): # type: ignore 'all files') group.add_argument('-d', metavar='PATH', dest='doctreedir', help='path for the cached environment and doctree ' - 'files (default: outdir/.doctrees)') + 'files (default: OUTPUTDIR/.doctrees)') group.add_argument('-j', metavar='N', default=1, type=int, dest='jobs', help='build in parallel with N processes where ' 'possible') @@ -120,7 +136,7 @@ def main(argv=sys.argv[1:]): # type: ignore group = parser.add_argument_group('build configuration options') group.add_argument('-c', metavar='PATH', dest='confdir', help='path where configuration file (conf.py) is ' - 'located (default: same as sourcedir)') + 'located (default: same as SOURCEDIR)') group.add_argument('-C', action='store_true', dest='noconfig', help='use no config file at all, only -D options') group.add_argument('-D', metavar='setting=value', action='append', @@ -159,6 +175,13 @@ def main(argv=sys.argv[1:]): # type: ignore group.add_argument('-P', action='store_true', dest='pdb', help='run Pdb on exception') + return parser + + +def main(argv=sys.argv[1:]): # type: ignore + # type: (List[unicode]) -> int + + parser = get_parser() # parse options try: args = parser.parse_args(argv) From 26796f6985ec52216a0e05e4b995d1c1e7c4d597 Mon Sep 17 00:00:00 2001 From: Frank Sachsenheim Date: Wed, 4 Oct 2017 20:22:34 +0200 Subject: [PATCH 0213/1814] Makefile: Makes PHONY statements more maintainable. --- Makefile | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a20df8f39..6e07a8c05 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,5 @@ PYTHON ?= python -.PHONY: all style-check type-check clean clean-pyc clean-patchfiles clean-backupfiles \ - clean-generated pylint reindent test covertest build - DONT_CHECK = -i .ropeproject \ -i .tox \ -i build \ @@ -35,33 +32,42 @@ DONT_CHECK = -i .ropeproject \ -i tests/typing_test_data.py \ -i utils/convert.py +.PHONY: all all: clean-pyc clean-backupfiles style-check type-check test +.PHONY: style-check style-check: @PYTHONWARNINGS=all $(PYTHON) utils/check_sources.py $(DONT_CHECK) . +.PHONY: type-check type-check: mypy sphinx/ +.PHONY: clean clean: clean-pyc clean-pycache clean-patchfiles clean-backupfiles clean-generated clean-testfiles clean-buildfiles clean-mypyfiles +.PHONY: clean-pyc clean-pyc: find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} + +.PHONY: clean-pycache clean-pycache: find . -name __pycache__ -exec rm -rf {} + +.PHONY: clean-patchfiles clean-patchfiles: find . -name '*.orig' -exec rm -f {} + find . -name '*.rej' -exec rm -f {} + +.PHONY: clean-backupfiles clean-backupfiles: find . -name '*~' -exec rm -f {} + find . -name '*.bak' -exec rm -f {} + find . -name '*.swp' -exec rm -f {} + find . -name '*.swo' -exec rm -f {} + +.PHONY: clean-generated clean-generated: find . -name '.DS_Store' -exec rm -f {} + rm -rf Sphinx.egg-info/ @@ -70,32 +76,41 @@ clean-generated: rm -f utils/*3.py* rm -f utils/regression_test.js +.PHONY: clean-testfiles clean-testfiles: rm -rf tests/.coverage rm -rf tests/build rm -rf .tox/ rm -rf .cache/ +.PHONY: clean-buildfiles clean-buildfiles: rm -rf build +.PHONY: clean-mypyfiles clean-mypyfiles: rm -rf .mypy_cache/ +.PHONY: pylint pylint: @pylint --rcfile utils/pylintrc sphinx +.PHONY: reindent reindent: @$(PYTHON) utils/reindent.py -r -n . +.PHONY: test test: @cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST) +.PHONY: test-async test-async: @cd tests; $(PYTHON) run.py -v $(TEST) +.PHONY: covertest covertest: @cd tests; $(PYTHON) run.py -v --cov=sphinx --junitxml=.junit.xml $(TEST) +.PHONY: build build: @$(PYTHON) setup.py build From b2959a91c51594560fb7342261e23b9ce9630d37 Mon Sep 17 00:00:00 2001 From: Frank Sachsenheim Date: Wed, 4 Oct 2017 20:31:50 +0200 Subject: [PATCH 0214/1814] Makefile: Adds a target to build docs from the root dir. --- CONTRIBUTING.rst | 3 +-- Makefile | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 4438e2838..5b9e38db5 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -126,8 +126,7 @@ These are the basic steps needed to start developing on Sphinx. * Build the documentation and check the output for different builders:: - cd doc - make clean html latexpdf + make docs target="clean html latexpdf" * Run code style checks and type checks (type checks require mypy):: diff --git a/Makefile b/Makefile index 6e07a8c05..5257b2ad5 100644 --- a/Makefile +++ b/Makefile @@ -114,3 +114,10 @@ covertest: .PHONY: build build: @$(PYTHON) setup.py build + +.PHONY: docs +docs: +ifndef target + $(info You need to give a provide a target variable, e.g. `make docs target=html`.) +endif + $(MAKE) -C doc $(target) From 990de5799a1c6b6f7767ad93ec003c3910aac723 Mon Sep 17 00:00:00 2001 From: Frank Sachsenheim Date: Wed, 4 Oct 2017 22:32:12 +0200 Subject: [PATCH 0215/1814] Adds a note about passing args to pytest. --- CONTRIBUTING.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 5b9e38db5..eca6a01ac 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -124,6 +124,11 @@ These are the basic steps needed to start developing on Sphinx. PYTHONWARNINGS=all make test + * Arguments to pytest can be passed via tox, e.g. in order to run a + particular test:: + + tox -e py27 tests/test_module.py::test_new_feature + * Build the documentation and check the output for different builders:: make docs target="clean html latexpdf" From 4faa727368d6b8a48965e2733f3a52696b091f03 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 10 Oct 2017 20:00:54 +0900 Subject: [PATCH 0216/1814] Update CHANGES for PR #4125 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 19461bfdd..3e382ef5d 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,8 @@ Features added * #4107: Make searchtools.js compatible with pre-Sphinx1.5 templates * #4112: Don't override the smart_quotes setting if it was already set +* #4125: Display reference texts of original and translated passages on + i18n warning message Bugs fixed ---------- From dbd58d4c5100dde6449c5a2fd567ab5ae52232c6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 5 Oct 2017 11:07:48 +0100 Subject: [PATCH 0217/1814] setup.py: Stop caring about pip 1.5.6 This version is silly old and anyone that's _still_ using this is not going to be building Sphinx from source. Simply remove it. Signed-off-by: Stephen Finucane --- setup.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/setup.py b/setup.py index af21f3938..b2d7ad4cc 100644 --- a/setup.py +++ b/setup.py @@ -75,13 +75,6 @@ extras_require = { ], } -# for sdist installation with pip-1.5.6 -if sys.platform == 'win32': - requires.append('colorama>=0.3.5') - -if sys.version_info < (3, 5): - requires.append('typing') - # Provide a "compile_catalog" command that also creates the translated # JavaScript files if Babel is available. From eb8efce7d8172e41139acd26196dd164c6272583 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 09:46:28 +0100 Subject: [PATCH 0218/1814] requirements: Reduce duplication Simply installing packages will ensure that most of the dependencies in 'setup.py' are installed, meaning 'test-reqs.txt' need only contain those necessary for testing. The only notable change is that the 'simplejson' module is dropped from the requirements list. This included as a dependency for the PyPy target, but it appears that this is not necessary today (though it may have been when the target was added in 2011). This retains 'setup.py test' which, as noted in the tox docs [1], is sometimes expected for downstream distribution testing. We may wish to find a way to synchronize requirements between 'test-reqs.txt' and this section in the future, but that's work for another day. [1] https://tox.readthedocs.io/en/latest/example/basic.html#integration-with-setup-py-test-command Signed-off-by: Stephen Finucane --- .appveyor.yml | 4 ++-- .travis.yml | 3 ++- setup.py | 16 ++++++++++------ test-reqs.txt | 19 +++---------------- tox.ini | 21 +++------------------ 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index deaf503b7..a3f83394f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,8 +18,8 @@ environment: install: - C:\Python%PYTHON%\python.exe -m pip install -U pip setuptools - - C:\Python%PYTHON%\python.exe -m pip install docutils==%DOCUTILS% - - C:\Python%PYTHON%\python.exe -m pip install -r test-reqs.txt + - C:\Python%PYTHON%\python.exe -m pip install docutils==%DOCUTILS% mock + - C:\Python%PYTHON%\python.exe -m pip install .[test,websupport] # No automatic build, just run python tests build: off diff --git a/.travis.yml b/.travis.yml index 6df4f7cfb..73fd9c459 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,8 @@ addons: install: - pip install -U pip setuptools - pip install docutils==$DOCUTILS - - pip install -r test-reqs.txt + - pip install .[test,websupport] + - pip install flake8 - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi script: - flake8 diff --git a/setup.py b/setup.py index b2d7ad4cc..618620b50 100644 --- a/setup.py +++ b/setup.py @@ -69,10 +69,17 @@ extras_require = { ], 'test': [ 'pytest', - 'mock', # it would be better for 'test:python_version in 2.7' - 'simplejson', # better: 'test:platform_python_implementation=="PyPy"' + 'pytest-cov', 'html5lib', ], + 'test:python_version<"3"': [ + 'enum34', + 'mock', + ], + 'test:python_version>="3"': [ + 'mypy', + 'typed_ast', + ], } # Provide a "compile_catalog" command that also creates the translated @@ -83,10 +90,7 @@ cmdclass = {} try: from babel.messages.pofile import read_po from babel.messages.frontend import compile_catalog - try: - from simplejson import dump - except ImportError: - from json import dump + from json import dump except ImportError: pass else: diff --git a/test-reqs.txt b/test-reqs.txt index 3a7bde8ea..be15ff1ab 100644 --- a/test-reqs.txt +++ b/test-reqs.txt @@ -1,20 +1,7 @@ flake8 pytest>=3.0 pytest-cov -mock -six>=1.4 -Jinja2>=2.3 -Pygments>=2.0 -docutils>=0.11 -snowballstemmer>=1.1 -babel -sqlalchemy>=0.9 -whoosh>=2.0 -alabaster -sphinx_rtd_theme -sphinxcontrib-websupport -imagesize -requests html5lib -enum34 -typing +mock;python_version<'3.3' +mypy;python_version>='3.2' +typed_ast;python_version>='3.2' diff --git a/tox.ini b/tox.ini index 519020f98..d78754dd4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,16 +1,10 @@ [tox] -envlist=flake8,py27,py34,py35,py36,pypy,du14,du13,du12,du11 +minversion=2.0 +envlist=flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} [testenv] passenv = https_proxy http_proxy no_proxy -deps= - six - pytest - pytest-cov - html5lib - mock - enum34 - typing +deps=-rtest-reqs.txt setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= @@ -18,11 +12,6 @@ commands= --durations 25 {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html -[testenv:pypy] -deps= - simplejson - {[testenv]deps} - [testenv:du11] deps= docutils==0.11 @@ -59,10 +48,6 @@ deps= {[testenv]deps} [testenv:py35] -deps= - mypy - typed_ast - {[testenv]deps} commands= {envpython} -Wall tests/run.py --cov=sphinx --durations 25 {posargs} sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html From 67753b7ce38e4ab6dab1377e37e9d1bce0364291 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 10 Oct 2017 14:10:11 +0100 Subject: [PATCH 0219/1814] Remove 'test-reqs.txt' We were never really using this file for its specified purpose [1]. Now that we have everything cleanly organized in 'setup.py', there really isn't any reason to keep it around. Remove it. [1] https://caremad.io/posts/2013/07/setup-vs-requirement/ Signed-off-by: Stephen Finucane --- CONTRIBUTING.rst | 2 +- MANIFEST.in | 1 - test-reqs.txt | 7 ------- tox.ini | 7 ++++++- 4 files changed, 7 insertions(+), 10 deletions(-) delete mode 100644 test-reqs.txt diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index eca6a01ac..7c8a90c6b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -116,7 +116,7 @@ These are the basic steps needed to start developing on Sphinx. * Run the unit tests:: - pip install -r test-reqs.txt + pip install .[test,websupport] make test * Again, it's useful to turn on deprecation warnings on so they're shown in diff --git a/MANIFEST.in b/MANIFEST.in index 1530c28cd..a5699c23c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -12,7 +12,6 @@ include sphinx-autogen.py include sphinx-build.py include sphinx-quickstart.py include sphinx-apidoc.py -include test-reqs.txt include tox.ini include sphinx/locale/.tx/config diff --git a/test-reqs.txt b/test-reqs.txt deleted file mode 100644 index be15ff1ab..000000000 --- a/test-reqs.txt +++ /dev/null @@ -1,7 +0,0 @@ -flake8 -pytest>=3.0 -pytest-cov -html5lib -mock;python_version<'3.3' -mypy;python_version>='3.2' -typed_ast;python_version>='3.2' diff --git a/tox.ini b/tox.ini index d78754dd4..00b3c99e2 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,12 @@ envlist=flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} [testenv] passenv = https_proxy http_proxy no_proxy -deps=-rtest-reqs.txt +# TODO(stephenfin) Replace this with the 'extras' config option when tox 2.4 is +# widely available, likely some time after the Ubuntu 18.04 release +# +# https://tox.readthedocs.io/en/latest/config.html#confval-extras=MULTI-LINE-LIST +deps = + .[test,websupport] setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= From 350f196c4fad6e9e14232dfbe019f4a20a3bae92 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Tue, 10 Oct 2017 16:23:38 +0100 Subject: [PATCH 0220/1814] Report the unimplemented node_name in exception --- sphinx/pycode/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 1be62a4e0..5bee020e4 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -63,7 +63,7 @@ def get_lvar_names(node, self=None): elif node_name == 'str': return [node] # type: ignore else: - raise NotImplementedError + raise NotImplementedError('Unexpected node name %r' % node_name) def dedent_docstring(s): From cc890937770c900828197f7413f9f6188b974ab8 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Tue, 10 Oct 2017 16:26:28 +0100 Subject: [PATCH 0221/1814] Treat lists like tuples in AST function get_lvar_namesl --- sphinx/pycode/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 5bee020e4..d488842e9 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -51,7 +51,7 @@ def get_lvar_names(node, self=None): return [node.id] # type: ignore else: raise TypeError('The assignment %r is not instance variable' % node) - elif node_name == 'Tuple': + elif node_name in ('Tuple', 'List'): members = [get_lvar_names(elt) for elt in node.elts] # type: ignore return sum(members, []) elif node_name == 'Attribute': From 61fe8b04cc5d04efc447ec3b9a175f6942c19d48 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 10 Oct 2017 17:59:47 -0400 Subject: [PATCH 0222/1814] Theme: Move body tag into a block Sometimes users might want to override this tag to include custom information such as `id`s e.g: `` Can be done with `{%- block body_tag %}{% endblock %}` --- sphinx/themes/basic/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 56743f27e..b337a977e 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -170,7 +170,7 @@ {%- endblock %} {%- block extrahead %} {% endblock %} - + {%- block body_tag %}{% endblock %} {%- block header %}{% endblock %} {%- block relbar1 %}{{ relbar() }}{% endblock %} From dd91df0be23374eecf3b31c937716bb1cb5d8d6e Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 11 Oct 2017 17:16:15 +0300 Subject: [PATCH 0223/1814] Update classifiers with supported versions --- setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup.py b/setup.py index af21f3938..cec86eed9 100644 --- a/setup.py +++ b/setup.py @@ -225,7 +225,13 @@ setup( 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Framework :: Sphinx', 'Framework :: Sphinx :: Extension', 'Framework :: Sphinx :: Theme', From cd1c7e01dcf49b115be825b86f742f2a10ec152a Mon Sep 17 00:00:00 2001 From: Yoshiki Shibukawa Date: Thu, 12 Oct 2017 23:16:50 +0900 Subject: [PATCH 0224/1814] fix #4063: Sphinx crushes when there are referenced todolist --- CHANGES | 1 + sphinx/ext/todo.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 3e382ef5d..1966e1f07 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,7 @@ Bugs fixed * #4070, #4111: crashes when the warning message contains format strings (again) * #4108: Search word highlighting breaks SVG images * #3692: Unable to build HTML if writing .buildinfo failed +* #4063: Sphinx crashes when labelling directive '.. todolist::' Testing -------- diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 24e9beec1..70974d8c8 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -138,10 +138,10 @@ def process_todo_nodes(app, doctree, fromdocname): for node in doctree.traverse(todolist): if not app.config['todo_include_todos']: - node.replace_self([]) + node.replace_self([nodes.target()]) continue - content = [] + content = [nodes.target()] for todo_info in env.todo_all_todos: # type: ignore para = nodes.paragraph(classes=['todo-source']) From 5fdad7b3a7627f97a2d1c7e81a2400fcd40394db Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Oct 2017 16:10:44 +1100 Subject: [PATCH 0225/1814] Include the exception when logging Without this there is no way to troubleshoot why (read/write)_po fails. --- sphinx/util/i18n.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 218fac163..a8c0bc555 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -67,15 +67,15 @@ class CatalogInfo(LocaleFileInfoBase): with io.open(self.po_path, 'rt', encoding=self.charset) as file_po: try: po = read_po(file_po, locale) - except Exception: - logger.warning('reading error: %s', self.po_path) + except Exception as ex: + logger.warning('reading error: %s, %s', self.po_path, ex) return with io.open(self.mo_path, 'wb') as file_mo: try: write_mo(file_mo, po) - except Exception: - logger.warning('writing error: %s', self.mo_path) + except Exception as ex: + logger.warning('writing error: %s, %s', self.mo_path, ex) def find_catalog(docname, compaction): From 542ca2183782b4a2c3e712f7f70efc1ec5183ac5 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Fri, 13 Oct 2017 13:23:59 +0100 Subject: [PATCH 0226/1814] Improve exception when parsing a Python file fails. --- sphinx/pycode/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index 450ac575b..66544f073 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -100,7 +100,7 @@ class ModuleAnalyzer(object): self.tags = parser.definitions self.tagorder = parser.deforders except Exception as exc: - raise PycodeError('parsing failed: %r' % exc) + raise PycodeError('parsing %r failed: %r' % (self.srcname, exc)) def find_attr_docs(self): # type: () -> Dict[Tuple[unicode, unicode], List[unicode]] From 7d2801e1e9e30f5f0226a1853ecfaa052efad45d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Oct 2017 23:56:53 +1100 Subject: [PATCH 0227/1814] Minor update --- sphinx/util/i18n.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index a8c0bc555..09b53b4a0 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -67,15 +67,15 @@ class CatalogInfo(LocaleFileInfoBase): with io.open(self.po_path, 'rt', encoding=self.charset) as file_po: try: po = read_po(file_po, locale) - except Exception as ex: - logger.warning('reading error: %s, %s', self.po_path, ex) + except Exception as exc: + logger.warning('reading error: %s, %s', self.po_path, exc) return with io.open(self.mo_path, 'wb') as file_mo: try: write_mo(file_mo, po) - except Exception as ex: - logger.warning('writing error: %s, %s', self.mo_path, ex) + except Exception as exc: + logger.warning('writing error: %s, %s', self.mo_path, exc) def find_catalog(docname, compaction): From 11d84b7895b135ce6a6a8e8fdf64ca1e5a8a8cd3 Mon Sep 17 00:00:00 2001 From: Peter Cock Date: Fri, 13 Oct 2017 14:21:13 +0100 Subject: [PATCH 0228/1814] pycode tests for multiple assignment via tuple/list --- tests/test_pycode_parser.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index 0f5208a8b..cfea2ca00 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -96,7 +96,10 @@ def test_complex_assignment(): 'c, d = (1, 1) #: unpack assignment\n' 'e = True #: first assignment\n' 'e = False #: second assignment\n' - 'f = g = None #: multiple assignment at once\n') + 'f = g = None #: multiple assignment at once\n' + '(theta, phi) = (0, 0.5) #: unpack assignment via tuple\n' + '[x, y] = (5, 6) #: unpack assignment via list\n' + ) parser = Parser(source) parser.parse() assert parser.comments == {('', 'b'): 'compound statement', @@ -104,7 +107,12 @@ def test_complex_assignment(): ('', 'd'): 'unpack assignment', ('', 'e'): 'second assignment', ('', 'f'): 'multiple assignment at once', - ('', 'g'): 'multiple assignment at once'} + ('', 'g'): 'multiple assignment at once', + ('', 'theta'): 'unpack assignment via tuple', + ('', 'phi'): 'unpack assignment via tuple', + ('', 'x'): 'unpack assignment via list', + ('', 'y'): 'unpack assignment via list', + } assert parser.definitions == {} From ae3e39a54677c39484e7d7472ade633b578bdebc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Oct 2017 16:10:44 +1100 Subject: [PATCH 0229/1814] Include the exception when logging Without this there is no way to troubleshoot why (read/write)_po fails. --- sphinx/util/i18n.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 218fac163..a8c0bc555 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -67,15 +67,15 @@ class CatalogInfo(LocaleFileInfoBase): with io.open(self.po_path, 'rt', encoding=self.charset) as file_po: try: po = read_po(file_po, locale) - except Exception: - logger.warning('reading error: %s', self.po_path) + except Exception as ex: + logger.warning('reading error: %s, %s', self.po_path, ex) return with io.open(self.mo_path, 'wb') as file_mo: try: write_mo(file_mo, po) - except Exception: - logger.warning('writing error: %s', self.mo_path) + except Exception as ex: + logger.warning('writing error: %s, %s', self.mo_path, ex) def find_catalog(docname, compaction): From 6f2b8a1f557367e57d6d0c45f067f90e00339ef5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Oct 2017 23:56:53 +1100 Subject: [PATCH 0230/1814] Minor update --- sphinx/util/i18n.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index a8c0bc555..09b53b4a0 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -67,15 +67,15 @@ class CatalogInfo(LocaleFileInfoBase): with io.open(self.po_path, 'rt', encoding=self.charset) as file_po: try: po = read_po(file_po, locale) - except Exception as ex: - logger.warning('reading error: %s, %s', self.po_path, ex) + except Exception as exc: + logger.warning('reading error: %s, %s', self.po_path, exc) return with io.open(self.mo_path, 'wb') as file_mo: try: write_mo(file_mo, po) - except Exception as ex: - logger.warning('writing error: %s, %s', self.mo_path, ex) + except Exception as exc: + logger.warning('writing error: %s, %s', self.mo_path, exc) def find_catalog(docname, compaction): From c9bb1b2743e9ae492d43237be17b0176cca2ca68 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 13 Oct 2017 23:00:55 +0900 Subject: [PATCH 0231/1814] Update CHANGES for PR #4147 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 3e382ef5d..030e4c6d2 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Features added * #4112: Don't override the smart_quotes setting if it was already set * #4125: Display reference texts of original and translated passages on i18n warning message +* #4147: Include the exception when logging PO/MO file read/write Bugs fixed ---------- From 8769f388b1631be7789ee55b1005cd7e8fc1a4e0 Mon Sep 17 00:00:00 2001 From: Yoshiki Shibukawa Date: Fri, 13 Oct 2017 23:15:20 +0900 Subject: [PATCH 0232/1814] supress empty span tag --- sphinx/ext/todo.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 70974d8c8..0e5a74720 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -137,11 +137,14 @@ def process_todo_nodes(app, doctree, fromdocname): env.todo_all_todos = [] # type: ignore for node in doctree.traverse(todolist): - if not app.config['todo_include_todos']: - node.replace_self([nodes.target()]) - continue + if node.get('ids'): + content = [nodes.target()] + else: + content = [] - content = [nodes.target()] + if not app.config['todo_include_todos']: + node.replace_self(content) + continue for todo_info in env.todo_all_todos: # type: ignore para = nodes.paragraph(classes=['todo-source']) From 2b1c1e657a9e231a3fdb4f21578e7b2d520fc64f Mon Sep 17 00:00:00 2001 From: Lennart Regebro Date: Thu, 12 Oct 2017 10:41:55 -0400 Subject: [PATCH 0233/1814] Initialize _fieldlist_row_index just like _table_row_index visit_field can be called before visit_field_list if the field list is at the beginning of the document. By initializing _fieldlist_row_index in __init__ this is supported. Closes #4145 --- sphinx/writers/html.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 6dd8bafe5..8d02793e3 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -89,6 +89,7 @@ class HTMLTranslator(BaseTranslator): self.param_separator = '' self.optional_param_level = 0 self._table_row_index = 0 + self._fieldlist_row_index = 0 self.required_params_left = 0 def visit_start_of_file(self, node): From 6e38c574f2a835eac3377f0d8ab646af4738c301 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 16 Oct 2017 10:38:17 +0900 Subject: [PATCH 0234/1814] Update CHANGES for PR #4152 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 030e4c6d2..1ec9054a2 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,7 @@ Bugs fixed * #4070, #4111: crashes when the warning message contains format strings (again) * #4108: Search word highlighting breaks SVG images * #3692: Unable to build HTML if writing .buildinfo failed +* #4152: HTML writer crashes if a field list is placed on top of the document Testing -------- From 327e6f27fb759e3daa1626dbe79b5670e86f78c0 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sun, 15 Oct 2017 19:33:10 -0700 Subject: [PATCH 0235/1814] Rename [wheel] section to [bdist_wheel] as the former is legacy For additional details, see: https://bitbucket.org/pypa/wheel/src/54ddbcc9cec25e1f4d111a142b8bfaa163130a61/wheel/bdist_wheel.py?fileviewer=file-view-default#bdist_wheel.py-119:125 http://pythonwheels.com/ --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 48045a292..edcf7d337 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,7 @@ output_dir = sphinx/locale/ domain = sphinx directory = sphinx/locale/ -[wheel] +[bdist_wheel] universal = 1 [flake8] From c53dc54a305c7aa06e783a352ebf520b6d649c80 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sun, 15 Oct 2017 19:40:10 -0700 Subject: [PATCH 0236/1814] Include license file in the generated wheel package The wheel package format supports including the license file. This is done using the [metadata] section in the setup.cfg file. For additional information on this feature, see: https://wheel.readthedocs.io/en/stable/index.html#including-the-license-in-the-generated-wheel-file --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 48045a292..4d42ee5c1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,6 +23,9 @@ directory = sphinx/locale/ [wheel] universal = 1 +[metadata] +license_file = LICENSE + [flake8] max-line-length = 95 ignore = E116,E241,E251 From d898613aabc85ea06ed00abf389613f3416f908b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 16 Oct 2017 21:03:32 +0900 Subject: [PATCH 0237/1814] Update CHANGES for PR #4140 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index ad6fe5759..051020a83 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,7 @@ Features added * #3972: epub: Sort manifest entries by filename * #4052: viewcode: Sort before highlighting module code * #1448: qthelp: Add new config value; :confval:`qthelp_namespace` +* #4140: html themes: Make body tag inheritable Features removed From 028198bae0a2055807ed4e6e697828d07d6c6426 Mon Sep 17 00:00:00 2001 From: Krassimir Valev Date: Tue, 17 Oct 2017 14:15:00 +0200 Subject: [PATCH 0238/1814] The exit code for 'python -msphinx' is incorrect The exit code was always 0, even if there were warnings and the -W flag was set. --- sphinx/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 9f0a295c6..68844b8a7 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -66,7 +66,7 @@ def main(*args, **kwargs): RemovedInSphinx20Warning, stacklevel=2, ) - build.main(*args, **kwargs) + return build.main(*args, **kwargs) if __name__ == '__main__': From ee24592905d85c16f66e445a654c7b0ace715a6d Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Tue, 17 Oct 2017 12:36:12 -0500 Subject: [PATCH 0239/1814] Typo --- sphinx/util/requests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index 3dc1a30b2..fb8761481 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -109,7 +109,7 @@ def ignore_insecure_warning(**kwargs): def _get_tls_cacert(url, config): # type: (unicode, Config) -> Union[str, bool] - """Get addiotinal CA cert for a specific URL. + """Get additional CA cert for a specific URL. This also returns ``False`` if verification is disabled. And returns ``True`` if additional CA cert not found. From 90279d4cf9d49a723f0cab181b40a34ed5686f6c Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Tue, 17 Oct 2017 20:26:17 -0700 Subject: [PATCH 0240/1814] Enable pip cache in Travis CI Can speed up builds and reduce load on PyPI servers. For more information, see: https://docs.travis-ci.com/user/caching/#pip-cache --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 73fd9c459..1d065b178 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ language: python sudo: false dist: trusty -cache: - directories: - - $HOME/.cache/pip +cache: pip python: - "pypy-5.4.1" - "3.6" From 77e673d08c7bab36cdd42972c2c67f65d36331b6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 18 Oct 2017 21:33:29 +0900 Subject: [PATCH 0241/1814] Fix typo in CHANGES --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 266282fae..40c91af68 100644 --- a/CHANGES +++ b/CHANGES @@ -30,7 +30,7 @@ Bugs fixed * #4108: Search word highlighting breaks SVG images * #3692: Unable to build HTML if writing .buildinfo failed * #4152: HTML writer crashes if a field list is placed on top of the document -* #4063: Sphinx crashes when labelling directive '.. todolist::' +* #4063: Sphinx crashes when labeling directive ``.. todolist::`` Testing -------- From 4fdcae05843cfc1be155620ade9dff10ab3e9853 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 18 Oct 2017 21:35:54 +0900 Subject: [PATCH 0242/1814] Fix #4158: pycode.parser failed to parse starred assignment --- sphinx/pycode/parser.py | 2 ++ tests/test_pycode_parser.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index d488842e9..1191551c4 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -62,6 +62,8 @@ def get_lvar_names(node, self=None): raise TypeError('The assignment %r is not instance variable' % node) elif node_name == 'str': return [node] # type: ignore + elif node_name == 'Starred': + return [node.value.id] # type: ignore else: raise NotImplementedError('Unexpected node name %r' % node_name) diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index cfea2ca00..0ff4752b3 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -9,6 +9,9 @@ :license: BSD, see LICENSE for details. """ +import pytest +from six import PY2 + from sphinx.pycode.parser import Parser @@ -116,6 +119,18 @@ def test_complex_assignment(): assert parser.definitions == {} +@pytest.mark.skipif(PY2, reason='tests for py3 syntax') +def test_complex_assignment_py3(): + source = 'a, *b, c = (1, 2, 3, 4) #: unpack assignment\n' + parser = Parser(source) + parser.parse() + assert parser.comments == {('', 'a'): 'unpack assignment', + ('', 'b'): 'unpack assignment', + ('', 'c'): 'unpack assignment', + } + assert parser.definitions == {} + + def test_obj_assignment(): source = ('obj = SomeObject() #: some object\n' 'obj.attr = 1 #: attr1\n' From 1dfe978fcb60c4ba4c30914f5c2f4916123d91b3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 19 Oct 2017 00:10:46 +0900 Subject: [PATCH 0243/1814] Support more complex starred asssignment case --- sphinx/pycode/parser.py | 13 +++++++++---- tests/test_pycode_parser.py | 7 ++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 1191551c4..a22891fd7 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -52,8 +52,13 @@ def get_lvar_names(node, self=None): else: raise TypeError('The assignment %r is not instance variable' % node) elif node_name in ('Tuple', 'List'): - members = [get_lvar_names(elt) for elt in node.elts] # type: ignore - return sum(members, []) + members = [] + for elt in node.elts: + try: + members.extend(get_lvar_names(elt, self)) + except TypeError: + pass + return members elif node_name == 'Attribute': if node.value.__class__.__name__ == 'Name' and self and node.value.id == self_id: # type: ignore # NOQA # instance variable @@ -63,7 +68,7 @@ def get_lvar_names(node, self=None): elif node_name == 'str': return [node] # type: ignore elif node_name == 'Starred': - return [node.value.id] # type: ignore + return get_lvar_names(node.value, self) # type: ignore else: raise NotImplementedError('Unexpected node name %r' % node_name) @@ -281,7 +286,7 @@ class VariableCommentPicker(ast.NodeVisitor): try: varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], []) # type: ignore # NOQA current_line = self.get_line(node.lineno) - except TypeError: + except TypeError as exc: return # this assignment is not new definition! # check comments after assignment diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index 0ff4752b3..d794376fa 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -121,12 +121,17 @@ def test_complex_assignment(): @pytest.mark.skipif(PY2, reason='tests for py3 syntax') def test_complex_assignment_py3(): - source = 'a, *b, c = (1, 2, 3, 4) #: unpack assignment\n' + source = ('a, *b, c = (1, 2, 3, 4) #: unpack assignment\n' + 'd, *self.attr = (5, 6, 7) #: unpack assignment2\n' + 'e, *f[0] = (8, 9, 0) #: unpack assignment3\n' + ) parser = Parser(source) parser.parse() assert parser.comments == {('', 'a'): 'unpack assignment', ('', 'b'): 'unpack assignment', ('', 'c'): 'unpack assignment', + ('', 'd'): 'unpack assignment2', + ('', 'e'): 'unpack assignment3', } assert parser.definitions == {} From 7fc43d336574a305cd119981256e93d7a4a2ce7e Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Thu, 5 Oct 2017 12:41:05 -0400 Subject: [PATCH 0244/1814] use numfig for numbering equations by section rather than page --- CHANGES | 1 + doc/ext/math.rst | 8 ++++++++ sphinx/ext/imgmath.py | 4 +++- sphinx/ext/jsmath.py | 4 +++- sphinx/ext/mathbase.py | 24 +++++++++++++++++++++++- sphinx/ext/mathjax.py | 4 +++- sphinx/ext/pngmath.py | 4 +++- 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 957881a53..6e203777f 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,7 @@ Features added * #4052: viewcode: Sort before highlighting module code * #1448: qthelp: Add new config value; :confval:`qthelp_namespace` * #4140: html themes: Make body tag inheritable +* #3991, #4080: Add :confval:`math_numfig` for equation numbering by section Features removed diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 54d77ed6c..fe7b85c83 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -44,6 +44,14 @@ or use Python raw strings (``r"raw"``). Example: ``'Eq.{number}'`` is rendered as ``Eq.10`` +.. confval:: math_numfig + + If ``True``, displayed math equations are numbered across pages using numfig. + The :confval:`numfig` config value must be enabled and + :confval:`numfig_secnum_depth` is respected. The ``:eq:`` role must be used + to refererence these equation numbers, not the ``:numref:`` role. + Default is ``False``. + :mod:`.mathbase` defines these new markup elements: .. rst:role:: math diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 8bf4fcad5..04d6b708a 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -30,6 +30,7 @@ from sphinx.util.png import read_png_depth, write_png_depth from sphinx.util.osutil import ensuredir, ENOENT, cd from sphinx.util.pycompat import sys_encoding from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath +from sphinx.ext.mathbase import get_node_equation_number if False: # For type annotation @@ -333,7 +334,8 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - self.body.append('(%s)' % node['number']) + number = get_node_equation_number(self.builder.env, node) + self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') if fname is None: diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index dc57c13c6..978e3f3d6 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -16,6 +16,7 @@ import sphinx from sphinx.locale import _ from sphinx.application import ExtensionError from sphinx.ext.mathbase import setup_math as mathbase_setup +from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): @@ -35,7 +36,8 @@ def html_visit_displaymath(self, node): if i == 0: # necessary to e.g. set the id property correctly if node['number']: - self.body.append('(%s)' % node['number']) + number = get_node_equation_number(self.builder.env, 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')) diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index f83ca5da8..31b33fe2a 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -84,6 +84,13 @@ class MathDomain(Domain): newnode['target'] = target return newnode else: + if env.config.math_numfig and env.config.numfig: + if docname in env.toc_fignumbers: + id = 'equation-' + target + number = env.toc_fignumbers[docname]['displaymath'].get(id, ()) + number = '.'.join(map(str, number)) + else: + number = '' try: eqref_format = env.config.math_eqref_format or "({number})" title = nodes.Text(eqref_format.format(number=number)) @@ -126,6 +133,20 @@ class MathDomain(Domain): return len(targets) + 1 +def get_node_equation_number(env, node): + if env.config.math_numfig and env.config.numfig: + docname = node['docname'] + if docname in env.toc_fignumbers: + id = node['ids'][0] + number = env.toc_fignumbers[docname]['displaymath'].get(id, ()) + number = '.'.join(map(str, number)) + else: + number = '' + else: + number = node['number'] + return number + + def wrap_displaymath(math, label, numbering): # type: (unicode, unicode, bool) -> unicode def is_equation(part): @@ -341,6 +362,7 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): # type: (Sphinx, Tuple[Callable, Any], Tuple[Callable, Any]) -> None app.add_config_value('math_number_all', False, 'env') app.add_config_value('math_eqref_format', None, 'env', string_classes) + app.add_config_value('math_numfig', False, 'env') app.add_domain(MathDomain) app.add_node(math, override=True, latex=(latex_visit_math, None), @@ -348,7 +370,7 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): man=(man_visit_math, None), texinfo=(texinfo_visit_math, None), html=htmlinlinevisitors) - app.add_node(displaymath, + app.add_enumerable_node(displaymath, 'displaymath', latex=(latex_visit_displaymath, None), text=(text_visit_displaymath, None), man=(man_visit_displaymath, man_depart_displaymath), diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index f25f91e74..aff5c103b 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -17,6 +17,7 @@ import sphinx from sphinx.locale import _ from sphinx.errors import ExtensionError from sphinx.ext.mathbase import setup_math as mathbase_setup +from sphinx.ext.mathbase import get_node_equation_number def html_visit_math(self, node): @@ -36,7 +37,8 @@ def html_visit_displaymath(self, node): # necessary to e.g. set the id property correctly if node['number']: - self.body.append('(%s)' % node['number']) + number = get_node_equation_number(self.builder.env, node) + self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') self.body.append(self.builder.config.mathjax_display[0]) diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py index 85010b799..968139f15 100644 --- a/sphinx/ext/pngmath.py +++ b/sphinx/ext/pngmath.py @@ -30,6 +30,7 @@ from sphinx.util.png import read_png_depth, write_png_depth from sphinx.util.osutil import ensuredir, ENOENT, cd from sphinx.util.pycompat import sys_encoding from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath +from sphinx.ext.mathbase import get_node_equation_number if False: # For type annotation @@ -242,7 +243,8 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - self.body.append('(%s)' % node['number']) + number = get_node_equation_number(self.builder.env, node) + self.body.append('(%s)' % number) if fname is None: # something failed -- use text-only as a bad substitute self.body.append('%s

\n' % From 783cff44b388faa15f277fe29c9a26e1a9e63700 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Thu, 5 Oct 2017 12:41:22 -0400 Subject: [PATCH 0245/1814] add tests for math_numfig --- tests/roots/test-ext-math/index.rst | 2 ++ tests/roots/test-ext-math/page.rst | 9 ++++++ tests/test_ext_math.py | 49 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/roots/test-ext-math/page.rst diff --git a/tests/roots/test-ext-math/index.rst b/tests/roots/test-ext-math/index.rst index 9d16824f6..4237b73ff 100644 --- a/tests/roots/test-ext-math/index.rst +++ b/tests/roots/test-ext-math/index.rst @@ -2,8 +2,10 @@ Test Math ========= .. toctree:: + :numbered: 1 math + page .. math:: a^2+b^2=c^2 diff --git a/tests/roots/test-ext-math/page.rst b/tests/roots/test-ext-math/page.rst new file mode 100644 index 000000000..ef8040910 --- /dev/null +++ b/tests/roots/test-ext-math/page.rst @@ -0,0 +1,9 @@ +Test multiple pages +=================== + +.. math:: + :label: bar + + a = b + 1 + +Referencing equations :eq:`foo` and :eq:`bar`. diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index 92501a3db..1ff34cf79 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -139,3 +139,52 @@ def test_math_eqref_format_latex(app, status, warning): content = (app.outdir / 'test.tex').text() macro = r'Referencing equation Eq.\\ref{equation:math:foo}.' assert re.search(macro, content, re.S) + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.mathjax'], + 'numfig': True, + 'math_numfig': True}) +def test_mathjax_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'math.html').text() + html = ('
\n' + '(1.2)') + assert html in content + html = ('

Referencing equation (1.1).

') + assert html in content + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.jsmath'], + 'jsmath_path': 'dummy.js', + 'numfig': True, + 'math_numfig': True}) +def test_jsmath_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'math.html').text() + html = '(1.2)Referencing equation (1.1).

') + assert html in content + + +@pytest.mark.sphinx('html', testroot='ext-math', + confoverrides={'extensions': ['sphinx.ext.imgmath'], + 'numfig': True, + 'numfig_secnum_depth': 0, + 'math_numfig': True}) +def test_imgmath_numfig_html(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'page.html').text() + html = '(3)Referencing equations (1) and ' + '(3).

') + assert html in content From fa6dd3485d4cd23127215668d888151b38a87989 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Wed, 18 Oct 2017 17:38:13 -0400 Subject: [PATCH 0246/1814] fix indentation --- sphinx/ext/mathbase.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index 31b33fe2a..313f72bd4 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -371,11 +371,11 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): texinfo=(texinfo_visit_math, None), html=htmlinlinevisitors) app.add_enumerable_node(displaymath, 'displaymath', - latex=(latex_visit_displaymath, None), - text=(text_visit_displaymath, None), - man=(man_visit_displaymath, man_depart_displaymath), - texinfo=(texinfo_visit_displaymath, texinfo_depart_displaymath), - html=htmldisplayvisitors) + latex=(latex_visit_displaymath, None), + text=(text_visit_displaymath, None), + man=(man_visit_displaymath, man_depart_displaymath), + texinfo=(texinfo_visit_displaymath, texinfo_depart_displaymath), + html=htmldisplayvisitors) app.add_node(eqref, latex=(latex_visit_eqref, None)) app.add_role('math', math_role) app.add_role('eq', EqXRefRole(warn_dangling=True)) From dc0c547b81628b958d6855e502f2bbed61ef3d85 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 19 Oct 2017 10:11:20 +0900 Subject: [PATCH 0247/1814] Fix flake8 and mypy violations --- sphinx/pycode/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index a22891fd7..28da09c78 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -53,7 +53,7 @@ def get_lvar_names(node, self=None): raise TypeError('The assignment %r is not instance variable' % node) elif node_name in ('Tuple', 'List'): members = [] - for elt in node.elts: + for elt in node.elts: # type: ignore try: members.extend(get_lvar_names(elt, self)) except TypeError: @@ -286,7 +286,7 @@ class VariableCommentPicker(ast.NodeVisitor): try: varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], []) # type: ignore # NOQA current_line = self.get_line(node.lineno) - except TypeError as exc: + except TypeError: return # this assignment is not new definition! # check comments after assignment From 08f6f7ba4d1fe610e530a6e0ec11fd474160ab6a Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sat, 14 Oct 2017 13:56:07 -0700 Subject: [PATCH 0248/1814] fix comment typo --- tests/test_writer_latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_writer_latex.py b/tests/test_writer_latex.py index 228161886..b026f8d17 100644 --- a/tests/test_writer_latex.py +++ b/tests/test_writer_latex.py @@ -27,7 +27,7 @@ def test_rstdim_to_latexdim(): assert rstdim_to_latexdim('30%') == '0.300\\linewidth' assert rstdim_to_latexdim('160') == '160\\sphinxpxdimen' - # flaot values + # float values assert rstdim_to_latexdim('160.0em') == '160.0em' assert rstdim_to_latexdim('.5em') == '.5em' From ed4949e00008311587dc57a3e84e203920f7af00 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sun, 15 Oct 2017 17:15:36 -0700 Subject: [PATCH 0249/1814] Closes #1020: ext.todo todolist not linking to the page in pdflatex --- AUTHORS | 1 + CHANGES | 1 + sphinx/ext/todo.py | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 580feeb32..13ce2df9f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,6 +29,7 @@ Other contributors, listed alphabetically, are: * Kevin Dunn -- MathJax extension * Josip Dzolonga -- coverage builder * Buck Evan -- dummy builder +* Matthew Fernandez -- todo extension fix * Hernan Grecco -- search improvements * Horst Gutmann -- internationalization support * Martin Hans -- autodoc improvements diff --git a/CHANGES b/CHANGES index 40c91af68..5f381b608 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,7 @@ Bugs fixed * #3692: Unable to build HTML if writing .buildinfo failed * #4152: HTML writer crashes if a field list is placed on top of the document * #4063: Sphinx crashes when labeling directive ``.. todolist::`` +* #1020: ext.todo todolist not linking to the page in pdflatex Testing -------- diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 0e5a74720..a58422793 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -69,6 +69,8 @@ class Todo(BaseAdmonition): env = self.state.document.settings.env targetid = 'index-%s' % env.new_serialno('index') + # Stash the target to be retrieved later in latex_visit_todo_node. + todo['targetref'] = '%s:%s' % (env.docname, targetid) targetnode = nodes.target('', '', ids=[targetid]) return [targetnode, todo] @@ -173,8 +175,12 @@ def process_todo_nodes(app, doctree, fromdocname): para += newnode para += nodes.Text(desc2, desc2) - # (Recursively) resolve references in the todo content todo_entry = todo_info['todo'] + # Remove targetref from the (copied) node to avoid emitting a + # duplicate label of the original entry when we walk this node. + del todo_entry['targetref'] + + # (Recursively) resolve references in the todo content env.resolve_references(todo_entry, todo_info['docname'], app.builder) @@ -216,7 +222,13 @@ def depart_todo_node(self, node): def latex_visit_todo_node(self, node): # type: (nodes.NodeVisitor, todo_node) -> None title = node.pop(0).astext().translate(tex_escape_map) - self.body.append(u'\n\\begin{sphinxadmonition}{note}{%s:}' % title) + self.body.append(u'\n\\begin{sphinxadmonition}{note}{') + # If this is the original todo node, emit a label that will be referenced by + # a hyperref in the todolist. + target = node.get('targetref') + if target is not None: + self.body.append(u'\\label{%s}' % target) + self.body.append('%s:}' % title) def latex_depart_todo_node(self, node): From 6553b2ed32e6ccf50ae852d470fd1684d0628941 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sat, 14 Oct 2017 14:34:48 -0700 Subject: [PATCH 0250/1814] add a test that confirms #1020 --- tests/roots/test-ext-todo/conf.py | 5 +++++ tests/test_ext_todo.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/roots/test-ext-todo/conf.py b/tests/roots/test-ext-todo/conf.py index c67a86c5a..5d5619245 100644 --- a/tests/roots/test-ext-todo/conf.py +++ b/tests/roots/test-ext-todo/conf.py @@ -2,3 +2,8 @@ extensions = ['sphinx.ext.todo'] master_doc = 'index' + +latex_documents = [ + (master_doc, 'TodoTests.tex', 'Todo Tests Documentation', + 'Robin Banks', 'manual'), +] diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 77d657adc..4f01a07ab 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -84,3 +84,31 @@ def test_todo_not_included(app, status, warning): # check handled event assert len(todos) == 2 assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar']) + +@pytest.mark.sphinx('latex', testroot='ext-todo', freshenv=True, + confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True}) +def test_todo_valid_link(app, status, warning): + """ + Test that the inserted "original entry" links for todo items have a target + that exists in the LaTeX output. The target was previously incorrectly + omitted (GitHub issue #1020). + """ + + # Ensure the LaTeX output is built. + app.builder.build_all() + + content = (app.outdir / 'TodoTests.tex').text() + + # Look for the link to foo. We could equally well look for the link to bar. + link = r'\{\\hyperref\[\\detokenize\{(.*?foo.*?)}]\{\\sphinxcrossref{' \ + r'\\sphinxstyleemphasis{original entry}}}}' + m = re.findall(link, content) + assert len(m) == 1 + target = m[0] + + # Look for the targets of this link. + labels = [m for m in re.findall(r'\\label\{([^}]*)}', content) + if m == target] + + # If everything is correct we should have exactly one target. + assert len(labels) == 1 From 77c5aaaa973dfaab652197ae345f17f904a943fe Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 19 Oct 2017 09:23:41 +0200 Subject: [PATCH 0251/1814] Fix #4134: [doc] docutils.conf is not documented explicitly --- CHANGES | 1 + doc/config.rst | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 40c91af68..6ebe2c50a 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,7 @@ Bugs fixed * #3692: Unable to build HTML if writing .buildinfo failed * #4152: HTML writer crashes if a field list is placed on top of the document * #4063: Sphinx crashes when labeling directive ``.. todolist::`` +* #4134: [doc] :file:`docutils.conf` is not documented explicitly Testing -------- diff --git a/doc/config.rst b/doc/config.rst index a094195e9..160cc3c5c 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -9,8 +9,20 @@ The build configuration file :synopsis: Build configuration file. The :term:`configuration directory` must contain a file named :file:`conf.py`. -This file (containing Python code) is called the "build configuration file" and -contains all configuration needed to customize Sphinx input and output behavior. +This file (containing Python code) is called the "build configuration file" +and contains (almost) all configuration needed to customize Sphinx input +and output behavior. + + An optional file `docutils.conf`_ can be added to the configuration + directory to adjust `Docutils`_ configuration if not otherwise overriden or + set by Sphinx; this applies in particular to the `Docutils smart_quotes + setting`_. + + .. _`docutils`: http://docutils.sourceforge.net/ + + .. _`docutils.conf`: http://docutils.sourceforge.net/docs/user/config.html + + .. _`Docutils smart_quotes setting`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes The configuration file is executed as Python code at build time (using :func:`execfile`, and with the current directory set to its containing From 6a897af1d9e22c0f933edeee7714114a03ff2b61 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 19 Oct 2017 09:56:14 +0200 Subject: [PATCH 0252/1814] Clarify docs about ``html_use_smartypants`` deprecation --- doc/config.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 160cc3c5c..3dbdbd1a7 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -781,8 +781,8 @@ that use Sphinx's HTMLWriter class. entities. Default: ``True``. .. deprecated:: 1.6 - Use the `smart_quotes option`_ in the Docutils configuration file - (``docutils.conf``) instead. + To disable or customize smart quotes, use the Docutils configuration file + (``docutils.conf``) instead to set there its `smart_quotes option`_. .. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes From 5dbfc43ddada57a3b7bf6ee4cf1e8e07a6a58db2 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 19 Oct 2017 10:00:08 +0200 Subject: [PATCH 0253/1814] Make clearer that Sphinx applies Smart quotes by default modified: doc/config.rst --- doc/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/config.rst b/doc/config.rst index 3dbdbd1a7..e96c075e9 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -16,7 +16,7 @@ and output behavior. An optional file `docutils.conf`_ can be added to the configuration directory to adjust `Docutils`_ configuration if not otherwise overriden or set by Sphinx; this applies in particular to the `Docutils smart_quotes - setting`_. + setting`_ (Note that Sphinx applies smart quotes transform by default.) .. _`docutils`: http://docutils.sourceforge.net/ From 7aab8c3b07653cceeea534bf536eb8bee2bb7f61 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 16 Oct 2017 22:33:38 +0900 Subject: [PATCH 0254/1814] Fix #4156: failed to parse class comment --- sphinx/pycode/parser.py | 1 + tests/test_pycode_parser.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index d488842e9..9b5cb13c9 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -336,6 +336,7 @@ class VariableCommentPicker(ast.NodeVisitor): self.current_classes.append(node.name) self.add_entry(node.name) self.context.append(node.name) + self.previous = node for child in node.body: self.visit(child) self.context.pop() diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py index cfea2ca00..8b7a945d4 100644 --- a/tests/test_pycode_parser.py +++ b/tests/test_pycode_parser.py @@ -226,6 +226,18 @@ def test_nested_class(): 'Foo.Bar.attr2': 3} +def test_class_comment(): + source = ('import logging\n' + 'logger = logging.getLogger(__name__)\n' + '\n' + 'class Foo(object):\n' + ' """Bar"""\n') + parser = Parser(source) + parser.parse() + assert parser.comments == {} + assert parser.definitions == {'Foo': ('class', 4, 5)} + + def test_comment_picker_multiline_string(): source = ('class Foo(object):\n' ' a = None\n' From 8c814ed2f3fe912a4f8015e13329dcabc4879642 Mon Sep 17 00:00:00 2001 From: fyears Date: Fri, 20 Oct 2017 11:57:02 +0800 Subject: [PATCH 0255/1814] improve zh search with jieba --- sphinx/search/zh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index 5d4f87b88..5ef4b5888 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -240,7 +240,7 @@ class SearchChinese(SearchLanguage): if JIEBA: dict_path = options.get('dict') if dict_path and os.path.isfile(dict_path): - jieba.set_dictionary(dict_path) + jieba.load_userdict(dict_path) self.stemmer = get_stemmer() From 44489029776b587ac1494df31d382cf8e595f2fa Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 01:42:53 +0900 Subject: [PATCH 0256/1814] Fix #4169: Chinese language doesn't trigger Chinese search automatically --- CHANGES | 1 + sphinx/search/__init__.py | 5 +++++ tests/test_search.py | 12 ++++++++++++ 3 files changed, 18 insertions(+) diff --git a/CHANGES b/CHANGES index 40c91af68..4e37d3b45 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,7 @@ Bugs fixed * #3692: Unable to build HTML if writing .buildinfo failed * #4152: HTML writer crashes if a field list is placed on top of the document * #4063: Sphinx crashes when labeling directive ``.. todolist::`` +* #4169: Chinese language doesn't trigger Chinese search automatically Testing -------- diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index ef74d3b71..17560213d 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -265,6 +265,11 @@ class IndexBuilder(object): # objtype index -> (domain, type, objname (localized)) lang_class = languages.get(lang) # type: Type[SearchLanguage] # add language-specific SearchLanguage instance + + # fallback; try again with language-code + if lang_class is None and '_' in lang: + lang_class = languages.get(lang.split('_')[0]) + if lang_class is None: self.lang = SearchEnglish(options) # type: SearchLanguage elif isinstance(lang_class, str): diff --git a/tests/test_search.py b/tests/test_search.py index 21c0badb7..f1825dfa4 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -228,3 +228,15 @@ def test_IndexBuilder(): } assert index._objtypes == {('dummy', 'objtype'): 0} assert index._objnames == {0: ('dummy', 'objtype', 'objtype')} + + +def test_IndexBuilder_lookup(): + env = DummyEnvironment('1.0', {}) + + # zh + index = IndexBuilder(env, 'zh', {}, None) + assert index.lang.lang == 'zh' + + # zh_CN + index = IndexBuilder(env, 'zh_CN', {}, None) + assert index.lang.lang == 'zh' From 53ed3342baa29006ea13cc7d46b7a5e940fc9bda Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 01:48:02 +0900 Subject: [PATCH 0257/1814] Update CHANGES for PR #4168 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 957881a53..b584105e7 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,7 @@ Features added * #4052: viewcode: Sort before highlighting module code * #1448: qthelp: Add new config value; :confval:`qthelp_namespace` * #4140: html themes: Make body tag inheritable +* #4168: improve zh search with jieba Features removed From 05516a61c82ed29deceeda503aa61afcaa87624e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 13:44:36 +0900 Subject: [PATCH 0258/1814] Fix mypy violation --- sphinx/ext/intersphinx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index d018603e2..ad50542a3 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -217,7 +217,7 @@ def load_mappings(app): if isinstance(value, (list, tuple)): # new format - name, (uri, inv) = key, value # type: ignore + name, (uri, inv) = key, value if not isinstance(name, string_types): logger.warning('intersphinx identifier %r is not string. Ignored', name) continue From 67981527a18e25a2aaf061cc470268b1074d235e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 13:48:42 +0900 Subject: [PATCH 0259/1814] Fix mypy violation --- sphinx/pycode/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index f9644c38e..7460dcfce 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -284,7 +284,7 @@ class VariableCommentPicker(ast.NodeVisitor): # type: (ast.Assign) -> None """Handles Assign node and pick up a variable comment.""" try: - varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], []) # type: ignore # NOQA + varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], []) current_line = self.get_line(node.lineno) except TypeError: return # this assignment is not new definition! From a4b7927a29cb0b38c00c7e83c2130cb426105bfa Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 20 Oct 2017 23:18:46 -0700 Subject: [PATCH 0260/1814] quickstart: fix return type of term_decode term_decode is documented as `(unicode) -> unicode`, but actually: * Accepts `bytes` arguments, despite not being documented to * Returns `bytes` when it shouldn't This is extracted from the more controversial #3584 --- sphinx/cmd/quickstart.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index ac0859c31..af0333d65 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -138,25 +138,25 @@ def ok(x): def term_decode(text): - # type: (unicode) -> unicode + # type: (Union[bytes,unicode]) -> unicode if isinstance(text, text_type): return text - # for Python 2.x, try to get a Unicode string out of it - if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: - return text - + # Use the known encoding, if possible if TERM_ENCODING: - text = text.decode(TERM_ENCODING) - else: - print(turquoise('* Note: non-ASCII characters entered ' - 'and terminal encoding unknown -- assuming ' - 'UTF-8 or Latin-1.')) - try: - text = text.decode('utf-8') - except UnicodeDecodeError: - text = text.decode('latin1') - return text + return text.decode(TERM_ENCODING) + + # If ascii is safe, use it with no warning + if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: + return text.decode('ascii') + + print(turquoise('* Note: non-ASCII characters entered ' + 'and terminal encoding unknown -- assuming ' + 'UTF-8 or Latin-1.')) + try: + return text.decode('utf-8') + except UnicodeDecodeError: + return text.decode('latin1') def do_prompt(d, key, text, default=None, validator=nonempty): From 58beeed235e5dddc7b040db03daa1a7fcc178d23 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Fri, 20 Oct 2017 23:53:33 -0700 Subject: [PATCH 0261/1814] fixup Warning and missing typing function --- sphinx/cmd/quickstart.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index af0333d65..ea28f4bd3 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -44,7 +44,7 @@ from sphinx.util import texescape if False: # For type annotation - from typing import Any, Callable, Dict, List, Pattern # NOQA + from typing import Any, Callable, Dict, List, Pattern, Union # NOQA TERM_ENCODING = getattr(sys.stdin, 'encoding', None) @@ -149,7 +149,7 @@ def term_decode(text): # If ascii is safe, use it with no warning if text.decode('ascii', 'replace').encode('ascii', 'replace') == text: return text.decode('ascii') - + print(turquoise('* Note: non-ASCII characters entered ' 'and terminal encoding unknown -- assuming ' 'UTF-8 or Latin-1.')) From a5f6e97ac45726dcad9dd267279b04d9539e7793 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 16:22:27 +0900 Subject: [PATCH 0262/1814] Revert "Default SPHINXBUILD to 'python -msphinx' instead of 'sphinx-build'." This reverts commit 0832aa73ab64d8cf5accbe4a5bbeaeedb7b46a52. --- sphinx/templates/quickstart/Makefile.new_t | 2 +- sphinx/templates/quickstart/Makefile_t | 2 +- sphinx/templates/quickstart/make.bat.new_t | 10 +++++----- sphinx/templates/quickstart/make.bat_t | 23 +++++++++++++++------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/sphinx/templates/quickstart/Makefile.new_t b/sphinx/templates/quickstart/Makefile.new_t index bba767a4c..c7cd62dda 100644 --- a/sphinx/templates/quickstart/Makefile.new_t +++ b/sphinx/templates/quickstart/Makefile.new_t @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = python -msphinx +SPHINXBUILD = sphinx-build SPHINXPROJ = {{ project_fn }} SOURCEDIR = {{ rsrcdir }} BUILDDIR = {{ rbuilddir }} diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index fdcf05691..5505f23f5 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -3,7 +3,7 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = python -msphinx +SPHINXBUILD = sphinx-build PAPER = BUILDDIR = {{ rbuilddir }} diff --git a/sphinx/templates/quickstart/make.bat.new_t b/sphinx/templates/quickstart/make.bat.new_t index a52951ebb..e49ffbe78 100644 --- a/sphinx/templates/quickstart/make.bat.new_t +++ b/sphinx/templates/quickstart/make.bat.new_t @@ -5,7 +5,7 @@ pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=python -msphinx + set SPHINXBUILD=sphinx-build ) set SOURCEDIR={{ rsrcdir }} set BUILDDIR={{ rbuilddir }} @@ -16,10 +16,10 @@ if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. - echo.The Sphinx module was not found. Make sure you have Sphinx installed, - echo.then set the SPHINXBUILD environment variable to point to the full - echo.path of the 'sphinx-build' executable. Alternatively you may add the - echo.Sphinx directory to PATH. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 03ae9d423..8438b5f7e 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -5,7 +5,7 @@ REM Command file for Sphinx documentation pushd %~dp0 if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=python -msphinx + set SPHINXBUILD=sphinx-build ) set BUILDDIR={{ rbuilddir }} set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% {{ rsrcdir }} @@ -52,20 +52,29 @@ if "%1" == "clean" ( ) -REM Check if sphinx-build is available +REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL -if errorlevel 1 ( +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( echo. - echo.The Sphinx module was not found. Make sure you have Sphinx installed, - echo.then set the SPHINXBUILD environment variable to point to the full - echo.path of the 'sphinx-build' executable. Alternatively you may add the - echo.Sphinx directory to PATH. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) +:sphinx_ok + if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html From b8b4d9b1870e8e61408daf3d3455ed3da39cefb2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 16:23:38 +0900 Subject: [PATCH 0263/1814] Update CHANGES for #3965 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 97a61c5d5..1ff3c8b34 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ Bugs fixed * #4134: [doc] :file:`docutils.conf` is not documented explicitly * #4169: Chinese language doesn't trigger Chinese search automatically * #1020: ext.todo todolist not linking to the page in pdflatex +* #3965: New quickstart generates wrong SPHINXBUILD in Makefile Testing -------- From 943cd788fc248c32a6f8b8296e2471b5b0e521e6 Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Thu, 28 Sep 2017 00:16:40 +0300 Subject: [PATCH 0264/1814] Make it easier to override variables in Makefiles generated by quickstart Refs #3965. --- sphinx/templates/quickstart/Makefile_t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 5505f23f5..4639a982b 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -2,9 +2,9 @@ # # You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +PAPER ?= BUILDDIR = {{ rbuilddir }} # Internal variables. From ffad4f08c7aa81f230ee6cc6205c80503bc25040 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 21 Oct 2017 21:21:37 +0900 Subject: [PATCH 0265/1814] Fix #3739: ``:module:`` option is ignored at content of pyobjects --- CHANGES | 1 + sphinx/domains/python.py | 10 ++++++++ tests/roots/test-domain-py/module_option.rst | 25 ++++++++++++++++++++ tests/test_domain_py.py | 9 +++++++ 4 files changed, 45 insertions(+) create mode 100644 tests/roots/test-domain-py/module_option.rst diff --git a/CHANGES b/CHANGES index 1ff3c8b34..139580a3e 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,7 @@ Bugs fixed * #4169: Chinese language doesn't trigger Chinese search automatically * #1020: ext.todo todolist not linking to the page in pdflatex * #3965: New quickstart generates wrong SPHINXBUILD in Makefile +* #3739: ``:module:`` option is ignored at content of pyobjects Testing -------- diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index eb6fe76cb..6aa00a8b0 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -348,6 +348,10 @@ class PyObject(ObjectDescription): if self.allow_nesting: classes = self.env.ref_context.setdefault('py:classes', []) classes.append(prefix) + if 'module' in self.options: + modules = self.env.ref_context.setdefault('py:modules', []) + modules.append(self.env.ref_context.get('py:module')) + self.env.ref_context['py:module'] = self.options['module'] def after_content(self): # type: () -> None @@ -368,6 +372,12 @@ class PyObject(ObjectDescription): pass self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0 else None) + if 'module' in self.options: + modules = self.env.ref_context.setdefault('py:modules', []) + if modules: + self.env.ref_context['py:module'] = modules.pop() + else: + self.env.ref_context.pop('py:module') class PyModulelevel(PyObject): diff --git a/tests/roots/test-domain-py/module_option.rst b/tests/roots/test-domain-py/module_option.rst new file mode 100644 index 000000000..1dec2ce0c --- /dev/null +++ b/tests/roots/test-domain-py/module_option.rst @@ -0,0 +1,25 @@ +module_option +============= + +.. py:class:: B + :module: test.extra + + This is also a test. + + + .. py:method:: B.baz() + :module: test.extra + + Does something similar to :meth:`foo`. + + + .. py:method:: B.foo() + :module: test.extra + + Does something. + + + .. py:method:: B.test() + :module: test.extra + + Does something completely unrelated to :meth:`foo` diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 28743f9e1..5596950df 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -115,6 +115,15 @@ def test_domain_py_xrefs(app, status, warning): assert_refnode(refnodes[10], False, False, 'float', 'obj') assert len(refnodes) == 11 + doctree = app.env.get_doctree('module_option') + refnodes = list(doctree.traverse(addnodes.pending_xref)) + print(refnodes) + print(refnodes[0]) + print(refnodes[1]) + assert_refnode(refnodes[0], 'test.extra', 'B', 'foo', 'meth') + assert_refnode(refnodes[1], 'test.extra', 'B', 'foo', 'meth') + assert len(refnodes) == 2 + @pytest.mark.sphinx('dummy', testroot='domain-py') def test_domain_py_objects(app, status, warning): From b78f3090a05f38fb3beb14f7e716f1b26a2ff253 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 Oct 2017 15:12:31 +0900 Subject: [PATCH 0266/1814] HTML themes can set up default sidebars through ``theme.conf`` --- CHANGES | 1 + doc/config.rst | 5 +++-- doc/theming.rst | 7 +++++++ sphinx/builders/html.py | 10 +++++++++- sphinx/templates/quickstart/conf.py_t | 9 +-------- sphinx/themes/basic/theme.conf | 1 + tests/roots/test-basic/index.rst | 3 +++ .../test_theme/test-theme/theme.conf | 1 + tests/test_build_html.py | 18 ++++++++++++++++++ tests/test_theming.py | 12 ++++++++++++ 10 files changed, 56 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index a958d185d..e8867b45c 100644 --- a/CHANGES +++ b/CHANGES @@ -38,6 +38,7 @@ Features added * #1448: qthelp: Add new config value; :confval:`qthelp_namespace` * #4140: html themes: Make body tag inheritable * #4168: improve zh search with jieba +* HTML themes can set up default sidebars through ``theme.conf`` Features removed diff --git a/doc/config.rst b/doc/config.rst index f23c22e00..b2cac41f0 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -820,8 +820,9 @@ that use Sphinx's HTMLWriter class. to include. If all or some of the default sidebars are to be included, they must be put into this list as well. - The default sidebars (for documents that don't match any pattern) are: - ``['localtoc.html', 'relations.html', 'sourcelink.html', + The default sidebars (for documents that don't match any pattern) are + defined by theme itself. Builtin themes are using these templates by + default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html']``. * If a value is a single string, it specifies a custom sidebar to be added diff --git a/doc/theming.rst b/doc/theming.rst index 01f72fde9..34bca9607 100644 --- a/doc/theming.rst +++ b/doc/theming.rst @@ -276,6 +276,7 @@ Python :mod:`ConfigParser` module) and has the following structure: inherit = base theme stylesheet = main CSS name pygments_style = stylename + sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html [options] variable = default value @@ -295,10 +296,16 @@ Python :mod:`ConfigParser` module) and has the following structure: highlighting. This can be overridden by the user in the :confval:`pygments_style` config value. +* The **sidebars** setting gives the comma separated list of sidebar templates + for constructing sidebars. This can be overridden by the user in the + :confval:`html_sidebars` config value. + * The **options** section contains pairs of variable names and default values. These options can be overridden by the user in :confval:`html_theme_options` and are accessible from all templates as ``theme_``. +.. versionadded:: 1.7 + sidebar settings .. _distribute-your-theme: diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 6313eef61..bb19a2d83 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -864,9 +864,16 @@ class StandaloneHTMLBuilder(Builder): def has_wildcard(pattern): # type: (unicode) -> bool return any(char in pattern for char in '*?[') - sidebars = None + sidebars = self.theme.get_config('theme', 'sidebars', None) matched = None customsidebar = None + + # default sidebars settings for selected theme + theme_default_sidebars = self.theme.get_config('theme', 'sidebars', None) + if theme_default_sidebars: + sidebars = [name.strip() for name in theme_default_sidebars.split(',')] + + # user sidebar settings for pattern, patsidebars in iteritems(self.config.html_sidebars): if patmatch(pagename, pattern): if matched: @@ -881,6 +888,7 @@ class StandaloneHTMLBuilder(Builder): continue matched = pattern sidebars = patsidebars + if sidebars is None: # keep defaults pass diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 8300e626f..9b321a404 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -110,14 +110,7 @@ html_static_path = ['{{ dot }}static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - ] -} +# html_sidebars = {} # -- Options for HTMLHelp output ------------------------------------------ diff --git a/sphinx/themes/basic/theme.conf b/sphinx/themes/basic/theme.conf index 3248070bc..25495e8c6 100644 --- a/sphinx/themes/basic/theme.conf +++ b/sphinx/themes/basic/theme.conf @@ -2,6 +2,7 @@ inherit = none stylesheet = basic.css pygments_style = none +sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html [options] nosidebar = false diff --git a/tests/roots/test-basic/index.rst b/tests/roots/test-basic/index.rst index 8c4ca7d80..48407e643 100644 --- a/tests/roots/test-basic/index.rst +++ b/tests/roots/test-basic/index.rst @@ -12,6 +12,9 @@ Sphinx uses reStructuredText as its markup language, and many of its strengths come from the power and straightforwardness of reStructuredText and its parsing and translating suite, the Docutils. +features +-------- + Among its features are the following: * Output formats: HTML (including derivative formats such as HTML Help, Epub diff --git a/tests/roots/test-theming/test_theme/test-theme/theme.conf b/tests/roots/test-theming/test_theme/test-theme/theme.conf index 0d8403f0b..b7518bc9c 100644 --- a/tests/roots/test-theming/test_theme/test-theme/theme.conf +++ b/tests/roots/test-theming/test_theme/test-theme/theme.conf @@ -1,2 +1,3 @@ [theme] inherit = classic +sidebars = globaltoc.html, searchbox.html diff --git a/tests/test_build_html.py b/tests/test_build_html.py index ceeb5f01c..5eaccb2bb 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -1245,3 +1245,21 @@ def test_html_remote_images(app, status, warning): assert ('https://www.python.org/static/img/python-logo.png' in result) assert not (app.outdir / 'python-logo.png').exists() + + +@pytest.mark.sphinx('html', testroot='basic') +def test_html_sidebar(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'index.html').text(encoding='utf8') + assert '

Table Of Contents

' in result + assert '

Related Topics

' in result + assert '

This Page

' in result + assert '

Quick search

' in result + + app.config.html_sidebars = {'**': []} + app.builder.build_all() + result = (app.outdir / 'index.html').text(encoding='utf8') + assert '

Table Of Contents

' not in result + assert '

Related Topics

' not in result + assert '

This Page

' not in result + assert '

Quick search

' not in result diff --git a/tests/test_theming.py b/tests/test_theming.py index 408a6503f..4a6b8c956 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -95,3 +95,15 @@ def test_double_inheriting_theme(app, status, warning): def test_nested_zipped_theme(app, status, warning): assert app.builder.theme.name == 'child' app.build() # => not raises TemplateNotFound + + +@pytest.mark.sphinx(testroot='theming') +def test_theme_sidebars(app, status, warning): + app.build() + + # test-theme specifies globaltoc and searchbox as default sidebars + result = (app.outdir / 'index.html').text(encoding='utf8') + assert '

Table Of Contents

' in result + assert '

Related Topics

' not in result + assert '

This Page

' not in result + assert '

Quick search

' in result From 90e3425ed751ded99e71174ece60a9fb6c63f03e Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 22 Oct 2017 11:45:28 +0200 Subject: [PATCH 0267/1814] Fix #4149: Documentation: Help choosing latex_engine --- CHANGES | 1 + doc/config.rst | 19 +++++++++++++++++++ doc/latex.rst | 1 + 3 files changed, 21 insertions(+) diff --git a/CHANGES b/CHANGES index 139580a3e..7add2c4b0 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,7 @@ Bugs fixed * #1020: ext.todo todolist not linking to the page in pdflatex * #3965: New quickstart generates wrong SPHINXBUILD in Makefile * #3739: ``:module:`` option is ignored at content of pyobjects +* #4149: Documentation: Help choosing :confval:`latex_engine` Testing -------- diff --git a/doc/config.rst b/doc/config.rst index e96c075e9..b615dc45a 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -1542,6 +1542,25 @@ These options influence LaTeX output. See further :doc:`latex`. * ``'lualatex'`` -- LuaLaTeX * ``'platex'`` -- pLaTeX (default if :confval:`language` is ``'ja'``) + PDFLaTeX's support for Unicode characters covers those from the document + language (the LaTeX ``babel`` and ``inputenc`` packages map them to glyph + slots in the document font, at various encodings allowing each only 256 + characters; Sphinx uses by default (except for Cyrillic languages) the + ``times`` package), but stray characters from other scripts or special + symbols may require adding extra LaTeX packages or macros to the LaTeX + preamble. + + If your project uses such extra Unicode characters, switching the engine to + XeLaTeX or LuaLaTeX often provides a quick fix. They only work with UTF-8 + encoded sources and can (in fact, should) use OpenType fonts, either from + the system or the TeX install tree. Recent LaTeX releases will default with + these engines to the Latin Modern OpenType font, which has good coverage of + Latin and Cyrillic scripts (it is provided by standard LaTeX installation), + and Sphinx does not modify this default. Refer to the documentation of the + LaTeX ``polyglossia`` package to see how to instruct LaTeX to use some + other OpenType font if Unicode coverage proves insufficient (or use + directly ``\setmainfont`` et. al. as in :ref:`this example `.) + .. confval:: latex_documents This value determines how to group the document tree into LaTeX source files. diff --git a/doc/latex.rst b/doc/latex.rst index 61689bda1..eaf147c1c 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -29,6 +29,7 @@ The *latex* target does not benefit from pre-prepared themes like the cautionBgColor={named}{LightCyan}} \relax +.. _latex-basic: Basic customization ------------------- From 5e86c1c934b0292efa79bbb51d5f36ebfa785d5b Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 22 Oct 2017 13:24:03 +0200 Subject: [PATCH 0268/1814] Fix #4090: extra LaTeX macros via ``latex_additional_files`` --- CHANGES | 2 ++ doc/latex.rst | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 7add2c4b0..b7f125b47 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,8 @@ Bugs fixed * #3965: New quickstart generates wrong SPHINXBUILD in Makefile * #3739: ``:module:`` option is ignored at content of pyobjects * #4149: Documentation: Help choosing :confval:`latex_engine` +* #4090: [doc] :confval:`latex_additional_files` with extra LaTeX macros should + not use ``.tex`` extension Testing -------- diff --git a/doc/latex.rst b/doc/latex.rst index eaf147c1c..f349b8fc0 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -65,14 +65,14 @@ If the size of the ``'preamble'`` contents becomes inconvenient, one may move all needed macros into some file :file:`mystyle.tex` of the project source repertory, and get LaTeX to import it at run time:: - 'preamble': r'\input{mystyle.tex}', + 'preamble': r'\input{mystyle.tex.txt}', # or, if the \ProvidesPackage LaTeX macro is used in a file mystyle.sty 'preamble': r'\usepackage{mystyle}', It is needed to set appropriately :confval:`latex_additional_files`, for example:: - latex_additional_files = ["mystyle.tex"] + latex_additional_files = ["mystyle.sty"] .. _latexsphinxsetup: From 6b4a0123fa3e1b26d78adb05c46b044cc8eb3044 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 22 Oct 2017 13:28:46 +0200 Subject: [PATCH 0269/1814] Fix the fix of #4090 (sorry) --- doc/latex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/latex.rst b/doc/latex.rst index f349b8fc0..0cd91fa97 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -62,7 +62,7 @@ It is achieved via usage of the .. highlight:: latex If the size of the ``'preamble'`` contents becomes inconvenient, one may move -all needed macros into some file :file:`mystyle.tex` of the project source +all needed macros into some file :file:`mystyle.tex.txt` of the project source repertory, and get LaTeX to import it at run time:: 'preamble': r'\input{mystyle.tex.txt}', From cfadf17379e394d5f38e50015b8729d6045985dd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 Oct 2017 20:33:18 +0900 Subject: [PATCH 0270/1814] Fix #4132: Failed to convert reST parser error to warning --- CHANGES | 1 + sphinx/util/docutils.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index b7f125b47..841273d5f 100644 --- a/CHANGES +++ b/CHANGES @@ -39,6 +39,7 @@ Bugs fixed * #4149: Documentation: Help choosing :confval:`latex_engine` * #4090: [doc] :confval:`latex_additional_files` with extra LaTeX macros should not use ``.tex`` extension +* Failed to convert reST parser error to warning (refs: #4132) Testing -------- diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index c984bcfaf..a8df9c59d 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -26,8 +26,7 @@ from sphinx.locale import __ from sphinx.util import logging logger = logging.getLogger(__name__) -report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ' - '(.+?)\n?$') +report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ') if False: # For type annotation @@ -162,7 +161,8 @@ class WarningStream(object): if not matched: logger.warning(text.rstrip("\r\n")) else: - location, type, level, message = matched.groups() + location, type, level = matched.groups() + message = report_re.sub('', text).rstrip() logger.log(type, message, location=location) From ad2610a0bcbf04ae57c3addafb2d7a4c81a5b198 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 Oct 2017 20:50:20 +0900 Subject: [PATCH 0271/1814] Fix mypy violation --- sphinx/util/docutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index a8df9c59d..92e6c8c22 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -162,7 +162,7 @@ class WarningStream(object): logger.warning(text.rstrip("\r\n")) else: location, type, level = matched.groups() - message = report_re.sub('', text).rstrip() + message = report_re.sub('', text).rstrip() # type: ignore logger.log(type, message, location=location) From 90352cf940e4ad3a516fc7da31065fb98f25973d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 23 Oct 2017 00:59:24 +0900 Subject: [PATCH 0272/1814] Fix #3919: become silent if logging settings are cleared --- sphinx/util/logging.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 17ee88a01..41dc6022f 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -29,6 +29,7 @@ if False: from sphinx.application import Sphinx # NOQA +NAMESPACE = 'sphinx' VERBOSE = 15 LEVEL_NAMES = defaultdict(lambda: logging.WARNING) # type: Dict[str, int] @@ -59,8 +60,18 @@ COLOR_MAP.update({ def getLogger(name): # type: (str) -> SphinxLoggerAdapter - """Get logger wrapped by SphinxLoggerAdapter.""" - return SphinxLoggerAdapter(logging.getLogger(name), {}) + """Get logger wrapped by SphinxLoggerAdapter. + + Sphinx logger always uses ``sphinx.*`` namesapce to be independent from + settings of root logger. It enables to log stably even if 3rd party + extension or imported application resets logger settings. + """ + # add sphinx prefix to name forcely + logger = logging.getLogger(NAMESPACE + '.' + name) + # Forcely enable logger + logger.disabled = False + # wrap logger by SphinxLoggerAdapter + return SphinxLoggerAdapter(logger, {}) def convert_serializable(records): @@ -203,7 +214,7 @@ class MemoryHandler(logging.handlers.BufferingHandler): def pending_warnings(): # type: () -> Generator """contextmanager to pend logging warnings temporary.""" - logger = logging.getLogger() + logger = logging.getLogger(NAMESPACE) memhandler = MemoryHandler() memhandler.setLevel(logging.WARNING) @@ -229,7 +240,7 @@ def pending_warnings(): def pending_logging(): # type: () -> Generator """contextmanager to pend logging all logs temporary.""" - logger = logging.getLogger() + logger = logging.getLogger(NAMESPACE) memhandler = MemoryHandler() try: @@ -253,7 +264,7 @@ def pending_logging(): def skip_warningiserror(skip=True): # type: (bool) -> Generator """contextmanager to skip WarningIsErrorFilter for a while.""" - logger = logging.getLogger() + logger = logging.getLogger(NAMESPACE) if skip is False: yield @@ -469,8 +480,9 @@ class LastMessagesWriter(object): def setup(app, status, warning): # type: (Sphinx, IO, IO) -> None """Setup root logger for Sphinx""" - logger = logging.getLogger() - logger.setLevel(logging.NOTSET) + logger = logging.getLogger(NAMESPACE) + logger.setLevel(logging.DEBUG) + logger.propagate = False # clear all handlers for handler in logger.handlers[:]: From 33fd46b2a5c994fd450da9b48e1d359eea34daf4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 23 Oct 2017 12:19:56 +0900 Subject: [PATCH 0273/1814] Bump to 1.6.5 final --- CHANGES | 16 ++-------------- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 841273d5f..70652ce48 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,5 @@ -Release 1.6.5 (in development) -============================== - -Dependencies ------------- - -Incompatible changes --------------------- - -Deprecated ----------- +Release 1.6.5 (released Oct 23, 2017) +===================================== Features added -------------- @@ -41,9 +32,6 @@ Bugs fixed not use ``.tex`` extension * Failed to convert reST parser error to warning (refs: #4132) -Testing --------- - Release 1.6.4 (released Sep 26, 2017) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 1d7bcc2ba..91e1f903c 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.5+' +__version__ = '1.6.5' __released__ = '1.6.5' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 5, 'beta', 0) +version_info = (1, 6, 5, 'final', 0) package_dir = path.abspath(path.dirname(__file__)) From 314831d332f73252214c090d356c6e84d6fb3795 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 23 Oct 2017 12:22:42 +0900 Subject: [PATCH 0274/1814] Bump version --- CHANGES | 21 +++++++++++++++++++++ sphinx/__init__.py | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 70652ce48..a7035bad1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Release 1.6.6 (in development) +============================== + +Dependencies +------------ + +Incompatible changes +-------------------- + +Deprecated +---------- + +Features added +-------------- + +Bugs fixed +---------- + +Testing +-------- + Release 1.6.5 (released Oct 23, 2017) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 91e1f903c..4facec53e 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.5' -__released__ = '1.6.5' # used when Sphinx builds its own docs +__version__ = '1.6.6+' +__released__ = '1.6.6' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 5, 'final', 0) +version_info = (1, 6, 6, 'beta', 0) package_dir = path.abspath(path.dirname(__file__)) From 47c869c89ab47f5c89300442d5b4a1abe4f3543c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 23 Oct 2017 23:01:18 +0900 Subject: [PATCH 0275/1814] Fix flake8 and style-check violations --- setup.cfg | 2 +- sphinx/domains/cpp.py | 2 +- sphinx/locale/__init__.py | 2 +- sphinx/testing/util.py | 2 +- sphinx/theming.py | 2 +- sphinx/util/images.py | 2 +- sphinx/util/smartypants.py | 2 +- tests/test_build_latex.py | 2 +- tests/test_intl.py | 22 +++++++++++----------- utils/bump_version.py | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/setup.cfg b/setup.cfg index e0312ce00..a5433c6b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ universal = 1 [flake8] max-line-length = 95 -ignore = E116,E241,E251 +ignore = E116,E241,E251,E741 exclude = .git,.tox,tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py [build_sphinx] diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index f55018b47..b81f6531e 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4258,7 +4258,7 @@ class DefinitionParser(object): pos = self.pos try: concept = self._parse_nested_name() - except: + except Exception: self.pos = pos return None self.skip_ws() diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 6c77eeb8b..68686e3fc 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -171,7 +171,7 @@ class _TranslationProxy(UserString, object): # type: () -> str try: return 'i' + repr(text_type(self.data)) - except: + except Exception: return '<%s broken>' % self.__class__.__name__ diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index 4ec2ee94a..c1b2ae2b2 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -137,7 +137,7 @@ class SphinxTestApp(application.Sphinx): application.Sphinx.__init__(self, srcdir, confdir, outdir, doctreedir, buildername, confoverrides, status, warning, freshenv, warningiserror, tags) - except: + except Exception: self.cleanup() raise diff --git a/sphinx/theming.py b/sphinx/theming.py index 1cd07b8dc..f787e8120 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -156,7 +156,7 @@ def is_archived_theme(filename): try: with ZipFile(filename) as f: # type: ignore return THEMECONF in f.namelist() - except: + except Exception: return False diff --git a/sphinx/util/images.py b/sphinx/util/images.py index eba295a3c..1c2b4033a 100644 --- a/sphinx/util/images.py +++ b/sphinx/util/images.py @@ -64,7 +64,7 @@ def get_image_size(filename): pass return size - except: + except Exception: return None diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py index c368d7d0f..03771d168 100644 --- a/sphinx/util/smartypants.py +++ b/sphinx/util/smartypants.py @@ -139,7 +139,7 @@ def educateQuotes(text, language='en'): smart = smartquotes.smartchars(language) try: apostrophe = smart.apostrophe - except: + except Exception: apostrophe = u'’' # oldtext = text diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index f36aa355b..b1ba73730 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1036,6 +1036,6 @@ def test_latex_image_in_parsed_literal(app, status, warning): app.builder.build_all() result = (app.outdir / 'Python.tex').text(encoding='utf8') - assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\height}' + assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\\height}' '{\\scalebox{2.000000}{\\sphinxincludegraphics[height=1cm]{{pic}.png}}}' '}AFTER') in result diff --git a/tests/test_intl.py b/tests/test_intl.py index f3952e9a1..8eff52340 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -197,28 +197,28 @@ def test_text_inconsistency_warnings(app, warning): expected_warning_expr = ( warning_fmt % { u'reftype': u'footnote references', - u'original': u"\[u?'\[#\]_'\]", - u'translated': u"\[\]" + u'original': u"\\[u?'\\[#\\]_'\\]", + u'translated': u"\\[\\]" } + warning_fmt % { u'reftype': u'footnote references', - u'original': u"\[u?'\[100\]_'\]", - u'translated': u"\[\]" + u'original': u"\\[u?'\\[100\\]_'\\]", + u'translated': u"\\[\\]" } + warning_fmt % { u'reftype': u'references', - u'original': u"\[u?'reference_'\]", - u'translated': u"\[u?'reference_', u?'reference_'\]" + u'original': u"\\[u?'reference_'\\]", + u'translated': u"\\[u?'reference_', u?'reference_'\\]" } + warning_fmt % { u'reftype': u'references', - u'original': u"\[\]", - u'translated': u"\[u?'`I18N WITH REFS INCONSISTENCY`_'\]" + u'original': u"\\[\\]", + u'translated': u"\\[u?'`I18N WITH REFS INCONSISTENCY`_'\\]" }) assert_re_search(expected_warning_expr, warnings) expected_citation_warning_expr = ( - u'.*/refs_inconsistency.txt:\\d+: WARNING: Citation \[ref2\] is not referenced.\n' + + u'.*/refs_inconsistency.txt:\\d+: WARNING: Citation \\[ref2\\] is not referenced.\n' + u'.*/refs_inconsistency.txt:\\d+: WARNING: citation not found: ref3') assert_re_search(expected_citation_warning_expr, warnings) @@ -300,8 +300,8 @@ def test_text_glossary_term_inconsistencies(app, warning): expected_warning_expr = ( u'.*/glossary_terms_inconsistency.txt:\\d+: ' u'WARNING: inconsistent term references in translated message.' - u" original: \[u?':term:`Some term`', u?':term:`Some other term`'\]," - u" translated: \[u?':term:`SOME NEW TERM`'\]\n") + u" original: \\[u?':term:`Some term`', u?':term:`Some other term`'\\]," + u" translated: \\[u?':term:`SOME NEW TERM`'\\]\n") assert_re_search(expected_warning_expr, warnings) diff --git a/utils/bump_version.py b/utils/bump_version.py index da193a3de..9033aee70 100755 --- a/utils/bump_version.py +++ b/utils/bump_version.py @@ -81,7 +81,7 @@ def processing(message): yield except Skip as exc: print('skip: %s' % exc) - except: + except Exception: print('error') raise else: From 5ae72bdd28075a02213ede26accd196c1a9dba05 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 23 Oct 2017 23:25:50 +0900 Subject: [PATCH 0276/1814] Fix flake8 violation --- sphinx/util/inspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index a2928fc7e..c50e0c5ef 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -273,7 +273,7 @@ class Signature(object): try: self.annotations = typing.get_type_hints(subject) # type: ignore - except: + except Exception: self.annotations = {} if bound_method: From 49e486ff47780a3113a98512a88086ffab0e1854 Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Sun, 22 Oct 2017 21:51:47 +0300 Subject: [PATCH 0277/1814] inspect: Sort dictionary keys when possible This should help for reproducible builds and for finding items in large dictionaries. --- sphinx/util/inspect.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 5e0d219ec..f29cd9a78 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -203,6 +203,14 @@ def safe_getmembers(object, predicate=None, attr_getter=safe_getattr): def object_description(object): # type: (Any) -> unicode """A repr() implementation that returns text safe to use in reST context.""" + if isinstance(object, dict): + try: + sorted_keys = sorted(object) + except TypeError: + pass # Cannot sort dict keys, fall back to generic repr + else: + items = ("%r: %r" % (key, object[key]) for key in sorted_keys) + return "{%s}" % ", ".join(items) try: s = repr(object) except Exception: From eb934cb66522a3b427f81a28babd8ab64eefa22f Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Mon, 23 Oct 2017 20:38:08 +0300 Subject: [PATCH 0278/1814] Add a test for the previous change --- tests/test_util_inspect.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 644eb8b2d..87b4d5186 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -130,3 +130,23 @@ class TestSafeGetAttr(TestCase): self.assertEqual(exc.args[0], 'bar') else: self.fail('AttributeError not raised') + + +class TestObjectDescription(TestCase): + def test_dictionary_sorting(self): + dictionary = {"c": 3, "a": 1, "d": 2, "b": 4} + description = inspect.object_description(dictionary) + assert description == "{'a': 1, 'b': 4, 'c': 3, 'd': 2}" + + def test_dict_customtype(self): + class CustomType(object): + def __init__(self, value): + self._value = value + + def __repr__(self): + return "" % self._value + + dictionary = {CustomType(2): 2, CustomType(1): 1} + description = inspect.object_description(dictionary) + # Type is unsortable, just check that it does not crash + assert ": 2" in description From e45b03dd50261d8f0171ca37a4b7cc6dcf6adea4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 25 Oct 2017 23:51:41 +0900 Subject: [PATCH 0279/1814] Update CHANGES for PR #4181 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index a7035bad1..1d05abd57 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,8 @@ Deprecated Features added -------------- +* #4181: autodoc: Sort dictionary keys when possible + Bugs fixed ---------- From 6288eac1ece9b1d684d8611c32afb027d56b0033 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 26 Oct 2017 00:01:09 +0900 Subject: [PATCH 0280/1814] Provide default settings for alabaster --- sphinx/builders/html.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index bb19a2d83..5c35fa145 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -872,6 +872,11 @@ class StandaloneHTMLBuilder(Builder): theme_default_sidebars = self.theme.get_config('theme', 'sidebars', None) if theme_default_sidebars: sidebars = [name.strip() for name in theme_default_sidebars.split(',')] + elif self.theme.name == 'alabaster': + # provide default settings for alabaster (for compatibility) + # Note: this will be removed before Sphinx-2.0 + sidebars = ['about.html', 'navigation.html', 'relation.html', + 'searchbox.html', 'donate.html'] # user sidebar settings for pattern, patsidebars in iteritems(self.config.html_sidebars): From c0aa0ce2d8bd96406f785dd5d225eca68b32b69b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 26 Oct 2017 00:04:23 +0900 Subject: [PATCH 0281/1814] Add hints for html_sidebars --- sphinx/templates/quickstart/conf.py_t | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 9b321a404..4e828f330 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -110,6 +110,11 @@ html_static_path = ['{{ dot }}static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# # html_sidebars = {} From 9aac2420d3840873928e2af29452b0cca5e60ff1 Mon Sep 17 00:00:00 2001 From: lucdanton Date: Wed, 25 Oct 2017 22:41:42 +0200 Subject: [PATCH 0282/1814] C++: remove function concepts. --- CHANGES | 1 + doc/domains.rst | 17 +++-------------- sphinx/domains/cpp.py | 26 ++++---------------------- tests/test_domain_cpp.py | 4 ---- 4 files changed, 8 insertions(+), 40 deletions(-) diff --git a/CHANGES b/CHANGES index 1d10d01fd..ebeffec52 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,7 @@ Features removed * ``sphinx.util.nodes.process_only_nodes()`` * LaTeX environment ``notice``, use ``sphinxadmonition`` instead * LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily`` +* C++, support of function concepts Bugs fixed ---------- diff --git a/doc/domains.rst b/doc/domains.rst index 1697c6605..e6a860bcd 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -720,13 +720,12 @@ a visibility statement (``public``, ``private`` or ``protected``). .. rst:directive:: .. cpp:concept:: template-parameter-list name - .. cpp:concept:: template-parameter-list name() .. warning:: The support for concepts is experimental. It is based on the Concepts Technical Specification, and the features may change as the TS evolves. - Describe a variable concept or a function concept. Both must have exactly 1 - template parameter list. The name may be a nested name. Examples:: + Describe a concept. It must have exactly 1 template parameter list. The name may be a + nested name. Example:: .. cpp:concept:: template std::Iterator @@ -744,12 +743,7 @@ a visibility statement (``public``, ``private`` or ``protected``). - :cpp:expr:`*r`, when :cpp:expr:`r` is dereferenceable. - :cpp:expr:`++r`, with return type :cpp:expr:`It&`, when :cpp:expr:`r` is incrementable. - .. cpp:concept:: template std::Container() - - Holder of elements, to which it can provide access via - :cpp:concept:`Iterator` s. - - They will render as follows: + This will render as follows: .. cpp:concept:: template std::Iterator @@ -767,11 +761,6 @@ a visibility statement (``public``, ``private`` or ``protected``). - :cpp:expr:`*r`, when :cpp:expr:`r` is dereferenceable. - :cpp:expr:`++r`, with return type :cpp:expr:`It&`, when :cpp:expr:`r` is incrementable. - .. cpp:concept:: template std::Container() - - Holder of elements, to which it can provide access via - :cpp:concept:`Iterator` s. - Options ....... diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 1db374205..a1b0a71c3 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -224,13 +224,12 @@ logger = logging.getLogger(__name__) concept_object: goal: just a declaration of the name (for now) - either a variable concept or function concept grammar: only a single template parameter list, and the nested name may not have any template argument lists "template" "<" template-parameter-list ">" - nested-name-specifier "()"[opt] + nested-name-specifier type_object: goal: @@ -2780,10 +2779,9 @@ class ASTTypeUsing(ASTBase): class ASTConcept(ASTBase): - def __init__(self, nestedName, isFunction, initializer): - # type: (Any, bool, Any) -> None + def __init__(self, nestedName, initializer): + # type: (Any, Any) -> None self.nestedName = nestedName - self.isFunction = isFunction # otherwise it's a variable concept self.initializer = initializer @property @@ -2800,18 +2798,13 @@ class ASTConcept(ASTBase): def __unicode__(self): # type: () -> unicode res = text_type(self.nestedName) - if self.isFunction: - res += "()" if self.initializer: res += text_type(self.initializer) return res def describe_signature(self, signode, mode, env, symbol): # type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None - signode += nodes.Text(text_type("bool ")) self.nestedName.describe_signature(signode, mode, env, symbol) - if self.isFunction: - signode += nodes.Text("()") if self.initializer: self.initializer.describe_signature(signode, mode, env, symbol) @@ -4718,20 +4711,9 @@ class DefinitionParser(object): def _parse_concept(self): # type: () -> ASTConcept nestedName = self._parse_nested_name() - isFunction = False - self.skip_ws() - if self.skip_string('('): - isFunction = True - self.skip_ws() - if not self.skip_string(')'): - self.fail("Expected ')' in function concept declaration.") - initializer = self._parse_initializer('member') - if initializer and isFunction: - self.fail("Function concept with initializer.") - - return ASTConcept(nestedName, isFunction, initializer) + return ASTConcept(nestedName, initializer) def _parse_class(self): # type: () -> ASTClass diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 8c0fae2e3..63682237f 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -231,10 +231,6 @@ def test_concept_definitions(): {2:'I0EN1A1B7ConceptE'}) check('concept', 'template Foo', {2:'I00DpE3Foo'}) - check('concept', 'template A::B::Concept()', - {2:'I0EN1A1B7ConceptE'}) - check('concept', 'template Foo()', - {2:'I00DpE3Foo'}) with pytest.raises(DefinitionError): parse('concept', 'Foo') with pytest.raises(DefinitionError): From bfd39c12b272a494bcf2f6e7477076f5f6b00d2f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 27 Oct 2017 00:39:48 +0900 Subject: [PATCH 0283/1814] Add :confval:`smart_quotes` to disable smart quotes through ``conf.py`` (refs: #4142) --- CHANGES | 2 ++ doc/config.rst | 14 +++++++++++--- sphinx/config.py | 1 + sphinx/environment/__init__.py | 7 ++++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 1d05abd57..d7250ae15 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,8 @@ Features added -------------- * #4181: autodoc: Sort dictionary keys when possible +* Add :confval:`smart_quotes` to disable smart quotes through ``conf.py`` + (refs: #3967) Bugs fixed ---------- diff --git a/doc/config.rst b/doc/config.rst index b615dc45a..dca199652 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -27,7 +27,6 @@ and output behavior. The configuration file is executed as Python code at build time (using :func:`execfile`, and with the current directory set to its containing directory), and therefore can execute arbitrarily complex code. Sphinx then -reads simple names from the file's namespace as its configuration. Important points to note: @@ -345,6 +344,14 @@ General configuration .. versionadded:: 1.3 +.. confval:: smart_quotes + + If true, `SmartyPants `_ + will be used to convert quotes and dashes to typographically correct + entities. Default: ``True``. + + .. versionadded:: 1.6.6 + .. confval:: tls_verify If true, Sphinx verifies server certifications. Default is ``True``. @@ -781,8 +788,9 @@ that use Sphinx's HTMLWriter class. entities. Default: ``True``. .. deprecated:: 1.6 - To disable or customize smart quotes, use the Docutils configuration file - (``docutils.conf``) instead to set there its `smart_quotes option`_. + To disable smart quotes, use :confval:`smart_quotes` or the Docutils + configuration file (``docutils.conf``) instead to set there its + `smart_quotes option`_. .. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes diff --git a/sphinx/config.py b/sphinx/config.py index 02ee529a3..5308c52bf 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -132,6 +132,7 @@ class Config(object): tls_verify = (True, 'env'), tls_cacerts = (None, 'env'), + smart_quotes = (True, 'env'), ) # type: Dict[unicode, Tuple] def __init__(self, dirname, filename, overrides, tags): diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index f522bd576..553ab794c 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -677,14 +677,15 @@ class BuildEnvironment(object): language = self.config.language or 'en' self.settings['language_code'] = language if 'smart_quotes' not in self.settings: - self.settings['smart_quotes'] = True if self.config.html_use_smartypants is not None: warnings.warn("html_use_smartypants option is deprecated. Smart " "quotes are on by default; if you want to disable " - "or customize them, use the smart_quotes option in " - "docutils.conf.", + "them, use the smart_quotes option", RemovedInSphinx17Warning) self.settings['smart_quotes'] = self.config.html_use_smartypants + else: + self.settings['smart_quotes'] = self.config.smart_quotes + for tag in normalize_language_tag(language): if tag in smartchars.quotes: break From 6274ea7ec8a0fae41e3f54c8161d16b5909daa8e Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 27 Oct 2017 10:57:46 +0200 Subject: [PATCH 0284/1814] Replace a few ``\undefined`` by ``\@undefined`` in LaTeX styles This prevents against unlikely event user via template or ``latex_elements`` keys insert some custom definition of ``\undefined`` macro before sphinx.sty gets loaded. For background of this LaTeX issue, cf For extra safe, Sphinx could use ``\sphinx@undefined`` rather. modified: footnotehyper-sphinx.sty modified: sphinx.sty --- sphinx/texinputs/footnotehyper-sphinx.sty | 5 +++-- sphinx/texinputs/sphinx.sty | 24 +++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/sphinx/texinputs/footnotehyper-sphinx.sty b/sphinx/texinputs/footnotehyper-sphinx.sty index ff23f6ebe..5995f012d 100644 --- a/sphinx/texinputs/footnotehyper-sphinx.sty +++ b/sphinx/texinputs/footnotehyper-sphinx.sty @@ -1,6 +1,6 @@ \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{footnotehyper-sphinx}% - [2017/03/07 v1.6 hyperref aware footnote.sty for sphinx (JFB)] + [2017/10/27 v1.7 hyperref aware footnote.sty for sphinx (JFB)] %% %% Package: footnotehyper-sphinx %% Version: based on footnotehyper.sty 2017/03/07 v1.0 @@ -16,6 +16,7 @@ %% 3. use of \sphinxunactivateextrasandspace from sphinx.sty, %% 4. macro definition \sphinxfootnotemark, %% 5. macro definition \sphinxlongtablepatch +%% 6. replaced an \undefined by \@undefined \DeclareOption*{\PackageWarning{footnotehyper-sphinx}{Option `\CurrentOption' is unknown}}% \ProcessOptions\relax \newbox\FNH@notes @@ -197,7 +198,7 @@ }% \AtBeginDocument{% \let\FNH@@makefntext\@makefntext - \ifx\@makefntextFB\undefined + \ifx\@makefntextFB\@undefined \expandafter\@gobble\else\expandafter\@firstofone\fi {\ifFBFrenchFootnotes \let\FNH@@makefntext\@makefntextFB \else \let\FNH@@makefntext\@makefntextORI\fi}% diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 28f0091ff..bc524911b 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -6,7 +6,7 @@ % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{sphinx}[2017/07/24 v1.6.4 LaTeX package (Sphinx markup)] +\ProvidesPackage{sphinx}[2017/10/27 v1.7 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but @@ -185,12 +185,12 @@ % to make pdf with correct encoded bookmarks in Japanese % this should precede the hyperref package -\ifx\kanjiskip\undefined +\ifx\kanjiskip\@undefined % for non-Japanese: make sure bookmarks are ok also with lualatex \PassOptionsToPackage{pdfencoding=unicode}{hyperref} \else \RequirePackage{atbegshi} - \ifx\ucs\undefined + \ifx\ucs\@undefined \ifnum 42146=\euc"A4A2 \AtBeginShipoutFirst{\special{pdf:tounicode EUC-UCS2}} \else @@ -201,7 +201,7 @@ \fi \fi -\ifx\@jsc@uplatextrue\undefined\else +\ifx\@jsc@uplatextrue\@undefined\else \PassOptionsToPackage{setpagesize=false}{hyperref} \fi @@ -223,7 +223,7 @@ \SetupKeyvalOptions{prefix=spx@opt@} % use \spx@opt@ prefix % Sphinx legacy text layout: 1in margins on all four sides -\ifx\@jsc@uplatextrue\undefined +\ifx\@jsc@uplatextrue\@undefined \DeclareStringOption[1in]{hmargin} \DeclareStringOption[1in]{vmargin} \DeclareStringOption[.5in]{marginpar} @@ -419,7 +419,7 @@ % % fix the double index and bibliography on the table of contents % in jsclasses (Japanese standard document classes) -\ifx\@jsc@uplatextrue\undefined\else +\ifx\@jsc@uplatextrue\@undefined\else \renewenvironment{sphinxtheindex} {\cleardoublepage\phantomsection \begin{theindex}} @@ -432,7 +432,7 @@ \fi % disable \@chappos in Appendix in pTeX -\ifx\kanjiskip\undefined\else +\ifx\kanjiskip\@undefined\else \let\py@OldAppendix=\appendix \renewcommand{\appendix}{ \py@OldAppendix @@ -446,10 +446,10 @@ {\newenvironment {sphinxthebibliography}{\begin{thebibliography}}{\end{thebibliography}}% } - {}% else clause of ifundefined + {}% else clause of \ltx@ifundefined \ltx@ifundefined{sphinxtheindex} {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}% - {}% else clause of ifundefined + {}% else clause of \ltx@ifundefined %% COLOR (general) @@ -503,7 +503,7 @@ } % geometry -\ifx\kanjiskip\undefined +\ifx\kanjiskip\@undefined \PassOptionsToPackage{% hmargin={\unexpanded{\spx@opt@hmargin}},% vmargin={\unexpanded{\spx@opt@vmargin}},% @@ -525,7 +525,7 @@ \newcommand*\sphinxtextlinesja[1]{% \numexpr\@ne+\dimexpr\paperheight-\topskip-\tw@\dimexpr#1\relax\relax/ \baselineskip\relax}% - \ifx\@jsc@uplatextrue\undefined\else + \ifx\@jsc@uplatextrue\@undefined\else % the way we found in order for the papersize special written by % geometry in the dvi file to be correct in case of jsbook class \ifnum\mag=\@m\else % do nothing special if nomag class option or 10pt @@ -542,7 +542,7 @@ }{geometry}% \AtBeginDocument {% update a dimension used by the jsclasses - \ifx\@jsc@uplatextrue\undefined\else\fullwidth\textwidth\fi + \ifx\@jsc@uplatextrue\@undefined\else\fullwidth\textwidth\fi % for some reason, jreport normalizes all dimensions with \@settopoint \@ifclassloaded{jreport} {\@settopoint\textwidth\@settopoint\textheight\@settopoint\marginparwidth} From d7d2e823fc1a59a4c94c471b4f1dfa1501f226b4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 29 Oct 2017 22:14:55 +0900 Subject: [PATCH 0285/1814] sphinx.config.ENUM allows to validate items of lists or tuples --- sphinx/config.py | 9 ++++++--- tests/test_config.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 02ee529a3..6abdbc55c 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -24,7 +24,7 @@ from sphinx.util.pycompat import execfile_, NoneType if False: # For type annotation - from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple # NOQA + from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple, Union # NOQA from sphinx.util.tags import Tags # NOQA logger = logging.getLogger(__name__) @@ -63,8 +63,11 @@ class ENUM(object): self.candidates = candidates def match(self, value): - # type: (unicode) -> bool - return value in self.candidates + # type: (Union[unicode,List,Tuple]) -> bool + if isinstance(value, (list, tuple)): + return all(item in self.candidates for item in value) + else: + return value in self.candidates string_classes = [text_type] # type: List diff --git a/tests/test_config.py b/tests/test_config.py index f9300c30e..578f6e55c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -240,3 +240,15 @@ def test_check_enum(app, status, warning): def test_check_enum_failed(app, status, warning): assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \ "but `invalid` is given." in warning.getvalue() + + +@pytest.mark.sphinx(testroot='config', confoverrides={'value17': ['one', 'two']}) +def test_check_enum_for_list(app, status, warning): + assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \ + not in warning.getvalue() + + +@pytest.mark.sphinx(testroot='config', confoverrides={'value17': ['one', 'two', 'invalid']}) +def test_check_enum_for_list_failed(app, status, warning): + assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \ + "but `['one', 'two', 'invalid']` is given." in warning.getvalue() From 83c266aa2ebae25bf9284aa6f9c98ab1b83908a5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 Oct 2017 15:25:47 +0900 Subject: [PATCH 0286/1814] using a string value for ``html_sidebars`` will be removed in 2.0 --- CHANGES | 3 +++ doc/config.rst | 4 ++++ sphinx/builders/html.py | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index a958d185d..55c9d0b27 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,9 @@ Incompatible changes Deprecated ---------- +* using a string value for :confval:`html_sidebars` is deprecated and only list + values will be accepted at 2.0. + Features added -------------- diff --git a/doc/config.rst b/doc/config.rst index f23c22e00..33c01d415 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -828,6 +828,10 @@ that use Sphinx's HTMLWriter class. between the ``'sourcelink.html'`` and ``'searchbox.html'`` entries. This is for compatibility with Sphinx versions before 1.0. + .. deprecated:: 1.7 + + a single string value for ``html_sidebars`` will be removed in 2.0 + Builtin sidebar templates that can be rendered are: * **localtoc.html** -- a fine-grained table of contents of the current diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 6313eef61..4f5cb6e14 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -888,6 +888,11 @@ class StandaloneHTMLBuilder(Builder): # 0.x compatible mode: insert custom sidebar before searchbox customsidebar = sidebars sidebars = None + warnings.warn('Now html_sidebars only allows list of sidebar ' + 'templates as a value. Support for a string value ' + 'will be removed at Sphinx-2.0.', + RemovedInSphinx20Warning) + ctx['sidebars'] = sidebars ctx['customsidebar'] = customsidebar From 831f89a687d754e3f471075009b9f59b35ec6cab Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 30 Oct 2017 10:22:11 -0500 Subject: [PATCH 0287/1814] Closes #3160: Use tag for :kbd: role in html writers --- CHANGES | 1 + sphinx/writers/html.py | 17 ++++++++++++----- sphinx/writers/html5.py | 17 ++++++++++++----- tests/test_build_html.py | 2 +- tests/test_build_html5.py | 2 +- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index 8fa96e052..649d88989 100644 --- a/CHANGES +++ b/CHANGES @@ -73,6 +73,7 @@ Features removed Bugs fixed ---------- +* #3160: Why doesn't Sphinx translate :kbd: roles to HTML's tags? * #3882: Update the order of files for HTMLHelp and QTHelp * #3962: sphinx-apidoc does not recognize implicit namespace packages correctly diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 8d02793e3..b3419b70a 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -491,14 +491,21 @@ class HTMLTranslator(BaseTranslator): # overwritten def visit_literal(self, node): # type: (nodes.Node) -> None - self.body.append(self.starttag(node, 'code', '', - CLASS='docutils literal')) - self.protect_literal_text += 1 + if 'kbd' in node['classes']: + self.body.append(self.starttag(node, 'kbd', '', + CLASS='docutils literal')) + else: + self.body.append(self.starttag(node, 'code', '', + CLASS='docutils literal')) + self.protect_literal_text += 1 def depart_literal(self, node): # type: (nodes.Node) -> None - self.protect_literal_text -= 1 - self.body.append('') + if 'kbd' in node['classes']: + self.body.append('') + else: + self.protect_literal_text -= 1 + self.body.append('') def visit_productionlist(self, node): # type: (nodes.Node) -> None diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 51c4e8ecb..1efd060f2 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -437,14 +437,21 @@ class HTML5Translator(BaseTranslator): # overwritten def visit_literal(self, node): # type: (nodes.Node) -> None - self.body.append(self.starttag(node, 'code', '', - CLASS='docutils literal')) - self.protect_literal_text += 1 + if 'kbd' in node['classes']: + self.body.append(self.starttag(node, 'kbd', '', + CLASS='docutils literal')) + else: + self.body.append(self.starttag(node, 'code', '', + CLASS='docutils literal')) + self.protect_literal_text += 1 def depart_literal(self, node): # type: (nodes.Node) -> None - self.protect_literal_text -= 1 - self.body.append('') + if 'kbd' in node['classes']: + self.body.append('') + else: + self.protect_literal_text -= 1 + self.body.append('') def visit_productionlist(self, node): # type: (nodes.Node) -> None diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 5eaccb2bb..dc06491e8 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -238,7 +238,7 @@ def test_static_output(app): (".//li/strong", r'^command\\n$'), (".//li/strong", r'^program\\n$'), (".//li/em", r'^dfn\\n$'), - (".//li/code/span[@class='pre']", r'^kbd\\n$'), + (".//li/kbd", r'^kbd\\n$'), (".//li/span", u'File \N{TRIANGULAR BULLET} Close'), (".//li/code/span[@class='pre']", '^a/$'), (".//li/code/em/span[@class='pre']", '^varpart$'), diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py index 12386705e..771994ca6 100644 --- a/tests/test_build_html5.py +++ b/tests/test_build_html5.py @@ -119,7 +119,7 @@ def cached_etree_parse(): (".//li/p/strong", r'^command\\n$'), (".//li/p/strong", r'^program\\n$'), (".//li/p/em", r'^dfn\\n$'), - (".//li/p/code/span[@class='pre']", r'^kbd\\n$'), + (".//li/p/kbd", r'^kbd\\n$'), (".//li/p/span", u'File \N{TRIANGULAR BULLET} Close'), (".//li/p/code/span[@class='pre']", '^a/$'), (".//li/p/code/em/span[@class='pre']", '^varpart$'), From bbe3f8fe0caa99227a3ecf8ac313aa8261c83075 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 10:52:47 +0900 Subject: [PATCH 0288/1814] Update CHANGES --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 0d2c497f1..2be36887f 100644 --- a/CHANGES +++ b/CHANGES @@ -42,6 +42,7 @@ Features added * #4140: html themes: Make body tag inheritable * #4168: improve zh search with jieba * HTML themes can set up default sidebars through ``theme.conf`` +* #3160: html: Use ```` to represent ``:kbd:`` role Features removed @@ -76,7 +77,6 @@ Features removed Bugs fixed ---------- -* #3160: Why doesn't Sphinx translate :kbd: roles to HTML's tags? * #3882: Update the order of files for HTMLHelp and QTHelp * #3962: sphinx-apidoc does not recognize implicit namespace packages correctly From c3fffc521bf03576f38c391db56d7231c781a2fa Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 22:57:28 +0900 Subject: [PATCH 0289/1814] Reduce warnings on testing --- tests/roots/test-root/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py index a23aec482..9e984635d 100644 --- a/tests/roots/test-root/conf.py +++ b/tests/roots/test-root/conf.py @@ -32,7 +32,8 @@ rst_epilog = '.. |subst| replace:: global substitution' html_theme = 'testtheme' html_theme_path = ['.'] html_theme_options = {'testopt': 'testoverride'} -html_sidebars = {'**': 'customsb.html', +html_sidebars = {'**': ['localtoc.html', 'relations.html', 'sourcelink.html', + 'customsb.html', 'searchbox.html'], 'contents': ['contentssb.html', 'localtoc.html', 'globaltoc.html']} html_style = 'default.css' From c05c4d19106bf4ffbd827e523f67e80f7620c13d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 20 Mar 2017 23:10:10 +0900 Subject: [PATCH 0290/1814] Add BuildEnvironment.write_doctree() --- sphinx/environment/__init__.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index d438b7c0f..e3f5201f1 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -756,24 +756,12 @@ class BuildEnvironment(object): list(merge_doctrees( old_doctree, doctree, self.versioning_condition)) - # make it picklable - doctree.reporter = None - doctree.transformer = None - doctree.settings.warning_stream = None - doctree.settings.env = None - doctree.settings.record_dependencies = None - # cleanup self.temp_data.clear() self.ref_context.clear() roles._roles.pop('', None) # if a document has set a local default role - # save the parsed doctree - doctree_filename = self.doc2path(docname, self.doctreedir, - '.doctree') - ensuredir(path.dirname(doctree_filename)) - with open(doctree_filename, 'wb') as f: - pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL) + self.write_doctree(docname, doctree) # utilities to use while reading a document @@ -877,6 +865,21 @@ class BuildEnvironment(object): doctree.reporter = Reporter(self.doc2path(docname), 2, 5, stream=WarningStream()) return doctree + def write_doctree(self, docname, doctree): + # type: (unicode, nodes.Node) -> None + """Write the doctree to a file.""" + # make it picklable + doctree.reporter = None + doctree.transformer = None + doctree.settings.warning_stream = None + doctree.settings.env = None + doctree.settings.record_dependencies = None + + doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree') + ensuredir(path.dirname(doctree_filename)) + with open(doctree_filename, 'wb') as f: + pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL) + def get_and_resolve_doctree(self, docname, builder, doctree=None, prune_toctrees=True, includehidden=False): # type: (unicode, Builder, nodes.Node, bool, bool) -> nodes.Node From 07220140ac18894d6102042ba3633df985df4942 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:24 +0900 Subject: [PATCH 0291/1814] Add BuildEnvironment.prepare_settings() --- sphinx/environment/__init__.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index e3f5201f1..666d29129 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -663,10 +663,9 @@ class BuildEnvironment(object): location=(self.docname, lineno)) return (u'?', error.end) - def read_doc(self, docname, app=None): - # type: (unicode, Sphinx) -> None - """Parse a file and add/update inventory entries for the doctree.""" - + def prepare_settings(self, docname): + """Prepare to set up environment for reading.""" + # type: (unicode) -> None self.temp_data['docname'] = docname # defaults to the global default, but can be re-set in a document self.temp_data['default_role'] = self.config.default_role @@ -688,6 +687,11 @@ class BuildEnvironment(object): else: self.settings['smart_quotes'] = False + def read_doc(self, docname, app=None): + # type: (unicode, Sphinx) -> None + """Parse a file and add/update inventory entries for the doctree.""" + self.prepare_settings(docname) + docutilsconf = path.join(self.srcdir, 'docutils.conf') # read docutils.conf from source dir, not from current dir OptionParser.standard_config_files[1] = docutilsconf From d23f29f301648ba9f84641fb44ebab43b07deb48 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:24 +0900 Subject: [PATCH 0292/1814] Refactor publishment --- sphinx/environment/__init__.py | 19 ++++++++++--------- sphinx/io.py | 5 +++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 666d29129..8897f1d33 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -33,7 +33,9 @@ from docutils.parsers.rst.languages import en as english from docutils.frontend import OptionParser from sphinx import addnodes -from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput +from sphinx.io import ( + SphinxStandaloneReader, SphinxDummySourceClass, SphinxDummyWriter, SphinxFileInput +) from sphinx.util import logging from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator from sphinx.util.nodes import is_translatable @@ -713,17 +715,16 @@ class BuildEnvironment(object): # publish manually reader = SphinxStandaloneReader(self.app, parsers=self.app.registry.get_source_parsers()) - pub = Publisher(reader=reader, - writer=SphinxDummyWriter(), - destination_class=NullOutput) - pub.set_components(None, 'restructuredtext', None) - pub.process_programmatic_settings(None, self.settings, None) src_path = self.doc2path(docname) source = SphinxFileInput(app, self, source=None, source_path=src_path, encoding=self.config.source_encoding) - pub.source = source - pub.settings._source = src_path - pub.set_destination(None, None) + pub = Publisher(reader=reader, + writer=SphinxDummyWriter(), + source_class=SphinxDummySourceClass, + destination=NullOutput()) + pub.set_components(None, 'restructuredtext', None) + pub.process_programmatic_settings(None, self.settings, None) + pub.set_source(source, src_path) pub.publish() doctree = pub.document diff --git a/sphinx/io.py b/sphinx/io.py index 8813cb3b6..9b27e04fd 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -143,6 +143,11 @@ class SphinxDummyWriter(UnfilteredWriter): pass +def SphinxDummySourceClass(source, *args, **kwargs): + """Bypass source object as is to cheat Publisher.""" + return source + + class SphinxFileInput(FileInput): def __init__(self, app, env, *args, **kwds): # type: (Sphinx, BuildEnvironment, Any, Any) -> None From 1200ab48e1f24fcc8cf3232ae21c056ed6bca0f8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:25 +0900 Subject: [PATCH 0293/1814] Refactor parsing by docutils --- sphinx/environment/__init__.py | 23 ++--------------------- sphinx/io.py | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 8897f1d33..e8b157c3d 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -24,8 +24,6 @@ from collections import defaultdict from six import BytesIO, itervalues, class_types, next from six.moves import cPickle as pickle -from docutils.io import NullOutput -from docutils.core import Publisher from docutils.utils import Reporter, get_source_line, normalize_language_tag from docutils.utils.smartquotes import smartchars from docutils.parsers.rst import roles @@ -33,9 +31,7 @@ from docutils.parsers.rst.languages import en as english from docutils.frontend import OptionParser from sphinx import addnodes -from sphinx.io import ( - SphinxStandaloneReader, SphinxDummySourceClass, SphinxDummyWriter, SphinxFileInput -) +from sphinx.io import read_doc from sphinx.util import logging from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator from sphinx.util.nodes import is_translatable @@ -711,22 +707,7 @@ class BuildEnvironment(object): location=docname) codecs.register_error('sphinx', self.warn_and_replace) # type: ignore - - # publish manually - reader = SphinxStandaloneReader(self.app, - parsers=self.app.registry.get_source_parsers()) - src_path = self.doc2path(docname) - source = SphinxFileInput(app, self, source=None, source_path=src_path, - encoding=self.config.source_encoding) - pub = Publisher(reader=reader, - writer=SphinxDummyWriter(), - source_class=SphinxDummySourceClass, - destination=NullOutput()) - pub.set_components(None, 'restructuredtext', None) - pub.process_programmatic_settings(None, self.settings, None) - pub.set_source(source, src_path) - pub.publish() - doctree = pub.document + doctree = read_doc(self.app, self, self.doc2path(docname)) # post-processing for domain in itervalues(self.domains): diff --git a/sphinx/io.py b/sphinx/io.py index 9b27e04fd..ab8c9d068 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -8,7 +8,8 @@ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from docutils.io import FileInput +from docutils.io import FileInput, NullOutput +from docutils.core import Publisher from docutils.readers import standalone from docutils.writers import UnfilteredWriter from six import string_types, text_type, iteritems @@ -185,3 +186,21 @@ class SphinxFileInput(FileInput): if self.env.config.rst_prolog: data = self.env.config.rst_prolog + '\n' + data return docinfo + data + + +def read_doc(app, env, filename): + """Parse a document and convert to doctree.""" + # type: (Sphinx, BuildEnvironment, unicode) -> nodes.document + reader = SphinxStandaloneReader(app, parsers=app.registry.get_source_parsers()) + source = SphinxFileInput(app, env, source=None, source_path=filename, + encoding=env.config.source_encoding) + + pub = Publisher(reader=reader, + writer=SphinxDummyWriter(), + source_class=SphinxDummySourceClass, + destination=NullOutput()) + pub.set_components(None, 'restructuredtext', None) + pub.process_programmatic_settings(None, env.settings, None) + pub.set_source(source, filename) + pub.publish() + return pub.document From f7dd8e94e2dca3ebb86acd4b1c00549b3c48a477 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:25 +0900 Subject: [PATCH 0294/1814] Add default_role contextmanager to enable default-role temporarily --- sphinx/environment/__init__.py | 18 ++---------------- sphinx/util/rst.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index e8b157c3d..c8c2c4acd 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -26,13 +26,11 @@ from six.moves import cPickle as pickle from docutils.utils import Reporter, get_source_line, normalize_language_tag from docutils.utils.smartquotes import smartchars -from docutils.parsers.rst import roles -from docutils.parsers.rst.languages import en as english from docutils.frontend import OptionParser from sphinx import addnodes from sphinx.io import read_doc -from sphinx.util import logging +from sphinx.util import logging, rst from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator from sphinx.util.nodes import is_translatable from sphinx.util.osutil import SEP, ensuredir @@ -80,8 +78,6 @@ default_settings = { ENV_VERSION = 52 + (sys.version_info[0] - 2) -dummy_reporter = Reporter('', 4, 4) - versioning_conditions = { 'none': False, 'text': is_translatable, @@ -696,16 +692,7 @@ class BuildEnvironment(object): if path.isfile(docutilsconf): self.note_dependency(docutilsconf) - with sphinx_domains(self): - if self.config.default_role: - role_fn, messages = roles.role(self.config.default_role, english, - 0, dummy_reporter) - if role_fn: - roles._roles[''] = role_fn - else: - logger.warning('default role %s not found', self.config.default_role, - location=docname) - + with sphinx_domains(self), rst.default_role(docname, self.config.default_role): codecs.register_error('sphinx', self.warn_and_replace) # type: ignore doctree = read_doc(self.app, self, self.doc2path(docname)) @@ -745,7 +732,6 @@ class BuildEnvironment(object): # cleanup self.temp_data.clear() self.ref_context.clear() - roles._roles.pop('', None) # if a document has set a local default role self.write_doctree(docname, doctree) diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index 8186130cf..b77e75ebf 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -8,12 +8,37 @@ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +from __future__ import absolute_import import re +from contextlib import contextmanager + +from docutils.parsers.rst import roles +from docutils.parsers.rst.languages import en as english +from docutils.utils import Reporter + +from sphinx.util import logging symbols_re = re.compile(r'([!-/:-@\[-`{-~])') +logger = logging.getLogger(__name__) def escape(text): # type: (unicode) -> unicode return symbols_re.sub(r'\\\1', text) # type: ignore + + +@contextmanager +def default_role(docname, name): + # type: (unicode, unicode) -> None + if name: + dummy_reporter = Reporter('', 4, 4) + role_fn, _ = roles.role(name, english, 0, dummy_reporter) + if role_fn: + roles._roles[''] = role_fn + else: + logger.warning('default role %s not found', name, location=docname) + + yield + + roles._roles.pop('', None) # if a document has set a local default role From e2be2ca77f54897a00dd7dd60decfa34ae7b9a06 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:26 +0900 Subject: [PATCH 0295/1814] Move env.warn_and_replace() to SphinxInput class --- sphinx/environment/__init__.py | 17 ----------------- sphinx/io.py | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index c8c2c4acd..76b360a0f 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -14,7 +14,6 @@ import os import sys import time import types -import codecs import fnmatch import warnings from os import path @@ -642,21 +641,6 @@ class BuildEnvironment(object): # --------- SINGLE FILE READING -------------------------------------------- - def warn_and_replace(self, error): - # type: (Any) -> Tuple - """Custom decoding error handler that warns and replaces.""" - linestart = error.object.rfind(b'\n', 0, error.start) - lineend = error.object.find(b'\n', error.start) - if lineend == -1: - lineend = len(error.object) - lineno = error.object.count(b'\n', 0, error.start) + 1 - logger.warning('undecodable source characters, replacing with "?": %r', - (error.object[linestart + 1:error.start] + b'>>>' + - error.object[error.start:error.end] + b'<<<' + - error.object[error.end:lineend]), - location=(self.docname, lineno)) - return (u'?', error.end) - def prepare_settings(self, docname): """Prepare to set up environment for reading.""" # type: (unicode) -> None @@ -693,7 +677,6 @@ class BuildEnvironment(object): self.note_dependency(docutilsconf) with sphinx_domains(self), rst.default_role(docname, self.config.default_role): - codecs.register_error('sphinx', self.warn_and_replace) # type: ignore doctree = read_doc(self.app, self, self.doc2path(docname)) # post-processing diff --git a/sphinx/io.py b/sphinx/io.py index ab8c9d068..b2e54622c 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -8,6 +8,8 @@ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import codecs + from docutils.io import FileInput, NullOutput from docutils.core import Publisher from docutils.readers import standalone @@ -25,6 +27,7 @@ from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.i18n import ( PreserveTranslatableMessages, Locale, RemoveTranslatableInline, ) +from sphinx.util import logging from sphinx.util import import_object, split_docinfo from sphinx.util.docutils import LoggingReporter @@ -40,6 +43,9 @@ if False: from sphinx.environment import BuildEnvironment # NOQA +logger = logging.getLogger(__name__) + + class SphinxBaseReader(standalone.Reader): """ Add our source parsers @@ -154,6 +160,10 @@ class SphinxFileInput(FileInput): # type: (Sphinx, BuildEnvironment, Any, Any) -> None self.app = app self.env = env + + # set up error handler + codecs.register_error('sphinx', self.warn_and_replace) # type: ignore + kwds['error_handler'] = 'sphinx' # py3: handle error on open. FileInput.__init__(self, *args, **kwds) @@ -187,6 +197,21 @@ class SphinxFileInput(FileInput): data = self.env.config.rst_prolog + '\n' + data return docinfo + data + def warn_and_replace(self, error): + # type: (Any) -> Tuple + """Custom decoding error handler that warns and replaces.""" + linestart = error.object.rfind(b'\n', 0, error.start) + lineend = error.object.find(b'\n', error.start) + if lineend == -1: + lineend = len(error.object) + lineno = error.object.count(b'\n', 0, error.start) + 1 + logger.warning('undecodable source characters, replacing with "?": %r', + (error.object[linestart + 1:error.start] + b'>>>' + + error.object[error.start:error.end] + b'<<<' + + error.object[error.end:lineend]), + location=(self.env.docname, lineno)) + return (u'?', error.end) + def read_doc(app, env, filename): """Parse a document and convert to doctree.""" From 7fab902561f2153e8c07b3bfd1368b148dca93a8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 23:04:26 +0900 Subject: [PATCH 0296/1814] Move UIDs assigning to sphinx.versioning --- sphinx/environment/__init__.py | 19 ++----------------- sphinx/versioning.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 76b360a0f..2669710d9 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -27,7 +27,7 @@ from docutils.utils import Reporter, get_source_line, normalize_language_tag from docutils.utils.smartquotes import smartchars from docutils.frontend import OptionParser -from sphinx import addnodes +from sphinx import addnodes, versioning from sphinx.io import read_doc from sphinx.util import logging, rst from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator @@ -42,7 +42,6 @@ from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError from sphinx.locale import __ from sphinx.transforms import SphinxTransformer -from sphinx.versioning import add_uids, merge_doctrees from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.environment.adapters.toctree import TocTree @@ -695,22 +694,8 @@ class BuildEnvironment(object): time.time(), path.getmtime(self.doc2path(docname))) if self.versioning_condition: - old_doctree = None - if self.versioning_compare: - # get old doctree - try: - with open(self.doc2path(docname, - self.doctreedir, '.doctree'), 'rb') as f: - old_doctree = pickle.load(f) - except EnvironmentError: - pass - # add uids for versioning - if not self.versioning_compare or old_doctree is None: - list(add_uids(doctree, self.versioning_condition)) - else: - list(merge_doctrees( - old_doctree, doctree, self.versioning_condition)) + versioning.prepare(doctree) # cleanup self.temp_data.clear() diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 97a013135..1e7c452bd 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -15,6 +15,9 @@ from itertools import product from six import iteritems from six.moves import range, zip_longest +from six.moves import cPickle as pickle + +from sphinx.transforms import SphinxTransform if False: # For type annotation @@ -148,3 +151,32 @@ def levenshtein_distance(a, b): current_row.append(min(insertions, deletions, substitutions)) previous_row = current_row # type: ignore return previous_row[-1] + + +class UIDTransform(SphinxTransform): + """Add UIDs to doctree for versioning.""" + default_priority = 100 + + def apply(self): + env = self.env + old_doctree = None + if env.versioning_compare: + # get old doctree + try: + filename = env.doc2path(env.docname, env.doctreedir, '.doctree') + with open(filename, 'rb') as f: + old_doctree = pickle.load(f) + except EnvironmentError: + pass + + # add uids for versioning + if not env.versioning_compare or old_doctree is None: + list(add_uids(self.document, env.versioning_condition)) + else: + list(merge_doctrees(old_doctree, self.document, env.versioning_condition)) + + +def prepare(document): + """Simple wrapper for UIDTransform.""" + transform = UIDTransform(document) + transform.apply() From e03ec5b9fb6c4ed3e86b1657cac709fd33cbd8d6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 1 Nov 2017 00:10:33 +0900 Subject: [PATCH 0297/1814] confirm selected language supports smart_quotes or not (refs: #4112) --- sphinx/environment/__init__.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 553ab794c..9aec464a4 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -686,11 +686,12 @@ class BuildEnvironment(object): else: self.settings['smart_quotes'] = self.config.smart_quotes - for tag in normalize_language_tag(language): - if tag in smartchars.quotes: - break - else: - self.settings['smart_quotes'] = False + # confirm selected language supports smart_quotes or not + for tag in normalize_language_tag(language): + if tag in smartchars.quotes: + break + else: + self.settings['smart_quotes'] = False docutilsconf = path.join(self.srcdir, 'docutils.conf') # read docutils.conf from source dir, not from current dir From 4b3d41c855b84fb6077938b03f2020c2da383996 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 31 Oct 2017 20:30:32 +0100 Subject: [PATCH 0298/1814] Fix typo in doc/config.rst --- doc/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/config.rst b/doc/config.rst index dca199652..55111930d 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -26,7 +26,7 @@ and output behavior. The configuration file is executed as Python code at build time (using :func:`execfile`, and with the current directory set to its containing -directory), and therefore can execute arbitrarily complex code. Sphinx then +directory), and therefore can execute arbitrarily complex code. Important points to note: From 9701c236d4cf26aeb5504fffa1f6af0f8e280409 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 31 Oct 2017 20:31:56 +0100 Subject: [PATCH 0299/1814] Trim docs/config.rst now that new config setting smart_quotes exists --- doc/config.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 55111930d..329b6fa20 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -15,15 +15,12 @@ and output behavior. An optional file `docutils.conf`_ can be added to the configuration directory to adjust `Docutils`_ configuration if not otherwise overriden or - set by Sphinx; this applies in particular to the `Docutils smart_quotes - setting`_ (Note that Sphinx applies smart quotes transform by default.) + set by Sphinx. .. _`docutils`: http://docutils.sourceforge.net/ .. _`docutils.conf`: http://docutils.sourceforge.net/docs/user/config.html - .. _`Docutils smart_quotes setting`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes - The configuration file is executed as Python code at build time (using :func:`execfile`, and with the current directory set to its containing directory), and therefore can execute arbitrarily complex code. From 29c62c64f5dfd989cca00028fff8936a324873b9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 1 Nov 2017 14:33:22 +0900 Subject: [PATCH 0300/1814] Fix #4206: latex: reST label between paragraphs loses paragraph break --- CHANGES | 2 ++ sphinx/writers/latex.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGES b/CHANGES index d7250ae15..4bd9b4622 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,8 @@ Features added Bugs fixed ---------- +* #4206: latex: reST label between paragraphs loses paragraph break + Testing -------- diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 83ccd54de..df39c84fd 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1919,6 +1919,12 @@ class LaTeXTranslator(nodes.NodeVisitor): # will be generated differently if id.startswith('index-'): return + + # insert blank line, if the target follows a paragraph node + index = node.parent.index(node) + if index > 0 and isinstance(node.parent[index - 1], nodes.paragraph): + self.body.append('\n') + # do not generate \phantomsection in \section{} anchor = not self.in_title self.body.append(self.hypertarget(id, anchor=anchor)) From 79df05b36d941f31a8abef3c609693c0d02f6743 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 1 Nov 2017 22:35:00 +0900 Subject: [PATCH 0301/1814] Revert "Add :confval:`smart_quotes` to disable smart quotes through ``conf.py`` (refs: #4142)" This reverts commit bfd39c12b272a494bcf2f6e7477076f5f6b00d2f. --- CHANGES | 2 -- doc/config.rst | 16 ++++------------ sphinx/config.py | 1 - sphinx/environment/__init__.py | 6 +++--- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 4bd9b4622..aa38012d1 100644 --- a/CHANGES +++ b/CHANGES @@ -14,8 +14,6 @@ Features added -------------- * #4181: autodoc: Sort dictionary keys when possible -* Add :confval:`smart_quotes` to disable smart quotes through ``conf.py`` - (refs: #3967) Bugs fixed ---------- diff --git a/doc/config.rst b/doc/config.rst index 329b6fa20..7a6d20147 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -23,7 +23,8 @@ and output behavior. The configuration file is executed as Python code at build time (using :func:`execfile`, and with the current directory set to its containing -directory), and therefore can execute arbitrarily complex code. +directory), and therefore can execute arbitrarily complex code. Sphinx then +reads simple names from the file's namespace as its configuration. Important points to note: @@ -341,14 +342,6 @@ General configuration .. versionadded:: 1.3 -.. confval:: smart_quotes - - If true, `SmartyPants `_ - will be used to convert quotes and dashes to typographically correct - entities. Default: ``True``. - - .. versionadded:: 1.6.6 - .. confval:: tls_verify If true, Sphinx verifies server certifications. Default is ``True``. @@ -785,9 +778,8 @@ that use Sphinx's HTMLWriter class. entities. Default: ``True``. .. deprecated:: 1.6 - To disable smart quotes, use :confval:`smart_quotes` or the Docutils - configuration file (``docutils.conf``) instead to set there its - `smart_quotes option`_. + To disable or customize smart quotes, use the Docutils configuration file + (``docutils.conf``) instead to set there its `smart_quotes option`_. .. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes diff --git a/sphinx/config.py b/sphinx/config.py index 5308c52bf..02ee529a3 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -132,7 +132,6 @@ class Config(object): tls_verify = (True, 'env'), tls_cacerts = (None, 'env'), - smart_quotes = (True, 'env'), ) # type: Dict[unicode, Tuple] def __init__(self, dirname, filename, overrides, tags): diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 9aec464a4..522414ea6 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -677,14 +677,14 @@ class BuildEnvironment(object): language = self.config.language or 'en' self.settings['language_code'] = language if 'smart_quotes' not in self.settings: + self.settings['smart_quotes'] = True if self.config.html_use_smartypants is not None: warnings.warn("html_use_smartypants option is deprecated. Smart " "quotes are on by default; if you want to disable " - "them, use the smart_quotes option", + "or customize them, use the smart_quotes option in " + "docutils.conf.", RemovedInSphinx17Warning) self.settings['smart_quotes'] = self.config.html_use_smartypants - else: - self.settings['smart_quotes'] = self.config.smart_quotes # confirm selected language supports smart_quotes or not for tag in normalize_language_tag(language): From c4e364ee630764437c6870aafa27cc8d87796e25 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 2 Nov 2017 00:03:29 +0900 Subject: [PATCH 0302/1814] Rename tests directory; roots/test-doctest -> roots/test-ext-doctest --- tests/roots/{test-doctest => test-ext-doctest}/conf.py | 0 tests/roots/{test-doctest => test-ext-doctest}/doctest.txt | 0 tests/test_ext_doctest.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/roots/{test-doctest => test-ext-doctest}/conf.py (100%) rename tests/roots/{test-doctest => test-ext-doctest}/doctest.txt (100%) diff --git a/tests/roots/test-doctest/conf.py b/tests/roots/test-ext-doctest/conf.py similarity index 100% rename from tests/roots/test-doctest/conf.py rename to tests/roots/test-ext-doctest/conf.py diff --git a/tests/roots/test-doctest/doctest.txt b/tests/roots/test-ext-doctest/doctest.txt similarity index 100% rename from tests/roots/test-doctest/doctest.txt rename to tests/roots/test-ext-doctest/doctest.txt diff --git a/tests/test_ext_doctest.py b/tests/test_ext_doctest.py index 705f6262a..fa3ad6bc4 100644 --- a/tests/test_ext_doctest.py +++ b/tests/test_ext_doctest.py @@ -14,7 +14,7 @@ from sphinx.ext.doctest import compare_version cleanup_called = 0 -@pytest.mark.sphinx('doctest', testroot='doctest') +@pytest.mark.sphinx('doctest', testroot='ext-doctest') def test_build(app, status, warning): global cleanup_called cleanup_called = 0 From d5bea6b85a56cb4ea052674bd0649818f8a89b2f Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Wed, 1 Nov 2017 22:03:45 +0100 Subject: [PATCH 0303/1814] autosummary: catch all exceptions when importing modules Module imports may raise any exceptions, including SystemExit, which need to be caught. --- sphinx/ext/autosummary/__init__.py | 23 +++++++++++++++++-- .../autosummary_importfail.py | 4 ++++ tests/roots/test-ext-autosummary/contents.rst | 5 ++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/roots/test-ext-autosummary/autosummary_importfail.py diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 67bbf6d91..4150ce83a 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -58,6 +58,8 @@ import re import sys import inspect import posixpath +import traceback +import warnings from six import string_types from types import ModuleType @@ -502,6 +504,22 @@ def import_by_name(name, prefixes=[None]): raise ImportError('no module named %s' % ' or '.join(tried)) +def _import_module(modname): + """ + Call __import__(modname), convert exceptions to ImportError + """ + try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=ImportWarning) + return __import__(modname) + except BaseException: + # Importing modules may cause any side effects, including + # SystemExit, so we need to catch all errors. + errmsg = "Failed to import %r: %s" % ( + modname, traceback.format_exc()) + raise ImportError(errmsg) + + def _import_by_name(name): # type: (str) -> Tuple[Any, Any, unicode] """Import a Python object given its full name.""" @@ -512,7 +530,7 @@ def _import_by_name(name): modname = '.'.join(name_parts[:-1]) if modname: try: - __import__(modname) + _import_module(modname) mod = sys.modules[modname] return getattr(mod, name_parts[-1]), mod, modname except (ImportError, IndexError, AttributeError): @@ -525,9 +543,10 @@ def _import_by_name(name): last_j = j modname = '.'.join(name_parts[:j]) try: - __import__(modname) + _import_module(modname) except ImportError: continue + if modname in sys.modules: break diff --git a/tests/roots/test-ext-autosummary/autosummary_importfail.py b/tests/roots/test-ext-autosummary/autosummary_importfail.py new file mode 100644 index 000000000..9e3f9f195 --- /dev/null +++ b/tests/roots/test-ext-autosummary/autosummary_importfail.py @@ -0,0 +1,4 @@ +import sys + +# Fail module import in a catastrophic way +sys.exit(1) diff --git a/tests/roots/test-ext-autosummary/contents.rst b/tests/roots/test-ext-autosummary/contents.rst index 3b43086a2..fc84927bb 100644 --- a/tests/roots/test-ext-autosummary/contents.rst +++ b/tests/roots/test-ext-autosummary/contents.rst @@ -1,6 +1,11 @@ +:autolink:`autosummary_dummy_module.Foo` + +:autolink:`autosummary_importfail` + .. autosummary:: :toctree: generated autosummary_dummy_module autosummary_dummy_module.Foo + autosummary_importfail From 6b15c9c1c738c587a73b4144e8fe2b0d3b8aa4b4 Mon Sep 17 00:00:00 2001 From: Matthew Woodcraft Date: Sun, 5 Nov 2017 22:47:57 +0000 Subject: [PATCH 0304/1814] #3998: Add optional section numbering in plain text output Controlled by new config values: text_add_secnumbers and text_secnumber_suffix. --- AUTHORS | 1 + CHANGES | 2 + doc/config.rst | 14 ++++++ sphinx/builders/text.py | 6 ++- sphinx/writers/text.py | 15 +++++++ tests/roots/test-build-text/contents.txt | 3 ++ tests/roots/test-build-text/doc1.txt | 2 + tests/roots/test-build-text/doc2.txt | 9 ++++ tests/test_build_text.py | 54 ++++++++++++++++++++++++ 9 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/roots/test-build-text/doc1.txt create mode 100644 tests/roots/test-build-text/doc2.txt diff --git a/AUTHORS b/AUTHORS index f4ce16164..5a7fb0842 100644 --- a/AUTHORS +++ b/AUTHORS @@ -67,6 +67,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 79c562606..98705d233 100644 --- a/CHANGES +++ b/CHANGES @@ -43,6 +43,8 @@ Features added * #4168: improve zh search with jieba * HTML themes can set up default sidebars through ``theme.conf`` * #3160: html: Use ```` to represent ``:kbd:`` role +* #3998: text: Add new config values :confval:`text_add_secnumbers` and + :confval:`text_secnumber_suffix` Features removed diff --git a/doc/config.rst b/doc/config.rst index 415a2298a..a5554d7cc 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -1959,6 +1959,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 ``False``. + + .. 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/sphinx/builders/text.py b/sphinx/builders/text.py index 29ceaa855..5c6aa94f2 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -39,7 +39,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 +73,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 +95,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', False, 'env') + app.add_config_value('text_secnumber_suffix', '. ', 'env') return { 'version': 'builtin', diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index d2b2f9045..ce60164b2 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: 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/test_build_text.py b/tests/test_build_text.py index 81e354ecd..6e9aec4b6 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -110,3 +110,57 @@ 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() + result = (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 result == expect + + app.config.text_add_secnumbers = True + app.builder.build_all() + result = (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 result == expect + + app.config.text_secnumber_suffix = " " + app.builder.build_all() + result = (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 result == expect + From 7fac34bb44282d26af0ba67fbda7544ccf53c33f Mon Sep 17 00:00:00 2001 From: Matthew Woodcraft Date: Mon, 6 Nov 2017 20:54:17 +0000 Subject: [PATCH 0305/1814] Fix typing imports for mypy in sphinx.builders.text --- sphinx/builders/text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index 5c6aa94f2..e553e89d0 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 From 604db47228689c512fd5f7eb75669b1a0f30e867 Mon Sep 17 00:00:00 2001 From: Matthew Woodcraft Date: Tue, 7 Nov 2017 23:10:11 +0000 Subject: [PATCH 0306/1814] #3998: Toctree section numbering in plain text output --- sphinx/writers/text.py | 5 +++- tests/test_build_text.py | 51 +++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index ce60164b2..b54bde38b 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -1002,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/test_build_text.py b/tests/test_build_text.py index 6e9aec4b6..2651f35ce 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -115,7 +115,20 @@ def test_list_items_in_admonition(app, status, warning): @with_text_app() def test_secnums(app, status, warning): app.builder.build_all() - result = (app.outdir / 'doc2.txt').text(encoding='utf8') + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + expect = ( + "* Section A\n" + "\n" + "* Section B\n" + "\n" + " * Sub Ba\n" + "\n" + " * Sub Bb\n" + "\n" + "* 日本語\n" + ) + assert contents == expect + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') expect = ( "Section B\n" "*********\n" @@ -128,11 +141,24 @@ def test_secnums(app, status, warning): "Sub Bb\n" "======\n" ) - assert result == expect + assert doc2 == expect app.config.text_add_secnumbers = True app.builder.build_all() - result = (app.outdir / 'doc2.txt').text(encoding='utf8') + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + expect = ( + "* 1. Section A\n" + "\n" + "* 2. Section B\n" + "\n" + " * 2.1. Sub Ba\n" + "\n" + " * 2.2. Sub Bb\n" + "\n" + "* 3. 日本語\n" + ) + assert contents == expect + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') expect = ( "2. Section B\n" "************\n" @@ -145,11 +171,24 @@ def test_secnums(app, status, warning): "2.2. Sub Bb\n" "===========\n" ) - assert result == expect + assert doc2 == expect app.config.text_secnumber_suffix = " " app.builder.build_all() - result = (app.outdir / 'doc2.txt').text(encoding='utf8') + contents = (app.outdir / 'contents.txt').text(encoding='utf8') + expect = ( + "* 1 Section A\n" + "\n" + "* 2 Section B\n" + "\n" + " * 2.1 Sub Ba\n" + "\n" + " * 2.2 Sub Bb\n" + "\n" + "* 3 日本語\n" + ) + assert contents == expect + doc2 = (app.outdir / 'doc2.txt').text(encoding='utf8') expect = ( "2 Section B\n" "***********\n" @@ -162,5 +201,5 @@ def test_secnums(app, status, warning): "2.2 Sub Bb\n" "==========\n" ) - assert result == expect + assert doc2 == expect From e99eb094295cecc17059c3ba210761d46c06ccd0 Mon Sep 17 00:00:00 2001 From: Matthew Woodcraft Date: Tue, 7 Nov 2017 23:51:45 +0000 Subject: [PATCH 0307/1814] Fix Python 2 problems in test_build_text --- tests/test_build_text.py | 60 ++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/tests/test_build_text.py b/tests/test_build_text.py index 2651f35ce..b18a08cbb 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -116,18 +116,14 @@ def test_list_items_in_admonition(app, status, warning): def test_secnums(app, status, warning): app.builder.build_all() contents = (app.outdir / 'contents.txt').text(encoding='utf8') - expect = ( - "* Section A\n" - "\n" - "* Section B\n" - "\n" - " * Sub Ba\n" - "\n" - " * Sub Bb\n" - "\n" - "* 日本語\n" - ) - assert contents == expect + 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" @@ -146,18 +142,14 @@ def test_secnums(app, status, warning): app.config.text_add_secnumbers = True app.builder.build_all() contents = (app.outdir / 'contents.txt').text(encoding='utf8') - expect = ( - "* 1. Section A\n" - "\n" - "* 2. Section B\n" - "\n" - " * 2.1. Sub Ba\n" - "\n" - " * 2.2. Sub Bb\n" - "\n" - "* 3. 日本語\n" - ) - assert contents == expect + 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" @@ -176,18 +168,14 @@ def test_secnums(app, status, warning): app.config.text_secnumber_suffix = " " app.builder.build_all() contents = (app.outdir / 'contents.txt').text(encoding='utf8') - expect = ( - "* 1 Section A\n" - "\n" - "* 2 Section B\n" - "\n" - " * 2.1 Sub Ba\n" - "\n" - " * 2.2 Sub Bb\n" - "\n" - "* 3 日本語\n" - ) - assert contents == expect + 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" From 17dc8beeaf5cdf1de7e833b223e3ca92f3576aaa Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Sat, 4 Nov 2017 14:08:59 +0300 Subject: [PATCH 0308/1814] Apply fixFirefoxAnchorBug only under Firefox A compatibility shim for `$.browser` was added in c608af4babe140626877be08535af095ff633c00. Fixes #3549 --- sphinx/themes/basic/static/doctools.js_t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/themes/basic/static/doctools.js_t b/sphinx/themes/basic/static/doctools.js_t index 9ceecef79..326856cfc 100644 --- a/sphinx/themes/basic/static/doctools.js_t +++ b/sphinx/themes/basic/static/doctools.js_t @@ -206,7 +206,7 @@ var Documentation = { * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 */ fixFirefoxAnchorBug : function() { - if (document.location.hash) + if (document.location.hash && $.browser.mozilla) window.setTimeout(function() { document.location.href += ''; }, 10); From 71d4bc4a3ef4f5c2957fca844760a68318e20afd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 16:21:17 +0900 Subject: [PATCH 0309/1814] Move import_module() to sphinx.ext.autodoc.importer --- sphinx/ext/autodoc/__init__.py | 10 ++++------ sphinx/ext/autodoc/importer.py | 17 +++++++++++++++++ sphinx/ext/autosummary/__init__.py | 24 +++--------------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index e8586943f..31fd47c1a 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -15,7 +15,6 @@ import re import sys import inspect import traceback -import warnings from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types @@ -25,7 +24,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx -from sphinx.ext.autodoc.importer import _MockImporter +from sphinx.ext.autodoc.importer import _MockImporter, import_module from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA from sphinx.util import rpartition, force_decode from sphinx.locale import _ @@ -392,10 +391,7 @@ class Documenter(object): import_hook = _MockImporter(self.env.config.autodoc_mock_imports) try: logger.debug('[autodoc] import %s', self.modname) - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=ImportWarning) - with logging.skip_warningiserror(not self.env.config.autodoc_warningiserror): - __import__(self.modname) + import_module(self.modname, self.env.config.autodoc_warningiserror) parent = None obj = self.module = sys.modules[self.modname] logger.debug('[autodoc] => %r', obj) @@ -420,6 +416,8 @@ class Documenter(object): if isinstance(e, SystemExit): errmsg += ('; the module executes module level statement ' + 'and it might call sys.exit().') + elif isinstance(e, ImportError): + errmsg += '; the following exception was raised:\n%s' % e.args[0] else: errmsg += '; the following exception was raised:\n%s' % \ traceback.format_exc() diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 1234d716a..cfa7411ec 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -10,6 +10,8 @@ """ import sys +import traceback +import warnings from types import FunctionType, MethodType, ModuleType from sphinx.util import logging @@ -116,3 +118,18 @@ class _MockImporter(object): sys.modules[name] = module self.mocked_modules.append(name) return module + + +def import_module(modname, warningiserror=False): + """ + Call __import__(modname), convert exceptions to ImportError + """ + try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=ImportWarning) + with logging.skip_warningiserror(not warningiserror): + return __import__(modname) + except BaseException as exc: + # Importing modules may cause any side effects, including + # SystemExit, so we need to catch all errors. + raise ImportError(traceback.format_exc()) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 4150ce83a..21bfe7b13 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -58,8 +58,6 @@ import re import sys import inspect import posixpath -import traceback -import warnings from six import string_types from types import ModuleType @@ -75,6 +73,7 @@ from sphinx.environment.adapters.toctree import TocTree from sphinx.util import import_object, rst, logging from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.ext.autodoc import Options +from sphinx.ext.autodoc.importer import import_module if False: # For type annotation @@ -504,22 +503,6 @@ def import_by_name(name, prefixes=[None]): raise ImportError('no module named %s' % ' or '.join(tried)) -def _import_module(modname): - """ - Call __import__(modname), convert exceptions to ImportError - """ - try: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=ImportWarning) - return __import__(modname) - except BaseException: - # Importing modules may cause any side effects, including - # SystemExit, so we need to catch all errors. - errmsg = "Failed to import %r: %s" % ( - modname, traceback.format_exc()) - raise ImportError(errmsg) - - def _import_by_name(name): # type: (str) -> Tuple[Any, Any, unicode] """Import a Python object given its full name.""" @@ -530,8 +513,7 @@ def _import_by_name(name): modname = '.'.join(name_parts[:-1]) if modname: try: - _import_module(modname) - mod = sys.modules[modname] + mod = import_module(modname) return getattr(mod, name_parts[-1]), mod, modname except (ImportError, IndexError, AttributeError): pass @@ -543,7 +525,7 @@ def _import_by_name(name): last_j = j modname = '.'.join(name_parts[:j]) try: - _import_module(modname) + import_module(modname) except ImportError: continue From 2c1ac5243cd88875700f1b6669713edb27ae8368 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 16:47:51 +0900 Subject: [PATCH 0310/1814] Update CHANGES for PR #4212 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 79c562606..f02b25a48 100644 --- a/CHANGES +++ b/CHANGES @@ -43,6 +43,7 @@ Features added * #4168: improve zh search with jieba * HTML themes can set up default sidebars through ``theme.conf`` * #3160: html: Use ```` to represent ``:kbd:`` role +* #4212: autosummary: catch all exceptions when importing modules Features removed From 8b090c6372513068d063dc74d614fcb6dbc60121 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 17:00:50 +0900 Subject: [PATCH 0311/1814] Fix flake8 violation --- sphinx/ext/autodoc/importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index cfa7411ec..b517cf911 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -129,7 +129,7 @@ def import_module(modname, warningiserror=False): warnings.filterwarnings("ignore", category=ImportWarning) with logging.skip_warningiserror(not warningiserror): return __import__(modname) - except BaseException as exc: + except BaseException: # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. raise ImportError(traceback.format_exc()) From c3113d2e17a9168097974bc8f01eb3f93277e660 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 18:30:32 +0900 Subject: [PATCH 0312/1814] Update CHANGES for PR #4231 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index aa38012d1..85433e2b8 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,7 @@ Bugs fixed ---------- * #4206: latex: reST label between paragraphs loses paragraph break +* #4231: html: Apply fixFirefoxAnchorBug only under Firefox Testing -------- From 507f172866deb5d7223f9e61c30a68b45d6f8f38 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 18:35:45 +0900 Subject: [PATCH 0313/1814] Make ShowUrlsTransform as a subclass of Transform --- sphinx/writers/latex.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 389d840c1..e48905757 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -25,6 +25,7 @@ from sphinx import addnodes from sphinx import highlighting from sphinx.errors import SphinxError from sphinx.locale import admonitionlabels, _ +from sphinx.transforms import SphinxTransform from sphinx.util import split_into, logging from sphinx.util.i18n import format_date from sphinx.util.nodes import clean_astext, traverse_parent @@ -222,12 +223,11 @@ class ExtBabel(Babel): return language -class ShowUrlsTransform(object): - expanded = False - - def __init__(self, document): - # type: (nodes.Node) -> None - self.document = document +class ShowUrlsTransform(SphinxTransform, object): + def __init__(self, document, startnode=None): + # type: (nodes.document, nodes.Node) -> None + super(ShowUrlsTransform, self).__init__(document, startnode) + self.expanded = False def apply(self): # type: () -> None From 3d8ce5a7c40b746aebc4113551ad1ae6144b9898 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 18:47:35 +0900 Subject: [PATCH 0314/1814] Fix mypy violations --- sphinx/environment/__init__.py | 2 +- sphinx/io.py | 2 +- sphinx/util/rst.py | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 2669710d9..7c76da925 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -641,8 +641,8 @@ class BuildEnvironment(object): # --------- SINGLE FILE READING -------------------------------------------- def prepare_settings(self, docname): - """Prepare to set up environment for reading.""" # type: (unicode) -> None + """Prepare to set up environment for reading.""" self.temp_data['docname'] = docname # defaults to the global default, but can be re-set in a document self.temp_data['default_role'] = self.config.default_role diff --git a/sphinx/io.py b/sphinx/io.py index b2e54622c..84e1d7bb3 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -214,8 +214,8 @@ class SphinxFileInput(FileInput): def read_doc(app, env, filename): - """Parse a document and convert to doctree.""" # type: (Sphinx, BuildEnvironment, unicode) -> nodes.document + """Parse a document and convert to doctree.""" reader = SphinxStandaloneReader(app, parsers=app.registry.get_source_parsers()) source = SphinxFileInput(app, env, source=None, source_path=filename, encoding=env.config.source_encoding) diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index b77e75ebf..6977cda96 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -19,6 +19,10 @@ from docutils.utils import Reporter from sphinx.util import logging +if False: + # For type annotation + from typing import Generator # NOQA + symbols_re = re.compile(r'([!-/:-@\[-`{-~])') logger = logging.getLogger(__name__) @@ -30,7 +34,7 @@ def escape(text): @contextmanager def default_role(docname, name): - # type: (unicode, unicode) -> None + # type: (unicode, unicode) -> Generator if name: dummy_reporter = Reporter('', 4, 4) role_fn, _ = roles.role(name, english, 0, dummy_reporter) From 4abe6cb62e54683c60f699d963333b91ee4676c1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 11 Nov 2017 21:53:20 +0900 Subject: [PATCH 0315/1814] Fix #4221: napoleon depends on autodoc, but users need to load it manually --- CHANGES | 1 + doc/ext/napoleon.rst | 9 ++++----- sphinx/ext/napoleon/__init__.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 85433e2b8..4bd6399ae 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,7 @@ Bugs fixed * #4206: latex: reST label between paragraphs loses paragraph break * #4231: html: Apply fixFirefoxAnchorBug only under Firefox +* #4221: napoleon depends on autodoc, but users need to load it manually Testing -------- diff --git a/doc/ext/napoleon.rst b/doc/ext/napoleon.rst index ea3e4042f..f7e9081f7 100644 --- a/doc/ext/napoleon.rst +++ b/doc/ext/napoleon.rst @@ -68,8 +68,8 @@ Getting Started # conf.py - # Add autodoc and napoleon to the extensions list - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] + # Add napoleon to the extensions list + extensions = ['sphinx.ext.napoleon'] 2. Use `sphinx-apidoc` to build your API documentation:: @@ -246,13 +246,12 @@ Configuration Listed below are all the settings used by napoleon and their default values. These settings can be changed in the Sphinx `conf.py` file. Make -sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are -enabled in `conf.py`:: +sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: # conf.py # Add any Sphinx extension module names here, as strings - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] + extensions = ['sphinx.ext.napoleon'] # Napoleon settings napoleon_google_docstring = True diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index f319a18c4..7aca9b629 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -27,13 +27,12 @@ class Config(object): Listed below are all the settings used by napoleon and their default values. These settings can be changed in the Sphinx `conf.py` file. Make - sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are - enabled in `conf.py`:: + sure that "sphinx.ext.napoleon" is enabled in `conf.py`:: # conf.py # Add any Sphinx extension module names here, as strings - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] + extensions = ['sphinx.ext.napoleon'] # Napoleon settings napoleon_google_docstring = True @@ -294,6 +293,7 @@ def setup(app): _patch_python_domain() + app.setup_extension('sphinx.ext.autodoc') app.connect('autodoc-process-docstring', _process_docstring) app.connect('autodoc-skip-member', _skip_member) From bdebbdf873074caca537a3829e55574db7b27823 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 12 Nov 2017 01:51:40 +0900 Subject: [PATCH 0316/1814] Update CHANGES for PR #2299 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 85433e2b8..cf86e266e 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,7 @@ Bugs fixed * #4206: latex: reST label between paragraphs loses paragraph break * #4231: html: Apply fixFirefoxAnchorBug only under Firefox +* #2298: automodule fails to document a class attribute Testing -------- From 189e25ac0e8c39db4f548a597ee566f5464124b0 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 11 Nov 2017 14:26:12 +0100 Subject: [PATCH 0317/1814] Fix issue in import_module returning wrong module --- sphinx/ext/autodoc/__init__.py | 4 ++-- sphinx/ext/autodoc/importer.py | 3 ++- tests/test_ext_autosummary.py | 25 ++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 31fd47c1a..3d7f85618 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -391,9 +391,9 @@ class Documenter(object): import_hook = _MockImporter(self.env.config.autodoc_mock_imports) try: logger.debug('[autodoc] import %s', self.modname) - import_module(self.modname, self.env.config.autodoc_warningiserror) + obj = import_module(self.modname, self.env.config.autodoc_warningiserror) parent = None - obj = self.module = sys.modules[self.modname] + self.module = obj logger.debug('[autodoc] => %r', obj) for part in self.objpath: parent = obj diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index b517cf911..e024d38f3 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -128,7 +128,8 @@ def import_module(modname, warningiserror=False): with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=ImportWarning) with logging.skip_warningiserror(not warningiserror): - return __import__(modname) + __import__(modname) + return sys.modules[modname] except BaseException: # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 81fd35762..b59f0cbc8 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -11,7 +11,7 @@ from six import iteritems, StringIO -from sphinx.ext.autosummary import mangle_signature +from sphinx.ext.autosummary import mangle_signature, import_by_name from sphinx.testing.util import etree_parse @@ -145,3 +145,26 @@ def test_autosummary_generate(app, status, warning): ' ~Foo.__init__\n' ' ~Foo.bar\n' ' \n' in Foo) + + +def test_import_by_name(): + import sphinx + import sphinx.ext.autosummary + + prefixed_name, obj, parent, modname = import_by_name('sphinx') + assert prefixed_name == 'sphinx' + assert obj is sphinx + assert parent is None + assert modname == 'sphinx' + + prefixed_name, obj, parent, modname = import_by_name('sphinx.ext.autosummary.__name__') + assert prefixed_name == 'sphinx.ext.autosummary.__name__' + assert obj is sphinx.ext.autosummary.__name__ + assert parent is sphinx.ext.autosummary + assert modname == 'sphinx.ext.autosummary' + + prefixed_name, obj, parent, modname = import_by_name('sphinx.ext.autosummary.Autosummary.get_items') + assert prefixed_name == 'sphinx.ext.autosummary.Autosummary.get_items' + assert obj == sphinx.ext.autosummary.Autosummary.get_items + assert parent is sphinx.ext.autosummary.Autosummary + assert modname == 'sphinx.ext.autosummary' From 199256e675a29309b08e4ae8fb26245c4bd3e40d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 12 Nov 2017 12:26:51 +0900 Subject: [PATCH 0318/1814] Fix #4226: apidoc: Generate new style makefile (make-mode) --- CHANGES | 1 + sphinx/ext/apidoc.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index e1f3db3ac..046ba5740 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Incompatible changes package when ``--implicit-namespaces`` option given, not subdirectories of given directory. * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc +* #4226: apidoc: Generate new style makefile (make-mode) Deprecated ---------- diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index cb020aba2..6edab379b 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -413,6 +413,7 @@ def main(argv=sys.argv[1:]): ext_todo = True, makefile = True, batchfile = True, + make_mode = True, mastertocmaxdepth = args.maxdepth, mastertoctree = text, language = 'en', From 3cef4b6e7cdbfccad05de0b9ad00b1c0bb30fc1f Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 16 Nov 2017 14:17:28 -0500 Subject: [PATCH 0319/1814] Themes: Add language to javascript vars list --- sphinx/themes/basic/layout.html | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index b337a977e..af91e42f2 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -91,6 +91,7 @@ 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 }}, From 098add17f6bcd79fc1cb801530f4223ba16bfcc8 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 17 Nov 2017 09:45:01 +0100 Subject: [PATCH 0320/1814] BUG: autosummary to list all class members --- sphinx/ext/autosummary/generate.py | 10 ++++------ .../test-ext-autosummary/autosummary_dummy_module.py | 4 ++++ tests/test_ext_autosummary.py | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index f02c50692..fce51924a 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -159,7 +159,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', except TemplateNotFound: template = template_env.get_template('autosummary/base.rst') - def get_members(obj, typ, include_public=[], imported=False): + def get_members(obj, typ, include_public=[], imported=True): # type: (Any, unicode, List[unicode], bool) -> Tuple[List[unicode], List[unicode]] # NOQA items = [] # type: List[unicode] for name in dir(obj): @@ -169,9 +169,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', continue documenter = get_documenter(value, obj) if documenter.objtype == typ: - if typ == 'method': - items.append(name) - elif imported or getattr(value, '__module__', None) == obj.__name__: + if imported or getattr(value, '__module__', None) == obj.__name__: # skip imported members if expected items.append(name) public = [x for x in items @@ -191,9 +189,9 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', elif doc.objtype == 'class': ns['members'] = dir(obj) ns['methods'], ns['all_methods'] = \ - get_members(obj, 'method', ['__init__'], imported=imported_members) + get_members(obj, 'method', ['__init__']) ns['attributes'], ns['all_attributes'] = \ - get_members(obj, 'attribute', imported=imported_members) + get_members(obj, 'attribute') parts = name.split('.') if doc.objtype in ('method', 'attribute'): diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index aa4aaa9f2..c76e73302 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -7,3 +7,7 @@ class Foo: def bar(self): pass + + @property + def baz(self): + pass diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index b59f0cbc8..5c7e7f844 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -145,6 +145,10 @@ def test_autosummary_generate(app, status, warning): ' ~Foo.__init__\n' ' ~Foo.bar\n' ' \n' in Foo) + assert (' .. autosummary::\n' + ' \n' + ' ~Foo.baz\n' + ' \n' in Foo) def test_import_by_name(): From 466241d43ada9c4d5317be86604446e8d6d8ffe6 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 25 Nov 2017 14:37:27 +0100 Subject: [PATCH 0321/1814] C++, small cleanup after PR #4189 --- CHANGES | 3 ++- doc/domains.rst | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index b5ff95063..39b9c5903 100644 --- a/CHANGES +++ b/CHANGES @@ -75,7 +75,8 @@ Features removed * ``sphinx.util.nodes.process_only_nodes()`` * LaTeX environment ``notice``, use ``sphinxadmonition`` instead * LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily`` -* C++, support of function concepts +* C++, support of function concepts. Thanks to mickk-on-cpp. + Bugs fixed ---------- diff --git a/doc/domains.rst b/doc/domains.rst index e6a860bcd..5bed02cf4 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -722,7 +722,8 @@ a visibility statement (``public``, ``private`` or ``protected``). .. rst:directive:: .. cpp:concept:: template-parameter-list name .. warning:: The support for concepts is experimental. It is based on the - Concepts Technical Specification, and the features may change as the TS evolves. + current draft standard and the Concepts Technical Specification. + The features may change as they evolve. Describe a concept. It must have exactly 1 template parameter list. The name may be a nested name. Example:: @@ -774,8 +775,9 @@ Some directives support options: Constrained Templates ~~~~~~~~~~~~~~~~~~~~~ -.. warning:: The support for constrained templates is experimental. It is based on the - Concepts Technical Specification, and the features may change as the TS evolves. +.. warning:: The support for concepts is experimental. It is based on the + current draft standard and the Concepts Technical Specification. + The features may change as they evolve. .. note:: Sphinx does not currently support ``requires`` clauses. From 0aa9d4c87e2c1691735b1a6ee00961c39066b718 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 12:45:27 +0100 Subject: [PATCH 0322/1814] C++, parse more types of integer literals Fixes case 0 of sphinx-doc/sphinx#4114 --- sphinx/domains/cpp.py | 18 +++++++++++++----- tests/test_domain_cpp.py | 17 ++++++++++++++--- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index a1b0a71c3..65376f24a 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -290,7 +290,11 @@ logger = logging.getLogger(__name__) """ # TODO: support hex, oct, etc. work -_integer_literal_re = re.compile(r'-?[1-9][0-9]*') +_integer_literal_re = re.compile(r'[1-9][0-9]*') +_octal_literal_re = re.compile(r'0[0-7]*') +_hex_literal_re = re.compile(r'0[xX][0-7a-fA-F][0-7a-fA-F]*') +_binary_literal_re = re.compile(r'0[bB][01][01]*') +_integer_suffix_re = re.compile(r'') _float_literal_re = re.compile(r'[+-]?[0-9]*\.[0-9]+') _identifier_re = re.compile(r'(~?\b[a-zA-Z_][a-zA-Z0-9_]*)\b') _whitespace_re = re.compile(r'(?u)\s+') @@ -3781,10 +3785,14 @@ class DefinitionParser(object): return ASTBooleanLiteral(True) if self.skip_word('false'): return ASTBooleanLiteral(False) - if self.match(_float_literal_re): - return ASTNumberLiteral(self.matched_text) - if self.match(_integer_literal_re): - return ASTNumberLiteral(self.matched_text) + for regex in [_float_literal_re, _binary_literal_re, _hex_literal_re, + _integer_literal_re, _octal_literal_re]: + pos = self.pos + if self.match(regex): + while self.current_char in 'uUlLfF': + self.pos += 1 + return ASTNumberLiteral(self.definition[pos:self.pos]) + string = self._parse_string() if string is not None: return ASTStringLiteral(string) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 63682237f..22cdce60f 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -111,9 +111,20 @@ def test_expressions(): exprCheck('nullptr', 'LDnE') exprCheck('true', 'L1E') exprCheck('false', 'L0E') - exprCheck('5', 'L5E') - exprCheck('5.0', 'L5.0E') - exprCheck('"abc\\"cba"', 'LA8_KcE') + ints = ['5', '0', '075', '0xF', '0XF', '0b1', '0B1'] + unsignedSuffix = ['', 'u', 'U'] + longSuffix = ['', 'l', 'L', 'll', 'LL'] + for i in ints: + for u in unsignedSuffix: + for l in longSuffix: + expr = i + u + l; + exprCheck(expr, 'L' + expr + 'E') + expr = i + l + u; + exprCheck(expr, 'L' + expr + 'E') + for suffix in ['', 'f', 'F', 'l', 'L']: + expr = '5.0' + suffix + exprCheck(expr, 'L' + expr + 'E') + exprCheck('"abc\\"cba"', 'LA8_KcE') # string # TODO: test the rest exprCheck('(... + Ns)', '(... + Ns)') exprCheck('(5)', 'L5E') From 94934b2bdfd6fca9d505577aa6314f522be148f6 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 15:36:35 +0100 Subject: [PATCH 0323/1814] C++, reintroduce expression fallback parser Part of fixing sphinx-doc/sphinx#4114. This reverts commit b55526f4e87ecfdd5c43cbe4e0dab847ebb0c7c9. --- sphinx/domains/cpp.py | 77 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 65376f24a..ed15f1272 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1073,6 +1073,20 @@ class ASTPostfixExpr(ASTBase): p.describe_signature(signode, mode, env, symbol) +class ASTFallbackExpr(ASTBase): + def __init__(self, expr): + self.expr = expr + + def __unicode__(self): + return self.expr + + def get_id(self, version): + return text_type(self.expr) + + def describe_signature(self, signode, mode, env, symbol): + signode += nodes.Text(self.expr) + + ################################################################################ # The Rest ################################################################################ @@ -4084,6 +4098,43 @@ class DefinitionParser(object): # TODO: actually parse the second production return self._parse_assignment_expression(inTemplate=inTemplate) + def _parse_expression_fallback(self, end, parser): + # type: (List[unicode]) -> unicode + # Stupidly "parse" an expression. + # 'end' should be a list of characters which ends the expression. + + # first try to use the provided parser + prevPos = self.pos + try: + return parser() + except DefinitionError as e: + self.warn("Parsing of expression failed. Using fallback parser." + " Error was:\n%s" % e.description) + self.pos = prevPos + # and then the fallback scanning + assert end is not None + self.skip_ws() + startPos = self.pos + if self.match(_string_re): + value = self.matched_text + else: + # TODO: add handling of more bracket-like things, and quote handling + brackets = {'(': ')', '[': ']', '<': '>'} # type: Dict[unicode, unicode] + symbols = [] # type: List[unicode] + while not self.eof: + if (len(symbols) == 0 and self.current_char in end): + break + if self.current_char in brackets.keys(): + symbols.append(brackets[self.current_char]) + elif len(symbols) > 0 and self.current_char == symbols[-1]: + symbols.pop() + self.pos += 1 + if len(end) > 0 and self.eof: + self.fail("Could not find end of expression starting at %d." + % startPos) + value = self.definition[startPos:self.pos].strip() + return ASTFallbackExpr(value.strip()) + def _parse_operator(self): # type: () -> Any self.skip_ws() @@ -4144,7 +4195,9 @@ class DefinitionParser(object): prevErrors.append((e, "If type argument")) self.pos = pos try: - value = self._parse_constant_expression(inTemplate=True) + def parser(): + return self._parse_constant_expression(inTemplate=True) + value = self._parse_expression_fallback([',', '>'], parser) self.skip_ws() if self.skip_string('>'): parsedEnd = True @@ -4486,7 +4539,10 @@ class DefinitionParser(object): if self.skip_string(']'): arrayOps.append(ASTArray(None)) continue - value = self._parse_expression(inTemplate=False) + + def parser(): + return self._parse_expression(inTemplate=False) + value = self._parse_expression_fallback([']'], parser) if not self.skip_string(']'): self.fail("Expected ']' in end of array operator.") arrayOps.append(ASTArray(value)) @@ -4606,11 +4662,17 @@ class DefinitionParser(object): return None else: if outer == 'member': - value = self._parse_assignment_expression(inTemplate=False) + def parser(): + return self._parse_assignment_expression(inTemplate=False) + value = self._parse_expression_fallback([], parser) elif outer == 'templateParam': - value = self._parse_assignment_expression(inTemplate=True) + def parser(): + return self._parse_assignment_expression(inTemplate=True) + value = self._parse_expression_fallback([',', '>'], parser) elif outer is None: # function parameter - value = self._parse_assignment_expression(inTemplate=False) + def parser(): + return self._parse_assignment_expression(inTemplate=False) + value = self._parse_expression_fallback([',', ')'], parser) else: self.fail("Internal error, initializer for outer '%s' not " "implemented." % outer) @@ -4772,7 +4834,10 @@ class DefinitionParser(object): init = None if self.skip_string('='): self.skip_ws() - initVal = self._parse_constant_expression(inTemplate=False) + + def parser(): + return self._parse_constant_expression(inTemplate=False) + initVal = self._parse_expression_fallback([], parser) init = ASTInitializer(initVal) return ASTEnumerator(name, init) From 6e721e98fefff7264af3707c6479bfbaa43ce168 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 20:32:24 +0100 Subject: [PATCH 0324/1814] C++, parse more unary expressions Last part, fixes sphinx-doc/sphinx#4114 --- sphinx/domains/cpp.py | 115 +++++++++++++++++++++++++++++++++++++++ tests/test_domain_cpp.py | 5 ++ 2 files changed, 120 insertions(+) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index ed15f1272..dca18ddb3 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -948,6 +948,85 @@ class ASTUnaryOpExpr(ASTBase): self.expr.describe_signature(signode, mode, env, symbol) +class ASTSizeofParamPack(ASTBase): + def __init__(self, identifier): + self.identifier = identifier + + def __unicode__(self): + return "sizeof...(" + text_type(self.identifier) + ")" + + def get_id(self, version): + return 'sZ' + self.identifier.get_id(version) + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('sizeof...(')) + self.identifier.describe_signature(signode, mode, env, symbol, "") + signode.append(nodes.Text(')')) + + +class ASTSizeofType(ASTBase): + def __init__(self, typ): + self.typ = typ + + def __unicode__(self): + return "sizeof(" + text_type(self.typ) + ")" + + def get_id(self, version): + return 'st' + self.typ.get_id(version) + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('sizeof(')) + self.typ.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + +class ASTSizeofExpr(ASTBase): + def __init__(self, expr): + self.expr = expr + + def __unicode__(self): + return "sizeof " + text_type(self.expr) + + def get_id(self, version): + return 'sz' + self.expr.get_id(version) + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('sizeof ')) + self.expr.describe_signature(signode, mode, env, symbol) + + +class ASTAlignofExpr(ASTBase): + def __init__(self, typ): + self.typ = typ + + def __unicode__(self): + return "alignof(" + text_type(self.typ) + ")" + + def get_id(self, version): + return 'at' + self.typ.get_id(version) + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('alignof(')) + self.typ.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + +class ASTNoexceptExpr(ASTBase): + def __init__(self, expr): + self.expr = expr + + def __unicode__(self): + return "noexcept(" + text_type(self.expr) + ")" + + def get_id(self, version): + return 'nx' + self.expr.get_id(version) + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('noexcept(')) + self.expr.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + class ASTPostfixCallExpr(ASTBase): def __init__(self, exprs): self.exprs = exprs @@ -3962,6 +4041,7 @@ class DefinitionParser(object): # | "++" cast # | "--" cast # | unary-operator cast -> (* | & | + | - | ! | ~) cast + # The rest: # | "sizeof" unary # | "sizeof" "(" type-id ")" # | "sizeof" "..." "(" identifier ")" @@ -3975,6 +4055,41 @@ class DefinitionParser(object): if self.skip_string(op): expr = self._parse_cast_expression() return ASTUnaryOpExpr(op, expr) + if self.skip_word_and_ws('sizeof'): + if self.skip_string_and_ws('...'): + if not self.skip_string_and_ws('('): + self.fail("Expecting '(' after 'sizeof...'.") + if not self.match(_identifier_re): + self.fail("Expecting identifier for 'sizeof...'.") + ident = ASTIdentifier(self.matched_text) + self.skip_ws() + if not self.skip_string(")"): + self.fail("Expecting ')' to end 'sizeof...'.") + return ASTSizeofParamPack(ident) + if self.skip_string_and_ws('('): + typ = self._parse_type(named=False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expecting ')' to end 'sizeof'.") + return ASTSizeofType(typ) + expr = self._parse_unary_expression() + return ASTSizeofExpr(expr) + if self.skip_word_and_ws('alignof'): + if not self.skip_string_and_ws('('): + self.fail("Expecting '(' after 'alignof'.") + typ = self._parse_type(named=False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expecting ')' to end 'alignof'.") + return ASTAlignofExpr(typ) + if self.skip_word_and_ws('noexcept'): + if not self.skip_string_and_ws('('): + self.fail("Expecting '(' after 'noexcept'.") + expr = self._parse_expression(inTemplate=False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expecting ')' to end 'noexcept'.") + return ASTNoexceptExpr(expr) # TODO: the rest return self._parse_postfix_expression() diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 22cdce60f..3fdb1ae23 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -146,6 +146,11 @@ def test_expressions(): exprCheck('-5', 'ngL5E') exprCheck('!5', 'ntL5E') exprCheck('~5', 'coL5E') + exprCheck('sizeof...(a)', 'sZ1a') + exprCheck('sizeof(T)', 'st1T') + exprCheck('sizeof -42', 'szngL42E') + exprCheck('alignof(T)', 'at1T') + exprCheck('noexcept(-42)', 'nxngL42E') # cast exprCheck('(int)2', 'cviL2E') # binary op From e7ba2abfb2416115fb5ed96eee1f3b27cd263c6f Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 20:40:04 +0100 Subject: [PATCH 0325/1814] Fix type annotation error --- sphinx/domains/cpp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index dca18ddb3..914b79668 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -4214,7 +4214,6 @@ class DefinitionParser(object): return self._parse_assignment_expression(inTemplate=inTemplate) def _parse_expression_fallback(self, end, parser): - # type: (List[unicode]) -> unicode # Stupidly "parse" an expression. # 'end' should be a list of characters which ends the expression. From d6ec677c6161f3fad1d1848f36feb5f35058e914 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 21:41:15 +0100 Subject: [PATCH 0326/1814] C++, parse decltype() Fixes sphinx-doc/sphinx#4094 --- sphinx/domains/cpp.py | 25 +++++++++++++++++++++++-- tests/test_domain_cpp.py | 7 +++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 914b79668..4e9eaeec4 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1931,6 +1931,24 @@ class ASTTrailingTypeSpecDecltypeAuto(ASTBase): signode.append(nodes.Text(text_type(self))) +class ASTTrailingTypeSpecDecltype(ASTBase): + def __init__(self, expr): + self.expr = expr + + def __unicode__(self): + return u'decltype(' + text_type(self.expr) + ')' + + def get_id(self, version): + if version == 1: + raise NoOldIdError() + return 'DT' + self.expr.get_id(version) + "E" + + def describe_signature(self, signode, mode, env, symbol): + signode.append(nodes.Text('decltype(')) + self.expr.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + class ASTFunctionParameter(ASTBase): def __init__(self, arg, ellipsis=False): # type: (Any, bool) -> None @@ -4413,8 +4431,11 @@ class DefinitionParser(object): if not self.skip_string(')'): self.fail("Expected ')' after 'decltype(auto'.") return ASTTrailingTypeSpecDecltypeAuto() - self.fail('"decltype()" in trailing_type_spec not implemented') - # return ASTTrailingTypeSpecDecltype() + expr = self._parse_expression(inTemplate=False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expected ')' after 'decltype('.") + return ASTTrailingTypeSpecDecltype(expr) # prefixed prefix = None diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 3fdb1ae23..8c838fcf8 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -235,6 +235,7 @@ def test_type_definitions(): check("type", "bool ::B::b", {1:"B::b", 2:"N1B1bE"}) check('type', 'A = B', {2:'1A'}) + check('type', 'A = decltype(b)', {2:'1A'}) # from breathe#267 (named function parameters for function pointers check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', @@ -389,6 +390,8 @@ def test_function_definitions(): check('function', 'extern int f()', {1:'f', 2:'1fv'}) + check('function', 'decltype(auto) f()', {1: 'f', 2:"1fv"}) + # TODO: make tests for functions in a template, e.g., Test # such that the id generation for function type types is correct. @@ -466,6 +469,10 @@ def test_class_definitions(): check('class', 'A : B, C...', {1:'A', 2:'1A'}) check('class', 'A : B..., C', {1:'A', 2:'1A'}) + # from #4094 + check('class', 'template> has_var', {2:'I00E7has_var'}) + check('class', 'template has_var>', {2:'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) + def test_enum_definitions(): check('enum', 'A', {2:"1A"}) From 56b520958f554be5a8e04d57c477bc520e2d4de6 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 26 Nov 2017 22:37:26 +0100 Subject: [PATCH 0327/1814] C++: properly link class reference to class from inside constructor Fixes sphinx-doc/sphinx#4099 --- CHANGES | 1 + sphinx/domains/cpp.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 75911ab8c..ff312f1d0 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ Bugs fixed * #4231: html: Apply fixFirefoxAnchorBug only under Firefox * #4221: napoleon depends on autodoc, but users need to load it manually * #2298: automodule fails to document a class attribute +* #4099: C++: properly link class reference to class from inside constructor Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index b81f6531e..23c398e13 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3144,8 +3144,8 @@ class Symbol(object): return None return s - def find_name(self, nestedName, templateDecls, templateShorthand, matchSelf): - # type: (Any, Any, Any, bool) -> Symbol + def find_name(self, nestedName, templateDecls, typ, templateShorthand, matchSelf): + # type: (Any, Any, Any, Any, bool) -> Symbol # templateShorthand: missing template parameter lists for templates is ok # TODO: unify this with the _add_symbols @@ -3163,7 +3163,14 @@ class Symbol(object): while parentSymbol.parent: if parentSymbol.find_identifier(firstName.identifier, matchSelf=matchSelf): - break + # if we are in the scope of a constructor but wants to reference the class + # we need to walk one extra up + if (len(names) == 1 and typ == 'class' and matchSelf and + parentSymbol.parent and parentSymbol.parent.identifier and + parentSymbol.parent.identifier == firstName.identifier): + pass + else: + break parentSymbol = parentSymbol.parent iTemplateDecl = 0 @@ -4945,7 +4952,7 @@ class CPPDomain(Domain): templateDecls = ast.templatePrefix.templates else: templateDecls = [] - s = parentSymbol.find_name(name, templateDecls, + s = parentSymbol.find_name(name, templateDecls, typ, templateShorthand=True, matchSelf=True) if s is None or s.declaration is None: From 9158a5be1b0af4bd515e7d3c9b56d2151933e8e3 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sun, 5 Nov 2017 13:58:27 -0800 Subject: [PATCH 0328/1814] remove todo_emit_warnings override from a test that doesn't need it --- tests/test_ext_todo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 4f01a07ab..6a4789928 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -86,7 +86,7 @@ def test_todo_not_included(app, status, warning): assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar']) @pytest.mark.sphinx('latex', testroot='ext-todo', freshenv=True, - confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True}) + confoverrides={'todo_include_todos': True}) def test_todo_valid_link(app, status, warning): """ Test that the inserted "original entry" links for todo items have a target From fd94702eedca9ce443f96fda1a9969ed54e81c54 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sun, 5 Nov 2017 14:01:55 -0800 Subject: [PATCH 0329/1814] fix #4214: Two todolist directives break sphinx-1.6.5 --- CHANGES | 1 + sphinx/ext/todo.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ff312f1d0..28df20245 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugs fixed * #4221: napoleon depends on autodoc, but users need to load it manually * #2298: automodule fails to document a class attribute * #4099: C++: properly link class reference to class from inside constructor +* #4214: Two todolist directives break sphinx-1.6.5 Testing -------- diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index a58422793..badfbc35f 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -178,7 +178,8 @@ def process_todo_nodes(app, doctree, fromdocname): todo_entry = todo_info['todo'] # Remove targetref from the (copied) node to avoid emitting a # duplicate label of the original entry when we walk this node. - del todo_entry['targetref'] + if 'targetref' in todo_entry: + del todo_entry['targetref'] # (Recursively) resolve references in the todo content env.resolve_references(todo_entry, todo_info['docname'], From 1b664248f4ed5e00f89574bd6568e86b29a9df0f Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sun, 5 Nov 2017 13:48:43 -0800 Subject: [PATCH 0330/1814] update todo extension test to test multiple todolists This tests for regression of previous bug #4214: Two todolist directives break sphinx-1.6.5. --- tests/roots/test-ext-todo/index.rst | 2 ++ tests/test_ext_todo.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/roots/test-ext-todo/index.rst b/tests/roots/test-ext-todo/index.rst index 6b95f73fd..781473d6a 100644 --- a/tests/roots/test-ext-todo/index.rst +++ b/tests/roots/test-ext-todo/index.rst @@ -7,3 +7,5 @@ test for sphinx.ext.todo bar .. todolist:: + +.. todolist:: diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 6a4789928..cee59fe9d 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -99,11 +99,13 @@ def test_todo_valid_link(app, status, warning): content = (app.outdir / 'TodoTests.tex').text() - # Look for the link to foo. We could equally well look for the link to bar. + # Look for the link to foo. Note that there are two of them because the + # source document uses todolist twice. We could equally well look for links + # to bar. link = r'\{\\hyperref\[\\detokenize\{(.*?foo.*?)}]\{\\sphinxcrossref{' \ r'\\sphinxstyleemphasis{original entry}}}}' m = re.findall(link, content) - assert len(m) == 1 + assert len(m) == 2 target = m[0] # Look for the targets of this link. From eff13bc4c457c0a9809952c751d62435803e79b9 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Mon, 27 Nov 2017 07:51:30 +0100 Subject: [PATCH 0331/1814] C++, fix bug in new sizeof... expression parsing See sphinx-doc/sphinx#4114 --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4e9eaeec4..37adb1525 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -960,7 +960,7 @@ class ASTSizeofParamPack(ASTBase): def describe_signature(self, signode, mode, env, symbol): signode.append(nodes.Text('sizeof...(')) - self.identifier.describe_signature(signode, mode, env, symbol, "") + self.identifier.describe_signature(signode, mode, env, symbol=symbol, prefix="") signode.append(nodes.Text(')')) From 10ec24b80db30dd9f24ad821d9195a47e03d1e91 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 29 Nov 2017 17:07:10 +0100 Subject: [PATCH 0332/1814] Fix #4267 by passing `warn` option to package textcomp. This silences its silly build-breaking errors in case some font substitution proved necessary for the characters it supports. --- sphinx/texinputs/sphinx.sty | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index a28220cbc..232a53b2f 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -6,7 +6,7 @@ % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{sphinx}[2017/07/24 v1.6.4 LaTeX package (Sphinx markup)] +\ProvidesPackage{sphinx}[2017/11/29 v1.6.6 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but @@ -39,7 +39,7 @@ \@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}} % for \text macro and \iffirstchoice@ conditional even if amsmath not loaded \RequirePackage{amstext} -\RequirePackage{textcomp} +\RequirePackage[warn]{textcomp} \RequirePackage{titlesec} \@ifpackagelater{titlesec}{2016/03/15}% {\@ifpackagelater{titlesec}{2016/03/21}% From 0ff217e1b277db4d93a0f25e03ec5add0d570586 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 30 Nov 2017 23:06:30 +0100 Subject: [PATCH 0333/1814] C++, fix hyperlinking of nested names --- CHANGES | 1 + sphinx/domains/cpp.py | 112 ++++++++++++++++++++++++++++----------- tests/test_domain_cpp.py | 4 ++ 3 files changed, 87 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index 39b9c5903..86366f215 100644 --- a/CHANGES +++ b/CHANGES @@ -83,6 +83,7 @@ Bugs fixed * #3882: Update the order of files for HTMLHelp and QTHelp * #3962: sphinx-apidoc does not recognize implicit namespace packages correctly +* C++: also hyperlink types in the name of declarations with qualified names. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 37adb1525..81fee9e62 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -555,12 +555,12 @@ class DefinitionError(UnicodeMixin, Exception): class _DuplicateSymbolError(UnicodeMixin, Exception): - def __init__(self, symbol, candSymbol): - # type: (Symbol, Symbol) -> None + def __init__(self, symbol, declaration): + # type: (Symbol, Any) -> None assert symbol - assert candSymbol + assert declaration self.symbol = symbol - self.candSymbol = candSymbol + self.declaration = declaration def __unicode__(self): # type: () -> unicode @@ -1286,6 +1286,10 @@ class ASTTemplateParamType(ASTBase): id = self.get_identifier() return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + @property + def isPack(self): + return self.data.parameterPack + def get_identifier(self): # type: () -> unicode return self.data.get_identifier() @@ -1447,6 +1451,16 @@ class ASTTemplateIntroductionParameter(ASTBase): self.identifier = identifier self.parameterPack = parameterPack + @property + def name(self): + # type: () -> ASTNestedName + id = self.get_identifier() + return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + + @property + def isPack(self): + return self.parameterPack + def get_identifier(self): # type: () -> unicode return self.identifier @@ -1819,36 +1833,42 @@ class ASTNestedName(ASTBase): # type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None _verify_description_mode(mode) # just print the name part, with template args, not template params - if mode == 'lastIsName': - addname = [] # type: List[unicode] - if self.rooted: - addname.append('') - for n in self.names[:-1]: - addname.append(text_type(n)) - addname = '::'.join(addname) # type: ignore - if len(self.names) > 1: - addname += '::' - signode += addnodes.desc_addname(addname, addname) - self.names[-1].describe_signature(signode, mode, env, '', symbol) - elif mode == 'noneIsName': + if mode == 'noneIsName': signode += nodes.Text(text_type(self)) elif mode == 'param': name = text_type(self) signode += nodes.emphasis(name, name) - elif mode == 'markType': - # each element should be a pending xref targeting the complete + elif mode == 'markType' or mode == 'lastIsName': + # Each element should be a pending xref targeting the complete # prefix. however, only the identifier part should be a link, such # that template args can be a link as well. + # For 'lastIsName' we should also prepend template parameter lists. + templateParams = [] # type: List[Any] + if mode == 'lastIsName': + assert symbol is not None + if symbol.declaration.templatePrefix is not None: + templateParams = symbol.declaration.templatePrefix.templates + iTemplateParams = 0 + templateParamsPrefix = u'' prefix = '' # type: unicode first = True - for name in self.names: + names = self.names[:-1] if mode == 'lastIsName' else self.names + for name in names: if not first: signode += nodes.Text('::') prefix += '::' first = False if name != '': - name.describe_signature(signode, mode, env, prefix, symbol) # type: ignore + if name.templateArgs and iTemplateParams < len(templateParams): # type: ignore + templateParamsPrefix += text_type(templateParams[iTemplateParams]) + iTemplateParams += 1 + name.describe_signature(signode, 'markType', # type: ignore + env, templateParamsPrefix + prefix, symbol) prefix += text_type(name) + if mode == 'lastIsName': + if len(self.names) > 1: + signode += addnodes.desc_addname('::', '::') + self.names[-1].describe_signature(signode, mode, env, '', symbol) else: raise Exception('Unknown description mode: %s' % mode) @@ -3131,15 +3151,15 @@ class ASTDeclaration(ASTBase): def describe_signature(self, signode, mode, env, options): # type: (addnodes.desc_signature, unicode, BuildEnvironment, Dict) -> None _verify_description_mode(mode) + assert self.symbol # The caller of the domain added a desc_signature node. # Always enable multiline: signode['is_multiline'] = True # Put each line in a desc_signature_line node. mainDeclNode = addnodes.desc_signature_line() mainDeclNode.sphinx_cpp_tagname = 'declarator' - mainDeclNode['add_permalink'] = True + mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration - assert self.symbol if self.templatePrefix: self.templatePrefix.describe_signature(signode, mode, env, symbol=self.symbol, @@ -3206,6 +3226,7 @@ class Symbol(object): self.templateArgs = templateArgs # identifier self.declaration = declaration self.docname = docname + self.isRedeclaration = False self._assert_invariants() self.children = [] # type: List[Any] @@ -3294,6 +3315,31 @@ class Symbol(object): # type: (Any, Any, Any, Any, Any, bool) -> Symbol assert (identifier is None) != (operator is None) + def isSpecialization(): + # the names of the template parameters must be given exactly as args + # and params that are packs must in the args be the name expanded + if len(templateParams.params) != len(templateArgs.args): + return True + for i in range(len(templateParams.params)): + param = templateParams.params[i] + arg = templateArgs.args[i] + # TODO: doing this by string manipulation is probably not the most efficient + paramName = text_type(param.name) + argTxt = text_type(arg) + isArgPackExpansion = argTxt.endswith('...') + if param.isPack != isArgPackExpansion: + return True + argName = argTxt[:-3] if isArgPackExpansion else argTxt + if paramName != argName: + return True + return False + if templateParams is not None and templateArgs is not None: + # If both are given, but it's not a specialization, then do lookup as if + # there is no argument list. + # For example: template int A::var; + if not isSpecialization(): + templateArgs = None + def matches(s): if s.identifier != identifier: return False @@ -3405,23 +3451,27 @@ class Symbol(object): # .. class:: Test symbol._fill_empty(declaration, docname) return symbol - # It may simply be a functin overload, so let's compare ids. + # It may simply be a function overload, so let's compare ids. + isRedeclaration = True candSymbol = Symbol(parent=parentSymbol, identifier=identifier, templateParams=templateParams, templateArgs=templateArgs, declaration=declaration, docname=docname) - newId = declaration.get_newest_id() - oldId = symbol.declaration.get_newest_id() - if newId != oldId: - # we already inserted the symbol, so return the new one - symbol = candSymbol - else: + if declaration.objectType == "function": + newId = declaration.get_newest_id() + oldId = symbol.declaration.get_newest_id() + if newId != oldId: + # we already inserted the symbol, so return the new one + symbol = candSymbol + isRedeclaration = False + if isRedeclaration: # Redeclaration of the same symbol. # Let the new one be there, but raise an error to the client # so it can use the real symbol as subscope. # This will probably result in a duplicate id warning. - raise _DuplicateSymbolError(symbol, candSymbol) + candSymbol.isRedeclaration = True + raise _DuplicateSymbolError(symbol, declaration) else: symbol = Symbol(parent=parentSymbol, identifier=identifier, templateParams=templateParams, @@ -5397,6 +5447,7 @@ class CPPObject(ObjectDescription): # Assume we are actually in the old symbol, # instead of the newly created duplicate. self.env.temp_data['cpp:last_symbol'] = e.symbol + self.warn("Duplicate declaration.") if ast.objectType == 'enumerator': self._add_enumerator_to_parent(ast) @@ -5738,6 +5789,7 @@ class CPPDomain(Domain): def _resolve_xref_inner(self, env, fromdocname, builder, typ, target, node, contnode, emitWarnings=True): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node, bool) -> nodes.Node # NOQA + class Warner(object): def warn(self, msg): if emitWarnings: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 8c838fcf8..4183fa471 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -508,6 +508,10 @@ def test_templates(): check('class', "template A", {2:"I0E1A"}) check('class', "template typename T> A", {2:"II0E0E1A"}) + check('class', "template typename> A", {2: "II0E0E1A"}) + check('class', "template typename ...T> A", {2:"II0EDpE1A"}) + check('class', "template typename...> A", {2: "II0EDpE1A"}) + check('class', "template A", {2:"I_iE1A"}) check('class', "template A", {2:"I_iE1A"}) check('class', "template A", {2:"I_DpiE1A"}) From 1db38e0eca560b59a8276c4a80efd9e42483ffff Mon Sep 17 00:00:00 2001 From: mark floyd Date: Fri, 1 Dec 2017 18:34:33 -0800 Subject: [PATCH 0334/1814] sphinx-build: Add support for "-j auto" Adjust -j argument so it can accept special keyword "auto", which will set -j to the number of CPUs on machine. Change was inspired by headaches while trying to find the best way to get sphinx-build to use the max number of cores from any machine we build on (Ubuntu, Mac, AWS Linux, etc). Rather than write external scripts to set this (sysctl calls, grepping /proc/cpuinfo, etc), it made more sense to build the functionality into sphinx-build itself. Change Summary: * New custom type in sphinx.cmdline for handling -j argument * Adjusted help string for -j flag --- sphinx/cmdline.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 11f1861d8..590aa8b0a 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -11,6 +11,7 @@ from __future__ import print_function import argparse +import multiprocessing import sys import traceback from os import path @@ -83,6 +84,19 @@ def handle_exception(app, args, exception, stderr=sys.stderr): file=stderr) +def jobs_argument(value): + # type (int, str) -> int + """ + Special type to handle 'auto' flags passed to 'sphinx-build' via -j flag. Can + be expanded to handle other special scaling requests, such as setting job count + to (cpu_count / 2) + """ + if value == 'auto': + return multiprocessing.cpu_count() + else: + return value + + def get_parser(): # type: () -> argparse.ArgumentParser parser = argparse.ArgumentParser( @@ -129,10 +143,9 @@ files can be built by specifying individual filenames. group.add_argument('-d', metavar='PATH', dest='doctreedir', help='path for the cached environment and doctree ' 'files (default: OUTPUTDIR/.doctrees)') - group.add_argument('-j', metavar='N', default=1, type=int, dest='jobs', + group.add_argument('-j', metavar='N', default=1, type=jobs_argument, dest='jobs', help='build in parallel with N processes where ' - 'possible') - + 'possible (special value "auto" will set N to number of CPUs') group = parser.add_argument_group('build configuration options') group.add_argument('-c', metavar='PATH', dest='confdir', help='path where configuration file (conf.py) is ' From 19efb4a39810f1035d9d891f26154c74c6b54a89 Mon Sep 17 00:00:00 2001 From: mark floyd Date: Fri, 1 Dec 2017 18:52:46 -0800 Subject: [PATCH 0335/1814] Fixing typo in help string --- sphinx/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 590aa8b0a..55b0cec98 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -145,7 +145,7 @@ files can be built by specifying individual filenames. 'files (default: OUTPUTDIR/.doctrees)') group.add_argument('-j', metavar='N', default=1, type=jobs_argument, dest='jobs', help='build in parallel with N processes where ' - 'possible (special value "auto" will set N to number of CPUs') + 'possible (special value "auto" will set N to cpu-count)') group = parser.add_argument_group('build configuration options') group.add_argument('-c', metavar='PATH', dest='confdir', help='path where configuration file (conf.py) is ' From 88d7dc1bd33a2ee91c9fa7d4237603bf33b597aa Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 11 Oct 2017 16:54:45 +0100 Subject: [PATCH 0336/1814] quickstart: Simplify --(no-)option handling The standard pattern for doing this is to use a common 'dest'. Signed-off-by: Stephen Finucane --- sphinx/cmd/quickstart.py | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index ee35b5cc1..533555373 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -378,17 +378,14 @@ imgmath has been deselected.''') do_prompt(d, 'ext_githubpages', 'githubpages: create .nojekyll file ' 'to publish the document on GitHub pages (y/n)', 'n', boolean) - if 'no_makefile' in d: - d['makefile'] = False - elif 'makefile' not in d: + if 'makefile' not in d: print(''' A Makefile and a Windows command file can be generated for you so that you only have to run e.g. `make html' instead of invoking sphinx-build directly.''') do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean) - if 'no_batchfile' in d: - d['batchfile'] = False - elif 'batchfile' not in d: + + if 'batchfile' not in d: do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)', 'y', boolean) print() @@ -593,22 +590,22 @@ Makefile to be used with sphinx-build. group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions', action='append', help='enable extensions') - # TODO(stephenfin): Consider using mutually exclusive groups here group = parser.add_argument_group('Makefile and Batchfile creation') - group.add_argument('--makefile', action='store_true', default=False, + group.add_argument('--makefile', action='store_true', dest='makefile', help='create makefile') - group.add_argument('--no-makefile', action='store_true', default=False, - help='not create makefile') - group.add_argument('--batchfile', action='store_true', default=False, + group.add_argument('--no-makefile', action='store_false', dest='makefile', + help='do not create makefile') + group.add_argument('--batchfile', action='store_true', dest='batchfile', help='create batchfile') - group.add_argument('--no-batchfile', action='store_true', default=False, - help='not create batchfile') - group.add_argument('-M', '--no-use-make-mode', action='store_false', - dest='make_mode', default=False, - help='not use make-mode for Makefile/make.bat') + group.add_argument('--no-batchfile', action='store_false', + dest='batchfile', + help='do not create batchfile') group.add_argument('-m', '--use-make-mode', action='store_true', - dest='make_mode', default=True, + dest='make_mode', help='use make-mode for Makefile/make.bat') + group.add_argument('-M', '--no-use-make-mode', action='store_false', + dest='make_mode', + help='do not use make-mode for Makefile/make.bat') group = parser.add_argument_group('Project templating') group.add_argument('-t', '--templatedir', metavar='TEMPLATEDIR', @@ -652,10 +649,6 @@ def main(argv=sys.argv[1:]): d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS)) d2.update(d) d = d2 - if 'no_makefile' in d: - d['makefile'] = False - if 'no_batchfile' in d: - d['batchfile'] = False if not valid_dir(d): print() From 4c0f657ee6423d102a8fb3f2e05ca44257874416 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 12 Oct 2017 14:36:19 +0100 Subject: [PATCH 0337/1814] quickstart: Rework 'do_prompt' function The 'd' and 'key' values are used on a single line. Move these outside the function to allow us to do other things with this function. Signed-off-by: Stephen Finucane --- sphinx/cmd/quickstart.py | 92 +++++++++++++++++++++------------------- tests/test_quickstart.py | 63 +++++++++++---------------- 2 files changed, 72 insertions(+), 83 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 533555373..830e38fb3 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -159,8 +159,8 @@ def term_decode(text): return text.decode('latin1') -def do_prompt(d, key, text, default=None, validator=nonempty): - # type: (Dict, unicode, unicode, unicode, Callable[[unicode], Any]) -> None +def do_prompt(text, default=None, validator=nonempty): + # type: (unicode, unicode, Callable[[unicode], Any]) -> Union[unicode, bool] while True: if default is not None: prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode @@ -191,7 +191,7 @@ def do_prompt(d, key, text, default=None, validator=nonempty): print(red('* ' + str(err))) continue break - d[key] = x + return x def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")): @@ -251,7 +251,7 @@ Selected root path: %s''' % d['path'])) else: print(''' Enter the root path for documentation.''') - do_prompt(d, 'path', 'Root path for the documentation', '.', is_path) + d['path'] = do_prompt('Root path for the documentation', '.', is_path) while path.isfile(path.join(d['path'], 'conf.py')) or \ path.isfile(path.join(d['path'], 'source', 'conf.py')): @@ -260,8 +260,8 @@ Enter the root path for documentation.''') 'selected root path.')) print('sphinx-quickstart will not overwrite existing Sphinx projects.') print() - do_prompt(d, 'path', 'Please enter a new root path (or just Enter ' - 'to exit)', '', is_path) + d['path'] = do_prompt('Please enter a new root path (or just Enter ' + 'to exit)', '', is_path) if not d['path']: sys.exit(1) @@ -270,22 +270,22 @@ Enter the root path for documentation.''') You have two options for placing the build directory for Sphinx output. Either, you use a directory "_build" within the root path, or you separate "source" and "build" directories within the root path.''') - do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n', - boolean) + d['sep'] = do_prompt('Separate source and build directories (y/n)', + 'n', boolean) if 'dot' not in d: print(''' Inside the root directory, two more directories will be created; "_templates" for custom HTML templates and "_static" for custom stylesheets and other static files. You can enter another prefix (such as ".") to replace the underscore.''') - do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok) + d['dot'] = do_prompt('Name prefix for templates and static dir', '_', ok) if 'project' not in d: print(''' The project name will occur in several places in the built documentation.''') - do_prompt(d, 'project', 'Project name') + d['project'] = do_prompt('Project name') if 'author' not in d: - do_prompt(d, 'author', 'Author name(s)') + d['author'] = do_prompt('Author name(s)') if 'version' not in d: print(''' @@ -294,9 +294,9 @@ software. Each version can have multiple releases. For example, for Python the version is something like 2.5 or 3.0, while the release is something like 2.5.1 or 3.0a1. If you don't need this dual structure, just set both to the same value.''') - do_prompt(d, 'version', 'Project version', '', allow_empty) + d['version'] = do_prompt('Project version', '', allow_empty) if 'release' not in d: - do_prompt(d, 'release', 'Project release', d['version'], allow_empty) + d['release'] = do_prompt('Project release', d['version'], allow_empty) if 'language' not in d: print(''' @@ -306,7 +306,7 @@ translate text that it generates into that language. For a list of supported codes, see http://sphinx-doc.org/config.html#confval-language.''') - do_prompt(d, 'language', 'Project language', 'en') + d['language'] = do_prompt('Project language', 'en') if d['language'] == 'en': d['language'] = None @@ -314,7 +314,7 @@ http://sphinx-doc.org/config.html#confval-language.''') print(''' The file name suffix for source files. Commonly, this is either ".txt" or ".rst". Only files with this suffix are considered documents.''') - do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix) + d['suffix'] = do_prompt('Source file suffix', '.rst', suffix) if 'master' not in d: print(''' @@ -322,8 +322,8 @@ One document is special in that it is considered the top node of the "contents tree", that is, it is the root of the hierarchical structure of the documents. Normally, this is "index", but if your "index" document is a custom template, you can also set this to another filename.''') - do_prompt(d, 'master', 'Name of your master document (without suffix)', - 'index') + d['master'] = do_prompt('Name of your master document (without suffix)', + 'index') while path.isfile(path.join(d['path'], d['master'] + d['suffix'])) or \ path.isfile(path.join(d['path'], 'source', d['master'] + d['suffix'])): @@ -332,62 +332,66 @@ document is a custom template, you can also set this to another filename.''') 'selected root path.' % (d['master'] + d['suffix']))) print('sphinx-quickstart will not overwrite the existing file.') print() - do_prompt(d, 'master', 'Please enter a new file name, or rename the ' - 'existing file and press Enter', d['master']) + d['master'] = do_prompt('Please enter a new file name, or rename the ' + 'existing file and press Enter', d['master']) if 'epub' not in d: print(''' Sphinx can also add configuration for epub output:''') - do_prompt(d, 'epub', 'Do you want to use the epub builder (y/n)', - 'n', boolean) + d['epub'] = do_prompt('Do you want to use the epub builder (y/n)', + 'n', boolean) if 'ext_autodoc' not in d: print(''' Please indicate if you want to use one of the following Sphinx extensions:''') - do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings ' - 'from modules (y/n)', 'n', boolean) + d['ext_autodoc'] = do_prompt('autodoc: automatically insert docstrings ' + 'from modules (y/n)', 'n', boolean) if 'ext_doctest' not in d: - do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets ' - 'in doctest blocks (y/n)', 'n', boolean) + d['ext_doctest'] = do_prompt('doctest: automatically test code snippets ' + 'in doctest blocks (y/n)', 'n', boolean) if 'ext_intersphinx' not in d: - do_prompt(d, 'ext_intersphinx', 'intersphinx: link between Sphinx ' - 'documentation of different projects (y/n)', 'n', boolean) + d['ext_intersphinx'] = do_prompt('intersphinx: link between Sphinx ' + 'documentation of different projects (y/n)', + 'n', boolean) if 'ext_todo' not in d: - do_prompt(d, 'ext_todo', 'todo: write "todo" entries ' - 'that can be shown or hidden on build (y/n)', 'n', boolean) + d['ext_todo'] = do_prompt('todo: write "todo" entries that can be ' + 'shown or hidden on build (y/n)', 'n', boolean) if 'ext_coverage' not in d: - do_prompt(d, 'ext_coverage', 'coverage: checks for documentation ' - 'coverage (y/n)', 'n', boolean) + d['ext_coverage'] = do_prompt('coverage: checks for documentation ' + 'coverage (y/n)', 'n', boolean) if 'ext_imgmath' not in d: - do_prompt(d, 'ext_imgmath', 'imgmath: include math, rendered ' - 'as PNG or SVG images (y/n)', 'n', boolean) + d['ext_imgmath'] = do_prompt('imgmath: include math, rendered as PNG ' + 'or SVG images (y/n)', 'n', boolean) if 'ext_mathjax' not in d: - do_prompt(d, 'ext_mathjax', 'mathjax: include math, rendered in the ' - 'browser by MathJax (y/n)', 'n', boolean) + d['ext_mathjax'] = do_prompt('mathjax: include math, rendered in the ' + 'browser by MathJax (y/n)', 'n', boolean) if d['ext_imgmath'] and d['ext_mathjax']: print('''Note: imgmath and mathjax cannot be enabled at the same time. imgmath has been deselected.''') d['ext_imgmath'] = False if 'ext_ifconfig' not in d: - do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of ' - 'content based on config values (y/n)', 'n', boolean) + d['ext_ifconfig'] = do_prompt('ifconfig: conditional inclusion of ' + 'content based on config values (y/n)', + 'n', boolean) if 'ext_viewcode' not in d: - do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source ' - 'code of documented Python objects (y/n)', 'n', boolean) + d['ext_viewcode'] = do_prompt('viewcode: include links to the source ' + 'code of documented Python objects (y/n)', + 'n', boolean) if 'ext_githubpages' not in d: - do_prompt(d, 'ext_githubpages', 'githubpages: create .nojekyll file ' - 'to publish the document on GitHub pages (y/n)', 'n', boolean) + d['ext_githubpages'] = do_prompt('githubpages: create .nojekyll file ' + 'to publish the document on GitHub ' + 'pages (y/n)', 'n', boolean) if 'makefile' not in d: print(''' A Makefile and a Windows command file can be generated for you so that you only have to run e.g. `make html' instead of invoking sphinx-build directly.''') - do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean) + d['makefile'] = do_prompt('Create Makefile? (y/n)', 'y', boolean) if 'batchfile' not in d: - do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)', - 'y', boolean) + d['batchfile'] = do_prompt('Create Windows command file? (y/n)', + 'y', boolean) print() diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 46ed3a0c1..81d16eae1 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -61,27 +61,7 @@ def teardown_module(): coloron() -def test_quickstart_inputstrip(): - d = {} - answers = { - 'Q1': 'Y', - 'Q2': ' Yes ', - 'Q3': 'N', - 'Q4': 'N ', - } - qs.term_input = mock_input(answers) - qs.do_prompt(d, 'k1', 'Q1') - assert d['k1'] == 'Y' - qs.do_prompt(d, 'k2', 'Q2') - assert d['k2'] == 'Yes' - qs.do_prompt(d, 'k3', 'Q3') - assert d['k3'] == 'N' - qs.do_prompt(d, 'k4', 'Q4') - assert d['k4'] == 'N' - - def test_do_prompt(): - d = {} answers = { 'Q2': 'v2', 'Q3': 'v3', @@ -90,24 +70,29 @@ def test_do_prompt(): 'Q6': 'foo', } qs.term_input = mock_input(answers) - try: - qs.do_prompt(d, 'k1', 'Q1') - except AssertionError: - assert 'k1' not in d - else: - assert False, 'AssertionError not raised' - qs.do_prompt(d, 'k1', 'Q1', default='v1') - assert d['k1'] == 'v1' - qs.do_prompt(d, 'k3', 'Q3', default='v3_default') - assert d['k3'] == 'v3' - qs.do_prompt(d, 'k2', 'Q2') - assert d['k2'] == 'v2' - qs.do_prompt(d, 'k4', 'Q4', validator=qs.boolean) - assert d['k4'] is True - qs.do_prompt(d, 'k5', 'Q5', validator=qs.boolean) - assert d['k5'] is False + + assert qs.do_prompt('Q1', default='v1') == 'v1' + assert qs.do_prompt('Q3', default='v3_default') == 'v3' + assert qs.do_prompt('Q2') == 'v2' + assert qs.do_prompt('Q4', validator=qs.boolean) is True + assert qs.do_prompt('Q5', validator=qs.boolean) is False with pytest.raises(AssertionError): - qs.do_prompt(d, 'k6', 'Q6', validator=qs.boolean) + qs.do_prompt('Q6', validator=qs.boolean) + + +def test_do_prompt_inputstrip(): + answers = { + 'Q1': 'Y', + 'Q2': ' Yes ', + 'Q3': 'N', + 'Q4': 'N ', + } + qs.term_input = mock_input(answers) + + assert qs.do_prompt('Q1') == 'Y' + assert qs.do_prompt('Q2') == 'Yes' + assert qs.do_prompt('Q3') == 'N' + assert qs.do_prompt('Q4') == 'N' def test_do_prompt_with_nonascii(): @@ -117,12 +102,12 @@ def test_do_prompt_with_nonascii(): } qs.term_input = mock_input(answers) try: - qs.do_prompt(d, 'k1', 'Q1', default=u'\u65e5\u672c') + result = qs.do_prompt('Q1', default=u'\u65e5\u672c') except UnicodeEncodeError: raise pytest.skip.Exception( 'non-ASCII console input not supported on this encoding: %s', qs.TERM_ENCODING) - assert d['k1'] == u'\u30c9\u30a4\u30c4' + assert result == u'\u30c9\u30a4\u30c4' def test_quickstart_defaults(tempdir): From d46273ca4a73d48dff60a1e95fbeb84b73516c8f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 13:48:27 +0100 Subject: [PATCH 0338/1814] quickstart: Rework how we collect extensions This is a little more flexible than the existing set up and makes maximum use of argparse capabilities. This has the side-effect of no longer including configuration for the 'sphinx.ext.todo' extension when said extension is not enabled. Signed-off-by: Stephen Finucane --- sphinx/cmd/quickstart.py | 99 ++++++++++----------------- sphinx/ext/apidoc.py | 14 ++-- sphinx/templates/quickstart/conf.py_t | 31 ++++++--- tests/test_quickstart.py | 1 - 4 files changed, 67 insertions(+), 78 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 830e38fb3..46d42f10b 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -16,6 +16,7 @@ import os import re import sys import time +from collections import OrderedDict from io import open from os import path @@ -48,7 +49,22 @@ if False: TERM_ENCODING = getattr(sys.stdin, 'encoding', None) -DEFAULT_VALUE = { +EXTENSIONS = OrderedDict([ + ('autodoc', 'automatically insert docstrings from modules'), + ('doctest', 'automatically test code snippets in doctest blocks'), + ('intersphinx', 'link between Sphinx documentation of different projects'), + ('todo', 'write "todo" entries that can be shown or hidden on build'), + ('coverage', 'checks for documentation coverage'), + ('imgmath', 'include math, rendered as PNG or SVG images'), + ('mathjax', 'include math, rendered in the browser by MathJax'), + ('ifconfig', 'conditional inclusion of content based on config values'), + ('viewcode', + 'include links to the source code of documented Python objects'), + ('githubpages', + 'create .nojekyll file to publish the document on GitHub pages'), +]) + +DEFAULTS = { 'path': '.', 'sep': False, 'dot': '_', @@ -56,16 +72,10 @@ DEFAULT_VALUE = { 'suffix': '.rst', 'master': 'index', 'epub': False, - 'ext_autodoc': False, - 'ext_doctest': False, - 'ext_todo': False, 'makefile': True, 'batchfile': True, } -EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage', - 'imgmath', 'mathjax', 'ifconfig', 'viewcode', 'githubpages') - PROMPT_PREFIX = '> ' @@ -235,7 +245,7 @@ def ask_user(d): * suffix: source file suffix * master: master document name * epub: use epub (bool) - * ext_*: extensions to use (bools) + * extensions: extensions to use (list) * makefile: make Makefile * batchfile: make command file """ @@ -341,46 +351,20 @@ Sphinx can also add configuration for epub output:''') d['epub'] = do_prompt('Do you want to use the epub builder (y/n)', 'n', boolean) - if 'ext_autodoc' not in d: - print(''' -Please indicate if you want to use one of the following Sphinx extensions:''') - d['ext_autodoc'] = do_prompt('autodoc: automatically insert docstrings ' - 'from modules (y/n)', 'n', boolean) - if 'ext_doctest' not in d: - d['ext_doctest'] = do_prompt('doctest: automatically test code snippets ' - 'in doctest blocks (y/n)', 'n', boolean) - if 'ext_intersphinx' not in d: - d['ext_intersphinx'] = do_prompt('intersphinx: link between Sphinx ' - 'documentation of different projects (y/n)', - 'n', boolean) - if 'ext_todo' not in d: - d['ext_todo'] = do_prompt('todo: write "todo" entries that can be ' - 'shown or hidden on build (y/n)', 'n', boolean) - if 'ext_coverage' not in d: - d['ext_coverage'] = do_prompt('coverage: checks for documentation ' - 'coverage (y/n)', 'n', boolean) - if 'ext_imgmath' not in d: - d['ext_imgmath'] = do_prompt('imgmath: include math, rendered as PNG ' - 'or SVG images (y/n)', 'n', boolean) - if 'ext_mathjax' not in d: - d['ext_mathjax'] = do_prompt('mathjax: include math, rendered in the ' - 'browser by MathJax (y/n)', 'n', boolean) - if d['ext_imgmath'] and d['ext_mathjax']: - print('''Note: imgmath and mathjax cannot be enabled at the same time. -imgmath has been deselected.''') - d['ext_imgmath'] = False - if 'ext_ifconfig' not in d: - d['ext_ifconfig'] = do_prompt('ifconfig: conditional inclusion of ' - 'content based on config values (y/n)', - 'n', boolean) - if 'ext_viewcode' not in d: - d['ext_viewcode'] = do_prompt('viewcode: include links to the source ' - 'code of documented Python objects (y/n)', - 'n', boolean) - if 'ext_githubpages' not in d: - d['ext_githubpages'] = do_prompt('githubpages: create .nojekyll file ' - 'to publish the document on GitHub ' - 'pages (y/n)', 'n', boolean) + if 'extensions' not in d: + print('Indicate which of the following Sphinx extensions should be ' + 'enabled:') + d['extensions'] = [] + for name, description in EXTENSIONS.items(): + if do_prompt('%s: %s (y/n)' % (name, description), 'n', boolean): + d['extensions'].append('sphinx.ext.%s' % name) + + # Handle conflicting options + if set(['sphinx.ext.imgmath', 'sphinx.ext.mathjax']).issubset( + d['extensions']): + print('Note: imgmath and mathjax cannot be enabled at the same ' + 'time. imgmath has been deselected.') + d['extensions'].remove('sphinx.ext.imgmath') if 'makefile' not in d: print(''' @@ -401,7 +385,6 @@ def generate(d, overwrite=True, silent=False, templatedir=None): template = QuickstartRenderer(templatedir=templatedir) texescape.init() - indent = ' ' * 4 if 'mastertoctree' not in d: d['mastertoctree'] = '' @@ -415,10 +398,6 @@ def generate(d, overwrite=True, silent=False, templatedir=None): d['now'] = time.asctime() d['project_underline'] = column_width(d['project']) * '=' d.setdefault('extensions', []) - for name in EXTENSIONS: - if d.get('ext_' + name): - d['extensions'].append('sphinx.ext.' + name) - d['extensions'] = (',\n' + indent).join(repr(name) for name in d['extensions']) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] d['author_texescaped'] = text_type(d['author']).\ translate(texescape.tex_escape_map) @@ -588,11 +567,11 @@ Makefile to be used with sphinx-build. group = parser.add_argument_group('Extension options') for ext in EXTENSIONS: - group.add_argument('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, + group.add_argument('--ext-%s' % ext, action='append_const', + const='sphinx.ext.%s' % ext, dest='extensions', help='enable %s extension' % ext) group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions', - action='append', help='enable extensions') + action='append', help='enable arbitrary extensions') group = parser.add_argument_group('Makefile and Batchfile creation') group.add_argument('--makefile', action='store_true', dest='makefile', @@ -649,8 +628,7 @@ def main(argv=sys.argv[1:]): # quiet mode with all required params satisfied, use default d.setdefault('version', '') d.setdefault('release', d['version']) - d2 = DEFAULT_VALUE.copy() - d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS)) + d2 = DEFAULTS.copy() d2.update(d) d = d2 @@ -673,13 +651,12 @@ def main(argv=sys.argv[1:]): if isinstance(value, binary_type): d[key] = term_decode(value) - # parse extensions list + # handle use of CSV-style extension values d.setdefault('extensions', []) for ext in d['extensions'][:]: if ',' in ext: d['extensions'].remove(ext) - for modname in ext.split(','): - d['extensions'].append(modname) + d['extensions'].extend(ext.split(',')) for variable in d.get('variables', []): try: diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 6edab379b..0bdeb9865 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -358,8 +358,8 @@ Note: By default this script will not overwrite already created files.""") group = parser.add_argument_group('extension options') for ext in EXTENSIONS: - group.add_argument('--ext-' + ext, action='store_true', - dest='ext_' + ext, default=False, + group.add_argument('--ext-%s' % ext, action='append_const', + const='sphinx.ext.%s' % ext, dest='extensions', help='enable %s extension' % ext) return parser @@ -408,9 +408,8 @@ def main(argv=sys.argv[1:]): suffix = '.' + args.suffix, master = 'index', epub = True, - ext_autodoc = True, - ext_viewcode = True, - ext_todo = True, + extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', + 'sphinx.ext.todo'], makefile = True, batchfile = True, make_mode = True, @@ -420,9 +419,8 @@ def main(argv=sys.argv[1:]): module_path = rootpath, append_syspath = args.append_syspath, ) - enabled_exts = {'ext_' + ext: getattr(args, 'ext_' + ext) - for ext in EXTENSIONS if getattr(args, 'ext_' + ext)} - d.update(enabled_exts) + if args.extensions: + d['extensions'].extend(args.extensions) if isinstance(args.header, binary_type): d['project'] = d['project'].decode('utf-8') diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 4e828f330..c42861c28 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -42,7 +42,11 @@ sys.path.insert(0, u'{{ module_path }}') # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [{{ extensions }}] +extensions = [ +{%- for ext in extensions %} + '{{ ext }}', +{%- endfor %} +] # Add any paths that contain templates here, relative to this directory. templates_path = ['{{ dot }}templates'] @@ -85,9 +89,6 @@ exclude_patterns = [{{ exclude_patterns }}] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = {{ ext_todo }} - # -- Options for HTML output ---------------------------------------------- @@ -173,8 +174,8 @@ texinfo_documents = [ author, '{{ project_fn }}', 'One line description of project.', 'Miscellaneous'), ] +{%- if epub %} -{% if epub %} # -- Options for Epub output ---------------------------------------------- @@ -195,9 +196,23 @@ epub_copyright = copyright # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] -{% endif %} +{%- endif %} +{%- if extensions %} + + +# -- Extension configuration ---------------------------------------------- +{%- endif %} +{%- if 'sphinx.ext.intersphinx' in extensions %} + +# -- Options for intersphinx extension ------------------------------------ -{% if ext_intersphinx %} # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} -{% endif %} +{%- endif %} +{%- if 'sphinx.ext.todo' in extensions %} + +# -- Options for todo extension ------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True +{%- endif %} diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 81d16eae1..f69a0a58e 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -134,7 +134,6 @@ def test_quickstart_defaults(tempdir): assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y') assert ns['version'] == '0.1' assert ns['release'] == '0.1' - assert ns['todo_include_todos'] is False assert ns['html_static_path'] == ['_static'] assert ns['latex_documents'] == [ ('index', 'SphinxTest.tex', 'Sphinx Test Documentation', From 77ff7d7e90f2b50b00c39f8acfd93b4d9aacdcf8 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 9 Nov 2017 18:07:58 +1100 Subject: [PATCH 0339/1814] sphinx-build: Use 'ArgumentParser.error' This simplifies a common pattern used here. This does result in a change in the output code from 1 to 2 for some cases, but this shouldn't be an issue as we already emit 2 for any parser issues. Signed-off-by: Stephen Finucane --- sphinx/cmdline.py | 56 ++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 11f1861d8..f18bbb286 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -182,11 +182,7 @@ def main(argv=sys.argv[1:]): # type: ignore # type: (List[unicode]) -> int parser = get_parser() - # parse options - try: - args = parser.parse_args(argv) - except SystemExit as err: - return err.code + args = parser.parse_args(argv) # get paths (first and second positional argument) try: @@ -194,34 +190,28 @@ def main(argv=sys.argv[1:]): # type: ignore confdir = abspath(args.confdir or srcdir) if args.noconfig: confdir = None + if not path.isdir(srcdir): - print('Error: Cannot find source directory `%s\'.' % srcdir, - file=sys.stderr) - return 1 + parser.error('cannot find source directory (%s)' % srcdir) if not args.noconfig and not path.isfile(path.join(confdir, 'conf.py')): - print('Error: Config directory doesn\'t contain a conf.py file.', - file=sys.stderr) - return 1 + parser.error("config directory doesn't contain a conf.py file " + "(%s)" % confdir) + outdir = abspath(args.outputdir) if srcdir == outdir: - print('Error: source directory and destination directory are same.', - file=sys.stderr) - return 1 + parser.error('source directory and destination directory are same') except UnicodeError: - print( - 'Error: Multibyte filename not supported on this filesystem ' - 'encoding (%r).' % fs_encoding, file=sys.stderr) - return 1 + parser.error('multibyte filename not supported on this filesystem ' + 'encoding (%r)' % fs_encoding) # handle remaining filename arguments filenames = args.filenames - errored = False + missing_files = [] for filename in filenames: if not path.isfile(filename): - print('Error: Cannot find file %r.' % filename, file=sys.stderr) - errored = True - if errored: - return 1 + missing_files.append(filename) + if missing_files: + parser.error('cannot find files %r' % missing_files) # likely encoding used for command-line arguments try: @@ -231,8 +221,7 @@ def main(argv=sys.argv[1:]): # type: ignore likely_encoding = None if args.force_all and filenames: - print('Error: Cannot combine -a option and filenames.', file=sys.stderr) - return 1 + parser.error('cannot combine -a option and filenames') if args.color == 'no' or (args.color == 'auto' and not color_terminal()): nocolor() @@ -245,15 +234,16 @@ def main(argv=sys.argv[1:]): # type: ignore if args.quiet: status = None + if args.really_quiet: status = warning = None + if warning and args.warnfile: try: warnfp = open(args.warnfile, 'w') except Exception as exc: - print('Error: Cannot open warning file %r: %s' % - (args.warnfile, exc), file=sys.stderr) - sys.exit(1) + parser.error('cannot open warning file %r: %s' % ( + args.warnfile, exc)) warning = Tee(warning, warnfp) # type: ignore error = warning @@ -262,9 +252,7 @@ def main(argv=sys.argv[1:]): # type: ignore try: key, val = val.split('=', 1) except ValueError: - print('Error: -D option argument must be in the form name=value.', - file=sys.stderr) - return 1 + parser.error('-D option argument must be in the form name=value') if likely_encoding and isinstance(val, binary_type): try: val = val.decode(likely_encoding) @@ -276,9 +264,7 @@ def main(argv=sys.argv[1:]): # type: ignore try: key, val = val.split('=') except ValueError: - print('Error: -A option argument must be in the form name=value.', - file=sys.stderr) - return 1 + parser.error('-A option argument must be in the form name=value') try: val = int(val) except ValueError: @@ -302,4 +288,4 @@ def main(argv=sys.argv[1:]): # type: ignore return app.statuscode except (Exception, KeyboardInterrupt) as exc: handle_exception(app, args, exc, error) - return 1 + return 2 From f3b440777bb75496e73c1869011aca3d1d1d1ac2 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Mon, 4 Dec 2017 09:44:29 +0100 Subject: [PATCH 0340/1814] C++, support explicit member instantiations See michaeljones/breathe#325 --- CHANGES | 1 + sphinx/domains/cpp.py | 65 +++++++++++++++++++++++++--------------- tests/test_domain_cpp.py | 7 +++++ 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/CHANGES b/CHANGES index 86366f215..234a9bdca 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,7 @@ Features added * #2406: C++, add proper parsing of expressions, including linking of identifiers. * C++, add a ``cpp:expr`` role for inserting inline C++ expressions or types. * #4094: C++, allow empty template argument lists. +* C++, support explicit member instantiations with shorthand ``template`` prefix. * #3638: Allow to change a label of reference to equation using ``math_eqref_format`` diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 81fee9e62..7fa27d4af 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -960,7 +960,8 @@ class ASTSizeofParamPack(ASTBase): def describe_signature(self, signode, mode, env, symbol): signode.append(nodes.Text('sizeof...(')) - self.identifier.describe_signature(signode, mode, env, symbol=symbol, prefix="") + self.identifier.describe_signature(signode, mode, env, + symbol=symbol, prefix="", templateArgs="") signode.append(nodes.Text(')')) @@ -1195,11 +1196,11 @@ class ASTIdentifier(ASTBase): # type: () -> unicode return self.identifier - def describe_signature(self, signode, mode, env, prefix, symbol): - # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None + def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): + # type: (Any, unicode, BuildEnvironment, unicode, unicode, Symbol) -> None _verify_description_mode(mode) if mode == 'markType': - targetText = prefix + self.identifier + targetText = prefix + self.identifier + templateArgs pnode = addnodes.pending_xref('', refdomain='cpp', reftype='identifier', reftarget=targetText, modname=None, @@ -1268,7 +1269,7 @@ class ASTTemplateKeyParamPackIdDefault(ASTBase): if self.identifier: if not self.parameterPack: signode += nodes.Text(' ') - self.identifier.describe_signature(signode, mode, env, '', symbol) + self.identifier.describe_signature(signode, mode, env, '', '', symbol) if self.default: signode += nodes.Text(' = ') self.default.describe_signature(signode, 'markType', env, symbol) @@ -1500,7 +1501,7 @@ class ASTTemplateIntroductionParameter(ASTBase): # type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None if self.parameterPack: signode += nodes.Text('...') - self.identifier.describe_signature(signode, mode, env, '', symbol) + self.identifier.describe_signature(signode, mode, env, '', '', symbol) class ASTTemplateIntroduction(ASTBase): @@ -1558,8 +1559,7 @@ class ASTTemplateIntroduction(ASTBase): class ASTTemplateDeclarationPrefix(ASTBase): def __init__(self, templates): # type: (List[Any]) -> None - assert templates is not None - assert len(templates) > 0 + # template is None means it's an explicit instantiation of a variable self.templates = templates def get_id(self, version): @@ -1775,8 +1775,9 @@ class ASTNestedNameElement(ASTBase): def describe_signature(self, signode, mode, env, prefix, symbol): # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None - self.identifier.describe_signature(signode, mode, env, prefix, symbol) - if self.templateArgs: + tArgs = text_type(self.templateArgs) if self.templateArgs is not None else '' + self.identifier.describe_signature(signode, mode, env, prefix, tArgs, symbol) + if self.templateArgs is not None: self.templateArgs.describe_signature(signode, mode, env, symbol) @@ -1859,7 +1860,8 @@ class ASTNestedName(ASTBase): prefix += '::' first = False if name != '': - if name.templateArgs and iTemplateParams < len(templateParams): # type: ignore + if (name.templateArgs and # type: ignore + iTemplateParams < len(templateParams)): templateParamsPrefix += text_type(templateParams[iTemplateParams]) iTemplateParams += 1 name.describe_signature(signode, 'markType', # type: ignore @@ -3594,7 +3596,6 @@ class Symbol(object): matchSelf=matchSelf): break parentSymbol = parentSymbol.parent - iTemplateDecl = 0 for iName in range(len(names)): name = names[iName] @@ -3614,15 +3615,19 @@ class Symbol(object): assert iTemplateDecl == len(templateDecls) templateParams = None symbol = parentSymbol._find_named_symbol(identifier, - templateParams, - templateArgs, + templateParams, templateArgs, operator, templateShorthand=templateShorthand, matchSelf=matchSelf) - if symbol: + if symbol is not None: return symbol - else: - return None + # try without template params and args + symbol = parentSymbol._find_named_symbol(identifier, + None, None, + operator, + templateShorthand=templateShorthand, + matchSelf=matchSelf) + return symbol else: # there shouldn't be anything inside an operator assert not name.is_operator() @@ -5144,7 +5149,13 @@ class DefinitionParser(object): # the saved position is only used to provide a better error message pos = self.pos if self.skip_word("template"): - params = self._parse_template_parameter_list() # type: Any + try: + params = self._parse_template_parameter_list() # type: Any + except DefinitionError as e: + if objectType == 'member' and len(templates) == 0: + return ASTTemplateDeclarationPrefix(None) + else: + raise e else: params = self._parse_template_introduction() if not params: @@ -5161,20 +5172,25 @@ class DefinitionParser(object): return ASTTemplateDeclarationPrefix(templates) def _check_template_consistency(self, nestedName, templatePrefix, - fullSpecShorthand): - # type: (Any, Any, bool) -> ASTTemplateDeclarationPrefix + fullSpecShorthand, isMember=False): + # type: (Any, Any, Any, bool) -> ASTTemplateDeclarationPrefix numArgs = nestedName.num_templates() + isMemberInstantiation = False if not templatePrefix: numParams = 0 else: - numParams = len(templatePrefix.templates) + if isMember and templatePrefix.templates is None: + numParams = 0 + isMemberInstantiation = True + else: + numParams = len(templatePrefix.templates) if numArgs + 1 < numParams: self.fail("Too few template argument lists comapred to parameter" " lists. Argument lists: %d, Parameter lists: %d." % (numArgs, numParams)) if numArgs > numParams: numExtra = numArgs - numParams - if not fullSpecShorthand: + if not fullSpecShorthand and not isMemberInstantiation: msg = "Too many template argument lists compared to parameter" \ " lists. Argument lists: %d, Parameter lists: %d," \ " Extra empty parameters lists prepended: %d." \ @@ -5188,7 +5204,7 @@ class DefinitionParser(object): newTemplates = [] for i in range(numExtra): newTemplates.append(ASTTemplateParams([])) - if templatePrefix: + if templatePrefix and not isMemberInstantiation: newTemplates.extend(templatePrefix.templates) templatePrefix = ASTTemplateDeclarationPrefix(newTemplates) return templatePrefix @@ -5243,7 +5259,8 @@ class DefinitionParser(object): assert False templatePrefix = self._check_template_consistency(declaration.name, templatePrefix, - fullSpecShorthand=False) + fullSpecShorthand=False, + isMember=objectType == 'member') return ASTDeclaration(objectType, visibility, templatePrefix, declaration) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 4183fa471..f3f0037f5 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -561,6 +561,13 @@ def test_templates(): check('concept', 'template Numerics = (... && Numeric)', {2:'IDpE8Numerics'}) + # explicit specializations of members + check('member', 'template<> int A::a', {2:'IEN1AIiE1aE'}) + check('member', 'template int A::a', {2: 'IEN1AIiE1aE'}, + output='template<> int A::a') # same as above + check('member', 'template<> template<> int A::B::b', {2:'IEIEN1AIiE1BIiE1bE'}) + check('member', 'template int A::B::b', {2: 'IEIEN1AIiE1BIiE1bE'}, + output='template<> template<> int A::B::b') # same as above def test_template_args(): From 6cb517dc2d857c3f3a1484ec0fc621ae43cfa453 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 20 Nov 2017 18:15:03 +0100 Subject: [PATCH 0341/1814] Fix #4249 by overriding Pygments latex formatter error highlighting --- sphinx/texinputs/sphinx.sty | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index a28220cbc..f6653e1a7 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -208,6 +208,17 @@ % stylesheet for highlighting with pygments \RequirePackage{sphinxhighlight} +% fix baseline increase from Pygments latex formatter in case of error tokens +% and keep \fboxsep's scope local via added braces +\def\PYG@tok@err{% + \def\PYG@bc##1{{\setlength{\fboxsep}{-\fboxrule}% + \fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}% +} +\def\PYG@tok@cs{% + \def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}% + \def\PYG@bc##1{{\setlength{\fboxsep}{0pt}% + \colorbox[rgb]{1.00,0.94,0.94}{\strut ##1}}}% +}% %% OPTIONS From 21d1025739b55d2fe169e47de815deab8190bef5 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 6 Dec 2017 18:43:37 +0100 Subject: [PATCH 0342/1814] Update CHANGES for PR #4268 modified: CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index ff312f1d0..ae1eb6142 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugs fixed * #4221: napoleon depends on autodoc, but users need to load it manually * #2298: automodule fails to document a class attribute * #4099: C++: properly link class reference to class from inside constructor +* #4267: PDF build broken by № (Unicode U+2116) character Testing -------- From 90ee039e349080fb86037aae4d59153cc7f03f4f Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 6 Dec 2017 19:02:11 +0100 Subject: [PATCH 0343/1814] =?UTF-8?q?Avoid=20=E2=84=96=20in=20CHANGES,=20a?= =?UTF-8?q?s=20PDF=20built=20with=20language=3D"ja"=20does=20not=20render?= =?UTF-8?q?=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ae1eb6142..1e6613b75 100644 --- a/CHANGES +++ b/CHANGES @@ -23,7 +23,7 @@ Bugs fixed * #4221: napoleon depends on autodoc, but users need to load it manually * #2298: automodule fails to document a class attribute * #4099: C++: properly link class reference to class from inside constructor -* #4267: PDF build broken by № (Unicode U+2116) character +* #4267: PDF build broken by Unicode U+2116 NUMERO SIGN character Testing -------- From 70f8d4ddfcd7ee0a1873ed5a9fbde283a74f818c Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 12:16:35 +0100 Subject: [PATCH 0344/1814] Support ``:emphasize-lines:`` in PDF output (closes #1238) --- doc/latex.rst | 5 +++++ doc/markup/code.rst | 3 +++ sphinx/texinputs/sphinx.sty | 18 +++++++++++++++++- sphinx/writers/latex.py | 3 +++ tests/roots/test-directive-code/emphasize.rst | 7 +++++++ .../expects/longtable_having_verbatim.tex | 1 + .../expects/table_having_verbatim.tex | 1 + tests/test_directive_code.py | 8 ++++++++ tests/test_markup.py | 3 ++- 9 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/roots/test-directive-code/emphasize.rst diff --git a/doc/latex.rst b/doc/latex.rst index 0cd91fa97..5c140d295 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -256,6 +256,11 @@ The available styling options ``VerbatimBorderColor`` default ``{rgb}{0,0,0}``. The frame color, defaults to black. +``VerbatimHighlightColor`` + default ``{rgb}{0.878,1,1}``. The color for highlighted lines. + + .. versionadded:: 1.6.6 + ``verbatimsep`` default ``\fboxsep``. The separation between code lines and the frame. diff --git a/doc/markup/code.rst b/doc/markup/code.rst index cb3e55bdc..9cb57129f 100644 --- a/doc/markup/code.rst +++ b/doc/markup/code.rst @@ -223,6 +223,9 @@ Includes .. versionchanged:: 1.6 With both ``start-after`` and ``lines`` in use, the first line as per ``start-after`` is considered to be with line number ``1`` for ``lines``. + .. versionchanged:: 1.6.6 + LaTeX supports the ``emphasize-lines`` option. + Caption and name ^^^^^^^^^^^^^^^^ diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 232a53b2f..b8412627b 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -159,6 +159,7 @@ % For highlighted code. \RequirePackage{fancyvrb} \fvset{fontsize=\small} +\define@key{FV}{hllines}{\def\sphinx@verbatim@checkifhl##1{\in@{, ##1,}{#1}}} % For hyperlinked footnotes in tables; also for gathering footnotes from % topic and warning blocks. Also to allow code-blocks in footnotes. \RequirePackage{footnotehyper-sphinx} @@ -299,6 +300,8 @@ \sphinxDeclareColorOption{OuterLinkColor}{{rgb}{0.216,0.439,0.388}} \sphinxDeclareColorOption{VerbatimColor}{{rgb}{1,1,1}} \sphinxDeclareColorOption{VerbatimBorderColor}{{rgb}{0,0,0}} +% also no prefix for this one, for consistency (sigh). Color as in minted! +\sphinxDeclareColorOption{VerbatimHighlightColor}{{rgb}{0.878,1,1}} % now the colours defined with "sphinx" prefix in their names \newcommand*{\sphinxDeclareSphinxColorOption}[2]{% % set the initial default @@ -886,11 +889,24 @@ \expandafter\def\expandafter\FV@SetupFont\expandafter {\FV@SetupFont\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}}% - \def\FancyVerbFormatLine ##1{\hsize\linewidth + \def\FancyVerbFormatLine ##1{% + \expandafter\sphinx@verbatim@checkifhl + \expandafter{\the\value{FancyVerbLine}}% + \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% + \toks@{% + \hsize\linewidth \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ \doublehyphendemerits\z@\finalhyphendemerits\z@ \strut ##1\strut}% }% + \ifin@ + \fboxsep0pt + \colorbox{VerbatimHighlightColor}{\sphinx@restorefboxsep\the\toks@}% + \sphinx@restorefboxsep + \else + \the\toks@ + \fi + }% \let\FV@Space\spx@verbatim@space % Allow breaks at special characters using \PYG... macros. \sphinxbreaksatspecials diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index df39c84fd..005f93a3d 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2270,6 +2270,8 @@ class LaTeXTranslator(nodes.NodeVisitor): lang = self.hlsettingstack[-1][0] linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1 highlight_args = node.get('highlight_args', {}) + hllines = '\\fvset{hllines={, %s,}}%%' %\ + str(highlight_args.get('hl_lines', []))[1:-1] if 'language' in node: # code-block directives lang = node['language'] @@ -2308,6 +2310,7 @@ class LaTeXTranslator(nodes.NodeVisitor): hlcode += '\\end{sphinxVerbatimintable}' else: hlcode += '\\end{sphinxVerbatim}' + self.body.append('\n' + hllines) self.body.append('\n' + hlcode + '\n') if ids: self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n') diff --git a/tests/roots/test-directive-code/emphasize.rst b/tests/roots/test-directive-code/emphasize.rst new file mode 100644 index 000000000..95db574ce --- /dev/null +++ b/tests/roots/test-directive-code/emphasize.rst @@ -0,0 +1,7 @@ +Literal Includes with Highlighted Lines +======================================= + +.. literalinclude:: target.py + :language: python + :emphasize-lines: 5-6, 13-15, 24- + diff --git a/tests/roots/test-latex-table/expects/longtable_having_verbatim.tex b/tests/roots/test-latex-table/expects/longtable_having_verbatim.tex index 979385785..7b4fb6964 100644 --- a/tests/roots/test-latex-table/expects/longtable_having_verbatim.tex +++ b/tests/roots/test-latex-table/expects/longtable_having_verbatim.tex @@ -27,6 +27,7 @@ header2 \endlastfoot +\fvset{hllines={, ,}}% \begin{sphinxVerbatimintable}[commandchars=\\\{\}] \PYG{n}{hello} \PYG{n}{world} \end{sphinxVerbatimintable} diff --git a/tests/roots/test-latex-table/expects/table_having_verbatim.tex b/tests/roots/test-latex-table/expects/table_having_verbatim.tex index d8231817a..4a49e4cbb 100644 --- a/tests/roots/test-latex-table/expects/table_having_verbatim.tex +++ b/tests/roots/test-latex-table/expects/table_having_verbatim.tex @@ -10,6 +10,7 @@ header1 header2 \unskip}\relax \\ \hline +\fvset{hllines={, ,}}% \begin{sphinxVerbatimintable}[commandchars=\\\{\}] \PYG{n}{hello} \PYG{n}{world} \end{sphinxVerbatimintable} diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py index 548a5d72c..e3069061b 100644 --- a/tests/test_directive_code.py +++ b/tests/test_directive_code.py @@ -349,6 +349,14 @@ def test_code_block_namedlink_latex(app, status, warning): assert link2 in latex +@pytest.mark.sphinx('latex', testroot='directive-code') +def test_code_block_emphasize_latex(app, status, warning): + app.builder.build(['emphasize']) + latex = (app.outdir / 'Python.tex').text(encoding='utf-8').replace('\r\n', '\n') + includes = '\\fvset{hllines={, 5, 6, 13, 14, 15, 24, 25, 26, 27,}}%\n' + assert includes in latex + + @pytest.mark.sphinx('xml', testroot='directive-code') def test_literal_include(app, status, warning): app.builder.build(['index']) diff --git a/tests/test_markup.py b/tests/test_markup.py index dfa4d74cf..9c41845fc 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -211,7 +211,8 @@ def get_verifier(verify, verify_re): 'verify', u'::\n\n @Γ\\∞${}', None, - (u'\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]\n' + (u'\\fvset{hllines={, ,}}%\n' + u'\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]\n' u'@\\(\\Gamma\\)\\PYGZbs{}\\(\\infty\\)\\PYGZdl{}\\PYGZob{}\\PYGZcb{}\n' u'\\end{sphinxVerbatim}'), ), From 8f2883761646fb1135349d72401dcec1c3f45a18 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 10 Dec 2017 21:08:52 +0900 Subject: [PATCH 0345/1814] Update CHANGES for PR #4274 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 234a9bdca..de81172e5 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,7 @@ Incompatible changes given directory. * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc * #4226: apidoc: Generate new style makefile (make-mode) +* #4274: sphinx-build returns 2 as an exit code on argument error Deprecated ---------- From 38b5dff20690b17bd30825694b43a7f05706d44e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 10 Dec 2017 21:10:56 +0900 Subject: [PATCH 0346/1814] Fix #4279: Sphinx crashes with pickling error when run with multiple processes and remote image --- CHANGES | 2 ++ sphinx/util/logging.py | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 1e6613b75..f2facb019 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,8 @@ Bugs fixed * #2298: automodule fails to document a class attribute * #4099: C++: properly link class reference to class from inside constructor * #4267: PDF build broken by Unicode U+2116 NUMERO SIGN character +* #4279: Sphinx crashes with pickling error when run with multiple processes and + remote image Testing -------- diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 41dc6022f..13a4cfe69 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -82,6 +82,10 @@ def convert_serializable(records): r.msg = r.getMessage() r.args = () + location = getattr(r, 'location', None) + if isinstance(location, nodes.Node): + r.location = get_node_location(location) + class SphinxWarningLogRecord(logging.LogRecord): """Log record class supporting location""" @@ -415,21 +419,26 @@ class WarningLogRecordTranslator(logging.Filter): else: record.location = None elif isinstance(location, nodes.Node): - (source, line) = get_source_line(location) - if source and line: - record.location = "%s:%s" % (source, line) - elif source: - record.location = "%s:" % source - elif line: - record.location = ":%s" % line - else: - record.location = None + record.location = get_node_location(location) elif location and ':' not in location: record.location = '%s' % self.app.env.doc2path(location) return True +def get_node_location(node): + # type: (nodes.Node) -> str + (source, line) = get_source_line(node) + if source and line: + return "%s:%s" % (source, line) + elif source: + return "%s:" % source + elif line: + return ":%s" % line + else: + return None + + class ColorizeFormatter(logging.Formatter): def format(self, record): # type: (logging.LogRecord) -> str From 8ac042a0f81a8aa5ea0a844ae229b43b16e9224c Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 15:45:57 +0100 Subject: [PATCH 0347/1814] Add emphasize-lines PDF support also under verbatimwrapslines=false --- sphinx/texinputs/sphinx.sty | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index b8412627b..7c2641b81 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -889,30 +889,31 @@ \expandafter\def\expandafter\FV@SetupFont\expandafter {\FV@SetupFont\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}}% - \def\FancyVerbFormatLine ##1{% - \expandafter\sphinx@verbatim@checkifhl - \expandafter{\the\value{FancyVerbLine}}% - \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% - \toks@{% - \hsize\linewidth + \def\sphinx@FancyVerbFormatLine ##1{\hsize\linewidth \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ \doublehyphendemerits\z@\finalhyphendemerits\z@ \strut ##1\strut}% }% - \ifin@ - \fboxsep0pt - \colorbox{VerbatimHighlightColor}{\sphinx@restorefboxsep\the\toks@}% - \sphinx@restorefboxsep - \else - \the\toks@ - \fi - }% \let\FV@Space\spx@verbatim@space % Allow breaks at special characters using \PYG... macros. \sphinxbreaksatspecials % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation) \def\FancyVerbCodes{\sphinxbreaksviaactive}% - \fi % end of conditional code for wrapping long code lines + \else % end of conditional code for wrapping long code lines + \let\sphinx@FancyVerbFormatLine\FancyVerbFormatLine + \fi + \renewcommand\FancyVerbFormatLine[1]{% + \expandafter\sphinx@verbatim@checkifhl + \expandafter{\the\value{FancyVerbLine}}% + \ifin@ + \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% + \fboxsep\z@ + \colorbox{VerbatimHighlightColor}% + {\sphinx@restorefboxsep\sphinx@FancyVerbFormatLine{##1}}% + \else + \sphinx@FancyVerbFormatLine{##1}% + \fi + }% % go around fancyvrb's check of \@currenvir \let\VerbatimEnvironment\sphinxVerbatimEnvironment % go around fancyvrb's check of current list depth From 347f15ca2805781662eb19d82999c84ef3a11eb8 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 16:18:08 +0100 Subject: [PATCH 0348/1814] Make PDF support for emphasize-lines work with lineno-start like html --- sphinx/texinputs/sphinx.sty | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 7c2641b81..6a86cc433 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -904,7 +904,7 @@ \fi \renewcommand\FancyVerbFormatLine[1]{% \expandafter\sphinx@verbatim@checkifhl - \expandafter{\the\value{FancyVerbLine}}% + \expandafter{\the\numexpr\value{FancyVerbLine}-\spx@verbatim@linedelta}% \ifin@ \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% \fboxsep\z@ @@ -914,6 +914,10 @@ \sphinx@FancyVerbFormatLine{##1}% \fi }% + % hook into this macro to recover the line numbering offset (default zero) + \expandafter\def\expandafter\FancyVerbCodes\expandafter{\FancyVerbCodes + \FV@SetLineNo + \edef\spx@verbatim@linedelta{\the\value{FancyVerbLine}}}% % go around fancyvrb's check of \@currenvir \let\VerbatimEnvironment\sphinxVerbatimEnvironment % go around fancyvrb's check of current list depth From c220ae3ecbc0b5d2fe007fb03d88b6e6719e9dfe Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 16:18:52 +0100 Subject: [PATCH 0349/1814] Update docs relative to emphasize-lines --- doc/markup/code.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/markup/code.rst b/doc/markup/code.rst index 9cb57129f..12eaa9b7d 100644 --- a/doc/markup/code.rst +++ b/doc/markup/code.rst @@ -121,6 +121,8 @@ emphasize particular lines:: .. versionchanged:: 1.3 ``lineno-start`` has been added. +.. versionchanged:: 1.6.6 + LaTeX supports the ``emphasize-lines`` option. Includes ^^^^^^^^ @@ -188,8 +190,8 @@ Includes ``lines``, the first allowed line having by convention the line number ``1``. When lines have been selected in any of the ways described above, the - line numbers in ``emphasize-lines`` also refer to the selection, with the - first selected line having number ``1``. + line numbers in ``emphasize-lines`` refer to those selected lines, counted + consecutively starting at ``1``. When specifying particular parts of a file to display, it can be useful to display the original line numbers. This can be done using the @@ -223,8 +225,6 @@ Includes .. versionchanged:: 1.6 With both ``start-after`` and ``lines`` in use, the first line as per ``start-after`` is considered to be with line number ``1`` for ``lines``. - .. versionchanged:: 1.6.6 - LaTeX supports the ``emphasize-lines`` option. Caption and name From 3bbfbadce539fd748525affe9b8eec31dc4f79b3 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 16:51:10 +0100 Subject: [PATCH 0350/1814] Add a note for future maintenance by TeX hackers --- doc/markup/code.rst | 1 - sphinx/texinputs/sphinx.sty | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/markup/code.rst b/doc/markup/code.rst index 12eaa9b7d..0021af501 100644 --- a/doc/markup/code.rst +++ b/doc/markup/code.rst @@ -226,7 +226,6 @@ Includes With both ``start-after`` and ``lines`` in use, the first line as per ``start-after`` is considered to be with line number ``1`` for ``lines``. - Caption and name ^^^^^^^^^^^^^^^^ diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 6a86cc433..30308ede2 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -898,9 +898,12 @@ % Allow breaks at special characters using \PYG... macros. \sphinxbreaksatspecials % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation) + % Hacker note: mark-up should not use codes=... option of Verbatim, but + % codes*=..., and \fvset{codes=...} if added by raw latex will be overwritten \def\FancyVerbCodes{\sphinxbreaksviaactive}% \else % end of conditional code for wrapping long code lines \let\sphinx@FancyVerbFormatLine\FancyVerbFormatLine + \let\FancyVerbCodes\@empty % only for clarity \fi \renewcommand\FancyVerbFormatLine[1]{% \expandafter\sphinx@verbatim@checkifhl From e583e5b0f3a761d3025fe0a247332ca2681e19f6 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 17:11:55 +0100 Subject: [PATCH 0351/1814] Fix highlighting in PDF if wrapping of long code lines was _not_ enabled --- sphinx/texinputs/sphinx.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 30308ede2..4c9a6385f 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -902,7 +902,7 @@ % codes*=..., and \fvset{codes=...} if added by raw latex will be overwritten \def\FancyVerbCodes{\sphinxbreaksviaactive}% \else % end of conditional code for wrapping long code lines - \let\sphinx@FancyVerbFormatLine\FancyVerbFormatLine + \def\sphinx@FancyVerbFormatLine ##1{\hb@xt@\linewidth{\strut ##1\hss}}% \let\FancyVerbCodes\@empty % only for clarity \fi \renewcommand\FancyVerbFormatLine[1]{% From 34634d6225a5d6d5ff4e6ffe2677973d7fc6375c Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 10 Dec 2017 23:31:44 +0100 Subject: [PATCH 0352/1814] Update CHANGES for PR #4250 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 1e6613b75..780040c2a 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,8 @@ Bugs fixed * #2298: automodule fails to document a class attribute * #4099: C++: properly link class reference to class from inside constructor * #4267: PDF build broken by Unicode U+2116 NUMERO SIGN character +* #4249: PDF output: Pygments error highlighting increases line spacing in + code blocks Testing -------- From 314f5291d4902b8a59afe602dc209132ddd74b3b Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Dec 2017 19:22:57 +0100 Subject: [PATCH 0353/1814] Replace two self.body.append by one in latex writer --- sphinx/writers/latex.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 005f93a3d..2c2b62659 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -2310,8 +2310,7 @@ class LaTeXTranslator(nodes.NodeVisitor): hlcode += '\\end{sphinxVerbatimintable}' else: hlcode += '\\end{sphinxVerbatim}' - self.body.append('\n' + hllines) - self.body.append('\n' + hlcode + '\n') + self.body.append('\n' + hllines + '\n' + hlcode + '\n') if ids: self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n') raise nodes.SkipNode From 2bbb699b01257615855f05ad2d7864354ce3da09 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Dec 2017 21:15:58 +0100 Subject: [PATCH 0354/1814] Move some LaTeX macros for easier customizability if needed --- sphinx/texinputs/sphinx.sty | 67 ++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 4c9a6385f..cbd2b82e4 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -840,6 +840,32 @@ % needed to create wrapper environments of fancyvrb's Verbatim \newcommand*{\sphinxVerbatimEnvironment}{\gdef\FV@EnvironName{sphinxVerbatim}} +% serves to implement line highlighting and line wrapping +\newcommand\sphinxFancyVerbFormatLine[1]{% + \expandafter\sphinx@verbatim@checkifhl + \expandafter{\the\numexpr\value{FancyVerbLine}-\spx@verbatim@linedelta}% + \ifin@ + \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% + \fboxsep\z@ + \colorbox{VerbatimHighlightColor}% + {\sphinx@restorefboxsep\sphinx@FancyVerbFormatLine{#1}}% + \else + \sphinx@FancyVerbFormatLine{#1}% + \fi +}% +\def\sphinx@FancyVerbFormatLine@wrap #1% +{\hsize\linewidth + \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ + \doublehyphendemerits\z@\finalhyphendemerits\z@ + \strut #1\strut}% +}% +\def\sphinx@FancyVerbFormatLine@nowrap #1{\hb@xt@\linewidth{\strut #1\hss}}% +\def\sphinx@FancyVerbCodesHook + {\FV@SetLineNo\edef\spx@verbatim@linedelta{\the\value{FancyVerbLine}}}% +\g@addto@macro\FV@SetupFont{% + \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% + \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% +}% % Sphinx <1.5 optional argument was in fact mandatory. It is now really % optional and handled by original Verbatim. \newenvironment{sphinxVerbatim}{% @@ -886,41 +912,20 @@ % to achieve this without extensive rewrite of fancyvrb. % - The (not used in sphinx) obeytabs option to Verbatim is % broken by this change (showtabs and tabspace work). - \expandafter\def\expandafter\FV@SetupFont\expandafter - {\FV@SetupFont\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% - \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}}% - \def\sphinx@FancyVerbFormatLine ##1{\hsize\linewidth - \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ - \doublehyphendemerits\z@\finalhyphendemerits\z@ - \strut ##1\strut}% - }% - \let\FV@Space\spx@verbatim@space + \let\sphinx@FancyVerbFormatLine\sphinx@FancyVerbFormatLine@wrap + \let\FV@Space\spx@verbatim@space % Allow breaks at special characters using \PYG... macros. - \sphinxbreaksatspecials + \sphinxbreaksatspecials % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation) - % Hacker note: mark-up should not use codes=... option of Verbatim, but - % codes*=..., and \fvset{codes=...} if added by raw latex will be overwritten - \def\FancyVerbCodes{\sphinxbreaksviaactive}% + \expandafter\def\expandafter\sphinx@FancyVerbCodesHook\expandafter + {\sphinx@FancyVerbCodesHook\sphinxbreaksviaactive}% \else % end of conditional code for wrapping long code lines - \def\sphinx@FancyVerbFormatLine ##1{\hb@xt@\linewidth{\strut ##1\hss}}% - \let\FancyVerbCodes\@empty % only for clarity + \let\sphinx@FancyVerbFormatLine\sphinx@FancyVerbFormatLine@nowrap \fi - \renewcommand\FancyVerbFormatLine[1]{% - \expandafter\sphinx@verbatim@checkifhl - \expandafter{\the\numexpr\value{FancyVerbLine}-\spx@verbatim@linedelta}% - \ifin@ - \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% - \fboxsep\z@ - \colorbox{VerbatimHighlightColor}% - {\sphinx@restorefboxsep\sphinx@FancyVerbFormatLine{##1}}% - \else - \sphinx@FancyVerbFormatLine{##1}% - \fi - }% - % hook into this macro to recover the line numbering offset (default zero) - \expandafter\def\expandafter\FancyVerbCodes\expandafter{\FancyVerbCodes - \FV@SetLineNo - \edef\spx@verbatim@linedelta{\the\value{FancyVerbLine}}}% + \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine + % hook into \FancyVerbCodes to recover at first code line the numbering offset + \expandafter\def\expandafter\FancyVerbCodes\expandafter + {\FancyVerbCodes\sphinx@FancyVerbCodesHook}% % go around fancyvrb's check of \@currenvir \let\VerbatimEnvironment\sphinxVerbatimEnvironment % go around fancyvrb's check of current list depth From f95464baf3b761b7fb437d7c5719ae62e6aba59a Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Dec 2017 22:10:53 +0100 Subject: [PATCH 0355/1814] Update CHANGES for PR #4285 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 780040c2a..74bbe17be 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,8 @@ Features added -------------- * #4181: autodoc: Sort dictionary keys when possible +* ``VerbatimHighlightColor`` is a new + :ref:`LaTeX 'sphinxsetup' ` key (refs: #4285) Bugs fixed ---------- @@ -26,6 +28,7 @@ Bugs fixed * #4267: PDF build broken by Unicode U+2116 NUMERO SIGN character * #4249: PDF output: Pygments error highlighting increases line spacing in code blocks +* #1238: Support ``:emphasize-lines:`` in PDF output Testing -------- From 1502fbda61240aae8ee799dc67c0536e0a210327 Mon Sep 17 00:00:00 2001 From: Dmitry Shachnev Date: Tue, 12 Dec 2017 00:12:45 +0300 Subject: [PATCH 0356/1814] Fix for reproducibility of htmlhelp and qthelp builds Make sure the generated list of files is sorted. This is similar to what was applied to EPub builder in 0b7c73a981. --- sphinx/builders/htmlhelp.py | 2 +- sphinx/builders/qthelp.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 764b01aae..c2e3bbe2c 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -246,7 +246,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): olen = len(outdir) for root, dirs, files in os.walk(outdir): staticdir = root.startswith(path.join(outdir, '_static')) - for fn in files: + for fn in sorted(files): if (staticdir and not fn.endswith('.js')) or \ fn.endswith('.html'): print(path.join(root, fn)[olen:].replace(os.sep, '\\'), diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index b1c94c548..14979fe4b 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -188,7 +188,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder): for root, dirs, files in os.walk(outdir): resourcedir = root.startswith(staticdir) or \ root.startswith(imagesdir) - for fn in files: + for fn in sorted(files): if (resourcedir and not fn.endswith('.js')) or \ fn.endswith('.html'): filename = path.join(root, fn)[olen:] From 43e6f1aa963cb85a1d65ea40a183598a05e1142b Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 11 Dec 2017 23:09:19 +0100 Subject: [PATCH 0357/1814] Fix VerbatimHighlightColor key declared non-sphinx-prefixed colour name --- doc/latex.rst | 10 +++++----- sphinx/texinputs/sphinx.sty | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/latex.rst b/doc/latex.rst index 5c140d295..58833a829 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -261,6 +261,11 @@ The available styling options .. versionadded:: 1.6.6 +.. note:: + + Starting with this colour key, and for all others coming next, the actual + names declared to "color" or "xcolor" are prefixed with "sphinx". + ``verbatimsep`` default ``\fboxsep``. The separation between code lines and the frame. @@ -282,11 +287,6 @@ The available styling options default ``{rgb}{0,0,0}`` (black). The colour for the two horizontal rules used by Sphinx in LaTeX for styling a :dudir:`note` type admonition. -.. note:: - - The actual colour names declared to "color" or "xcolor" are prefixed with - "sphinx". - ``noteborder``, ``hintborder``, ``importantborder``, ``tipborder`` default ``0.5pt``. The width of the two horizontal rules. diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 8db09d4a2..49da59363 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -311,8 +311,6 @@ \sphinxDeclareColorOption{OuterLinkColor}{{rgb}{0.216,0.439,0.388}} \sphinxDeclareColorOption{VerbatimColor}{{rgb}{1,1,1}} \sphinxDeclareColorOption{VerbatimBorderColor}{{rgb}{0,0,0}} -% also no prefix for this one, for consistency (sigh). Color as in minted! -\sphinxDeclareColorOption{VerbatimHighlightColor}{{rgb}{0.878,1,1}} % now the colours defined with "sphinx" prefix in their names \newcommand*{\sphinxDeclareSphinxColorOption}[2]{% % set the initial default @@ -320,6 +318,8 @@ % set the key handler. The "value" ##1 must be acceptable by \definecolor. \define@key{sphinx}{#1}{\definecolor{sphinx#1}##1}% }% +% Default color chosen to be as in minted.sty LaTeX package! +\sphinxDeclareSphinxColorOption{VerbatimHighlightColor}{{rgb}{0.878,1,1}} % admonition boxes, "light" style \sphinxDeclareSphinxColorOption{noteBorderColor}{{rgb}{0,0,0}} \sphinxDeclareSphinxColorOption{hintBorderColor}{{rgb}{0,0,0}} @@ -858,7 +858,7 @@ \ifin@ \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% \fboxsep\z@ - \colorbox{VerbatimHighlightColor}% + \colorbox{sphinxVerbatimHighlightColor}% {\sphinx@restorefboxsep\sphinx@FancyVerbFormatLine{#1}}% \else \sphinx@FancyVerbFormatLine{#1}% From a12399dbe429f552ab012099491c577de668a81d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 7 Dec 2017 23:49:32 +0900 Subject: [PATCH 0358/1814] Refactor sphinx.io; independ parser generation from reader class --- sphinx/io.py | 41 ++++----------------------------------- sphinx/registry.py | 23 +++++++++++++++++++++- sphinx/transforms/i18n.py | 9 +++------ 3 files changed, 29 insertions(+), 44 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 84e1d7bb3..47e701f35 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -50,37 +50,6 @@ class SphinxBaseReader(standalone.Reader): """ Add our source parsers """ - def __init__(self, app, parsers={}, *args, **kwargs): - # type: (Sphinx, Dict[unicode, Parser], Any, Any) -> None - standalone.Reader.__init__(self, *args, **kwargs) - self.parser_map = {} # type: Dict[unicode, Parser] - for suffix, parser_class in parsers.items(): - if isinstance(parser_class, string_types): - parser_class = import_object(parser_class, 'source parser') # type: ignore - parser = parser_class() - if hasattr(parser, 'set_application'): - parser.set_application(app) - self.parser_map[suffix] = parser - - def read(self, source, parser, settings): - # type: (Input, Parser, Dict) -> nodes.document - self.source = source - - for suffix in self.parser_map: - if source.source_path.endswith(suffix): - self.parser = self.parser_map[suffix] - break - else: - # use special parser for unknown file-extension '*' (if exists) - self.parser = self.parser_map.get('*') - - if not self.parser: - self.parser = parser - self.settings = settings - self.input = self.source.read() - self.parse() - return self.document - def get_transforms(self): # type: () -> List[Transform] return standalone.Reader.get_transforms(self) + self.transforms @@ -114,17 +83,13 @@ class SphinxI18nReader(SphinxBaseReader): This class provides the correct line numbers when reporting. """ + lineno = None # type: int transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, SortIds, RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform, UnreferencedFootnotesDetector] - def __init__(self, *args, **kwargs): - # type: (Any, Any) -> None - SphinxBaseReader.__init__(self, *args, **kwargs) - self.lineno = None # type: int - def set_lineno_for_reporter(self, lineno): # type: (int) -> None self.lineno = lineno @@ -216,11 +181,13 @@ class SphinxFileInput(FileInput): def read_doc(app, env, filename): # type: (Sphinx, BuildEnvironment, unicode) -> nodes.document """Parse a document and convert to doctree.""" - reader = SphinxStandaloneReader(app, parsers=app.registry.get_source_parsers()) + reader = SphinxStandaloneReader() source = SphinxFileInput(app, env, source=None, source_path=filename, encoding=env.config.source_encoding) + parser = app.registry.create_source_parser(app, filename) pub = Publisher(reader=reader, + parser=parser, writer=SphinxDummyWriter(), source_class=SphinxDummySourceClass, destination=NullOutput()) diff --git a/sphinx/registry.py b/sphinx/registry.py index 0861575db..c8ce4ad5e 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -13,15 +13,17 @@ from __future__ import print_function import traceback from pkg_resources import iter_entry_points -from six import itervalues +from six import iteritems, itervalues, string_types from sphinx.errors import ExtensionError, SphinxError, VersionRequirementError from sphinx.extension import Extension from sphinx.domains import ObjType from sphinx.domains.std import GenericObject, Target from sphinx.locale import __ +from sphinx.parsers import Parser as SphinxParser from sphinx.roles import XRefRole from sphinx.util import logging +from sphinx.util import import_object from sphinx.util.docutils import directive_helper if False: @@ -160,6 +162,25 @@ class SphinxComponentRegistry(object): raise ExtensionError(__('source_parser for %r is already registered') % suffix) self.source_parsers[suffix] = parser + def create_source_parser(self, app, filename): + # type: (Sphinx, unicode) -> Parser + for suffix, parser_class in iteritems(self.source_parsers): + if filename.endswith(suffix): + break + else: + # use special parser for unknown file-extension '*' (if exists) + parser_class = self.source_parsers.get('*') + + if parser_class is None: + raise SphinxError(__('Source parser for %s not registered') % filename) + else: + if isinstance(parser_class, string_types): + parser_class = import_object(parser_class, 'source parser') # type: ignore + parser = parser_class() + if isinstance(parser, SphinxParser): + parser.set_application(app) + return parser + def get_source_parsers(self): # type: () -> Dict[unicode, Parser] return self.source_parsers diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 4c1fbc2a7..d08cc81f4 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -50,15 +50,12 @@ def publish_msgstr(app, source, source_path, source_line, config, settings): :rtype: docutils.nodes.document """ from sphinx.io import SphinxI18nReader - reader = SphinxI18nReader( - app=app, - parsers=app.registry.get_source_parsers(), - parser_name='restructuredtext', # default parser - ) + reader = SphinxI18nReader() reader.set_lineno_for_reporter(source_line) + parser = app.registry.create_source_parser(app, '') doc = reader.read( source=StringInput(source=source, source_path=source_path), - parser=reader.parser, + parser=parser, settings=settings, ) try: From a0200ad4995967fc28f0e6ac70d0f15779d0e8bb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 15 Nov 2017 11:02:36 +0900 Subject: [PATCH 0359/1814] Refactor sphinx.io; dependent parser detection from SphinxFileInput --- sphinx/io.py | 13 +++---------- sphinx/registry.py | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 47e701f35..71701e10d 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -140,22 +140,15 @@ class SphinxFileInput(FileInput): def read(self): # type: () -> unicode - def get_parser_type(source_path): - # type: (unicode) -> Tuple[unicode] - for suffix, parser_class in iteritems(self.app.registry.get_source_parsers()): - if source_path.endswith(suffix): - if isinstance(parser_class, string_types): - parser_class = import_object(parser_class, 'source parser') # type: ignore # NOQA - return parser_class.supported - return ('restructuredtext',) - data = FileInput.read(self) if self.app: arg = [data] self.app.emit('source-read', self.env.docname, arg) data = arg[0] + + parser = self.app.registry.get_source_parser(self.source_path) docinfo, data = split_docinfo(data) - if 'restructuredtext' in get_parser_type(self.source_path): + if 'restructuredtext' in parser.supported: if self.env.config.rst_epilog: data = data + '\n' + self.env.config.rst_epilog + '\n' if self.env.config.rst_prolog: diff --git a/sphinx/registry.py b/sphinx/registry.py index c8ce4ad5e..3723bcc29 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -157,13 +157,13 @@ class SphinxComponentRegistry(object): stddomain.object_types[directivename] = ObjType(objname or directivename, rolename) def add_source_parser(self, suffix, parser): - # type: (unicode, Parser) -> None + # type: (unicode, Type[Parser]) -> None if suffix in self.source_parsers: raise ExtensionError(__('source_parser for %r is already registered') % suffix) self.source_parsers[suffix] = parser - def create_source_parser(self, app, filename): - # type: (Sphinx, unicode) -> Parser + def get_source_parser(self, filename): + # type: (unicode) -> Type[Parser] for suffix, parser_class in iteritems(self.source_parsers): if filename.endswith(suffix): break @@ -176,15 +176,20 @@ class SphinxComponentRegistry(object): else: if isinstance(parser_class, string_types): parser_class = import_object(parser_class, 'source parser') # type: ignore - parser = parser_class() - if isinstance(parser, SphinxParser): - parser.set_application(app) - return parser + return parser_class def get_source_parsers(self): # type: () -> Dict[unicode, Parser] return self.source_parsers + def create_source_parser(self, app, filename): + # type: (Sphinx, unicode) -> Parser + parser_class = self.get_source_parser(filename) + parser = parser_class() + if isinstance(parser, SphinxParser): + parser.set_application(app) + return parser + def add_translator(self, name, translator): # type: (unicode, Type[nodes.NodeVisitor]) -> None self.translators[name] = translator From aa4fd0e1b7e3043dee6ad3344c477cc59d41f0e8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 15 Nov 2017 11:34:52 +0900 Subject: [PATCH 0360/1814] refactor sphinx.io; SphinxFileInput can expect that app argument is always available --- sphinx/io.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 71701e10d..c290e7831 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -141,10 +141,11 @@ class SphinxFileInput(FileInput): def read(self): # type: () -> unicode data = FileInput.read(self) - if self.app: - arg = [data] - self.app.emit('source-read', self.env.docname, arg) - data = arg[0] + + # emit source-read event + arg = [data] + self.app.emit('source-read', self.env.docname, arg) + data = arg[0] parser = self.app.registry.get_source_parser(self.source_path) docinfo, data = split_docinfo(data) From 0e86ff2f1133e529d148cea6cc235218d73cc7d4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 15 Nov 2017 14:48:30 +0900 Subject: [PATCH 0361/1814] Refactor sphinx.io; separate FileInput class for each file type --- sphinx/application.py | 1 + sphinx/io.py | 41 ++++++++++++++++++++++++++++------------- sphinx/registry.py | 24 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 209c73202..05d302c81 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -83,6 +83,7 @@ builtin_extensions = ( 'sphinx.directives.code', 'sphinx.directives.other', 'sphinx.directives.patches', + 'sphinx.io', 'sphinx.parsers', 'sphinx.roles', 'sphinx.transforms.post_transforms', diff --git a/sphinx/io.py b/sphinx/io.py index c290e7831..418e91b12 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -120,7 +120,9 @@ def SphinxDummySourceClass(source, *args, **kwargs): return source -class SphinxFileInput(FileInput): +class SphinxBaseFileInput(FileInput): + """A base class of SphinxFileInput.""" + def __init__(self, app, env, *args, **kwds): # type: (Sphinx, BuildEnvironment, Any, Any) -> None self.app = app @@ -145,16 +147,7 @@ class SphinxFileInput(FileInput): # emit source-read event arg = [data] self.app.emit('source-read', self.env.docname, arg) - data = arg[0] - - parser = self.app.registry.get_source_parser(self.source_path) - docinfo, data = split_docinfo(data) - if 'restructuredtext' in parser.supported: - if self.env.config.rst_epilog: - data = data + '\n' + self.env.config.rst_epilog + '\n' - if self.env.config.rst_prolog: - data = self.env.config.rst_prolog + '\n' + data - return docinfo + data + return arg[0] def warn_and_replace(self, error): # type: (Any) -> Tuple @@ -172,12 +165,29 @@ class SphinxFileInput(FileInput): return (u'?', error.end) +class SphinxFileInput(SphinxBaseFileInput): + pass + + +class SphinxRSTFileInput(SphinxBaseFileInput): + def read(self): + # type: () -> unicode + data = SphinxBaseFileInput.read(self) + docinfo, data = split_docinfo(data) + if self.env.config.rst_epilog: + data = data + '\n' + self.env.config.rst_epilog + '\n' + if self.env.config.rst_prolog: + data = self.env.config.rst_prolog + '\n' + data + return docinfo + data + + def read_doc(app, env, filename): # type: (Sphinx, BuildEnvironment, unicode) -> nodes.document """Parse a document and convert to doctree.""" + input_class = app.registry.get_source_input(filename) reader = SphinxStandaloneReader() - source = SphinxFileInput(app, env, source=None, source_path=filename, - encoding=env.config.source_encoding) + source = input_class(app, env, source=None, source_path=filename, + encoding=env.config.source_encoding) parser = app.registry.create_source_parser(app, filename) pub = Publisher(reader=reader, @@ -190,3 +200,8 @@ def read_doc(app, env, filename): pub.set_source(source, filename) pub.publish() return pub.document + + +def setup(app): + app.registry.add_source_input('*', SphinxFileInput) + app.registry.add_source_input('restructuredtext', SphinxRSTFileInput) diff --git a/sphinx/registry.py b/sphinx/registry.py index 3723bcc29..b627f23af 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -30,6 +30,7 @@ if False: # For type annotation from typing import Any, Callable, Dict, Iterator, List, Type # NOQA from docutils import nodes # NOQA + from docutils.io import Input # NOQA from docutils.parsers import Parser # NOQA from sphinx.application import Sphinx # NOQA from sphinx.builders import Builder # NOQA @@ -50,6 +51,7 @@ class SphinxComponentRegistry(object): self.builders = {} # type: Dict[unicode, Type[Builder]] self.domains = {} # type: Dict[unicode, Type[Domain]] self.source_parsers = {} # type: Dict[unicode, Parser] + self.source_inputs = {} # type: Dict[unicode, Input] self.translators = {} # type: Dict[unicode, nodes.NodeVisitor] def add_builder(self, builder): @@ -190,6 +192,28 @@ class SphinxComponentRegistry(object): parser.set_application(app) return parser + def add_source_input(self, filetype, input_class): + # type: (unicode, Type[Input]) -> None + if filetype in self.source_inputs: + raise ExtensionError(__('source_input for %r is already registered') % filetype) + self.source_inputs[filetype] = input_class + + def get_source_input(self, filename): + # type: (unicode) -> Type[Input] + parser = self.get_source_parser(filename) + for filetype in parser.supported: + if filetype in self.source_inputs: + input_class = self.source_inputs[filetype] + break + else: + # use special source_input for unknown file-type '*' (if exists) + input_class = self.source_inputs.get('*') + + if input_class is None: + raise SphinxError(__('source_input for %s not registered') % filename) + else: + return input_class + def add_translator(self, name, translator): # type: (unicode, Type[nodes.NodeVisitor]) -> None self.translators[name] = translator From 16c244cd6af79afa85202af1a0f1e325c175994f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 14 Nov 2017 22:33:56 +0900 Subject: [PATCH 0362/1814] Add LoggingReporter.from_reporter() constructor --- sphinx/io.py | 4 +--- sphinx/util/docutils.py | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 418e91b12..5868bd7b5 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -58,9 +58,7 @@ class SphinxBaseReader(standalone.Reader): # type: () -> nodes.document document = standalone.Reader.new_document(self) reporter = document.reporter - document.reporter = LoggingReporter(reporter.source, reporter.report_level, - reporter.halt_level, reporter.debug_flag, - reporter.error_handler) + document.reporter = LoggingReporter.from_reporter(reporter) return document diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 92e6c8c22..d24a8f827 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -167,6 +167,13 @@ class WarningStream(object): class LoggingReporter(Reporter): + @classmethod + def from_reporter(cls, reporter): + # type: (Reporter) -> LoggingReporter + """Create an instance of LoggingReporter from other reporter object.""" + return cls(reporter.source, reporter.report_level, reporter.halt_level, + reporter.debug_flag, reporter.error_handler) + def __init__(self, source, report_level, halt_level, debug=False, error_handler='backslashreplace'): # type: (unicode, int, int, bool, unicode) -> None From 773173b11f04f08547999c0799911fc7aa96d0d3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 14 Nov 2017 22:34:32 +0900 Subject: [PATCH 0363/1814] Remove LoggingReporter.set_conditions() (unused) --- sphinx/util/docutils.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index d24a8f827..8da89713d 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -181,10 +181,6 @@ class LoggingReporter(Reporter): Reporter.__init__(self, source, report_level, halt_level, stream, debug, error_handler=error_handler) - def set_conditions(self, category, report_level, halt_level, debug=False): - # type: (unicode, int, int, bool) -> None - Reporter.set_conditions(self, category, report_level, halt_level, debug=debug) - def is_html5_writer_available(): # type: () -> bool From 07c5348a56471201b5901881b0d9d83f4823a6fd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 7 Dec 2017 15:45:29 +0900 Subject: [PATCH 0364/1814] Add test_io.py --- sphinx/io.py | 55 ++++++++++++++++++--- sphinx/parsers.py | 22 +++++++++ sphinx/util/__init__.py | 10 ---- sphinx/util/docutils.py | 19 ++++++- tests/test_io.py | 107 ++++++++++++++++++++++++++++++++++++++++ tests/test_util.py | 25 +--------- 6 files changed, 195 insertions(+), 43 deletions(-) create mode 100644 tests/test_io.py diff --git a/sphinx/io.py b/sphinx/io.py index 5868bd7b5..056c763b1 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -8,13 +8,15 @@ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import re import codecs from docutils.io import FileInput, NullOutput from docutils.core import Publisher from docutils.readers import standalone +from docutils.statemachine import StringList from docutils.writers import UnfilteredWriter -from six import string_types, text_type, iteritems +from six import text_type from typing import Any, Union # NOQA from sphinx.transforms import ( @@ -28,7 +30,6 @@ from sphinx.transforms.i18n import ( PreserveTranslatableMessages, Locale, RemoveTranslatableInline, ) from sphinx.util import logging -from sphinx.util import import_object, split_docinfo from sphinx.util.docutils import LoggingReporter if False: @@ -42,6 +43,8 @@ if False: from sphinx.builders import Builder # NOQA from sphinx.environment import BuildEnvironment # NOQA +docinfo_re = re.compile(':\\w+:.*?') + logger = logging.getLogger(__name__) @@ -59,6 +62,7 @@ class SphinxBaseReader(standalone.Reader): document = standalone.Reader.new_document(self) reporter = document.reporter document.reporter = LoggingReporter.from_reporter(reporter) + document.reporter.set_source(self.source) return document @@ -168,15 +172,50 @@ class SphinxFileInput(SphinxBaseFileInput): class SphinxRSTFileInput(SphinxBaseFileInput): + def prepend_prolog(self, text, prolog): + # type: (StringList, unicode) -> None + docinfo = self.count_docinfo_lines(text) + if docinfo: + # insert a blank line after docinfo + text.insert(docinfo, '', '', 0) + docinfo += 1 + + # insert prolog (after docinfo if exists) + for lineno, line in enumerate(prolog.splitlines()): + text.insert(docinfo + lineno, line, '', lineno) + + text.insert(docinfo + lineno + 1, '', '', 0) + + def append_epilog(self, text, epilog): + # type: (StringList, unicode) -> None + # append a blank line and rst_epilog + text.append('', '', 0) + for lineno, line in enumerate(epilog.splitlines()): + text.append(line, '', lineno) + def read(self): - # type: () -> unicode + # type: () -> StringList data = SphinxBaseFileInput.read(self) - docinfo, data = split_docinfo(data) - if self.env.config.rst_epilog: - data = data + '\n' + self.env.config.rst_epilog + '\n' + content = StringList() + for lineno, line in enumerate(data.splitlines()): + content.append(line, self.source_path, lineno) + if self.env.config.rst_prolog: - data = self.env.config.rst_prolog + '\n' + data - return docinfo + data + self.prepend_prolog(content, self.env.config.rst_prolog) + if self.env.config.rst_epilog: + self.append_epilog(content, self.env.config.rst_epilog) + + return content + + def count_docinfo_lines(self, content): + # type: (StringList) -> int + if len(content) == 0: + return 0 + else: + for lineno, line in enumerate(content.data): + if not docinfo_re.match(line): + break + return lineno def read_doc(app, env, filename): diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 33556e487..085e45070 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -11,6 +11,8 @@ import docutils.parsers import docutils.parsers.rst +from docutils.parsers.rst import states +from docutils.statemachine import StringList from docutils.transforms.universal import SmartQuotes from sphinx.transforms import SphinxSmartQuotes @@ -66,6 +68,26 @@ class RSTParser(docutils.parsers.rst.Parser): transforms.append(SphinxSmartQuotes) return transforms + def parse(self, inputstring, document): + # type: (Any, nodes.document) -> None + """Parse text and generate a document tree. + + This derived method accepts StringList as a inputstring parameter. + It enables to handle mixed contents (cf. rst_prolog) correctly. + """ + if isinstance(inputstring, StringList): + self.setup_parse(inputstring, document) + self.statemachine = states.RSTStateMachine( + state_classes=self.state_classes, + initial_state=self.initial_state, + debug=document.reporter.debug_flag) + # Give inputstring directly to statemachine. + self.statemachine.run(inputstring, document, inliner=self.inliner) + self.finish_parse() + else: + # otherwise, inputstring might be a string. It will be handled by superclass. + docutils.parsers.rst.Parser.parse(self, inputstring, document) + def setup(app): # type: (Sphinx) -> Dict[unicode, Any] diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 03f8ce6a3..da0f6ac3a 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -564,16 +564,6 @@ def encode_uri(uri): return urlunsplit(split) -def split_docinfo(text): - # type: (unicode) -> Sequence[unicode] - docinfo_re = re.compile('\\A((?:\\s*:\\w+:.*?\n(?:[ \\t]+.*?\n)*)+)', re.M) - result = docinfo_re.split(text, 1) # type: ignore - if len(result) == 1: - return '', result[0] - else: - return result[1:] - - def display_chunk(chunk): # type: (Any) -> unicode if isinstance(chunk, (list, tuple)): diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 8da89713d..d1b7ac431 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -18,8 +18,9 @@ from contextlib import contextmanager import docutils from docutils.languages import get_language -from docutils.utils import Reporter +from docutils.statemachine import ViewList from docutils.parsers.rst import directives, roles, convert_directive_function +from docutils.utils import Reporter from sphinx.errors import ExtensionError from sphinx.locale import __ @@ -33,6 +34,7 @@ if False: from typing import Any, Callable, Iterator, List, Tuple # NOQA from docutils import nodes # NOQA from sphinx.environment import BuildEnvironment # NOQA + from sphinx.io import SphinxFileInput # NOQA __version_info__ = tuple(LooseVersion(docutils.__version__).version) @@ -180,6 +182,21 @@ class LoggingReporter(Reporter): stream = WarningStream() Reporter.__init__(self, source, report_level, halt_level, stream, debug, error_handler=error_handler) + self.source_and_line = None + + def set_source(self, source): + # type: (SphinxFileInput) -> None + self.source_and_line = source + + def system_message(self, *args, **kwargs): + # type: (Any, Any) -> Any + if kwargs.get('line') and isinstance(self.source_and_line, ViewList): + # replace source parameter if source is set + source, lineno = self.source_and_line.info(kwargs.get('line')) + kwargs['source'] = source + kwargs['line'] = lineno + + return Reporter.system_message(self, *args, **kwargs) def is_html5_writer_available(): diff --git a/tests/test_io.py b/tests/test_io.py new file mode 100644 index 000000000..a017a2cc0 --- /dev/null +++ b/tests/test_io.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +""" + test_sphinx_io + ~~~~~~~~~~~~~~ + + Tests io modules. + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import pytest +from six import StringIO + +from sphinx.io import SphinxRSTFileInput + + +@pytest.mark.sphinx(testroot='basic') +def test_SphinxRSTFileInput(app): + app.env.temp_data['docname'] = 'index' + + # normal case + text = ('hello Sphinx world\n' + 'Sphinx is a document generator') + source = SphinxRSTFileInput(app, app.env, source=StringIO(text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == ['hello Sphinx world', + 'Sphinx is a document generator'] + assert result.info(0) == ('dummy.rst', 0) + assert result.info(1) == ('dummy.rst', 1) + assert result.info(2) == ('dummy.rst', None) # out of range + + # having rst_prolog ends without CR + app.env.config.rst_prolog = 'this is rst_prolog\nhello reST!' + source = SphinxRSTFileInput(app, app.env, source=StringIO(text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == ['this is rst_prolog', + 'hello reST!', + '', + 'hello Sphinx world', + 'Sphinx is a document generator'] + assert result.info(0) == ('', 0) + assert result.info(1) == ('', 1) + assert result.info(2) == ('', 0) + assert result.info(3) == ('dummy.rst', 0) + assert result.info(4) == ('dummy.rst', 1) + + # having rst_prolog ends with CR + app.env.config.rst_prolog = 'this is rst_prolog\nhello reST!\n' + source = SphinxRSTFileInput(app, app.env, source=StringIO(text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == ['this is rst_prolog', + 'hello reST!', + '', + 'hello Sphinx world', + 'Sphinx is a document generator'] + + # having docinfo and rst_prolog + docinfo_text = (':title: test of SphinxFileInput\n' + ':author: Sphinx team\n' + '\n' + 'hello Sphinx world\n' + 'Sphinx is a document generator\n') + app.env.config.rst_prolog = 'this is rst_prolog\nhello reST!' + source = SphinxRSTFileInput(app, app.env, source=StringIO(docinfo_text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == [':title: test of SphinxFileInput', + ':author: Sphinx team', + '', + 'this is rst_prolog', + 'hello reST!', + '', + '', + 'hello Sphinx world', + 'Sphinx is a document generator'] + assert result.info(0) == ('dummy.rst', 0) + assert result.info(1) == ('dummy.rst', 1) + assert result.info(2) == ('', 0) + assert result.info(3) == ('', 0) + assert result.info(4) == ('', 1) + assert result.info(5) == ('', 0) + assert result.info(6) == ('dummy.rst', 2) + assert result.info(7) == ('dummy.rst', 3) + assert result.info(8) == ('dummy.rst', 4) + assert result.info(9) == ('dummy.rst', None) # out of range + + # having rst_epilog + app.env.config.rst_prolog = None + app.env.config.rst_epilog = 'this is rst_epilog\ngood-bye reST!' + source = SphinxRSTFileInput(app, app.env, source=StringIO(text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == ['hello Sphinx world', + 'Sphinx is a document generator', + '', + 'this is rst_epilog', + 'good-bye reST!'] + assert result.info(0) == ('dummy.rst', 0) + assert result.info(1) == ('dummy.rst', 1) + assert result.info(2) == ('', 0) + assert result.info(3) == ('', 0) + assert result.info(4) == ('', 1) + assert result.info(5) == ('', None) # out of range diff --git a/tests/test_util.py b/tests/test_util.py index 84ce44007..aae54eaf0 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -14,8 +14,7 @@ from mock import patch from sphinx.util import logging from sphinx.util import ( - display_chunk, encode_uri, parselinenos, split_docinfo, status_iterator, - xmlname_checker + display_chunk, encode_uri, parselinenos, status_iterator, xmlname_checker ) from sphinx.testing.util import strip_escseq @@ -36,28 +35,6 @@ def test_encode_uri(): assert expected, encode_uri(uri) -def test_splitdocinfo(): - source = "Hello world.\n" - docinfo, content = split_docinfo(source) - assert docinfo == '' - assert content == 'Hello world.\n' - - source = ":orphan:\n\nHello world.\n" - docinfo, content = split_docinfo(source) - assert docinfo == ':orphan:\n' - assert content == '\nHello world.\n' - - source = ":author: Georg Brandl\n:title: Manual of Sphinx\n\nHello world.\n" - docinfo, content = split_docinfo(source) - assert docinfo == ':author: Georg Brandl\n:title: Manual of Sphinx\n' - assert content == '\nHello world.\n' - - source = ":multiline: one\n\ttwo\n\tthree\n\nHello world.\n" - docinfo, content = split_docinfo(source) - assert docinfo == ":multiline: one\n\ttwo\n\tthree\n" - assert content == '\nHello world.\n' - - def test_display_chunk(): assert display_chunk('hello') == 'hello' assert display_chunk(['hello']) == 'hello' From faadbef7575d63e617007040a64935e6a5226856 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 12 Dec 2017 10:56:54 +0100 Subject: [PATCH 0365/1814] Expose some sphinx.sty LaTeX internals for customizability (refs: #4285) --- CHANGES | 1 + doc/latex.rst | 5 +++++ sphinx/texinputs/sphinx.sty | 25 +++++++++++++++---------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 74bbe17be..748eb2962 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,7 @@ Features added * #4181: autodoc: Sort dictionary keys when possible * ``VerbatimHighlightColor`` is a new :ref:`LaTeX 'sphinxsetup' ` key (refs: #4285) +* Easier customizability of LaTeX macros involved in rendering of code-blocks Bugs fixed ---------- diff --git a/doc/latex.rst b/doc/latex.rst index 58833a829..2197efcd6 100644 --- a/doc/latex.rst +++ b/doc/latex.rst @@ -448,6 +448,11 @@ Environments .. versionadded:: 1.5 options ``verbatimwithframe``, ``verbatimwrapslines``, ``verbatimsep``, ``verbatimborder``. + .. versionadded:: 1.6.6 + support for ``:emphasize-lines:`` option + .. versionadded:: 1.6.6 + easier customizability of the formatting via exposed to user LaTeX macros + such as ``\sphinxVerbatimHighlightLine``. - the bibliography uses ``sphinxthebibliography`` and the Python Module index as well as the general index both use ``sphinxtheindex``; these environments are wrappers of the ``thebibliography`` and respectively ``theindex`` diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 49da59363..15fe9ee04 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -856,21 +856,26 @@ \expandafter\sphinx@verbatim@checkifhl \expandafter{\the\numexpr\value{FancyVerbLine}-\spx@verbatim@linedelta}% \ifin@ - \edef\sphinx@restorefboxsep{\fboxsep\the\fboxsep\relax}% - \fboxsep\z@ - \colorbox{sphinxVerbatimHighlightColor}% - {\sphinx@restorefboxsep\sphinx@FancyVerbFormatLine{#1}}% + \sphinxVerbatimHighlightLine{#1}% \else - \sphinx@FancyVerbFormatLine{#1}% + \sphinxVerbatimFormatLine{#1}% \fi }% -\def\sphinx@FancyVerbFormatLine@wrap #1% -{\hsize\linewidth +\newcommand\sphinxVerbatimHighlightLine[1]{% + \edef\sphinxrestorefboxsep{\fboxsep\the\fboxsep\relax}% + \fboxsep0pt\relax % cf LaTeX bug graphics/4524 + \colorbox{sphinxVerbatimHighlightColor}% + {\sphinxrestorefboxsep\sphinxVerbatimFormatLine{#1}}% + % no need to restore \fboxsep here, as this ends up in a \hbox from fancyvrb +}% +% \sphinxVerbatimFormatLine will be set locally to one of those two: +\newcommand\sphinxVerbatimFormatLineWrap[1]{% + \hsize\linewidth \vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@ \doublehyphendemerits\z@\finalhyphendemerits\z@ \strut #1\strut}% }% -\def\sphinx@FancyVerbFormatLine@nowrap #1{\hb@xt@\linewidth{\strut #1\hss}}% +\newcommand\sphinxVerbatimFormatLineNoWrap[1]{\hb@xt@\linewidth{\strut #1\hss}}% \def\sphinx@FancyVerbCodesHook {\FV@SetLineNo\edef\spx@verbatim@linedelta{\the\value{FancyVerbLine}}}% \g@addto@macro\FV@SetupFont{% @@ -923,7 +928,7 @@ % to achieve this without extensive rewrite of fancyvrb. % - The (not used in sphinx) obeytabs option to Verbatim is % broken by this change (showtabs and tabspace work). - \let\sphinx@FancyVerbFormatLine\sphinx@FancyVerbFormatLine@wrap + \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineWrap \let\FV@Space\spx@verbatim@space % Allow breaks at special characters using \PYG... macros. \sphinxbreaksatspecials @@ -931,7 +936,7 @@ \expandafter\def\expandafter\sphinx@FancyVerbCodesHook\expandafter {\sphinx@FancyVerbCodesHook\sphinxbreaksviaactive}% \else % end of conditional code for wrapping long code lines - \let\sphinx@FancyVerbFormatLine\sphinx@FancyVerbFormatLine@nowrap + \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineNoWrap \fi \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine % hook into \FancyVerbCodes to recover at first code line the numbering offset From b5e50d652c351c81fd89afbb82d5a77575685271 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 12 Dec 2017 10:59:25 +0100 Subject: [PATCH 0366/1814] Update LaTeX style file's version date --- sphinx/texinputs/sphinx.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 15fe9ee04..45944885d 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -6,7 +6,7 @@ % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{sphinx}[2017/11/29 v1.6.6 LaTeX package (Sphinx markup)] +\ProvidesPackage{sphinx}[2017/12/12 v1.6.6 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but From 0b0ac8b3bd0c6ff44c2465a7bdfdc67c375fe705 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 12 Dec 2017 11:02:19 +0100 Subject: [PATCH 0367/1814] Fix merge error --- sphinx/texinputs/sphinx.sty | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 0cf18f1ae..453234fd4 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -7,7 +7,6 @@ \NeedsTeXFormat{LaTeX2e}[1995/12/01] \ProvidesPackage{sphinx}[2017/12/12 v1.7 LaTeX package (Sphinx markup)] -\ProvidesPackage{sphinx}[2017/12/12 v1.6.6 LaTeX package (Sphinx markup)] % provides \ltx@ifundefined % (many packages load ltxcmds: graphicx does for pdftex and lualatex but From d4243a10fef2988d76d308668e4596c0a6873fc2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 12 Dec 2017 23:28:30 +0900 Subject: [PATCH 0368/1814] Fix mypy violation --- sphinx/util/logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 13a4cfe69..6148a5445 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -84,7 +84,7 @@ def convert_serializable(records): location = getattr(r, 'location', None) if isinstance(location, nodes.Node): - r.location = get_node_location(location) + r.location = get_node_location(location) # type: ignore class SphinxWarningLogRecord(logging.LogRecord): From d9006ef5b287ab459007833f549bc05b19ac7218 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 12 Dec 2017 09:54:20 +0100 Subject: [PATCH 0369/1814] C++, make function params linkable --- CHANGES | 3 +- sphinx/domains/cpp.py | 74 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 342aa92d2..caa8b1324 100644 --- a/CHANGES +++ b/CHANGES @@ -26,8 +26,8 @@ Features added * C++, handle ``decltype(auto)``. * #2406: C++, add proper parsing of expressions, including linking of identifiers. * C++, add a ``cpp:expr`` role for inserting inline C++ expressions or types. -* #4094: C++, allow empty template argument lists. * C++, support explicit member instantiations with shorthand ``template`` prefix. +* C++, make function parameters linkable, like template params. * #3638: Allow to change a label of reference to equation using ``math_eqref_format`` @@ -85,6 +85,7 @@ Bugs fixed * #3882: Update the order of files for HTMLHelp and QTHelp * #3962: sphinx-apidoc does not recognize implicit namespace packages correctly +* #4094: C++, allow empty template argument lists. * C++: also hyperlink types in the name of declarations with qualified names. Testing diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 6e08f2742..378c24da1 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1977,8 +1977,13 @@ class ASTFunctionParameter(ASTBase): self.arg = arg self.ellipsis = ellipsis - def get_id(self, version): - # type: (int) -> unicode + def get_id(self, version, objectType=None, symbol=None): + # type: (int, unicode, Symbol) -> unicode + # this is not part of the normal name mangling in C++ + if symbol: + # the anchor will be our parent + return symbol.parent.declaration.get_id(version, prefixed=None) + # else, do the usual if self.ellipsis: return 'z' else: @@ -2013,6 +2018,11 @@ class ASTParametersQualifiers(ASTBase): self.final = final self.initializer = initializer + @property + def function_params(self): + # type: () -> Any + return self.args + def get_modifiers_id(self, version): # type: (int) -> unicode res = [] @@ -2316,6 +2326,11 @@ class ASTDeclaratorPtr(ASTBase): # type: () -> unicode return self.next.name + @property + def function_params(self): + # type: () -> Any + return self.next.function_params + def require_space_after_declSpecs(self): # type: () -> bool # TODO: if has paramPack, then False ? @@ -2408,6 +2423,11 @@ class ASTDeclaratorRef(ASTBase): # type: () -> unicode return self.next.name + @property + def function_params(self): + # type: () -> Any + return self.next.function_params + def require_space_after_declSpecs(self): # type: () -> bool return self.next.require_space_after_declSpecs() @@ -2459,6 +2479,11 @@ class ASTDeclaratorParamPack(ASTBase): # type: () -> unicode return self.next.name + @property + def function_params(self): + # type: () -> Any + return self.next.function_params + def require_space_after_declSpecs(self): # type: () -> bool return False @@ -2519,6 +2544,11 @@ class ASTDeclaratorMemPtr(ASTBase): # type: () -> unicode return self.next.name + @property + def function_params(self): + # type: () -> Any + return self.next.function_params + def require_space_after_declSpecs(self): # type: () -> bool return True @@ -2611,6 +2641,11 @@ class ASTDeclaratorParen(ASTBase): # type: () -> unicode return self.inner.name + @property + def function_params(self): + # type: () -> Any + return self.inner.function_params + def require_space_after_declSpecs(self): # type: () -> bool return True @@ -2673,6 +2708,11 @@ class ASTDeclaratorNameParamQual(ASTBase): # type: () -> unicode return self.declId + @property + def function_params(self): + # type: () -> Any + return self.paramQual.function_params + def get_modifiers_id(self, version): # only the modifiers for a function, e.g., # type: (int) -> unicode # cv-qualifiers @@ -2769,6 +2809,11 @@ class ASTType(ASTBase): name = self.decl.name return name + @property + def function_params(self): + # type: () -> Any + return self.decl.function_params + def get_id(self, version, objectType=None, symbol=None): # type: (int, unicode, Symbol) -> unicode if version == 1: @@ -3115,6 +3160,13 @@ class ASTDeclaration(ASTBase): # type: () -> unicode return self.declaration.name + @property + def function_params(self): + # type: () -> Any + if self.objectType != 'function': + return None + return self.declaration.function_params + def get_id(self, version, prefixed=True): # type: (int, bool) -> unicode if version == 1: @@ -3242,7 +3294,7 @@ class Symbol(object): for p in self.templateParams.params: if not p.get_identifier(): continue - # only add a declaration if we our selfs from a declaration + # only add a declaration if we our selfs are from a declaration if declaration: decl = ASTDeclaration('templateParam', None, None, p) else: @@ -3250,6 +3302,22 @@ class Symbol(object): nne = ASTNestedNameElement(p.get_identifier(), None) nn = ASTNestedName([nne], rooted=False) self._add_symbols(nn, [], decl, docname) + # add symbols for function parameters, if any + if declaration is not None and declaration.function_params is not None: + for p in declaration.function_params: + if p.arg is None: + continue + nn = p.arg.name + if nn is None: + continue + # (comparing to the template params: we have checked that we are a declaration) + decl = ASTDeclaration('functionParam', None, None, p) + assert not nn.rooted + assert len(nn.names) == 1 + identifier = nn.names[0].identifier + Symbol(parent=self, identifier=identifier, + templateParams=None, templateArgs=None, + declaration=decl, docname=docname) def _fill_empty(self, declaration, docname): # type: (Any, unicode) -> None From 809388d8366c845e921a5b679c8d3e90d545acc9 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 12 Dec 2017 15:03:41 +0100 Subject: [PATCH 0370/1814] C++, do not add index entries for decls in concepts --- CHANGES | 3 ++- sphinx/domains/cpp.py | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index caa8b1324..77df660ac 100644 --- a/CHANGES +++ b/CHANGES @@ -86,7 +86,8 @@ Bugs fixed * #3882: Update the order of files for HTMLHelp and QTHelp * #3962: sphinx-apidoc does not recognize implicit namespace packages correctly * #4094: C++, allow empty template argument lists. -* C++: also hyperlink types in the name of declarations with qualified names. +* C++, also hyperlink types in the name of declarations with qualified names. +* C++, do not add index entries for declarations inside concepts. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 378c24da1..c77c38413 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -5474,13 +5474,25 @@ class CPPObject(ObjectDescription): 'report as bug (id=%s).' % (text_type(ast), newestId)) name = text_type(ast.symbol.get_full_nested_name()).lstrip(':') - strippedName = name - for prefix in self.env.config.cpp_index_common_prefix: - if name.startswith(prefix): - strippedName = strippedName[len(prefix):] + # Add index entry, but not if it's a declaration inside a concept + isInConcept = False + s = ast.symbol.parent + while s is not None: + decl = s.declaration + s = s.parent + if decl is None: + continue + if decl.objectType == 'concept': + isInConcept = True break - indexText = self.get_index_text(strippedName) - self.indexnode['entries'].append(('single', indexText, newestId, '', None)) + if not isInConcept: + strippedName = name + for prefix in self.env.config.cpp_index_common_prefix: + if name.startswith(prefix): + strippedName = strippedName[len(prefix):] + break + indexText = self.get_index_text(strippedName) + self.indexnode['entries'].append(('single', indexText, newestId, '', None)) if newestId not in self.state.document.ids: # if the name is not unique, the first one will win From 8de0abd1b669b7ccf70a54187937d34dcfd69c56 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 13 Dec 2017 11:12:18 +0100 Subject: [PATCH 0371/1814] Make PDF highlighting work as expected also in absence of ``:linenos:`` Method at 347f15ca2 was overly complicated, due to not enough understanding of LaTeX package fancyvrb's innards. --- sphinx/texinputs/sphinx.sty | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 45944885d..2705cfdfe 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -853,8 +853,7 @@ \newcommand*{\sphinxVerbatimEnvironment}{\gdef\FV@EnvironName{sphinxVerbatim}} % serves to implement line highlighting and line wrapping \newcommand\sphinxFancyVerbFormatLine[1]{% - \expandafter\sphinx@verbatim@checkifhl - \expandafter{\the\numexpr\value{FancyVerbLine}-\spx@verbatim@linedelta}% + \expandafter\sphinx@verbatim@checkifhl\expandafter{\the\FV@CodeLineNo}% \ifin@ \sphinxVerbatimHighlightLine{#1}% \else @@ -876,8 +875,6 @@ \strut #1\strut}% }% \newcommand\sphinxVerbatimFormatLineNoWrap[1]{\hb@xt@\linewidth{\strut #1\hss}}% -\def\sphinx@FancyVerbCodesHook - {\FV@SetLineNo\edef\spx@verbatim@linedelta{\the\value{FancyVerbLine}}}% \g@addto@macro\FV@SetupFont{% \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}% @@ -933,15 +930,11 @@ % Allow breaks at special characters using \PYG... macros. \sphinxbreaksatspecials % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation) - \expandafter\def\expandafter\sphinx@FancyVerbCodesHook\expandafter - {\sphinx@FancyVerbCodesHook\sphinxbreaksviaactive}% + \fvset{codes*=\sphinxbreaksviaactive}% \else % end of conditional code for wrapping long code lines \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineNoWrap \fi \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine - % hook into \FancyVerbCodes to recover at first code line the numbering offset - \expandafter\def\expandafter\FancyVerbCodes\expandafter - {\FancyVerbCodes\sphinx@FancyVerbCodesHook}% % go around fancyvrb's check of \@currenvir \let\VerbatimEnvironment\sphinxVerbatimEnvironment % go around fancyvrb's check of current list depth From 6dae5db9af55807de1db4067203e57dabb6ed774 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 13 Dec 2017 20:49:50 +0900 Subject: [PATCH 0372/1814] Fix SphinxRSTFileInput should expand tabs --- sphinx/io.py | 7 ++++--- tests/test_io.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 056c763b1..5f34b74dd 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -14,7 +14,7 @@ import codecs from docutils.io import FileInput, NullOutput from docutils.core import Publisher from docutils.readers import standalone -from docutils.statemachine import StringList +from docutils.statemachine import StringList, string2lines from docutils.writers import UnfilteredWriter from six import text_type from typing import Any, Union # NOQA @@ -195,9 +195,10 @@ class SphinxRSTFileInput(SphinxBaseFileInput): def read(self): # type: () -> StringList - data = SphinxBaseFileInput.read(self) + inputstring = SphinxBaseFileInput.read(self) + lines = string2lines(inputstring, convert_whitespace=True) content = StringList() - for lineno, line in enumerate(data.splitlines()): + for lineno, line in enumerate(lines): content.append(line, self.source_path, lineno) if self.env.config.rst_prolog: diff --git a/tests/test_io.py b/tests/test_io.py index a017a2cc0..ecd4a1009 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -105,3 +105,14 @@ def test_SphinxRSTFileInput(app): assert result.info(3) == ('', 0) assert result.info(4) == ('', 1) assert result.info(5) == ('', None) # out of range + + # expandtabs / convert whitespaces + app.env.config.rst_prolog = None + app.env.config.rst_epilog = None + text = ('\thello Sphinx world\n' + '\v\fSphinx is a document generator') + source = SphinxRSTFileInput(app, app.env, source=StringIO(text), + source_path='dummy.rst', encoding='utf-8') + result = source.read() + assert result.data == [' hello Sphinx world', + ' Sphinx is a document generator'] From 974b1be21870344645655c875592d5ec5dde7f31 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 4 Oct 2017 23:25:19 +0100 Subject: [PATCH 0373/1814] Fix #1421: Respect the quiet flag in sphinx-quickstart Calling 'sphinx-quickstart --quiet' should not print anything to stdout. Resolve this. Signed-off-by: Stephen Finucane --- sphinx/quickstart.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 67a59b059..d23dc3b74 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -455,11 +455,13 @@ def generate(d, overwrite=True, silent=False, templatedir=None): def write_file(fpath, content, newline=None): # type: (unicode, unicode, unicode) -> None if overwrite or not path.isfile(fpath): - print('Creating file %s.' % fpath) + if 'quiet' not in d: + print('Creating file %s.' % fpath) with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: f.write(content) else: - print('File %s already exists, skipping.' % fpath) + if 'quiet' not in d: + print('File %s already exists, skipping.' % fpath) conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None if not conf_path or not path.isfile(conf_path): From a5ef67b96a7c8aa362b2358766fba9150904e34d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 13 Dec 2017 19:57:24 +0000 Subject: [PATCH 0374/1814] setup: Install mock for Python 3 too 'mock' is part of the standard library in Python 3 since Python 3.3. However, it's found in 'unittest.mock' - not 'mock'. We should install the version for PyPi in all cases to minimize differences between the two. When Python 2.7 support is dropped, we can consider switching to the standard library version. Signed-off-by: Stephen Finucane Fixes #4284 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a4dd6b078..10a513166 100644 --- a/setup.py +++ b/setup.py @@ -68,13 +68,13 @@ extras_require = { 'whoosh>=2.0', ], 'test': [ + 'mock', 'pytest', 'pytest-cov', 'html5lib', ], 'test:python_version<"3"': [ 'enum34', - 'mock', ], 'test:python_version>="3"': [ 'mypy', From 64bb48ad2d19ec3c8fb636cd79ff0366e89dd097 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 13 Dec 2017 22:29:56 +0100 Subject: [PATCH 0375/1814] Fix some French English encountered in sphinx.sty's comments ... --- sphinx/texinputs/sphinx.sty | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 2705cfdfe..5ceb05e19 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -376,7 +376,7 @@ \expandafter\let \csname @list\romannumeral\the\count@\expandafter\endcsname \csname @list\romannumeral\the\numexpr\count@-\@ne\endcsname - % work around 2.6--3.2d babel-french issue (fixed in 3.2e; no change needed) + % workaround 2.6--3.2d babel-french issue (fixed in 3.2e; no change needed) \ltx@ifundefined{leftmargin\romannumeral\the\count@} {\expandafter\let \csname leftmargin\romannumeral\the\count@\expandafter\endcsname @@ -935,9 +935,9 @@ \let\sphinxVerbatimFormatLine\sphinxVerbatimFormatLineNoWrap \fi \let\FancyVerbFormatLine\sphinxFancyVerbFormatLine - % go around fancyvrb's check of \@currenvir + % workaround to fancyvrb's check of \@currenvir \let\VerbatimEnvironment\sphinxVerbatimEnvironment - % go around fancyvrb's check of current list depth + % workaround to fancyvrb's check of current list depth \def\@toodeep {\advance\@listdepth\@ne}% % The list environment is needed to control perfectly the vertical space. % Note: \OuterFrameSep used by framed.sty is later set to \topsep hence 0pt. @@ -1024,7 +1024,7 @@ \sphinxunactivateextras}% % now for the modified alltt environment \newenvironment{sphinxalltt} -{% at start of next line to work around Emacs/AUCTeX issue with this file +{% at start of next line to workaround Emacs/AUCTeX issue with this file \begin{alltt}% \ifspx@opt@parsedliteralwraps \sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}% @@ -1250,7 +1250,7 @@ \spx@notice@border \dimexpr\csname spx@opt@#1border\endcsname\relax % start specific environment, passing the heading as argument \begin{sphinx#1}{#2}} - % in end part, need to go around a LaTeX's "feature" + % workaround some LaTeX "feature" of \end command {\edef\spx@temp{\noexpand\end{sphinx\spx@noticetype}}\spx@temp} % use of ``notice'' is for backwards compatibility and will be removed in % Sphinx 1.7. From 9b3ef92d7b52f3d2d21f1d1285af56d09dc71d4e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 17 Jun 2017 22:31:38 +0900 Subject: [PATCH 0376/1814] autodoc: refactor MockImporter --- sphinx/ext/autodoc/__init__.py | 81 +++++++++++++++++----------------- sphinx/ext/autodoc/importer.py | 16 +++++-- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 305242f66..d183331ae 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -24,7 +24,8 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx -from sphinx.ext.autodoc.importer import _MockImporter, import_module +from sphinx.ext.autodoc.importer import mock, import_module +from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA from sphinx.util import rpartition, force_decode from sphinx.locale import _ @@ -388,47 +389,45 @@ class Documenter(object): self.modname, '.'.join(self.objpath)) # always enable mock import hook # it will do nothing if autodoc_mock_imports is empty - import_hook = _MockImporter(self.env.config.autodoc_mock_imports) - try: - logger.debug('[autodoc] import %s', self.modname) - obj = import_module(self.modname, self.env.config.autodoc_warningiserror) - parent = None - self.module = obj - logger.debug('[autodoc] => %r', obj) - for part in self.objpath: - parent = obj - logger.debug('[autodoc] getattr(_, %r)', part) - obj = self.get_attr(obj, part) + with mock(self.env.config.autodoc_mock_imports): + try: + logger.debug('[autodoc] import %s', self.modname) + obj = import_module(self.modname, self.env.config.autodoc_warningiserror) + parent = None + self.module = obj logger.debug('[autodoc] => %r', obj) - self.object_name = part - self.parent = parent - self.object = obj - return True - # this used to only catch SyntaxError, ImportError and AttributeError, - # but importing modules with side effects can raise all kinds of errors - except (Exception, SystemExit) as e: - if self.objpath: - errmsg = 'autodoc: failed to import %s %r from module %r' % \ - (self.objtype, '.'.join(self.objpath), self.modname) - else: - errmsg = 'autodoc: failed to import %s %r' % \ - (self.objtype, self.fullname) - if isinstance(e, SystemExit): - errmsg += ('; the module executes module level statement ' + - 'and it might call sys.exit().') - elif isinstance(e, ImportError): - errmsg += '; the following exception was raised:\n%s' % e.args[0] - else: - errmsg += '; the following exception was raised:\n%s' % \ - traceback.format_exc() - if PY2: - errmsg = errmsg.decode('utf-8') # type: ignore - logger.debug(errmsg) - self.directive.warn(errmsg) - self.env.note_reread() - return False - finally: - import_hook.disable() + for part in self.objpath: + parent = obj + logger.debug('[autodoc] getattr(_, %r)', part) + obj = self.get_attr(obj, part) + logger.debug('[autodoc] => %r', obj) + self.object_name = part + self.parent = parent + self.object = obj + return True + # this used to only catch SyntaxError, ImportError and AttributeError, + # but importing modules with side effects can raise all kinds of errors + except (Exception, SystemExit) as e: + if self.objpath: + errmsg = 'autodoc: failed to import %s %r from module %r' % \ + (self.objtype, '.'.join(self.objpath), self.modname) + else: + errmsg = 'autodoc: failed to import %s %r' % \ + (self.objtype, self.fullname) + if isinstance(e, SystemExit): + errmsg += ('; the module executes module level statement ' + + 'and it might call sys.exit().') + elif isinstance(e, ImportError): + errmsg += '; the following exception was raised:\n%s' % e.args[0] + else: + errmsg += '; the following exception was raised:\n%s' % \ + traceback.format_exc() + if PY2: + errmsg = errmsg.decode('utf-8') # type: ignore + logger.debug(errmsg) + self.directive.warn(errmsg) + self.env.note_reread() + return False def get_real_modname(self): # type: () -> str diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index e024d38f3..be03cba9b 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -10,15 +10,16 @@ """ import sys -import traceback import warnings +import traceback +import contextlib from types import FunctionType, MethodType, ModuleType from sphinx.util import logging if False: # For type annotation - from typing import Any, List, Set # NOQA + from typing import Any, Generator, List, Set # NOQA logger = logging.getLogger(__name__) @@ -77,7 +78,6 @@ class _MockModule(ModuleType): class _MockImporter(object): - def __init__(self, names): # type: (List[str]) -> None self.base_packages = set() # type: Set[str] @@ -120,6 +120,16 @@ class _MockImporter(object): return module +@contextlib.contextmanager +def mock(names): + # type: (List[str]) -> Generator + try: + importer = _MockImporter(names) + yield + finally: + importer.disable() + + def import_module(modname, warningiserror=False): """ Call __import__(modname), convert exceptions to ImportError From fdd87e504cc6e3632776bca771f874fa8ffa9701 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 14 Dec 2017 12:03:42 +0100 Subject: [PATCH 0377/1814] Docs of make latexpdfja --- doc/man/sphinx-build.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 4866282d4..6194d89ff 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -103,7 +103,7 @@ Options **latexpdfja** Build LaTeX files and run them through :program:`platex/dvipdfmx`. - We recommend using ``latexpdf`` instead. + For Japanese documents. **info** Build Texinfo files and run them through :program:`makeinfo`. From e782ee6b630ceb820510a9c6584c5b340dcc9c3a Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 14 Dec 2017 12:42:17 +0100 Subject: [PATCH 0378/1814] Again docs of make latexpdf/latexpdfja --- doc/man/sphinx-build.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 6194d89ff..1a97919e9 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -100,16 +100,20 @@ Options **latexpdf** Build LaTeX files and run them through :program:`pdflatex`. + If :confval:`language` is set to ``'ja'``, build LaTeX files and run them + through :program:`platex/dvipdfmx`, rather. **latexpdfja** Build LaTeX files and run them through :program:`platex/dvipdfmx`. - For Japanese documents. + As :progname:`platex` is a TeX-engine designed for use with Japanese + LaTeX document classes, this is a priori not recommended (nor needed, see + previous item.) **info** Build Texinfo files and run them through :program:`makeinfo`. .. important:: - Sphinx only recognizes the ``-M`` option if it is placed first. + Sphinx only recognizes the ``-M`` option if it is placed first. .. versionadded:: 1.2.1 From a1b04e05d78e6b1c713e3ad0c85176e86701b14e Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 14 Dec 2017 12:47:11 +0100 Subject: [PATCH 0379/1814] Remove docs of ``-M latexpdfja`` sphinx-build option Indeed, if latex_engine is not appropriately set, the ``make latexpdf`` then fails because the Makefile in latex build repertory is the one for pdflatex, not platex+dvipdfmx. Besides, if language is 'ja', then latexpdf automatically uses the platex latex_engine, hence the platex/dvipdfmx pipeline, and latexpdfja is not needed. For now, only removing documentation. --- doc/man/sphinx-build.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 1a97919e9..498425c4e 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -103,12 +103,6 @@ Options If :confval:`language` is set to ``'ja'``, build LaTeX files and run them through :program:`platex/dvipdfmx`, rather. - **latexpdfja** - Build LaTeX files and run them through :program:`platex/dvipdfmx`. - As :progname:`platex` is a TeX-engine designed for use with Japanese - LaTeX document classes, this is a priori not recommended (nor needed, see - previous item.) - **info** Build Texinfo files and run them through :program:`makeinfo`. From 7e75d46ea1b1b43f65782a482d326090c3992a45 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 14 Dec 2017 12:54:29 +0100 Subject: [PATCH 0380/1814] Again docs of ``-M latexpdf``! --- doc/man/sphinx-build.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 498425c4e..46f213989 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -99,9 +99,10 @@ Options :ref:`builders `, the following build pipelines are available: **latexpdf** - Build LaTeX files and run them through :program:`pdflatex`. - If :confval:`language` is set to ``'ja'``, build LaTeX files and run them - through :program:`platex/dvipdfmx`, rather. + Build LaTeX files and run them through :program:`pdflatex`, or as per + :confval:`latex_engine` setting. + If :confval:`language` is set to ``'ja'``, will use automatically + the :program:`platex/dvipdfmx` latex to PDF pipeline. **info** Build Texinfo files and run them through :program:`makeinfo`. From 0dfa88ec4bd6d6443d6d63b8b1f1d87cdb308191 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 Dec 2017 21:15:36 +0900 Subject: [PATCH 0381/1814] Fix mypy violation --- sphinx/parsers.py | 1 + sphinx/util/docutils.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 085e45070..5d19ae67c 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -20,6 +20,7 @@ from sphinx.transforms import SphinxSmartQuotes if False: # For type annotation from typing import Any, Dict, List, Type # NOQA + from docutils import nodes # NOQA from docutils.transforms import Transform # NOQA from sphinx.application import Sphinx # NOQA diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index d1b7ac431..00ea5919e 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -182,7 +182,7 @@ class LoggingReporter(Reporter): stream = WarningStream() Reporter.__init__(self, source, report_level, halt_level, stream, debug, error_handler=error_handler) - self.source_and_line = None + self.source_and_line = None # type: SphinxFileInput def set_source(self, source): # type: (SphinxFileInput) -> None From 51580fabb4be6d596f10dbc5de4757e99c076628 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 Dec 2017 21:15:36 +0900 Subject: [PATCH 0382/1814] Update docstrings --- sphinx/io.py | 48 +++++++++++++++++++++++++++++++++++++++++------ sphinx/parsers.py | 6 +++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 5f34b74dd..8a41069db 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -51,14 +51,20 @@ logger = logging.getLogger(__name__) class SphinxBaseReader(standalone.Reader): """ - Add our source parsers + A base class of readers for Sphinx. + + This replaces reporter by Sphinx's on generating document. """ + def get_transforms(self): # type: () -> List[Transform] return standalone.Reader.get_transforms(self) + self.transforms def new_document(self): # type: () -> nodes.document + """Creates a new document object which having a special reporter object good + for logging. + """ document = standalone.Reader.new_document(self) reporter = document.reporter document.reporter = LoggingReporter.from_reporter(reporter) @@ -68,7 +74,7 @@ class SphinxBaseReader(standalone.Reader): class SphinxStandaloneReader(SphinxBaseReader): """ - Add our own transforms. + A basic document reader for Sphinx. """ transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, @@ -79,10 +85,11 @@ class SphinxStandaloneReader(SphinxBaseReader): class SphinxI18nReader(SphinxBaseReader): """ - Replacer for document.reporter.get_source_and_line method. + A document reader for i18n. - reST text lines for translation do not have the original source line number. - This class provides the correct line numbers when reporting. + This returns the source line number of original text as current source line number + to let users know where the error happened. + Because the translated texts are partial and they don't have correct line numbers. """ lineno = None # type: int @@ -94,10 +101,14 @@ class SphinxI18nReader(SphinxBaseReader): def set_lineno_for_reporter(self, lineno): # type: (int) -> None + """Stores the source line number of original text.""" self.lineno = lineno def new_document(self): # type: () -> nodes.document + """Creates a new document object which having a special reporter object for + translation. + """ document = SphinxBaseReader.new_document(self) reporter = document.reporter @@ -110,6 +121,8 @@ class SphinxI18nReader(SphinxBaseReader): class SphinxDummyWriter(UnfilteredWriter): + """Dummy writer module used for generating doctree.""" + supported = ('html',) # needed to keep "meta" nodes def translate(self): @@ -123,7 +136,11 @@ def SphinxDummySourceClass(source, *args, **kwargs): class SphinxBaseFileInput(FileInput): - """A base class of SphinxFileInput.""" + """A base class of SphinxFileInput. + + It supports to replace unknown Unicode characters to '?'. And it also emits + Sphinx events ``source-read`` on reading. + """ def __init__(self, app, env, *args, **kwds): # type: (Sphinx, BuildEnvironment, Any, Any) -> None @@ -144,6 +161,10 @@ class SphinxBaseFileInput(FileInput): def read(self): # type: () -> unicode + """Reads the contents from file. + + After reading, it emits Sphinx event ``source-read``. + """ data = FileInput.read(self) # emit source-read event @@ -168,10 +189,25 @@ class SphinxBaseFileInput(FileInput): class SphinxFileInput(SphinxBaseFileInput): + """A basic FileInput for Sphinx.""" pass class SphinxRSTFileInput(SphinxBaseFileInput): + """A reST FileInput for Sphinx. + + This FileInput automatically prepends and appends text by :confval:`rst_prolog` and + :confval:`rst_epilog`. + + .. important:: + + This FileInput uses an instance of ``StringList`` as a return value of ``read()`` + method to indicate original source filename and line numbers after prepending and + appending. + For that reason, ``sphinx.parsers.RSTParser`` should be used with this to parse + a content correctly. + """ + def prepend_prolog(self, text, prolog): # type: (StringList, unicode) -> None docinfo = self.count_docinfo_lines(text) diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 5d19ae67c..92bea9461 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -59,7 +59,7 @@ class Parser(docutils.parsers.Parser): class RSTParser(docutils.parsers.rst.Parser): - """A reST parser customized for Sphinx.""" + """A reST parser for Sphinx.""" def get_transforms(self): # type: () -> List[Type[Transform]] @@ -73,8 +73,8 @@ class RSTParser(docutils.parsers.rst.Parser): # type: (Any, nodes.document) -> None """Parse text and generate a document tree. - This derived method accepts StringList as a inputstring parameter. - It enables to handle mixed contents (cf. rst_prolog) correctly. + This accepts StringList as an inputstring parameter. + It enables to handle mixed contents (cf. :confval:`rst_prolog`) correctly. """ if isinstance(inputstring, StringList): self.setup_parse(inputstring, document) From 49e1fbe0df95267f1b1e9e5f606fa8398cfba44b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 Dec 2017 22:09:43 +0900 Subject: [PATCH 0383/1814] Update CHANGES for PR #4273 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 0d7a47530..b7a16af4f 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Bugs fixed * #1238: Support ``:emphasize-lines:`` in PDF output * #4279: Sphinx crashes with pickling error when run with multiple processes and remote image +* #1421: Respect the quiet flag in sphinx-quickstart Testing -------- From b6d6e4cc739a578a309f124791ed286058cdf0d6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 Dec 2017 16:36:10 +0900 Subject: [PATCH 0384/1814] autodoc: Fix error handling for import_module() --- sphinx/ext/autodoc/__init__.py | 28 ++++++++++++++++++---------- sphinx/ext/autodoc/importer.py | 4 ++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index d183331ae..ff161565c 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -405,23 +405,31 @@ class Documenter(object): self.parent = parent self.object = obj return True - # this used to only catch SyntaxError, ImportError and AttributeError, - # but importing modules with side effects can raise all kinds of errors - except (Exception, SystemExit) as e: + except (AttributeError, ImportError) as exc: if self.objpath: errmsg = 'autodoc: failed to import %s %r from module %r' % \ (self.objtype, '.'.join(self.objpath), self.modname) else: errmsg = 'autodoc: failed to import %s %r' % \ (self.objtype, self.fullname) - if isinstance(e, SystemExit): - errmsg += ('; the module executes module level statement ' + - 'and it might call sys.exit().') - elif isinstance(e, ImportError): - errmsg += '; the following exception was raised:\n%s' % e.args[0] + + if isinstance(exc, ImportError): + # import_module() raises ImportError having real exception obj and + # traceback + real_exc, traceback_msg = exc.args + if isinstance(real_exc, SystemExit): + errmsg += ('; the module executes module level statement ' + + 'and it might call sys.exit().') + elif isinstance(real_exc, ImportError): + errmsg += ('; the following exception was raised:\n%s' % + real_exc.args[0]) + else: + errmsg += ('; the following exception was raised:\n%s' % + traceback_msg) else: - errmsg += '; the following exception was raised:\n%s' % \ - traceback.format_exc() + errmsg += ('; the following exception was raised:\n%s' % + traceback.format_exc()) + if PY2: errmsg = errmsg.decode('utf-8') # type: ignore logger.debug(errmsg) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index be03cba9b..5c28f490d 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -140,7 +140,7 @@ def import_module(modname, warningiserror=False): with logging.skip_warningiserror(not warningiserror): __import__(modname) return sys.modules[modname] - except BaseException: + except BaseException as exc: # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. - raise ImportError(traceback.format_exc()) + raise ImportError(exc, traceback.format_exc()) From ed1f47e1908b322de1ac0348ad42c61366cd131d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 May 2017 13:09:15 +0900 Subject: [PATCH 0385/1814] Move logs to registry --- sphinx/application.py | 15 --------------- sphinx/registry.py | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 05d302c81..c184e43c4 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -444,7 +444,6 @@ class Sphinx(object): def add_builder(self, builder): # type: (Type[Builder]) -> None - logger.debug('[app] adding builder: %r', builder) self.registry.add_builder(builder) def add_config_value(self, name, default, rebuild, types=()): @@ -464,7 +463,6 @@ class Sphinx(object): def set_translator(self, name, translator_class): # type: (unicode, Type[nodes.NodeVisitor]) -> None - logger.info(bold(__('Change of translator for the %s builder.') % name)) self.registry.add_translator(name, translator_class) def add_node(self, node, **kwds): @@ -553,39 +551,30 @@ class Sphinx(object): def add_domain(self, domain): # type: (Type[Domain]) -> None - logger.debug('[app] adding domain: %r', domain) self.registry.add_domain(domain) def override_domain(self, domain): # type: (Type[Domain]) -> None - logger.debug('[app] overriding domain: %r', domain) self.registry.override_domain(domain) def add_directive_to_domain(self, domain, name, obj, has_content=None, argument_spec=None, **option_spec): # type: (unicode, unicode, Any, bool, Any, Any) -> None - logger.debug('[app] adding directive to domain: %r', - (domain, name, obj, has_content, argument_spec, option_spec)) self.registry.add_directive_to_domain(domain, name, obj, has_content, argument_spec, **option_spec) def add_role_to_domain(self, domain, name, role): # type: (unicode, unicode, Any) -> None - logger.debug('[app] adding role to domain: %r', (domain, name, role)) self.registry.add_role_to_domain(domain, name, role) def add_index_to_domain(self, domain, index): # type: (unicode, Type[Index]) -> None - logger.debug('[app] adding index to domain: %r', (domain, index)) self.registry.add_index_to_domain(domain, index) def add_object_type(self, directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='', doc_field_types=[]): # type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None - logger.debug('[app] adding object type: %r', - (directivename, rolename, indextemplate, parse_node, - ref_nodeclass, objname, doc_field_types)) self.registry.add_object_type(directivename, rolename, indextemplate, parse_node, ref_nodeclass, objname, doc_field_types) @@ -602,9 +591,6 @@ class Sphinx(object): def add_crossref_type(self, directivename, rolename, indextemplate='', ref_nodeclass=None, objname=''): # type: (unicode, unicode, unicode, nodes.Node, unicode) -> None - logger.debug('[app] adding crossref type: %r', - (directivename, rolename, indextemplate, ref_nodeclass, - objname)) self.registry.add_crossref_type(directivename, rolename, indextemplate, ref_nodeclass, objname) @@ -677,7 +663,6 @@ class Sphinx(object): def add_source_parser(self, suffix, parser): # type: (unicode, Parser) -> None - logger.debug('[app] adding search source_parser: %r, %r', suffix, parser) self.registry.add_source_parser(suffix, parser) def add_env_collector(self, collector): diff --git a/sphinx/registry.py b/sphinx/registry.py index b627f23af..6da6dbeaf 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -24,6 +24,7 @@ from sphinx.parsers import Parser as SphinxParser from sphinx.roles import XRefRole from sphinx.util import logging from sphinx.util import import_object +from sphinx.util.console import bold # type: ignore from sphinx.util.docutils import directive_helper if False: @@ -56,6 +57,7 @@ class SphinxComponentRegistry(object): def add_builder(self, builder): # type: (Type[Builder]) -> None + logger.debug('[app] adding builder: %r', builder) if not hasattr(builder, 'name'): raise ExtensionError(__('Builder class %s has no "name" attribute') % builder) if builder.name in self.builders: @@ -87,6 +89,7 @@ class SphinxComponentRegistry(object): def add_domain(self, domain): # type: (Type[Domain]) -> None + logger.debug('[app] adding domain: %r', domain) if domain.name in self.domains: raise ExtensionError(__('domain %s already registered') % domain.name) self.domains[domain.name] = domain @@ -102,6 +105,7 @@ class SphinxComponentRegistry(object): def override_domain(self, domain): # type: (Type[Domain]) -> None + logger.debug('[app] overriding domain: %r', domain) if domain.name not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain.name) if not issubclass(domain, self.domains[domain.name]): @@ -112,6 +116,8 @@ class SphinxComponentRegistry(object): def add_directive_to_domain(self, domain, name, obj, has_content=None, argument_spec=None, **option_spec): # type: (unicode, unicode, Any, bool, Any, Any) -> None + logger.debug('[app] adding directive to domain: %r', + (domain, name, obj, has_content, argument_spec, option_spec)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) directive = directive_helper(obj, has_content, argument_spec, **option_spec) @@ -119,12 +125,14 @@ class SphinxComponentRegistry(object): def add_role_to_domain(self, domain, name, role): # type: (unicode, unicode, Any) -> None + logger.debug('[app] adding role to domain: %r', (domain, name, role)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) self.domains[domain].roles[name] = role def add_index_to_domain(self, domain, index): # type: (unicode, Type[Index]) -> None + logger.debug('[app] adding index to domain: %r', (domain, index)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) self.domains[domain].indices.append(index) @@ -133,6 +141,10 @@ class SphinxComponentRegistry(object): parse_node=None, ref_nodeclass=None, objname='', doc_field_types=[]): # type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None + logger.debug('[app] adding object type: %r', + (directivename, rolename, indextemplate, parse_node, + ref_nodeclass, objname, doc_field_types)) + # create a subclass of GenericObject as the new directive directive = type(directivename, # type: ignore (GenericObject, object), @@ -148,6 +160,9 @@ class SphinxComponentRegistry(object): def add_crossref_type(self, directivename, rolename, indextemplate='', ref_nodeclass=None, objname=''): # type: (unicode, unicode, unicode, nodes.Node, unicode) -> None + logger.debug('[app] adding crossref type: %r', + (directivename, rolename, indextemplate, ref_nodeclass, objname)) + # create a subclass of Target as the new directive directive = type(directivename, # type: ignore (Target, object), @@ -160,6 +175,7 @@ class SphinxComponentRegistry(object): def add_source_parser(self, suffix, parser): # type: (unicode, Type[Parser]) -> None + logger.debug('[app] adding search source_parser: %r, %r', suffix, parser) if suffix in self.source_parsers: raise ExtensionError(__('source_parser for %r is already registered') % suffix) self.source_parsers[suffix] = parser @@ -216,6 +232,7 @@ class SphinxComponentRegistry(object): def add_translator(self, name, translator): # type: (unicode, Type[nodes.NodeVisitor]) -> None + logger.info(bold(__('Change of translator for the %s builder.') % name)) self.translators[name] = translator def get_translator_class(self, builder): From 27ea988f6e5a6637441f418a8f0c5dff5d5397bf Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 May 2017 14:09:32 +0900 Subject: [PATCH 0386/1814] Move Transform manager to registry --- sphinx/application.py | 3 +-- sphinx/io.py | 10 ++++++++-- sphinx/registry.py | 11 +++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index c184e43c4..fc669d798 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -596,8 +596,7 @@ class Sphinx(object): def add_transform(self, transform): # type: (Type[Transform]) -> None - logger.debug('[app] adding transform: %r', transform) - SphinxStandaloneReader.transforms.append(transform) + self.registry.add_transform(transform) def add_post_transform(self, transform): # type: (Type[Transform]) -> None diff --git a/sphinx/io.py b/sphinx/io.py index 8a41069db..4bb554742 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -80,7 +80,13 @@ class SphinxStandaloneReader(SphinxBaseReader): Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, - RefOnlyBulletListTransform, UnreferencedFootnotesDetector] + RefOnlyBulletListTransform, UnreferencedFootnotesDetector + ] # type: List[Transform] + + def __init__(self, app, *args, **kwargs): + # type: (Sphinx, Any, Any) -> None + self.transforms = self.transforms + app.registry.get_transforms() + SphinxBaseReader.__init__(self, *args, **kwargs) class SphinxI18nReader(SphinxBaseReader): @@ -259,7 +265,7 @@ def read_doc(app, env, filename): # type: (Sphinx, BuildEnvironment, unicode) -> nodes.document """Parse a document and convert to doctree.""" input_class = app.registry.get_source_input(filename) - reader = SphinxStandaloneReader() + reader = SphinxStandaloneReader(app) source = input_class(app, env, source=None, source_path=filename, encoding=env.config.source_encoding) parser = app.registry.create_source_parser(app, filename) diff --git a/sphinx/registry.py b/sphinx/registry.py index 6da6dbeaf..95320db36 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -33,6 +33,7 @@ if False: from docutils import nodes # NOQA from docutils.io import Input # NOQA from docutils.parsers import Parser # NOQA + from docutils.transform import Transform # NOQA from sphinx.application import Sphinx # NOQA from sphinx.builders import Builder # NOQA from sphinx.domains import Domain, Index # NOQA @@ -54,6 +55,7 @@ class SphinxComponentRegistry(object): self.source_parsers = {} # type: Dict[unicode, Parser] self.source_inputs = {} # type: Dict[unicode, Input] self.translators = {} # type: Dict[unicode, nodes.NodeVisitor] + self.transforms = [] # type: List[Type[Transform]] def add_builder(self, builder): # type: (Type[Builder]) -> None @@ -245,6 +247,15 @@ class SphinxComponentRegistry(object): translator_class = self.get_translator_class(builder) return translator_class(builder, document) + def add_transform(self, transform): + # type: (Type[Transform]) -> None + logger.debug('[app] adding transform: %r', transform) + self.transforms.append(transform) + + def get_transforms(self): + # type: () -> List[Type[Transform]] + return self.transforms + def load_extension(self, app, extname): # type: (Sphinx, unicode) -> None """Load a Sphinx extension.""" From 2a26656ce6e508e080aaa18922f2a75541f1c96c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 May 2017 14:40:02 +0900 Subject: [PATCH 0387/1814] Move post-transform manager to registry --- sphinx/application.py | 4 +--- sphinx/environment/__init__.py | 2 +- sphinx/registry.py | 10 ++++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index fc669d798..ef20e56d8 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -120,7 +120,6 @@ class Sphinx(object): self.env = None # type: BuildEnvironment self.registry = SphinxComponentRegistry() self.enumerable_nodes = {} # type: Dict[nodes.Node, Tuple[unicode, Callable]] # NOQA - self.post_transforms = [] # type: List[Transform] self.html_themes = {} # type: Dict[unicode, unicode] self.srcdir = srcdir @@ -600,8 +599,7 @@ class Sphinx(object): def add_post_transform(self, transform): # type: (Type[Transform]) -> None - logger.debug('[app] adding post transform: %r', transform) - self.post_transforms.append(transform) + self.registry.add_post_transform(transform) def add_javascript(self, filename): # type: (unicode) -> None diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 5ebf9d4d5..b4c40b608 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -878,7 +878,7 @@ class BuildEnvironment(object): transformer = SphinxTransformer(doctree) transformer.set_environment(self) - transformer.add_transforms(self.app.post_transforms) + transformer.add_transforms(self.app.registry.get_post_transforms()) transformer.apply_transforms() finally: self.temp_data = backup diff --git a/sphinx/registry.py b/sphinx/registry.py index 95320db36..6f9bbe4d9 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -52,6 +52,7 @@ class SphinxComponentRegistry(object): def __init__(self): self.builders = {} # type: Dict[unicode, Type[Builder]] self.domains = {} # type: Dict[unicode, Type[Domain]] + self.post_transforms = [] # type: List[Type[Transform]] self.source_parsers = {} # type: Dict[unicode, Parser] self.source_inputs = {} # type: Dict[unicode, Input] self.translators = {} # type: Dict[unicode, nodes.NodeVisitor] @@ -256,6 +257,15 @@ class SphinxComponentRegistry(object): # type: () -> List[Type[Transform]] return self.transforms + def add_post_transform(self, transform): + # type: (Type[Transform]) -> None + logger.debug('[app] adding post transform: %r', transform) + self.post_transforms.append(transform) + + def get_post_transforms(self): + # type: () -> List[Type[Transform]] + return self.post_transforms + def load_extension(self, app, extname): # type: (Sphinx, unicode) -> None """Load a Sphinx extension.""" From c09f3e77677625374b7c81131c883ca6a5b7b645 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 May 2017 19:41:27 +0900 Subject: [PATCH 0388/1814] Transplant directives on instantiate domain --- sphinx/domains/__init__.py | 12 ++++++++---- sphinx/registry.py | 26 ++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 6edc3cdb0..6af0870de 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -161,6 +161,14 @@ class Domain(object): def __init__(self, env): # type: (BuildEnvironment) -> None self.env = env # type: BuildEnvironment + self._role_cache = {} # type: Dict[unicode, Callable] + self._directive_cache = {} # type: Dict[unicode, Callable] + self._role2type = {} # type: Dict[unicode, List[unicode]] + self._type2role = {} # type: Dict[unicode, unicode] + + # convert class variables to instance one (to enhance through API) + self.directives = dict(self.directives) + if self.name not in env.domaindata: assert isinstance(self.initial_data, dict) new_data = copy.deepcopy(self.initial_data) @@ -170,10 +178,6 @@ class Domain(object): self.data = env.domaindata[self.name] if self.data['version'] != self.data_version: raise IOError('data of %r domain out of date' % self.label) - self._role_cache = {} # type: Dict[unicode, Callable] - self._directive_cache = {} # type: Dict[unicode, Callable] - self._role2type = {} # type: Dict[unicode, List[unicode]] - self._type2role = {} # type: Dict[unicode, unicode] for name, obj in iteritems(self.object_types): for rolename in obj.roles: self._role2type.setdefault(rolename, []).append(name) diff --git a/sphinx/registry.py b/sphinx/registry.py index 6f9bbe4d9..0bbd59756 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -50,13 +50,14 @@ EXTENSION_BLACKLIST = { class SphinxComponentRegistry(object): def __init__(self): - self.builders = {} # type: Dict[unicode, Type[Builder]] - self.domains = {} # type: Dict[unicode, Type[Domain]] - self.post_transforms = [] # type: List[Type[Transform]] - self.source_parsers = {} # type: Dict[unicode, Parser] - self.source_inputs = {} # type: Dict[unicode, Input] - self.translators = {} # type: Dict[unicode, nodes.NodeVisitor] - self.transforms = [] # type: List[Type[Transform]] + self.builders = {} # type: Dict[unicode, Type[Builder]] + self.domains = {} # type: Dict[unicode, Type[Domain]] + self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] + self.post_transforms = [] # type: List[Type[Transform]] + self.source_parsers = {} # type: Dict[unicode, Parser] + self.source_inputs = {} # type: Dict[unicode, Input] + self.translators = {} # type: Dict[unicode, nodes.NodeVisitor] + self.transforms = [] # type: List[Type[Transform]] def add_builder(self, builder): # type: (Type[Builder]) -> None @@ -104,7 +105,12 @@ class SphinxComponentRegistry(object): def create_domains(self, env): # type: (BuildEnvironment) -> Iterator[Domain] for DomainClass in itervalues(self.domains): - yield DomainClass(env) + domain = DomainClass(env) + + # transplant components added by extensions + domain.directives.update(self.domain_directives.get(domain.name, {})) + + yield domain def override_domain(self, domain): # type: (Type[Domain]) -> None @@ -123,8 +129,8 @@ class SphinxComponentRegistry(object): (domain, name, obj, has_content, argument_spec, option_spec)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) - directive = directive_helper(obj, has_content, argument_spec, **option_spec) - self.domains[domain].directives[name] = directive + directives = self.domain_directives.setdefault(domain, {}) + directives[name] = directive_helper(obj, has_content, argument_spec, **option_spec) def add_role_to_domain(self, domain, name, role): # type: (unicode, unicode, Any) -> None From a2880dffe66aa25d7212002ac395cf9687f65138 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 2 May 2017 12:31:36 +0900 Subject: [PATCH 0389/1814] Transplant roles on instantiate domain --- sphinx/domains/__init__.py | 1 + sphinx/registry.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 6af0870de..dbd8c6c33 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -168,6 +168,7 @@ class Domain(object): # convert class variables to instance one (to enhance through API) self.directives = dict(self.directives) + self.roles = dict(self.roles) if self.name not in env.domaindata: assert isinstance(self.initial_data, dict) diff --git a/sphinx/registry.py b/sphinx/registry.py index 0bbd59756..fba90934a 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -53,6 +53,7 @@ class SphinxComponentRegistry(object): self.builders = {} # type: Dict[unicode, Type[Builder]] self.domains = {} # type: Dict[unicode, Type[Domain]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] + self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Any]] self.post_transforms = [] # type: List[Type[Transform]] self.source_parsers = {} # type: Dict[unicode, Parser] self.source_inputs = {} # type: Dict[unicode, Input] @@ -109,6 +110,7 @@ class SphinxComponentRegistry(object): # transplant components added by extensions domain.directives.update(self.domain_directives.get(domain.name, {})) + domain.roles.update(self.domain_roles.get(domain.name, {})) yield domain @@ -137,7 +139,8 @@ class SphinxComponentRegistry(object): logger.debug('[app] adding role to domain: %r', (domain, name, role)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) - self.domains[domain].roles[name] = role + roles = self.domain_roles.setdefault(domain, {}) + roles[name] = role def add_index_to_domain(self, domain, index): # type: (unicode, Type[Index]) -> None From a7d4fd1a503cd7b1bbe3d3c7bf6d41ab86cc936d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 2 May 2017 12:38:55 +0900 Subject: [PATCH 0390/1814] Transplant indices on instantiate domain --- sphinx/domains/__init__.py | 1 + sphinx/registry.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index dbd8c6c33..510d997ae 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -169,6 +169,7 @@ class Domain(object): # convert class variables to instance one (to enhance through API) self.directives = dict(self.directives) self.roles = dict(self.roles) + self.indices = list(self.indices) if self.name not in env.domaindata: assert isinstance(self.initial_data, dict) diff --git a/sphinx/registry.py b/sphinx/registry.py index fba90934a..cba2aaeca 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -53,6 +53,7 @@ class SphinxComponentRegistry(object): self.builders = {} # type: Dict[unicode, Type[Builder]] self.domains = {} # type: Dict[unicode, Type[Domain]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] + self.domain_indices = {} # type: Dict[unicode, List[Index]] self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Any]] self.post_transforms = [] # type: List[Type[Transform]] self.source_parsers = {} # type: Dict[unicode, Parser] @@ -111,6 +112,7 @@ class SphinxComponentRegistry(object): # transplant components added by extensions domain.directives.update(self.domain_directives.get(domain.name, {})) domain.roles.update(self.domain_roles.get(domain.name, {})) + domain.indices.extend(self.domain_indices.get(domain.name, [])) yield domain @@ -147,7 +149,8 @@ class SphinxComponentRegistry(object): logger.debug('[app] adding index to domain: %r', (domain, index)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) - self.domains[domain].indices.append(index) + indices = self.domain_indices.setdefault(domain, []) + indices.append(index) def add_object_type(self, directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='', From b2837eee0ccd6020c3c1d6470381f6a07185ca0e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 2 May 2017 12:45:16 +0900 Subject: [PATCH 0391/1814] Transplant object_types on instantiate domain --- sphinx/domains/__init__.py | 1 + sphinx/registry.py | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 510d997ae..ddb6c7c66 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -167,6 +167,7 @@ class Domain(object): self._type2role = {} # type: Dict[unicode, unicode] # convert class variables to instance one (to enhance through API) + self.object_types = dict(self.object_types) self.directives = dict(self.directives) self.roles = dict(self.roles) self.indices = list(self.indices) diff --git a/sphinx/registry.py b/sphinx/registry.py index cba2aaeca..265524b28 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -54,6 +54,7 @@ class SphinxComponentRegistry(object): self.domains = {} # type: Dict[unicode, Type[Domain]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] self.domain_indices = {} # type: Dict[unicode, List[Index]] + self.domain_object_types = {} # type: Dict[unicode, Dict[unicode, ObjType]] self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Any]] self.post_transforms = [] # type: List[Type[Transform]] self.source_parsers = {} # type: Dict[unicode, Parser] @@ -110,6 +111,7 @@ class SphinxComponentRegistry(object): domain = DomainClass(env) # transplant components added by extensions + domain.object_types.update(self.domain_object_types.get(domain.name, {})) domain.directives.update(self.domain_directives.get(domain.name, {})) domain.roles.update(self.domain_roles.get(domain.name, {})) domain.indices.extend(self.domain_indices.get(domain.name, [])) @@ -167,10 +169,11 @@ class SphinxComponentRegistry(object): 'parse_node': staticmethod(parse_node), 'doc_field_types': doc_field_types}) - stddomain = self.domains['std'] - stddomain.directives[directivename] = directive - stddomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass) - stddomain.object_types[directivename] = ObjType(objname or directivename, rolename) + self.add_directive_to_domain('std', directivename, directive) + self.add_role_to_domain('std', rolename, XRefRole(innernodeclass=ref_nodeclass)) + + object_types = self.domain_object_types.setdefault('std', {}) + object_types[directivename] = ObjType(objname or directivename, rolename) def add_crossref_type(self, directivename, rolename, indextemplate='', ref_nodeclass=None, objname=''): @@ -183,10 +186,11 @@ class SphinxComponentRegistry(object): (Target, object), {'indextemplate': indextemplate}) - stddomain = self.domains['std'] - stddomain.directives[directivename] = directive - stddomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass) - stddomain.object_types[directivename] = ObjType(objname or directivename, rolename) + self.add_directive_to_domain('std', directive) + self.add_role_to_domain('std', XRefRole(innernodeclass=ref_nodeclass)) + + object_types = self.domain_object_types.setdefault('std', {}) + object_types[directivename] = ObjType(objname or directivename, rolename) def add_source_parser(self, suffix, parser): # type: (unicode, Type[Parser]) -> None From 60f3968ef787257283a6af8023ae9890f3ae8384 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 13 Dec 2017 23:48:07 +0900 Subject: [PATCH 0392/1814] diet test-root: Move ziptheme to test-theming --- .../roots/{test-root => test-theming}/ziptheme.zip | Bin tests/test_theming.py | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) rename tests/roots/{test-root => test-theming}/ziptheme.zip (100%) diff --git a/tests/roots/test-root/ziptheme.zip b/tests/roots/test-theming/ziptheme.zip similarity index 100% rename from tests/roots/test-root/ziptheme.zip rename to tests/roots/test-theming/ziptheme.zip diff --git a/tests/test_theming.py b/tests/test_theming.py index ef9656bc5..f8cfd395e 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -17,6 +17,7 @@ from sphinx.theming import ThemeError @pytest.mark.sphinx( + testroot='theming', confoverrides={'html_theme': 'ziptheme', 'html_theme_options.testopt': 'foo'}) def test_theme_api(app, status, warning): @@ -25,9 +26,9 @@ def test_theme_api(app, status, warning): # test Theme class API assert set(app.html_themes.keys()) == \ set(['basic', 'default', 'scrolls', 'agogo', 'sphinxdoc', 'haiku', - 'traditional', 'testtheme', 'ziptheme', 'epub', 'nature', - 'pyramid', 'bizstyle', 'classic', 'nonav']) - assert app.html_themes['testtheme'] == app.srcdir / 'testtheme' + 'traditional', 'test-theme', 'ziptheme', 'epub', 'nature', + 'pyramid', 'bizstyle', 'classic', 'nonav', 'parent', 'child']) + assert app.html_themes['test-theme'] == app.srcdir / 'test_theme/test-theme' assert app.html_themes['ziptheme'] == app.srcdir / 'ziptheme.zip' # test Theme instance API From a8ab1f164b069528344a880e75550f57ec05a6b5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 13 Dec 2017 23:48:07 +0900 Subject: [PATCH 0393/1814] diet test-root: Move testtheme to test-theming --- tests/roots/test-root/conf.py | 3 --- .../test_theme/staticfiles}/layout.html | 0 .../staticfiles}/static/staticimg.png | Bin .../staticfiles}/static/statictmpl.html_t | 0 .../test_theme/staticfiles}/theme.conf | 0 tests/test_build_html.py | 4 ---- tests/test_build_html5.py | 4 ---- tests/test_theming.py | 22 +++++++++++++++--- 8 files changed, 19 insertions(+), 14 deletions(-) rename tests/roots/{test-root/testtheme => test-theming/test_theme/staticfiles}/layout.html (100%) rename tests/roots/{test-root/testtheme => test-theming/test_theme/staticfiles}/static/staticimg.png (100%) rename tests/roots/{test-root/testtheme => test-theming/test_theme/staticfiles}/static/statictmpl.html_t (100%) rename tests/roots/{test-root/testtheme => test-theming/test_theme/staticfiles}/theme.conf (100%) diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py index a23aec482..c25beb9f1 100644 --- a/tests/roots/test-root/conf.py +++ b/tests/roots/test-root/conf.py @@ -29,9 +29,6 @@ numfig = True rst_epilog = '.. |subst| replace:: global substitution' -html_theme = 'testtheme' -html_theme_path = ['.'] -html_theme_options = {'testopt': 'testoverride'} html_sidebars = {'**': 'customsb.html', 'contents': ['contentssb.html', 'localtoc.html', 'globaltoc.html']} diff --git a/tests/roots/test-root/testtheme/layout.html b/tests/roots/test-theming/test_theme/staticfiles/layout.html similarity index 100% rename from tests/roots/test-root/testtheme/layout.html rename to tests/roots/test-theming/test_theme/staticfiles/layout.html diff --git a/tests/roots/test-root/testtheme/static/staticimg.png b/tests/roots/test-theming/test_theme/staticfiles/static/staticimg.png similarity index 100% rename from tests/roots/test-root/testtheme/static/staticimg.png rename to tests/roots/test-theming/test_theme/staticfiles/static/staticimg.png diff --git a/tests/roots/test-root/testtheme/static/statictmpl.html_t b/tests/roots/test-theming/test_theme/staticfiles/static/statictmpl.html_t similarity index 100% rename from tests/roots/test-root/testtheme/static/statictmpl.html_t rename to tests/roots/test-theming/test_theme/staticfiles/static/statictmpl.html_t diff --git a/tests/roots/test-root/testtheme/theme.conf b/tests/roots/test-theming/test_theme/staticfiles/theme.conf similarity index 100% rename from tests/roots/test-root/testtheme/theme.conf rename to tests/roots/test-theming/test_theme/staticfiles/theme.conf diff --git a/tests/test_build_html.py b/tests/test_build_html.py index ceeb5f01c..6fa769b8b 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -377,7 +377,6 @@ def test_static_output(app): 'contents.html': [ (".//meta[@name='hc'][@content='hcval']", ''), (".//meta[@name='hc_co'][@content='hcval_co']", ''), - (".//meta[@name='testopt'][@content='testoverride']", ''), (".//td[@class='label']", r'\[Ref1\]'), (".//td[@class='label']", ''), (".//li[@class='toctree-l1']/a", 'Testing various markup'), @@ -410,9 +409,6 @@ def test_static_output(app): (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"), (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"), ], - '_static/statictmpl.html': [ - (".//project", 'Sphinx '), - ], 'genindex.html': [ # index entries (".//a/strong", "Main"), diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py index 7fc91b9ec..4ad282973 100644 --- a/tests/test_build_html5.py +++ b/tests/test_build_html5.py @@ -252,7 +252,6 @@ def cached_etree_parse(): 'contents.html': [ (".//meta[@name='hc'][@content='hcval']", ''), (".//meta[@name='hc_co'][@content='hcval_co']", ''), - (".//meta[@name='testopt'][@content='testoverride']", ''), (".//dt[@class='label']/span[@class='brackets']", r'Ref1'), (".//dt[@class='label']", ''), (".//li[@class='toctree-l1']/a", 'Testing various markup'), @@ -285,9 +284,6 @@ def cached_etree_parse(): (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"), (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"), ], - '_static/statictmpl.html': [ - (".//project", 'Sphinx '), - ], 'genindex.html': [ # index entries (".//a/strong", "Main"), diff --git a/tests/test_theming.py b/tests/test_theming.py index f8cfd395e..176c9eebc 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -26,10 +26,11 @@ def test_theme_api(app, status, warning): # test Theme class API assert set(app.html_themes.keys()) == \ set(['basic', 'default', 'scrolls', 'agogo', 'sphinxdoc', 'haiku', - 'traditional', 'test-theme', 'ziptheme', 'epub', 'nature', - 'pyramid', 'bizstyle', 'classic', 'nonav', 'parent', 'child']) - assert app.html_themes['test-theme'] == app.srcdir / 'test_theme/test-theme' + 'traditional', 'epub', 'nature', 'pyramid', 'bizstyle', 'classic', 'nonav', + 'test-theme', 'ziptheme', 'staticfiles', 'parent', 'child']) + assert app.html_themes['test-theme'] == app.srcdir / 'test_theme' / 'test-theme' assert app.html_themes['ziptheme'] == app.srcdir / 'ziptheme.zip' + assert app.html_themes['staticfiles'] == app.srcdir / 'test_theme' / 'staticfiles' # test Theme instance API theme = app.builder.theme @@ -94,3 +95,18 @@ def test_double_inheriting_theme(app, status, warning): def test_nested_zipped_theme(app, status, warning): assert app.builder.theme.name == 'child' app.build() # => not raises TemplateNotFound + + +@pytest.mark.sphinx(testroot='theming', + confoverrides={'html_theme': 'staticfiles'}) +def test_staticfiles(app, status, warning): + app.build() + assert (app.outdir / '_static' / 'staticimg.png').exists() + assert (app.outdir / '_static' / 'statictmpl.html').exists() + assert (app.outdir / '_static' / 'statictmpl.html').text() == ( + '\n' + 'Python' + ) + + result = (app.outdir / 'index.html').text() + assert '' in result From a5b64c98af1f898f95484010e0eb67f3ef4d6c3d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 13 Dec 2017 23:46:57 +0900 Subject: [PATCH 0394/1814] diet test-root: Remove html_static_path and html_extra_path (duplicated with test-html_assets) --- tests/roots/test-root/_static/README | 1 - tests/roots/test-root/_static/excluded.css | 1 - tests/roots/test-root/_static/subdir/foo.css | 1 - tests/roots/test-root/conf.py | 2 -- tests/roots/test-root/robots.txt | 2 -- tests/roots/test-root/templated.css_t | 2 -- tests/test_build_html.py | 27 -------------------- 7 files changed, 36 deletions(-) delete mode 100644 tests/roots/test-root/_static/README delete mode 100644 tests/roots/test-root/_static/excluded.css delete mode 100644 tests/roots/test-root/_static/subdir/foo.css delete mode 100644 tests/roots/test-root/robots.txt delete mode 100644 tests/roots/test-root/templated.css_t diff --git a/tests/roots/test-root/_static/README b/tests/roots/test-root/_static/README deleted file mode 100644 index 9e1ec3569..000000000 --- a/tests/roots/test-root/_static/README +++ /dev/null @@ -1 +0,0 @@ -This whole directory is there to test html_static_path. diff --git a/tests/roots/test-root/_static/excluded.css b/tests/roots/test-root/_static/excluded.css deleted file mode 100644 index 03c941a44..000000000 --- a/tests/roots/test-root/_static/excluded.css +++ /dev/null @@ -1 +0,0 @@ -/* This file should be excluded from being copied over */ diff --git a/tests/roots/test-root/_static/subdir/foo.css b/tests/roots/test-root/_static/subdir/foo.css deleted file mode 100644 index 9427981d6..000000000 --- a/tests/roots/test-root/_static/subdir/foo.css +++ /dev/null @@ -1 +0,0 @@ -/* Stub file */ diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py index c25beb9f1..bd3cb9a9b 100644 --- a/tests/roots/test-root/conf.py +++ b/tests/roots/test-root/conf.py @@ -33,8 +33,6 @@ html_sidebars = {'**': 'customsb.html', 'contents': ['contentssb.html', 'localtoc.html', 'globaltoc.html']} html_style = 'default.css' -html_static_path = ['_static', 'templated.css_t'] -html_extra_path = ['robots.txt'] html_last_updated_fmt = '%b %d, %Y' html_context = {'hckey': 'hcval', 'hckey_co': 'wrong_hcval_co'} diff --git a/tests/roots/test-root/robots.txt b/tests/roots/test-root/robots.txt deleted file mode 100644 index 1b425ee0f..000000000 --- a/tests/roots/test-root/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: /cgi-bin/ diff --git a/tests/roots/test-root/templated.css_t b/tests/roots/test-root/templated.css_t deleted file mode 100644 index 72ddb807c..000000000 --- a/tests/roots/test-root/templated.css_t +++ /dev/null @@ -1,2 +0,0 @@ -/* Stub file, templated */ -{{ sphinx_version }} diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 6fa769b8b..c27dad42b 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -126,24 +126,6 @@ def check_xpath(etree, fname, path, check, be_found=True): [node.text for node in nodes])) -def check_static_entries(outdir): - staticdir = outdir / '_static' - assert staticdir.isdir() - # a file from a directory entry in html_static_path - assert (staticdir / 'README').isfile() - # a directory from a directory entry in html_static_path - assert (staticdir / 'subdir' / 'foo.css').isfile() - # a file from a file entry in html_static_path - assert (staticdir / 'templated.css').isfile() - assert (staticdir / 'templated.css').text().splitlines()[1] == __display_version__ - # a file from _static, but matches exclude_patterns - assert not (staticdir / 'excluded.css').exists() - - -def check_extra_entries(outdir): - assert (outdir / 'robots.txt').isfile() - - @pytest.mark.sphinx('html', testroot='warnings') def test_html_warnings(app, warning): app.build() @@ -156,15 +138,6 @@ def test_html_warnings(app, warning): '--- Got:\n' + html_warnings -@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={ - 'html_context.hckey_co': 'hcval_co'}) -@pytest.mark.test_params(shared_result='test_build_html_output') -def test_static_output(app): - app.build() - check_static_entries(app.builder.outdir) - check_extra_entries(app.builder.outdir) - - @pytest.mark.parametrize("fname,expect", flat_dict({ 'images.html': [ (".//img[@src='_images/img.png']", ''), From a3f04c3397726ee688a5ebdebbbd23510f973d7f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 Dec 2017 02:30:09 +0900 Subject: [PATCH 0395/1814] Refactor test_build_html: Use basic project instead roots --- tests/test_build_html.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index c27dad42b..083add9a1 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -1114,16 +1114,22 @@ def test_html_assets(app): assert not (app.outdir / 'subdir' / '.htpasswd').exists() -@pytest.mark.sphinx('html', confoverrides={'html_sourcelink_suffix': ''}) +@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.txt'}) def test_html_sourcelink_suffix(app): app.builder.build_all() - content_otherext = (app.outdir / 'otherext.html').text() - content_images = (app.outdir / 'images.html').text() + assert (app.outdir / '_sources' / 'index.rst.txt').exists() - assert ' Date: Fri, 15 Dec 2017 02:30:25 +0900 Subject: [PATCH 0396/1814] test: Add test_html_copy_source --- tests/test_build_html.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 083add9a1..0ccd4da01 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -1114,6 +1114,12 @@ def test_html_assets(app): assert not (app.outdir / 'subdir' / '.htpasswd').exists() +@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False}) +def test_html_copy_source(app): + app.builder.build_all() + assert not (app.outdir / '_sources' / 'index.rst.txt').exists() + + @pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.txt'}) def test_html_sourcelink_suffix(app): app.builder.build_all() From 451ba5e76a2417c70ae4e2213b78c109d17bca05 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 Dec 2017 21:11:38 +0900 Subject: [PATCH 0397/1814] Fix ResourceWarning on pycode --- sphinx/pycode/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index 66544f073..20de2a656 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -36,11 +36,11 @@ class ModuleAnalyzer(object): if ('file', filename) in cls.cache: return cls.cache['file', filename] try: - fileobj = open(filename, 'rb') + with open(filename, 'rb') as f: + obj = cls(f, modname, filename) + cls.cache['file', filename] = obj except Exception as err: raise PycodeError('error opening %r' % filename, err) - obj = cls(fileobj, modname, filename) - cls.cache['file', filename] = obj return obj @classmethod From 2a2ed8915a2eaea45f2f65ca08dd563708b5c0a4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 Dec 2017 21:14:19 +0900 Subject: [PATCH 0398/1814] diet test-root: Move .mo files to new testroot (for test_html_rebuild_mo) --- .../bom.po | 0 tests/roots/test-builder-gettext-dont-rebuild-mo/bom.rst | 5 +++++ tests/roots/test-builder-gettext-dont-rebuild-mo/conf.py | 7 +++++++ .../roots/test-builder-gettext-dont-rebuild-mo/index.rst | 6 ++++++ tests/roots/test-root/subdir.po | 9 --------- tests/test_intl.py | 4 ++-- 6 files changed, 20 insertions(+), 11 deletions(-) rename tests/roots/{test-root => test-builder-gettext-dont-rebuild-mo}/bom.po (100%) create mode 100644 tests/roots/test-builder-gettext-dont-rebuild-mo/bom.rst create mode 100644 tests/roots/test-builder-gettext-dont-rebuild-mo/conf.py create mode 100644 tests/roots/test-builder-gettext-dont-rebuild-mo/index.rst delete mode 100644 tests/roots/test-root/subdir.po diff --git a/tests/roots/test-root/bom.po b/tests/roots/test-builder-gettext-dont-rebuild-mo/bom.po similarity index 100% rename from tests/roots/test-root/bom.po rename to tests/roots/test-builder-gettext-dont-rebuild-mo/bom.po diff --git a/tests/roots/test-builder-gettext-dont-rebuild-mo/bom.rst b/tests/roots/test-builder-gettext-dont-rebuild-mo/bom.rst new file mode 100644 index 000000000..3fea824f8 --- /dev/null +++ b/tests/roots/test-builder-gettext-dont-rebuild-mo/bom.rst @@ -0,0 +1,5 @@ +File with UTF-8 BOM +=================== + +This file has a UTF-8 "BOM". + diff --git a/tests/roots/test-builder-gettext-dont-rebuild-mo/conf.py b/tests/roots/test-builder-gettext-dont-rebuild-mo/conf.py new file mode 100644 index 000000000..31e7a6ed4 --- /dev/null +++ b/tests/roots/test-builder-gettext-dont-rebuild-mo/conf.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' + +latex_documents = [ + (master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report') +] diff --git a/tests/roots/test-builder-gettext-dont-rebuild-mo/index.rst b/tests/roots/test-builder-gettext-dont-rebuild-mo/index.rst new file mode 100644 index 000000000..7ff38c5a8 --- /dev/null +++ b/tests/roots/test-builder-gettext-dont-rebuild-mo/index.rst @@ -0,0 +1,6 @@ +The basic Sphinx documentation for testing +========================================== + +.. toctree:: + + bom diff --git a/tests/roots/test-root/subdir.po b/tests/roots/test-root/subdir.po deleted file mode 100644 index f515f2207..000000000 --- a/tests/roots/test-root/subdir.po +++ /dev/null @@ -1,9 +0,0 @@ -#, fuzzy -msgid "" -msgstr "" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "Including in subdir" -msgstr "translation" diff --git a/tests/test_intl.py b/tests/test_intl.py index 8eff52340..6b72438bd 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -520,7 +520,7 @@ def test_gettext_buildr_ignores_only_directive(app): @sphinx_intl # use individual shared_result directory to avoid "incompatible doctree" error -@pytest.mark.test_params(shared_result='test_gettext_dont_rebuild_mo') +@pytest.mark.sphinx(testroot='builder-gettext-dont-rebuild-mo') def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo): # --- don't rebuild by .mo mtime def get_number_of_update_targets(app_): @@ -533,7 +533,7 @@ def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo): app0 = make_app('dummy', *args, **kwargs) build_mo(app0.srcdir) app0.build() - assert (app0.srcdir / 'bom.mo') + assert (app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').exists() # Since it is after the build, the number of documents to be updated is 0 assert get_number_of_update_targets(app0) == 0 # When rewriting the timestamp of mo file, the number of documents to be From c250c63daaf67e9ca3f24ed9974d17016326de07 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 Dec 2017 21:14:20 +0900 Subject: [PATCH 0399/1814] test: Skip some builders on test_build_all --- tests/test_build.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_build.py b/tests/test_build.py index 2372b102b..c61fbb5c2 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -59,13 +59,13 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir): return srcdir +# note: this test skips building docs for some builders because they have independent testcase. +# (html, latex, texinfo and manpage) @pytest.mark.parametrize( "buildername", [ - # note: no 'html' - if it's ok with dirhtml it's ok with html - 'dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle', 'json', 'text', - 'htmlhelp', 'qthelp', 'epub2', 'epub', 'applehelp', 'changes', 'xml', - 'pseudoxml', 'man', 'linkcheck', + 'dirhtml', 'singlehtml', 'pickle', 'json', 'text', 'htmlhelp', 'qthelp', + 'epub2', 'epub', 'applehelp', 'changes', 'xml', 'pseudoxml', 'linkcheck', ], ) @mock.patch('sphinx.builders.linkcheck.requests.head', From fe07365a8cea7186261930f19b7f15735e545c57 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 Dec 2017 22:17:03 +0900 Subject: [PATCH 0400/1814] Fix mypy violations --- sphinx/application.py | 5 +++-- sphinx/domains/__init__.py | 2 +- sphinx/io.py | 2 +- sphinx/registry.py | 13 +++++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index ef20e56d8..3edd3fb98 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -33,7 +33,6 @@ from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.environment import BuildEnvironment from sphinx.events import EventManager from sphinx.extension import verify_required_extensions -from sphinx.io import SphinxStandaloneReader from sphinx.locale import __ from sphinx.registry import SphinxComponentRegistry from sphinx.util import pycompat # noqa: F401 @@ -54,7 +53,9 @@ if False: from sphinx.domains import Domain, Index # NOQA from sphinx.environment.collectors import EnvironmentCollector # NOQA from sphinx.extension import Extension # NOQA + from sphinx.roles import XRefRole # NOQA from sphinx.theming import Theme # NOQA + from sphinx.util.typing import RoleFunction # NOQA builtin_extensions = ( 'sphinx.builders.applehelp', @@ -563,7 +564,7 @@ class Sphinx(object): has_content, argument_spec, **option_spec) def add_role_to_domain(self, domain, name, role): - # type: (unicode, unicode, Any) -> None + # type: (unicode, unicode, Union[RoleFunction, XRefRole]) -> None self.registry.add_role_to_domain(domain, name, role) def add_index_to_domain(self, domain, index): diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index ddb6c7c66..1b9a7345a 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -141,7 +141,7 @@ class Domain(object): #: domain label: longer, more descriptive (used in messages) label = '' #: type (usually directive) name -> ObjType instance - object_types = {} # type: Dict[unicode, Any] + object_types = {} # type: Dict[unicode, ObjType] #: directive name -> directive class directives = {} # type: Dict[unicode, Any] #: role name -> role callable diff --git a/sphinx/io.py b/sphinx/io.py index 4bb554742..804932863 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -86,7 +86,7 @@ class SphinxStandaloneReader(SphinxBaseReader): def __init__(self, app, *args, **kwargs): # type: (Sphinx, Any, Any) -> None self.transforms = self.transforms + app.registry.get_transforms() - SphinxBaseReader.__init__(self, *args, **kwargs) + SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore class SphinxI18nReader(SphinxBaseReader): diff --git a/sphinx/registry.py b/sphinx/registry.py index 265524b28..885c7a256 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -29,7 +29,7 @@ from sphinx.util.docutils import directive_helper if False: # For type annotation - from typing import Any, Callable, Dict, Iterator, List, Type # NOQA + from typing import Any, Callable, Dict, Iterator, List, Type, Union # NOQA from docutils import nodes # NOQA from docutils.io import Input # NOQA from docutils.parsers import Parser # NOQA @@ -38,6 +38,7 @@ if False: from sphinx.builders import Builder # NOQA from sphinx.domains import Domain, Index # NOQA from sphinx.environment import BuildEnvironment # NOQA + from sphinx.util.typing import RoleFunction # NOQA logger = logging.getLogger(__name__) @@ -53,9 +54,9 @@ class SphinxComponentRegistry(object): self.builders = {} # type: Dict[unicode, Type[Builder]] self.domains = {} # type: Dict[unicode, Type[Domain]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] - self.domain_indices = {} # type: Dict[unicode, List[Index]] + self.domain_indices = {} # type: Dict[unicode, List[Type[Index]]] self.domain_object_types = {} # type: Dict[unicode, Dict[unicode, ObjType]] - self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Any]] + self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Union[RoleFunction, XRefRole]]] # NOQA self.post_transforms = [] # type: List[Type[Transform]] self.source_parsers = {} # type: Dict[unicode, Parser] self.source_inputs = {} # type: Dict[unicode, Input] @@ -139,7 +140,7 @@ class SphinxComponentRegistry(object): directives[name] = directive_helper(obj, has_content, argument_spec, **option_spec) def add_role_to_domain(self, domain, name, role): - # type: (unicode, unicode, Any) -> None + # type: (unicode, unicode, Union[RoleFunction, XRefRole]) -> None logger.debug('[app] adding role to domain: %r', (domain, name, role)) if domain not in self.domains: raise ExtensionError(__('domain %s not yet registered') % domain) @@ -186,8 +187,8 @@ class SphinxComponentRegistry(object): (Target, object), {'indextemplate': indextemplate}) - self.add_directive_to_domain('std', directive) - self.add_role_to_domain('std', XRefRole(innernodeclass=ref_nodeclass)) + self.add_directive_to_domain('std', directivename, directive) + self.add_role_to_domain('std', rolename, XRefRole(innernodeclass=ref_nodeclass)) object_types = self.domain_object_types.setdefault('std', {}) object_types[directivename] = ObjType(objname or directivename, rolename) From facce1fb020a61637a8d110cf556a08912e64035 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 Dec 2017 01:27:18 +0900 Subject: [PATCH 0401/1814] quickstart: Fix make_mode should be chosen by default --- sphinx/cmd/quickstart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index af07d4978..80e9e3dd4 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -586,7 +586,7 @@ Makefile to be used with sphinx-build. dest='batchfile', help='do not create batchfile') group.add_argument('-m', '--use-make-mode', action='store_true', - dest='make_mode', + dest='make_mode', default=True, help='use make-mode for Makefile/make.bat') group.add_argument('-M', '--no-use-make-mode', action='store_false', dest='make_mode', From b131c33af5ea49c6416026050725a0121c8991f3 Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 15 Dec 2017 22:54:52 +0100 Subject: [PATCH 0402/1814] Fix markup in doc/ext/math.rst --- doc/ext/math.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 3d25d09ba..ca53f3a8e 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -78,7 +78,7 @@ or use Python raw strings (``r"raw"``). Normally, equations are not numbered. If you want your equation to get a number, use the ``label`` option. When given, it selects an internal label for the equation, by which it can be cross-referenced, and causes an equation - number to be issued. See :rst:role:`eqref` for an example. The numbering + number to be issued. See :rst:role:`eq` for an example. The numbering style depends on the output format. There is also an option ``nowrap`` that prevents any wrapping of the given From 7cabd6cbb053965e1930b53c27d596fd1a52dd78 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 Dec 2017 14:51:55 +0900 Subject: [PATCH 0403/1814] Fix mypy violations --- sphinx/builders/html.py | 2 +- sphinx/builders/qthelp.py | 2 +- sphinx/config.py | 2 +- sphinx/domains/cpp.py | 2 +- sphinx/environment/collectors/toctree.py | 2 +- sphinx/ext/napoleon/docstring.py | 22 +++++++++++----------- sphinx/pycode/nodes.py | 2 +- sphinx/setup_command.py | 10 +++++----- sphinx/transforms/compact_bullet_list.py | 6 +++++- sphinx/util/__init__.py | 8 +++----- sphinx/util/logging.py | 4 ++-- 11 files changed, 32 insertions(+), 30 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index ead51a983..e50d2abe4 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -274,7 +274,7 @@ class StandaloneHTMLBuilder(Builder): # type: () -> Iterator[unicode] cfgdict = dict((confval.name, confval.value) for confval in self.config.filter('html')) self.config_hash = get_stable_hash(cfgdict) - self.tags_hash = get_stable_hash(sorted(self.tags)) # type: ignore + self.tags_hash = get_stable_hash(sorted(self.tags)) old_config_hash = old_tags_hash = '' try: with open(path.join(self.outdir, '.buildinfo')) as fp: diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 14979fe4b..12a50d140 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -264,7 +264,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder): link = node['refuri'] title = htmlescape(node.astext()).replace('"', '"') item = section_template % {'title': title, 'ref': link} - item = u' ' * 4 * indentlevel + item # type: ignore + item = u' ' * 4 * indentlevel + item parts.append(item.encode('ascii', 'xmlcharrefreplace')) elif isinstance(node, nodes.bullet_list): for subnode in node: diff --git a/sphinx/config.py b/sphinx/config.py index 02ee529a3..cc5f57e8e 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -288,7 +288,7 @@ class Config(object): logger.warning("%s", exc) for name in config: if name in self.values: - self.__dict__[name] = config[name] + self.__dict__[name] = config[name] # type: ignore if isinstance(self.source_suffix, string_types): # type: ignore self.source_suffix = [self.source_suffix] # type: ignore diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 23c398e13..aa97481ab 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -528,7 +528,7 @@ class ASTBase(UnicodeMixin): if type(self) is not type(other): return False try: - for key, value in iteritems(self.__dict__): # type: ignore + for key, value in iteritems(self.__dict__): if value != getattr(other, key): return False except AttributeError: diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index f19fd5d26..91aa21f2e 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -262,7 +262,7 @@ class TocTreeCollector(EnvironmentCollector): continue - figtype = env.get_domain('std').get_figtype(subnode) # type: ignore + figtype = env.get_domain('std').get_figtype(subnode) if figtype and subnode['ids']: register_fignumber(docname, secnum, figtype, subnode) diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index c77598ef1..d3a64049b 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -194,7 +194,7 @@ class GoogleDocstring(UnicodeMixin): line = self._line_iter.peek() while(not self._is_section_break() and (not line or self._is_indented(line, indent))): - lines.append(next(self._line_iter)) # type: ignore + lines.append(next(self._line_iter)) line = self._line_iter.peek() return lines @@ -204,7 +204,7 @@ class GoogleDocstring(UnicodeMixin): while (self._line_iter.has_next() and self._line_iter.peek() and not self._is_section_header()): - lines.append(next(self._line_iter)) # type: ignore + lines.append(next(self._line_iter)) return lines def _consume_empty(self): @@ -212,13 +212,13 @@ class GoogleDocstring(UnicodeMixin): lines = [] line = self._line_iter.peek() while self._line_iter.has_next() and not line: - lines.append(next(self._line_iter)) # type: ignore + lines.append(next(self._line_iter)) line = self._line_iter.peek() return lines def _consume_field(self, parse_type=True, prefer_type=False): # type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]] - line = next(self._line_iter) # type: ignore + line = next(self._line_iter) before, colon, after = self._partition_field_on_colon(line) _name, _type, _desc = before, '', after # type: unicode, unicode, unicode @@ -250,7 +250,7 @@ class GoogleDocstring(UnicodeMixin): def _consume_inline_attribute(self): # type: () -> Tuple[unicode, List[unicode]] - line = next(self._line_iter) # type: ignore + line = next(self._line_iter) _type, colon, _desc = self._partition_field_on_colon(line) if not colon: _type, _desc = _desc, _type @@ -285,7 +285,7 @@ class GoogleDocstring(UnicodeMixin): def _consume_section_header(self): # type: () -> unicode - section = next(self._line_iter) # type: ignore + section = next(self._line_iter) stripped_section = section.strip(':') if stripped_section.lower() in self._sections: section = stripped_section @@ -295,7 +295,7 @@ class GoogleDocstring(UnicodeMixin): # type: () -> List[unicode] lines = [] while self._line_iter.has_next(): - lines.append(next(self._line_iter)) # type: ignore + lines.append(next(self._line_iter)) return lines def _consume_to_next_section(self): @@ -303,7 +303,7 @@ class GoogleDocstring(UnicodeMixin): self._consume_empty() lines = [] while not self._is_section_break(): - lines.append(next(self._line_iter)) # type: ignore + lines.append(next(self._line_iter)) return lines + self._consume_empty() def _dedent(self, lines, full=False): @@ -886,7 +886,7 @@ class NumpyDocstring(GoogleDocstring): def _consume_field(self, parse_type=True, prefer_type=False): # type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]] - line = next(self._line_iter) # type: ignore + line = next(self._line_iter) if parse_type: _name, _, _type = self._partition_field_on_colon(line) else: @@ -907,10 +907,10 @@ class NumpyDocstring(GoogleDocstring): def _consume_section_header(self): # type: () -> unicode - section = next(self._line_iter) # type: ignore + section = next(self._line_iter) if not _directive_regex.match(section): # Consume the header underline - next(self._line_iter) # type: ignore + next(self._line_iter) return section def _is_section_break(self): diff --git a/sphinx/pycode/nodes.py b/sphinx/pycode/nodes.py index cecde9bd0..ea3b3e9ad 100644 --- a/sphinx/pycode/nodes.py +++ b/sphinx/pycode/nodes.py @@ -208,5 +208,5 @@ class NodeVisitor(object): def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" if isinstance(node, Node): - for child in node: # type: ignore + for child in node: self.visit(child) diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index d219a14d9..8c00a2ff8 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -136,8 +136,8 @@ class BuildDoc(Command): # type: () -> None if self.source_dir is None: self.source_dir = self._guess_source_dir() - self.announce('Using source directory %s' % self.source_dir) # type: ignore - self.ensure_dirname('source_dir') # type: ignore + self.announce('Using source directory %s' % self.source_dir) + self.ensure_dirname('source_dir') if self.source_dir is None: self.source_dir = os.curdir self.source_dir = abspath(self.source_dir) @@ -145,10 +145,10 @@ class BuildDoc(Command): self.config_dir = self.source_dir self.config_dir = abspath(self.config_dir) - self.ensure_string_list('builder') # type: ignore + self.ensure_string_list('builder') if self.build_dir is None: - build = self.get_finalized_command('build') # type: ignore - self.build_dir = os.path.join(abspath(build.build_base), 'sphinx') + build = self.get_finalized_command('build') + self.build_dir = os.path.join(abspath(build.build_base), 'sphinx') # type: ignore self.mkpath(self.build_dir) # type: ignore self.build_dir = abspath(self.build_dir) self.doctree_dir = os.path.join(self.build_dir, 'doctrees') diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py index 006ae7161..8c930c8bc 100644 --- a/sphinx/transforms/compact_bullet_list.py +++ b/sphinx/transforms/compact_bullet_list.py @@ -14,6 +14,10 @@ from docutils import nodes from sphinx import addnodes from sphinx.transforms import SphinxTransform +if False: + # For type annotation + from typing import List # NOQA + class RefOnlyListChecker(nodes.GenericNodeVisitor): """Raise `nodes.NodeFound` if non-simple list item is encountered. @@ -32,7 +36,7 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor): def visit_list_item(self, node): # type: (nodes.Node) -> None - children = [] + children = [] # type: List[nodes.Node] for child in node.children: if not isinstance(child, nodes.Invisible): children.append(child) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 03f8ce6a3..55fb9fcc1 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -398,10 +398,8 @@ def parselinenos(spec, total): elif len(begend) == 1: items.append(int(begend[0]) - 1) elif len(begend) == 2: - start = int(begend[0] or 1) # type: ignore - # left half open (cf. -10) - end = int(begend[1] or max(start, total)) # type: ignore - # right half open (cf. 10-) + start = int(begend[0] or 1) # left half open (cf. -10) + end = int(begend[1] or max(start, total)) # right half open (cf. 10-) if start > end: # invalid range (cf. 10-1) raise ValueError items.extend(range(start - 1, end)) @@ -528,7 +526,7 @@ class PeekableIterator(object): def peek(self): # type: () -> Any """Return the next item without changing the state of the iterator.""" - item = next(self) # type: ignore + item = next(self) self.push(item) return item diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 6148a5445..00c12ec4f 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -156,8 +156,8 @@ class NewLineStreamHandlerPY2(logging.StreamHandler): # remove return code forcely when nonl=True self.stream = StringIO() super(NewLineStreamHandlerPY2, self).emit(record) - stream.write(self.stream.getvalue()[:-1]) # type: ignore - stream.flush() # type: ignore + stream.write(self.stream.getvalue()[:-1]) + stream.flush() else: super(NewLineStreamHandlerPY2, self).emit(record) finally: From f07b080331f49b2b873995962c06f82ee576229c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 Dec 2017 15:01:23 +0900 Subject: [PATCH 0404/1814] Fix mypy violations --- sphinx/ext/autodoc/inspector.py | 10 +++++----- sphinx/util/inspect.py | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sphinx/ext/autodoc/inspector.py b/sphinx/ext/autodoc/inspector.py index f1faf2043..5d157c797 100644 --- a/sphinx/ext/autodoc/inspector.py +++ b/sphinx/ext/autodoc/inspector.py @@ -65,7 +65,7 @@ def format_annotation(annotation): elif (hasattr(typing, 'UnionMeta') and isinstance(annotation, typing.UnionMeta) and # type: ignore hasattr(annotation, '__union_params__')): - params = annotation.__union_params__ # type: ignore + params = annotation.__union_params__ if params is not None: param_str = ', '.join(format_annotation(p) for p in params) return '%s[%s]' % (qualified_name, param_str) @@ -74,7 +74,7 @@ def format_annotation(annotation): getattr(annotation, '__args__', None) is not None and hasattr(annotation, '__result__')): # Skipped in the case of plain typing.Callable - args = annotation.__args__ # type: ignore + args = annotation.__args__ if args is None: return qualified_name elif args is Ellipsis: @@ -84,15 +84,15 @@ def format_annotation(annotation): args_str = '[%s]' % ', '.join(formatted_args) return '%s[%s, %s]' % (qualified_name, args_str, - format_annotation(annotation.__result__)) # type: ignore + format_annotation(annotation.__result__)) elif (hasattr(typing, 'TupleMeta') and isinstance(annotation, typing.TupleMeta) and # type: ignore hasattr(annotation, '__tuple_params__') and hasattr(annotation, '__tuple_use_ellipsis__')): - params = annotation.__tuple_params__ # type: ignore + params = annotation.__tuple_params__ if params is not None: param_strings = [format_annotation(p) for p in params] - if annotation.__tuple_use_ellipsis__: # type: ignore + if annotation.__tuple_use_ellipsis__: param_strings.append('...') return '%s[%s]' % (qualified_name, ', '.join(param_strings)) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 2d15c2883..da13b8af0 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -434,7 +434,7 @@ class Signature(object): elif (hasattr(typing, 'UnionMeta') and # for py35 or below isinstance(annotation, typing.UnionMeta) and # type: ignore hasattr(annotation, '__union_params__')): - params = annotation.__union_params__ # type: ignore + params = annotation.__union_params__ if params is not None: param_str = ', '.join(self.format_annotation(p) for p in params) return '%s[%s]' % (qualified_name, param_str) @@ -442,7 +442,7 @@ class Signature(object): getattr(annotation, '__args__', None) is not None and hasattr(annotation, '__result__')): # Skipped in the case of plain typing.Callable - args = annotation.__args__ # type: ignore + args = annotation.__args__ if args is None: return qualified_name elif args is Ellipsis: @@ -452,14 +452,14 @@ class Signature(object): args_str = '[%s]' % ', '.join(formatted_args) return '%s[%s, %s]' % (qualified_name, args_str, - self.format_annotation(annotation.__result__)) # type: ignore # NOQA + self.format_annotation(annotation.__result__)) elif (isinstance(annotation, typing.TupleMeta) and # type: ignore hasattr(annotation, '__tuple_params__') and hasattr(annotation, '__tuple_use_ellipsis__')): - params = annotation.__tuple_params__ # type: ignore + params = annotation.__tuple_params__ if params is not None: param_strings = [self.format_annotation(p) for p in params] - if annotation.__tuple_use_ellipsis__: # type: ignore + if annotation.__tuple_use_ellipsis__: param_strings.append('...') return '%s[%s]' % (qualified_name, ', '.join(param_strings)) From 14af6b429ef2355ba0e8342c4af0f9dd9aafab1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 7 Dec 2017 23:15:05 +0100 Subject: [PATCH 0405/1814] Use ensuredir() instead of os.makedirs() to fix race conditions Use the ensuredir() function consistently across Sphinx code to avoid race conditions e.g. when multiple Sphinx instances attempt to create the same output directory. The ensuredir() function that was already present in sphinx.util.osutil correctly catches EEXIST exception that occurs if the specified directory already exists (i.e. it was created between the call to os.path.isdir() and os.makedirs() that follows it). While at it, remove redundant os.path.isdir() calls when they only guarded the os.makedirs() call, and replace mkdir_p() which had pretty much the same purpose, except for being prone to race conditions. I did not modify testing-related code as race conditions mostly affect real applications and not the test environment. Fix #4281: Race conditions when creating output directory --- CHANGES | 1 + sphinx/apidoc.py | 7 +++---- sphinx/application.py | 4 ++-- sphinx/builders/__init__.py | 6 ++---- sphinx/quickstart.py | 19 ++++++------------- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/CHANGES b/CHANGES index b7a16af4f..1b8289784 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,7 @@ Bugs fixed * #4279: Sphinx crashes with pickling error when run with multiple processes and remote image * #1421: Respect the quiet flag in sphinx-quickstart +* #4281: Race conditions when creating output directory Testing -------- diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index 24ed874b0..b764cfc35 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -26,7 +26,7 @@ from fnmatch import fnmatch from sphinx import __display_version__ from sphinx.quickstart import EXTENSIONS from sphinx.util import rst -from sphinx.util.osutil import FileAvoidWrite, walk +from sphinx.util.osutil import FileAvoidWrite, ensuredir, walk if False: # For type annotation @@ -375,9 +375,8 @@ Note: By default this script will not overwrite already created files.""") if not path.isdir(rootpath): print('%s is not a directory.' % rootpath, file=sys.stderr) sys.exit(1) - if not path.isdir(opts.destdir): - if not opts.dryrun: - os.makedirs(opts.destdir) + if not opts.dryrun: + ensuredir(opts.destdir) rootpath = path.abspath(rootpath) excludes = normalize_excludes(rootpath, excludes) modules = recurse_tree(rootpath, excludes, opts) diff --git a/sphinx/application.py b/sphinx/application.py index 0d6d3d0b3..b5705face 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -41,7 +41,7 @@ from sphinx.util import import_object from sphinx.util import logging from sphinx.util import status_iterator, old_status_iterator, display_chunk from sphinx.util.tags import Tags -from sphinx.util.osutil import ENOENT +from sphinx.util.osutil import ENOENT, ensuredir from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.docutils import is_html5_writer_available, directive_helper from sphinx.util.i18n import find_catalog_source_files @@ -160,7 +160,7 @@ class Sphinx(object): if not path.isdir(outdir): logger.info('making output directory...') - os.makedirs(outdir) + ensuredir(outdir) # read config self.tags = Tags(tags) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 007964e82..a1d5c5d22 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -9,7 +9,6 @@ :license: BSD, see LICENSE for details. """ -import os from os import path import warnings @@ -24,7 +23,7 @@ from docutils import nodes from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.environment.adapters.asset import ImageAdapter from sphinx.util import i18n, path_stabilize, logging, status_iterator -from sphinx.util.osutil import SEP, relative_uri +from sphinx.util.osutil import SEP, ensuredir, relative_uri from sphinx.util.i18n import find_catalog from sphinx.util.console import bold # type: ignore from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \ @@ -79,8 +78,7 @@ class Builder(object): self.confdir = app.confdir self.outdir = app.outdir self.doctreedir = app.doctreedir - if not path.isdir(self.doctreedir): - os.makedirs(self.doctreedir) + ensuredir(self.doctreedir) self.app = app # type: Sphinx self.env = None # type: BuildEnvironment diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index d23dc3b74..5d8738996 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -35,7 +35,7 @@ from six.moves.urllib.parse import quote as urlquote from docutils.utils import column_width from sphinx import __display_version__, package_dir -from sphinx.util.osutil import make_filename +from sphinx.util.osutil import ensuredir, make_filename from sphinx.util.console import ( # type: ignore purple, bold, red, turquoise, nocolor, color_terminal ) @@ -69,13 +69,6 @@ EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage', PROMPT_PREFIX = '> ' -def mkdir_p(dir): - # type: (unicode) -> None - if path.isdir(dir): - return - os.makedirs(dir) - - # function to get input from terminal -- overridden by the test suite def term_input(prompt): # type: (unicode) -> unicode @@ -433,11 +426,11 @@ def generate(d, overwrite=True, silent=False, templatedir=None): d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'") if not path.isdir(d['path']): - mkdir_p(d['path']) + ensuredir(d['path']) srcdir = d['sep'] and path.join(d['path'], 'source') or d['path'] - mkdir_p(srcdir) + ensuredir(srcdir) if d['sep']: builddir = path.join(d['path'], 'build') d['exclude_patterns'] = '' @@ -448,9 +441,9 @@ def generate(d, overwrite=True, silent=False, templatedir=None): 'Thumbs.db', '.DS_Store', ]) d['exclude_patterns'] = ', '.join(exclude_patterns) - mkdir_p(builddir) - mkdir_p(path.join(srcdir, d['dot'] + 'templates')) - mkdir_p(path.join(srcdir, d['dot'] + 'static')) + ensuredir(builddir) + ensuredir(path.join(srcdir, d['dot'] + 'templates')) + ensuredir(path.join(srcdir, d['dot'] + 'static')) def write_file(fpath, content, newline=None): # type: (unicode, unicode, unicode) -> None From 070fbb97e5a8f41a398ac5de16938f2da5797a5a Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 16 Dec 2017 11:05:33 +0100 Subject: [PATCH 0406/1814] Add markup and clarify numfig_secnum_depth docs --- doc/config.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 7a6d20147..3b490c5d3 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -311,8 +311,8 @@ General configuration .. confval:: numfig If true, figures, tables and code-blocks are automatically numbered if they - have a caption. At same time, the `numref` role is enabled. For now, it - works only with the HTML builder and LaTeX builder. Default is ``False``. + have a caption. The :rst:role:`numref` role is enabled. + Obeyed so far only by HTML and LaTeX builders. Default is ``False``. .. note:: @@ -335,10 +335,12 @@ General configuration .. confval:: numfig_secnum_depth - The scope of figure numbers, that is, the numfig feature numbers figures - in which scope. ``0`` means "whole document". ``1`` means "in a section". - Sphinx numbers like x.1, x.2, x.3... ``2`` means "in a subsection". Sphinx - numbers like x.x.1, x.x.2, x.x.3..., and so on. Default is ``1``. + The scope for numbering: ``0`` means "continuous numbering", + ``1`` means "reset per section" + (i.e. numbers will be x.1, x.2, x.3 ... with x the section number), + ``2`` means "per subsection" + (i.e. numbers will be x.y.1, x.y.2, ...), + and so on. Default is ``1``. .. versionadded:: 1.3 From f780f92d1b0eb1c3f6b37dc1e75e0980d046b134 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 16 Dec 2017 11:32:40 +0100 Subject: [PATCH 0407/1814] Mention ``:numbered:`` needed in numfig_secnum_depth docs --- doc/config.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/config.rst b/doc/config.rst index 3b490c5d3..fc87c4ddc 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -337,7 +337,9 @@ General configuration The scope for numbering: ``0`` means "continuous numbering", ``1`` means "reset per section" - (i.e. numbers will be x.1, x.2, x.3 ... with x the section number), + (i.e. numbers will be x.1, x.2, x.3 ... with x the section number, + assuming that the :rst:dir:`toctree` directive was used with its option + ``:numbered:``), ``2`` means "per subsection" (i.e. numbers will be x.y.1, x.y.2, ...), and so on. Default is ``1``. From a9602e4597a75889edc91e65f226c72a5ae73d0e Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 16 Dec 2017 11:46:33 +0100 Subject: [PATCH 0408/1814] Improve numref docs --- doc/markup/inline.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index a59585bab..09ea49003 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -222,15 +222,15 @@ Cross-referencing figures by figure number reST labels are used. When you use this role, it will insert a reference to the figure with link text by its figure number like "Fig. 1.1". - If an explicit link text is given (like usual: ``:numref:`Image of Sphinx (Fig. - %s) ```), the link caption will be the title of the reference. - As a special character, `%s` and `{number}` will be replaced to figure - number. `{name}` will be replaced to figure caption. - If no explicit link text is given, the value of :confval:`numfig_format` is - used to default value of link text. + If an explicit link text is given (as usual: ``:numref:`Image of Sphinx (Fig. + %s) ```), the link caption will serve as title of the reference. + As place holders, `%s` and `{number}` get replaced by the figure + number and `{name}` by the figure caption. + If no explicit link text is given, the :confval:`numfig_format` setting is + used as fall-back default. - If :confval:`numfig` is ``False``, figures are not numbered. - so this role inserts not a reference but labels or link text. + If :confval:`numfig` is ``False``, figures are not numbered, + so this role inserts not a reference but the label or the link text. Cross-referencing other items of interest ----------------------------------------- From ba1368072fdfc143322a38335ebcdd8d83c6f720 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 16 Dec 2017 11:51:00 +0100 Subject: [PATCH 0409/1814] Typo place holder --> placeholder --- doc/markup/inline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index 09ea49003..7ed3e7207 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -224,7 +224,7 @@ Cross-referencing figures by figure number If an explicit link text is given (as usual: ``:numref:`Image of Sphinx (Fig. %s) ```), the link caption will serve as title of the reference. - As place holders, `%s` and `{number}` get replaced by the figure + As placeholders, `%s` and `{number}` get replaced by the figure number and `{name}` by the figure caption. If no explicit link text is given, the :confval:`numfig_format` setting is used as fall-back default. From 04f2929f59b49fefbc6804088089994567b67ad9 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Sat, 16 Dec 2017 10:34:06 -0500 Subject: [PATCH 0410/1814] mention limitation to html-like targets --- doc/ext/math.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index fe7b85c83..0fb3a17cf 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -46,10 +46,10 @@ or use Python raw strings (``r"raw"``). .. confval:: math_numfig - If ``True``, displayed math equations are numbered across pages using numfig. - The :confval:`numfig` config value must be enabled and - :confval:`numfig_secnum_depth` is respected. The ``:eq:`` role must be used - to refererence these equation numbers, not the ``:numref:`` role. + If ``True``, displayed math equations are numbered across pages in html and + related (epub, ...) output. The :confval:`numfig` config value must be + enabled and :confval:`numfig_secnum_depth` is respected. The ``:eq:`` role + must be used to reference equation numbers, not the ``:numref:`` role. Default is ``False``. :mod:`.mathbase` defines these new markup elements: From 53a84de822c94b14a10cb5f416668b2834983c12 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Sat, 16 Dec 2017 09:37:38 -0500 Subject: [PATCH 0411/1814] make math_numfig work with singlehtml writer --- sphinx/ext/imgmath.py | 2 +- sphinx/ext/jsmath.py | 2 +- sphinx/ext/mathbase.py | 19 +++++++++++-------- sphinx/ext/mathjax.py | 2 +- sphinx/ext/pngmath.py | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 04d6b708a..a8a7f5d8c 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -334,7 +334,7 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - number = get_node_equation_number(self.builder.env, node) + number = get_node_equation_number(self, node) self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index 978e3f3d6..3c31b0a02 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -36,7 +36,7 @@ def html_visit_displaymath(self, node): if i == 0: # necessary to e.g. set the id property correctly if node['number']: - number = get_node_equation_number(self.builder.env, node) + number = get_node_equation_number(self, node) self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index 313f72bd4..5f353ac9c 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -133,17 +133,20 @@ class MathDomain(Domain): return len(targets) + 1 -def get_node_equation_number(env, node): - if env.config.math_numfig and env.config.numfig: - docname = node['docname'] - if docname in env.toc_fignumbers: - id = node['ids'][0] - number = env.toc_fignumbers[docname]['displaymath'].get(id, ()) - number = '.'.join(map(str, number)) +def get_node_equation_number(writer, node): + if writer.builder.config.math_numfig and writer.builder.config.numfig: + figtype = 'displaymath' + if writer.builder.name == 'singlehtml': + key = u"%s/%s" % (writer.docnames[-1], figtype) else: - number = '' + key = figtype + + id = node['ids'][0] + number = writer.builder.fignumbers.get(key, {}).get(id, ()) + number = '.'.join(map(str, number)) else: number = node['number'] + return number diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index aff5c103b..8b7e700ac 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -37,7 +37,7 @@ def html_visit_displaymath(self, node): # necessary to e.g. set the id property correctly if node['number']: - number = get_node_equation_number(self.builder.env, node) + number = get_node_equation_number(self, node) self.body.append('(%s)' % number) self.add_permalink_ref(node, _('Permalink to this equation')) self.body.append('') diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py index 968139f15..499f37e79 100644 --- a/sphinx/ext/pngmath.py +++ b/sphinx/ext/pngmath.py @@ -243,7 +243,7 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append('

') if node['number']: - number = get_node_equation_number(self.builder.env, node) + number = get_node_equation_number(self, node) self.body.append('(%s)' % number) if fname is None: # something failed -- use text-only as a bad substitute From 832914423e84067f3cf764bcb84e20ade00f02af Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 00:03:56 +0900 Subject: [PATCH 0412/1814] autodoc: refactor AutoDirective --- sphinx/application.py | 3 +- sphinx/ext/autodoc/__init__.py | 123 +-------------------- sphinx/ext/autodoc/directive.py | 172 +++++++++++++++++++++++++++++ sphinx/ext/autosummary/__init__.py | 2 +- sphinx/util/docutils.py | 8 +- 5 files changed, 180 insertions(+), 128 deletions(-) create mode 100644 sphinx/ext/autodoc/directive.py diff --git a/sphinx/application.py b/sphinx/application.py index 05d302c81..e49ac6174 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -659,8 +659,9 @@ class Sphinx(object): # type: (Any) -> None logger.debug('[app] adding autodocumenter: %r', cls) from sphinx.ext import autodoc + from sphinx.ext.autodoc.directive import AutodocDirective autodoc.add_documenter(cls) - self.add_directive('auto' + cls.objtype, autodoc.AutoDirective) + self.add_directive('auto' + cls.objtype, AutodocDirective) def add_autodoc_attrgetter(self, type, getter): # type: (Any, Callable) -> None diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ff161565c..c74ca43c9 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -18,8 +18,6 @@ import traceback from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types -from docutils import nodes -from docutils.utils import assemble_option_dict from docutils.parsers.rst import Directive from docutils.statemachine import ViewList @@ -32,7 +30,6 @@ from sphinx.locale import _ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.application import ExtensionError from sphinx.util import logging -from sphinx.util.nodes import nested_parse_with_titles from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \ safe_getattr, object_description, is_builtin_class_method, \ isenumclass, isenumattribute, getdoc @@ -42,11 +39,11 @@ if False: # For type annotation from types import ModuleType # NOQA from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union # NOQA - from docutils.utils import Reporter # NOQA from sphinx.application import Sphinx # NOQA logger = logging.getLogger(__name__) + # This type isn't exposed directly in any modules, but can be found # here in most Python versions MethodDescriptorType = type(type.__subclasses__) @@ -63,42 +60,11 @@ py_ext_sig_re = re.compile( ''', re.VERBOSE) -class DefDict(dict): - """A dict that returns a default on nonexisting keys.""" - def __init__(self, default): - # type: (Any) -> None - dict.__init__(self) - self.default = default - - def __getitem__(self, key): - # type: (Any) -> Any - try: - return dict.__getitem__(self, key) - except KeyError: - return self.default - - def __bool__(self): - # type: () -> bool - # docutils check "if option_spec" - return True - __nonzero__ = __bool__ # for python2 compatibility - - def identity(x): # type: (Any) -> Any return x -class Options(dict): - """A dict/attribute hybrid that returns None on nonexisting keys.""" - def __getattr__(self, name): - # type: (unicode) -> Any - try: - return self[name.replace('_', '-')] - except KeyError: - return None - - ALL = object() INSTANCEATTR = object() @@ -1525,93 +1491,6 @@ class AutoDirective(Directive): # a registry of type -> getattr function _special_attrgetters = {} # type: Dict[Type, Callable] - # flags that can be given in autodoc_default_flags - _default_flags = set([ - 'members', 'undoc-members', 'inherited-members', 'show-inheritance', - 'private-members', 'special-members', - ]) - - # standard docutils directive settings - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - # allow any options to be passed; the options are parsed further - # by the selected Documenter - option_spec = DefDict(identity) - - def warn(self, msg): - # type: (unicode) -> None - self.warnings.append(self.reporter.warning(msg, line=self.lineno)) - - def run(self): - # type: () -> List[nodes.Node] - self.filename_set = set() # type: Set[unicode] - # a set of dependent filenames - self.reporter = self.state.document.reporter - self.env = self.state.document.settings.env - self.warnings = [] # type: List[unicode] - self.result = ViewList() - - try: - source, lineno = self.reporter.get_source_and_line(self.lineno) - except AttributeError: - source = lineno = None - logger.debug('[autodoc] %s:%s: input:\n%s', - source, lineno, self.block_text) - - # find out what documenter to call - objtype = self.name[4:] - doc_class = self._registry[objtype] - # add default flags - for flag in self._default_flags: - if flag not in doc_class.option_spec: - continue - negated = self.options.pop('no-' + flag, 'not given') is None - if flag in self.env.config.autodoc_default_flags and \ - not negated: - self.options[flag] = None - # process the options with the selected documenter's option_spec - try: - self.genopt = Options(assemble_option_dict( - self.options.items(), doc_class.option_spec)) - except (KeyError, ValueError, TypeError) as err: - # an option is either unknown or has a wrong type - msg = self.reporter.error('An option to %s is either unknown or ' - 'has an invalid value: %s' % (self.name, err), - line=self.lineno) - return [msg] - # generate the output - documenter = doc_class(self, self.arguments[0]) - documenter.generate(more_content=self.content) - if not self.result: - return self.warnings - - logger.debug('[autodoc] output:\n%s', '\n'.join(self.result)) - - # record all filenames as dependencies -- this will at least - # partially make automatic invalidation possible - for fn in self.filename_set: - self.state.document.settings.record_dependencies.add(fn) - - # use a custom reporter that correctly assigns lines to source - # filename/description and lineno - old_reporter = self.state.memo.reporter - self.state.memo.reporter = AutodocReporter(self.result, - self.state.memo.reporter) - - if documenter.titles_allowed: - node = nodes.section() - # necessary so that the child nodes get the right source/line set - node.document = self.state.document - nested_parse_with_titles(self.state, self.result, node) - else: - node = nodes.paragraph() - node.document = self.state.document - self.state.nested_parse(self.result, 0, node) - self.state.memo.reporter = old_reporter - return self.warnings + node.children - def add_documenter(cls): # type: (Type[Documenter]) -> None diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py new file mode 100644 index 000000000..9be273982 --- /dev/null +++ b/sphinx/ext/autodoc/directive.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- +""" + sphinx.ext.autodoc.directive + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.statemachine import ViewList +from docutils.utils import assemble_option_dict + +from sphinx.ext.autodoc import AutoDirective, AutodocReporter, identity +from sphinx.util import logging +from sphinx.util.nodes import nested_parse_with_titles + +if False: + # For type annotation + from typing import Any, Dict, List, Set, Type # NOQA + from docutils.statemachine import State, StateMachine, StringList # NOQA + from docutils.utils import Reporter # NOQA + from sphinx.config import Config # NOQA + from sphinx.environment import BuildEnvironment # NOQA + from sphinx.ext.autodoc import Documenter # NOQA + +logger = logging.getLogger(__name__) + + +# common option names for autodoc directives +AUTODOC_DEFAULT_OPTIONS = ['members', 'undoc-members', 'inherited-members', + 'show-inheritance', 'private-members', 'special-members'] + + +class DefDict(dict): + """A dict that returns a default on nonexisting keys.""" + def __init__(self, default): + # type: (Any) -> None + dict.__init__(self) + self.default = default + + def __getitem__(self, key): + # type: (Any) -> Any + try: + return dict.__getitem__(self, key) + except KeyError: + return self.default + + def __bool__(self): + # type: () -> bool + # docutils check "if option_spec" + return True + + __nonzero__ = __bool__ # for python2 compatibility + + +class Options(dict): + """A dict/attribute hybrid that returns None on nonexisting keys.""" + def __getattr__(self, name): + # type: (unicode) -> Any + try: + return self[name.replace('_', '-')] + except KeyError: + return None + + +class DocumenterBridge(object): + def __init__(self, env, reporter, options, lineno): + # type: (BuildEnvironment, Reporter, Options, int) -> None + self.env = env + self.reporter = reporter + self.genopt = options + self.lineno = lineno + self.filename_set = set() # type: Set[unicode] + self.warnings = [] # type: List[nodes.Node] + self.result = ViewList() + + def warn(self, msg): + # type: (unicode) -> None + self.warnings.append(self.reporter.warning(msg, line=self.lineno)) + + +def process_documenter_options(documenter, config, options): + # type: (Type[Documenter], Config, Dict) -> Options + for name in AUTODOC_DEFAULT_OPTIONS: + if name not in documenter.option_spec: + continue + else: + negated = options.pop('no-' + name, True) is None + if name in config.autodoc_default_flags and not negated: + options[name] = None + + return Options(assemble_option_dict(options.items(), documenter.option_spec)) + + +def parse_generated_content(state, content, documenter): + # type: (State, StringList, Documenter) -> List[nodes.Node] + try: + # use a custom reporter that correctly assigns lines to source + # filename/description and lineno + old_reporter = state.memo.reporter + state.memo.reporter = AutodocReporter(content, state.memo.reporter) + + if documenter.titles_allowed: + node = nodes.section() + # necessary so that the child nodes get the right source/line set + node.document = state.document + nested_parse_with_titles(state, content, node) + else: + node = nodes.paragraph() + node.document = state.document + state.nested_parse(content, 0, node) + + return node.children + finally: + state.memo.reporter = old_reporter + + +class AutodocDirective(Directive): + """A directive class for all autodoc directives. It works as a dispatcher of Documenters. + + It invokes a Documenter on running. After the processing, it parses and returns + the generated content by Documenter. + """ + option_spec = DefDict(identity) + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + + def run(self): + # type: () -> List[nodes.Node] + env = self.state.document.settings.env + reporter = self.state.document.reporter + + try: + source, lineno = reporter.get_source_and_line(self.lineno) + except AttributeError: + source, lineno = (None, None) + logger.debug('[autodoc] %s:%s: input:\n%s', source, lineno, self.block_text) + + # look up target Documenter + objtype = self.name[4:] # strip prefix (auto-). + doccls = AutoDirective._registry[objtype] + + # process the options with the selected documenter's option_spec + try: + documenter_options = process_documenter_options(doccls, env.config, self.options) + except (KeyError, ValueError, TypeError) as exc: + # an option is either unknown or has a wrong type + msg = reporter.error('An option to %s is either unknown or ' + 'has an invalid value: %s' % (self.name, exc), + line=lineno) + return [msg] + + # generate the output + params = DocumenterBridge(env, reporter, documenter_options, lineno) + documenter = doccls(params, self.arguments[0]) + documenter.generate(more_content=self.content) + if not params.result: + return params.warnings + + logger.debug('[autodoc] output:\n%s', '\n'.join(params.result)) + + # record all filenames as dependencies -- this will at least + # partially make automatic invalidation possible + for fn in params.filename_set: + self.state.document.settings.record_dependencies.add(fn) + + result = parse_generated_content(self.state, params.result, documenter) + return params.warnings + result diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 21bfe7b13..b56f649bf 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -72,7 +72,7 @@ from sphinx import addnodes from sphinx.environment.adapters.toctree import TocTree from sphinx.util import import_object, rst, logging from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.ext.autodoc import Options +from sphinx.ext.autodoc.directive import Options from sphinx.ext.autodoc.importer import import_module if False: diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 00ea5919e..a745e058a 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -31,7 +31,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/( if False: # For type annotation - from typing import Any, Callable, Iterator, List, Tuple # NOQA + from typing import Any, Callable, Dict, Iterator, List, Tuple # NOQA from docutils import nodes # NOQA from sphinx.environment import BuildEnvironment # NOQA from sphinx.io import SphinxFileInput # NOQA @@ -204,12 +204,12 @@ def is_html5_writer_available(): return __version_info__ > (0, 13, 0) -def directive_helper(obj, has_content=None, argument_spec=None, **option_spec): - # type: (Any, bool, Tuple[int, int, bool], Any) -> Any +def directive_helper(obj, has_content=None, argument_spec=None, option_spec=None, **options): + # type: (Any, bool, Tuple[int, int, bool], Dict, Any) -> Any if isinstance(obj, (types.FunctionType, types.MethodType)): obj.content = has_content # type: ignore obj.arguments = argument_spec or (0, 0, False) # type: ignore - obj.options = option_spec # type: ignore + obj.options = option_spec or options # type: ignore return convert_directive_function(obj) else: if has_content or argument_spec or option_spec: From cac965cf77cb69d7807df566bcaa62d31cafd143 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 Dec 2017 23:43:08 +0900 Subject: [PATCH 0413/1814] autodoc: refactor option_spec of autodirectives --- sphinx/ext/autodoc/directive.py | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index 9be273982..f348e105a 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -12,7 +12,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList from docutils.utils import assemble_option_dict -from sphinx.ext.autodoc import AutoDirective, AutodocReporter, identity +from sphinx.ext.autodoc import AutoDirective, AutodocReporter from sphinx.util import logging from sphinx.util.nodes import nested_parse_with_titles @@ -33,26 +33,12 @@ AUTODOC_DEFAULT_OPTIONS = ['members', 'undoc-members', 'inherited-members', 'show-inheritance', 'private-members', 'special-members'] -class DefDict(dict): - """A dict that returns a default on nonexisting keys.""" - def __init__(self, default): - # type: (Any) -> None - dict.__init__(self) - self.default = default +class DummyOptionSpec(object): + """An option_spec allows any options.""" def __getitem__(self, key): # type: (Any) -> Any - try: - return dict.__getitem__(self, key) - except KeyError: - return self.default - - def __bool__(self): - # type: () -> bool - # docutils check "if option_spec" - return True - - __nonzero__ = __bool__ # for python2 compatibility + return lambda x: x class Options(dict): @@ -123,7 +109,7 @@ class AutodocDirective(Directive): It invokes a Documenter on running. After the processing, it parses and returns the generated content by Documenter. """ - option_spec = DefDict(identity) + option_spec = DummyOptionSpec() has_content = True required_arguments = 1 optional_arguments = 0 From 299b11f26f98b1f6bf61602ff9955a12b7d1593e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 01:20:18 +0900 Subject: [PATCH 0414/1814] Replace AutodocReporter by switch_source_input() --- CHANGES | 2 ++ doc/extdev/markupapi.rst | 22 ++++++++++++++++++++-- sphinx/ext/autodoc/__init__.py | 5 +++++ sphinx/ext/autodoc/directive.py | 12 +++--------- sphinx/util/docutils.py | 22 +++++++++++++++++++++- 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/CHANGES b/CHANGES index ed76ea4a7..73a75a894 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,8 @@ Deprecated * using a string value for :confval:`html_sidebars` is deprecated and only list values will be accepted at 2.0. +* ``sphinx.ext.autodoc.AutodocReporter`` is replaced by ``sphinx.util.docutils. + switch_source_input()`` and now deprecated. It will be removed in Sphinx-2.0. Features added -------------- diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index df23f164d..8a18e2306 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -117,12 +117,30 @@ Both APIs parse the content into a given node. They are used like this:: node = docutils.nodes.paragraph() # either - from sphinx.ext.autodoc import AutodocReporter - self.state.memo.reporter = AutodocReporter(self.result, self.state.memo.reporter) # override reporter to avoid errors from "include" directive nested_parse_with_titles(self.state, self.result, node) # or self.state.nested_parse(self.result, 0, node) +.. note:: + + ``sphinx.util.docutils.switch_source_input()`` allows to change a target file + during nested_parse. It is useful to mixture contents. For example, ``sphinx. + ext.autodoc`` uses it to parse docstrings. + + from sphinx.util.docutils import switch_source_input + + # Switch source_input between parsing content. + # Inside this context, all parsing errors and warnings are reported as + # happened in new source_input (in this case, ``self.result``). + with switch_source_input(self.state, self.result): + node = docutils.nodes.paragraph() + self.state.nested_parse(self.result, 0, node) + + .. deprecated:: 1.7 + + Since Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this purpose. + For now, it is replaced by ``switch_source_input()``. + If you don't need the wrapping node, you can use any concrete node type and return ``node.children`` from the Directive. diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index c74ca43c9..ebe929ea3 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -15,6 +15,7 @@ import re import sys import inspect import traceback +import warnings from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types @@ -22,6 +23,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx +from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.ext.autodoc.importer import mock, import_module from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA @@ -112,6 +114,9 @@ class AutodocReporter(object): """ def __init__(self, viewlist, reporter): # type: (ViewList, Reporter) -> None + warnings.warn('AutodocRerporter is now deprecated. ' + 'Use sphinx.util.docutils.switch_source_input() instead.', + RemovedInSphinx20Warning) self.viewlist = viewlist self.reporter = reporter diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index f348e105a..78593d27c 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -12,8 +12,9 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList from docutils.utils import assemble_option_dict -from sphinx.ext.autodoc import AutoDirective, AutodocReporter +from sphinx.ext.autodoc import AutoDirective from sphinx.util import logging +from sphinx.util.docutils import switch_source_input from sphinx.util.nodes import nested_parse_with_titles if False: @@ -82,12 +83,7 @@ def process_documenter_options(documenter, config, options): def parse_generated_content(state, content, documenter): # type: (State, StringList, Documenter) -> List[nodes.Node] - try: - # use a custom reporter that correctly assigns lines to source - # filename/description and lineno - old_reporter = state.memo.reporter - state.memo.reporter = AutodocReporter(content, state.memo.reporter) - + with switch_source_input(state, content): if documenter.titles_allowed: node = nodes.section() # necessary so that the child nodes get the right source/line set @@ -99,8 +95,6 @@ def parse_generated_content(state, content, documenter): state.nested_parse(content, 0, node) return node.children - finally: - state.memo.reporter = old_reporter class AutodocDirective(Directive): diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index a745e058a..f4dd96158 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -18,7 +18,7 @@ from contextlib import contextmanager import docutils from docutils.languages import get_language -from docutils.statemachine import ViewList +from docutils.statemachine import StateMachine, ViewList from docutils.parsers.rst import directives, roles, convert_directive_function from docutils.utils import Reporter @@ -33,6 +33,7 @@ if False: # For type annotation from typing import Any, Callable, Dict, Iterator, List, Tuple # NOQA from docutils import nodes # NOQA + from docutils.statemachine import State # NOQA from sphinx.environment import BuildEnvironment # NOQA from sphinx.io import SphinxFileInput # NOQA @@ -216,3 +217,22 @@ def directive_helper(obj, has_content=None, argument_spec=None, option_spec=None raise ExtensionError(__('when adding directive classes, no ' 'additional arguments may be given')) return obj + + +@contextmanager +def switch_source_input(state, content): + # type: (State, ViewList) -> None + """Switch current source input of state temporarily.""" + try: + # remember the original ``get_source_and_line()`` method + get_source_and_line = state.memo.reporter.get_source_and_line + + # replace it by new one + state_machine = StateMachine([], None) + state_machine.input_lines = content + state.memo.reporter.get_source_and_line = state_machine.get_source_and_line + + yield + finally: + # restore the method + state.memo.reporter.get_source_and_line = get_source_and_line From 1ab0d96a5f8b3ef1f07598a80aaf6c1f9eb5076c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 01:31:32 +0900 Subject: [PATCH 0415/1814] Update docstrings --- sphinx/ext/autodoc/directive.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index 78593d27c..077ee5dfd 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -53,6 +53,8 @@ class Options(dict): class DocumenterBridge(object): + """A parameters container for Documenters.""" + def __init__(self, env, reporter, options, lineno): # type: (BuildEnvironment, Reporter, Options, int) -> None self.env = env @@ -70,6 +72,7 @@ class DocumenterBridge(object): def process_documenter_options(documenter, config, options): # type: (Type[Documenter], Config, Dict) -> Options + """Recognize options of Documenter from user input.""" for name in AUTODOC_DEFAULT_OPTIONS: if name not in documenter.option_spec: continue @@ -83,6 +86,7 @@ def process_documenter_options(documenter, config, options): def parse_generated_content(state, content, documenter): # type: (State, StringList, Documenter) -> List[nodes.Node] + """Parse a generated content by Documenter.""" with switch_source_input(state, content): if documenter.titles_allowed: node = nodes.section() From 9b18e83e32942bd1b4b8e636619ec3d479302194 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 01:39:15 +0900 Subject: [PATCH 0416/1814] Make AutoDirective as a simple object (not directive) --- sphinx/ext/autodoc/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ebe929ea3..45195ff41 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1475,11 +1475,11 @@ class InstanceAttributeDocumenter(AttributeDocumenter): AttributeDocumenter.add_content(self, more_content, no_docstring=True) -class AutoDirective(Directive): +class AutoDirective(object): """ - The AutoDirective class is used for all autodoc directives. It dispatches - most of the work to one of the Documenters, which it selects through its - *_registry* dictionary. + A registry of Documenters and attrgetters. + + The *_registry* attribute is used to store registered Documenters. The *_special_attrgetters* attribute is used to customize ``getattr()`` calls that the Documenters make; its entries are of the form ``type: From 8bb6a01210ffc9994b4a2642545fb7b049655558 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 02:21:10 +0900 Subject: [PATCH 0417/1814] Fix mark up --- doc/extdev/markupapi.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index 8a18e2306..6f289ed9f 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -125,7 +125,7 @@ Both APIs parse the content into a given node. They are used like this:: ``sphinx.util.docutils.switch_source_input()`` allows to change a target file during nested_parse. It is useful to mixture contents. For example, ``sphinx. - ext.autodoc`` uses it to parse docstrings. + ext.autodoc`` uses it to parse docstrings:: from sphinx.util.docutils import switch_source_input From c6775bce0778b76efa0bd525fba681ba239c2606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vedran=20Mileti=C4=87?= Date: Thu, 5 Oct 2017 01:07:05 +0200 Subject: [PATCH 0418/1814] Add more EXAMPLES --- EXAMPLES | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/EXAMPLES b/EXAMPLES index 7c88805eb..0b2de95d9 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -34,6 +34,8 @@ Documentation using the alabaster theme * pytest: https://docs.pytest.org/ (customized) * python-apt: https://apt.alioth.debian.org/python-apt-doc/ * PyVisfile: https://documen.tician.de/pyvisfile/ +* Requests: http://www.python-requests.org/ +* searx: https://asciimoo.github.io/searx/ * Tablib: http://docs.python-tablib.org/ * urllib3: https://urllib3.readthedocs.io/ (customized) * Werkzeug: http://werkzeug.pocoo.org/docs/ (customized) @@ -46,6 +48,7 @@ Documentation using the classic theme * APSW: https://rogerbinns.github.io/apsw/ * Arb: http://arblib.org/ * Bazaar: http://doc.bazaar.canonical.com/ (customized) +* Beautiful Soup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/ * Blender: https://docs.blender.org/api/current/ * Bugzilla: https://bugzilla.readthedocs.io/ * Buildbot: https://docs.buildbot.net/latest/ @@ -79,6 +82,8 @@ Documentation using the classic theme * Pyevolve: http://pyevolve.sourceforge.net/ * Pygame: https://www.pygame.org/docs/ (customized) * PyMQI: https://pythonhosted.org/pymqi/ +* PyQt4: http://pyqt.sourceforge.net/Docs/PyQt4/ (customized) +* PyQt5: http://pyqt.sourceforge.net/Docs/PyQt5/ (customized) * Python 2: https://docs.python.org/2/ * Python 3: https://docs.python.org/3/ (customized) * Python Packaging Authority: https://www.pypa.io/ (customized) @@ -121,11 +126,16 @@ Documentation using the nature theme * Alembic: http://alembic.zzzcomputing.com/ * Cython: http://docs.cython.org/ +* easybuild: https://easybuild.readthedocs.io/ * jsFiddle: http://doc.jsfiddle.net/ * libLAS: https://www.liblas.org/ (customized) +* Lmod: https://lmod.readthedocs.io/ * MapServer: http://mapserver.org/ (customized) +* Pandas: https://pandas.pydata.org/pandas-docs/stable/ +* pyglet: https://pyglet.readthedocs.io/ (customized) * Setuptools: https://setuptools.readthedocs.io/ * Spring Python: https://docs.spring.io/spring-python/1.2.x/sphinx/html/ +* StatsModels: http://www.statsmodels.org/ (customized) * Sylli: http://sylli.sourceforge.net/ Documentation using another builtin theme @@ -133,6 +143,7 @@ Documentation using another builtin theme * Breathe: https://breathe.readthedocs.io/ (haiku) * MPipe: https://vmlaker.github.io/mpipe/ (sphinx13) +* NLTK: http://www.nltk.org/ (agogo) * Programmieren mit PyGTK und Glade (German): http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo, customized) * PyPubSub: https://pypubsub.readthedocs.io/ (bizstyle) @@ -150,8 +161,10 @@ Documentation using sphinx_rtd_theme * ASE: https://wiki.fysik.dtu.dk/ase/ * Autofac: http://docs.autofac.org/ * BigchainDB: https://docs.bigchaindb.com/ +* Blocks: https://blocks.readthedocs.io/ * bootstrap-datepicker: https://bootstrap-datepicker.readthedocs.io/ * Certbot: https://letsencrypt.readthedocs.io/ +* Chainer: https://docs.chainer.org/ (customized) * CherryPy: http://docs.cherrypy.org/ * Chainer: https://docs.chainer.org/ * CodeIgniter: https://www.codeigniter.com/user_guide/ @@ -178,14 +191,18 @@ Documentation using sphinx_rtd_theme * Idris: http://docs.idris-lang.org/ * javasphinx: https://bronto-javasphinx.readthedocs.io/ * Julia: https://julia.readthedocs.io/ +* Jupyter Notebook: https://jupyter-notebook.readthedocs.io/ +* Lasagne: https://lasagne.readthedocs.io/ * Linguistica: https://linguistica-uchicago.github.io/lxa5/ * Linux kernel: https://www.kernel.org/doc/html/latest/index.html * MathJax: https://docs.mathjax.org/ * MDTraj: http://mdtraj.org/latest/ (customized) * MICrobial Community Analysis (micca): http://micca.org/docs/latest/ * MicroPython: https://docs.micropython.org/ +* Minds: https://www.minds.org/docs/ (customized) * Mink: http://mink.behat.org/ * Mockery: http://docs.mockery.io/ +* mod_wsgi: https://modwsgi.readthedocs.io/ * MoinMoin: https://moin-20.readthedocs.io/ * Mopidy: https://docs.mopidy.com/ * MyHDL: http://docs.myhdl.org/ @@ -224,13 +241,16 @@ Documentation using sphinx_rtd_theme * Sylius: http://docs.sylius.org/ * Tango Controls: https://tango-controls.readthedocs.io/ (customized) * Topshelf: http://docs.topshelf-project.com/ +* Theano: http://www.deeplearning.net/software/theano/ * ThreatConnect: https://docs.threatconnect.com/ * Tuleap: https://tuleap.net/doc/en/ * TYPO3: https://docs.typo3.org/ (customized) +* uWSGI: https://uwsgi-docs.readthedocs.io/ * Wagtail: http://docs.wagtail.io/ * Web Application Attack and Audit Framework (w3af): http://docs.w3af.org/ * Weblate: https://docs.weblate.org/ * x265: https://x265.readthedocs.io/ +* ZeroNet: https://zeronet.readthedocs.io/ Documentation using sphinx_bootstrap_theme ------------------------------------------ @@ -245,12 +265,14 @@ Documentation using sphinx_bootstrap_theme * Open Dylan: https://opendylan.org/documentation/ * Pootle: http://docs.translatehouse.org/projects/pootle/ * PyUblas: https://documen.tician.de/pyublas/ +* seaborn: https://seaborn.pydata.org/ Documentation using a custom theme or integrated in a website ------------------------------------------------------------- * Apache Cassandra: https://cassandra.apache.org/doc/ * Astropy: http://docs.astropy.org/ +* Bokeh: https://bokeh.pydata.org/ * Boto 3: https://boto3.readthedocs.io/ * CakePHP: https://book.cakephp.org/ * CasperJS: http://docs.casperjs.org/ @@ -263,6 +285,7 @@ Documentation using a custom theme or integrated in a website * Enterprise Toolkit for Acrobat products: https://www.adobe.com/devnet-docs/acrobatetk/ * Gameduino: http://excamera.com/sphinx/gameduino/ +* gensim: https://radimrehurek.com/gensim/ * GeoServer: http://docs.geoserver.org/ * gevent: http://www.gevent.org/ * GHC - Glasgow Haskell Compiler: http://downloads.haskell.org/~ghc/master/users-guide/ @@ -307,6 +330,7 @@ Documentation using a custom theme or integrated in a website * Sulu: http://docs.sulu.io/ * SQLAlchemy: https://docs.sqlalchemy.org/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ +* Twisted: http://twistedmatrix.com/documents/current/ * Ubuntu Packaging Guide: http://packaging.ubuntu.com/html/ * WebFaction: https://docs.webfaction.com/ * WTForms: https://wtforms.readthedocs.io/ @@ -320,8 +344,10 @@ Homepages and other non-documentation sites * Benoit Boissinot: https://bboissin.appspot.com/ (classic, customized) * Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab): https://lab.miletic.net/ (sphinx_rtd_theme) +* Deep Learning Tutorials: http://www.deeplearning.net/tutorial/ (sphinxdoc) * Loyola University Chicago COMP 339-439 Distributed Systems course: http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme) +* Pylearn2: http://www.deeplearning.net/software/pylearn2/ (sphinxdoc, customized) * SciPy Cookbook: https://scipy-cookbook.readthedocs.io/ (sphinx_rtd_theme) * The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc) * Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials: From 464f94c2380b4cb2600735c0c0085e771da2bce4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 15:25:44 +0900 Subject: [PATCH 0419/1814] deprecate formatargspec() and format_annotation() --- CHANGES | 2 ++ sphinx/ext/autodoc/inspector.py | 8 ++++++ tests/test_autodoc.py | 50 --------------------------------- 3 files changed, 10 insertions(+), 50 deletions(-) diff --git a/CHANGES b/CHANGES index ed76ea4a7..2ec7d56bb 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,8 @@ Deprecated * using a string value for :confval:`html_sidebars` is deprecated and only list values will be accepted at 2.0. +* ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use + ``sphinx.util.inspect.Signature`` instead. Features added -------------- diff --git a/sphinx/ext/autodoc/inspector.py b/sphinx/ext/autodoc/inspector.py index 5d157c797..50c5a9082 100644 --- a/sphinx/ext/autodoc/inspector.py +++ b/sphinx/ext/autodoc/inspector.py @@ -10,9 +10,11 @@ """ import typing +import warnings from six import StringIO, string_types +from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.util.inspect import object_description if False: @@ -29,6 +31,9 @@ def format_annotation(annotation): Displaying complex types from ``typing`` relies on its private API. """ + warnings.warn('format_annotation() is now deprecated. ' + 'Please use sphinx.util.inspect.Signature instead.', + RemovedInSphinx20Warning) if isinstance(annotation, typing.TypeVar): # type: ignore return annotation.__name__ if annotation == Ellipsis: @@ -107,6 +112,9 @@ def formatargspec(function, args, varargs=None, varkw=None, defaults=None, An enhanced version of ``inspect.formatargspec()`` that handles typing annotations better. """ + warnings.warn('formatargspec() is now deprecated. ' + 'Please use sphinx.util.inspect.Signature instead.', + RemovedInSphinx20Warning) def format_arg_with_annotation(name): # type: (str) -> str diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 11958800a..989c367b6 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -1108,53 +1108,3 @@ class EnumCls(enum.Enum): val2 = 23 #: doc for val2 val3 = 34 """doc for val3""" - - -def test_type_hints(): - from sphinx.ext.autodoc import formatargspec - from sphinx.util.inspect import getargspec - - try: - from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11 - except (ImportError, SyntaxError): - pytest.skip('Cannot import Python code with function annotations') - - def verify_arg_spec(f, expected): - assert formatargspec(f, *getargspec(f)) == expected - - # Class annotations - verify_arg_spec(f0, '(x: int, y: numbers.Integral) -> None') - - # Generic types with concrete parameters - verify_arg_spec(f1, '(x: typing.List[int]) -> typing.List[int]') - - # TypeVars and generic types with TypeVars - verify_arg_spec(f2, '(x: typing.List[T],' - ' y: typing.List[T_co],' - ' z: T) -> typing.List[T_contra]') - - # Union types - verify_arg_spec(f3, '(x: typing.Union[str, numbers.Integral]) -> None') - - # Quoted annotations - verify_arg_spec(f4, '(x: str, y: str) -> None') - - # Keyword-only arguments - verify_arg_spec(f5, '(x: int, *, y: str, z: str) -> None') - - # Keyword-only arguments with varargs - verify_arg_spec(f6, '(x: int, *args, y: str, z: str) -> None') - - # Space around '=' for defaults - verify_arg_spec(f7, '(x: int = None, y: dict = {}) -> None') - - # Callable types - verify_arg_spec(f8, '(x: typing.Callable[[int, str], int]) -> None') - verify_arg_spec(f9, '(x: typing.Callable) -> None') - - # Tuple types - verify_arg_spec(f10, '(x: typing.Tuple[int, str],' - ' y: typing.Tuple[int, ...]) -> None') - - # Instance annotations - verify_arg_spec(f11, '(x: CustomAnnotation, y: 123) -> None') From 41f9cb200acfa506b8cebed37841fa39a625a719 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 23:44:28 +0900 Subject: [PATCH 0420/1814] Fix doc: now eq role works whole of project --- doc/ext/math.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 2aad7853f..66c24e902 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -102,8 +102,7 @@ or use Python raw strings (``r"raw"``). .. rst:role:: eq - Role for cross-referencing equations via their label. This currently works - only within the same document. Example:: + Role for cross-referencing equations via their label. Example:: .. math:: e^{i\pi} + 1 = 0 :label: euler From 109e01d94b7a9db338b4b0c5eea24aedffa7d245 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 18 Dec 2017 00:59:00 +0900 Subject: [PATCH 0421/1814] Fix mypy violations --- sphinx/ext/autodoc/__init__.py | 6 ++++-- sphinx/ext/autosummary/__init__.py | 8 ++++---- sphinx/util/docutils.py | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 45195ff41..150620a62 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -19,7 +19,6 @@ import warnings from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types -from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx @@ -41,7 +40,10 @@ if False: # For type annotation from types import ModuleType # NOQA from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union # NOQA + from docutils import nodes # NOQA + from docutils.utils import Reporter # NOQA from sphinx.application import Sphinx # NOQA + from sphinx.ext.autodoc.directive import DocumenterBridge # NOQA logger = logging.getLogger(__name__) @@ -271,7 +273,7 @@ class Documenter(object): raise NotImplementedError('must be implemented in subclasses') def __init__(self, directive, name, indent=u''): - # type: (Directive, unicode, unicode) -> None + # type: (DocumenterBridge, unicode, unicode) -> None self.directive = directive self.env = directive.env self.options = directive.genopt diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index b56f649bf..3294709ad 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -72,7 +72,7 @@ from sphinx import addnodes from sphinx.environment.adapters.toctree import TocTree from sphinx.util import import_object, rst, logging from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.ext.autodoc.directive import Options +from sphinx.ext.autodoc.directive import DocumenterBridge, Options from sphinx.ext.autodoc.importer import import_module if False: @@ -153,9 +153,9 @@ def autosummary_table_visit_html(self, node): # -- autodoc integration ------------------------------------------------------- -class FakeDirective(object): - env = {} # type: Dict - genopt = Options() +class FakeDirective(DocumenterBridge): + def __init__(self): + super(FakeDirective, self).__init__({}, None, Options(), 0) # type: ignore def get_documenter(obj, parent): diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index f4dd96158..5377e493c 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -31,7 +31,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/( if False: # For type annotation - from typing import Any, Callable, Dict, Iterator, List, Tuple # NOQA + from typing import Any, Callable, Dict, Generator, Iterator, List, Tuple # NOQA from docutils import nodes # NOQA from docutils.statemachine import State # NOQA from sphinx.environment import BuildEnvironment # NOQA @@ -221,7 +221,7 @@ def directive_helper(obj, has_content=None, argument_spec=None, option_spec=None @contextmanager def switch_source_input(state, content): - # type: (State, ViewList) -> None + # type: (State, ViewList) -> Generator """Switch current source input of state temporarily.""" try: # remember the original ``get_source_and_line()`` method From 46b18962283d4ed7cab4e87a737ab9001d6933aa Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 17 Dec 2017 17:56:03 +0100 Subject: [PATCH 0422/1814] Again rewording docs about numfig_secnum_depth --- doc/config.rst | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index fc87c4ddc..8f4656060 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -335,14 +335,21 @@ General configuration .. confval:: numfig_secnum_depth - The scope for numbering: ``0`` means "continuous numbering", - ``1`` means "reset per section" - (i.e. numbers will be x.1, x.2, x.3 ... with x the section number, - assuming that the :rst:dir:`toctree` directive was used with its option - ``:numbered:``), - ``2`` means "per subsection" - (i.e. numbers will be x.y.1, x.y.2, ...), - and so on. Default is ``1``. + - if set to ``0``, figures, tables and code-blocks are continuously numbered + starting at ``1``. + - if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x`` + the section number (top level sectioning; no ``x.`` if no section). + This naturally applies only if section numbering has been activated via + the ``:numbered:`` option of the :rst:dir:`toctree` directive. + - ``2`` means that numbers will be ``x.y.1``, ``x.y.2``, ... if located in + a sub-section (but still ``x.1``, ``x.2``, ... if located directly under a + section and ``1``, ``2``, ... if not in any top level section.) + - etc... + + .. note:: + + The LaTeX builder currently ignores this configuration setting. It will + obey it at Sphinx 1.7. .. versionadded:: 1.3 From 27285dfeed9f732727be7500335e34b8434a4478 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Sun, 17 Dec 2017 13:56:06 -0500 Subject: [PATCH 0423/1814] use :rst:role: markup --- doc/ext/math.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 5fdf842ee..6dddd7ece 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -48,9 +48,9 @@ or use Python raw strings (``r"raw"``). If ``True``, displayed math equations are numbered across pages in html and related (epub, ...) output. The :confval:`numfig` config value must be - enabled and :confval:`numfig_secnum_depth` is respected. The ``:eq:`` role - must be used to reference equation numbers, not the ``:numref:`` role. - Default is ``False``. + enabled and :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` + role must be used to reference equation numbers, not the :rst:role:`numref` + role. Default is ``False``. :mod:`.mathbase` defines these new markup elements: From 56d4e0c80d8c63b409ed33e2bf241bdc05ef9d64 Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Sun, 17 Dec 2017 14:02:32 -0500 Subject: [PATCH 0424/1814] make math_numfig default to True --- doc/ext/math.rst | 8 ++++---- sphinx/ext/mathbase.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 6dddd7ece..fe0baefea 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -47,10 +47,10 @@ or use Python raw strings (``r"raw"``). .. confval:: math_numfig If ``True``, displayed math equations are numbered across pages in html and - related (epub, ...) output. The :confval:`numfig` config value must be - enabled and :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` - role must be used to reference equation numbers, not the :rst:role:`numref` - role. Default is ``False``. + related (epub, ...) output when :confval:`numfig` is enabled. + :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` role must + be used to reference equation numbers, not the :rst:role:`numref` role. + Default is ``True``. :mod:`.mathbase` defines these new markup elements: diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index 5f353ac9c..50c4b157f 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -365,7 +365,7 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors): # type: (Sphinx, Tuple[Callable, Any], Tuple[Callable, Any]) -> None app.add_config_value('math_number_all', False, 'env') app.add_config_value('math_eqref_format', None, 'env', string_classes) - app.add_config_value('math_numfig', False, 'env') + app.add_config_value('math_numfig', True, 'env') app.add_domain(MathDomain) app.add_node(math, override=True, latex=(latex_visit_math, None), From af46ed16b023ad2b4a2ff4c71b57f638ce7ca363 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 18 Dec 2017 00:26:36 +0100 Subject: [PATCH 0425/1814] Fixes #4315: latex_toplevel_sectioning induced \chapter in article class --- sphinx/writers/latex.py | 45 +++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 2c2b62659..39c7bc81e 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -48,6 +48,8 @@ BEGIN_DOC = r''' URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:') SECNUMDEPTH = 3 +LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection", + "subsubsection", "paragraph", "subparagraph"] DEFAULT_SETTINGS = { 'latex_engine': 'pdflatex', @@ -501,8 +503,6 @@ def rstdim_to_latexdim(width_str): class LaTeXTranslator(nodes.NodeVisitor): - sectionnames = ["part", "chapter", "section", "subsection", - "subsubsection", "paragraph", "subparagraph"] ignore_missing_images = False @@ -532,16 +532,6 @@ class LaTeXTranslator(nodes.NodeVisitor): self.compact_list = 0 self.first_param = 0 - # determine top section level - if builder.config.latex_toplevel_sectioning: - self.top_sectionlevel = \ - self.sectionnames.index(builder.config.latex_toplevel_sectioning) - else: - if document.settings.docclass == 'howto': - self.top_sectionlevel = 2 - else: - self.top_sectionlevel = 1 - # sort out some elements self.elements = DEFAULT_SETTINGS.copy() self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {})) @@ -564,11 +554,30 @@ class LaTeXTranslator(nodes.NodeVisitor): }) if builder.config.latex_keep_old_macro_names: self.elements['sphinxpkgoptions'] = '' + + # we assume LaTeX class provides \chapter command except in case + # of non-Japanese 'howto' case + self.sectionnames = LATEXSECTIONNAMES[:] if document.settings.docclass == 'howto': docclass = builder.config.latex_docclass.get('howto', 'article') + if docclass[0] == 'j': # Japanese class... + pass + else: + self.sectionnames.remove('chapter') else: docclass = builder.config.latex_docclass.get('manual', 'report') self.elements['docclass'] = docclass + + # determine top section level + self.top_sectionlevel = 1 + if builder.config.latex_toplevel_sectioning: + try: + self.top_sectionlevel = \ + self.sectionnames.index(builder.config.latex_toplevel_sectioning) + except ValueError: + logger.warning('unknown %r toplevel_sectioning for class %r' % + (builder.config.latex_toplevel_sectioning, docclass)) + if builder.config.today: self.elements['date'] = builder.config.today else: @@ -631,21 +640,23 @@ class LaTeXTranslator(nodes.NodeVisitor): usepackages = (declare_package(*p) for p in builder.usepackages) self.elements['usepackages'] += "\n".join(usepackages) if document.get('tocdepth'): - # redece tocdepth if `part` or `chapter` is used for top_sectionlevel + # reduce tocdepth if `part` or `chapter` is used for top_sectionlevel # tocdepth = -1: show only parts # tocdepth = 0: show parts and chapters # tocdepth = 1: show parts, chapters and sections # tocdepth = 2: show parts, chapters, sections and subsections # ... + tocdepth = document['tocdepth'] + self.top_sectionlevel - 2 - maxdepth = len(self.sectionnames) - self.top_sectionlevel - if tocdepth > maxdepth: + if len(self.sectionnames) < 7 and self.top_sectionlevel > 0: + tocdepth += 1 # because top_sectionlevel is shifted by -1 + if tocdepth > 5: # 5 corresponds to subparagraph logger.warning('too large :maxdepth:, ignored.') - tocdepth = maxdepth + tocdepth = 5 self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth if tocdepth >= SECNUMDEPTH: - # Increase secnumdepth if tocdepth is depther than default SECNUMDEPTH + # Increase secnumdepth if tocdepth is deeper than default SECNUMDEPTH self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' % tocdepth if getattr(document.settings, 'contentsname', None): From 245876c6e7917f315857ee59e4c456959f4e6e5c Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 18 Dec 2017 08:13:28 +0100 Subject: [PATCH 0426/1814] Add test for latex_toplevel_sectioning --- tests/roots/test-latex-toplevel/conf.py | 12 ++++++++++++ tests/roots/test-latex-toplevel/index.rst | 8 ++++++++ tests/roots/test-latex-toplevel/indexhowto.rst | 10 ++++++++++ tests/roots/test-latex-toplevel/indexmanual.rst | 13 +++++++++++++ tests/test_build_latex.py | 14 ++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 tests/roots/test-latex-toplevel/conf.py create mode 100644 tests/roots/test-latex-toplevel/index.rst create mode 100644 tests/roots/test-latex-toplevel/indexhowto.rst create mode 100644 tests/roots/test-latex-toplevel/indexmanual.rst diff --git a/tests/roots/test-latex-toplevel/conf.py b/tests/roots/test-latex-toplevel/conf.py new file mode 100644 index 000000000..88efc87ed --- /dev/null +++ b/tests/roots/test-latex-toplevel/conf.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' + +latex_toplevel_sectioning = 'part' + +latex_documents = [ + ('indexmanual', 'SphinxManual.tex', 'Test toplevel manual', + 'Sphinx', 'manual'), + ('indexhowto', 'SphinxHowTo.tex', 'Test toplevel howto', + 'Sphinx', 'howto'), +] diff --git a/tests/roots/test-latex-toplevel/index.rst b/tests/roots/test-latex-toplevel/index.rst new file mode 100644 index 000000000..833bc67bb --- /dev/null +++ b/tests/roots/test-latex-toplevel/index.rst @@ -0,0 +1,8 @@ +=================== +test-latex-toplevel +=================== + +.. toctree:: + + indexmanual + indexhowto diff --git a/tests/roots/test-latex-toplevel/indexhowto.rst b/tests/roots/test-latex-toplevel/indexhowto.rst new file mode 100644 index 000000000..7c0c92d1a --- /dev/null +++ b/tests/roots/test-latex-toplevel/indexhowto.rst @@ -0,0 +1,10 @@ +========================= +test-latex-toplevel-howto +========================= + +This is a part +============== + +This is a section +----------------- + diff --git a/tests/roots/test-latex-toplevel/indexmanual.rst b/tests/roots/test-latex-toplevel/indexmanual.rst new file mode 100644 index 000000000..2181b1426 --- /dev/null +++ b/tests/roots/test-latex-toplevel/indexmanual.rst @@ -0,0 +1,13 @@ +========================== +test-latex-toplevel-manual +========================== + +First part +========== + +This is chapter +--------------- + +This is section +~~~~~~~~~~~~~~~ + diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index b1ba73730..edaf107c4 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1039,3 +1039,17 @@ def test_latex_image_in_parsed_literal(app, status, warning): assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\\height}' '{\\scalebox{2.000000}{\\sphinxincludegraphics[height=1cm]{{pic}.png}}}' '}AFTER') in result + + +@pytest.mark.sphinx('latex', testroot='latex-toplevel') +def test_latex_toplevel_is_part(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') + assert ('\\part{First part}') in result + assert ('\\chapter{This is chapter}') in result + assert ('\\section{This is section}') in result + + result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') + assert ('\\part{This is a part}') in result + assert ('\\section{This is a section}') in result From 72bffcf0f4bb81fe934c1065d27c8bff1e510fe9 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 18 Dec 2017 11:15:51 +0100 Subject: [PATCH 0427/1814] Add precision to docs of latex_toplevel_sectioning --- doc/config.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 8f4656060..1f222451d 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -1617,10 +1617,15 @@ These options influence LaTeX output. See further :doc:`latex`. .. confval:: latex_toplevel_sectioning This value determines the topmost sectioning unit. It should be chosen from - ``part``, ``chapter`` or ``section``. The default is ``None``; the topmost - sectioning unit is switched by documentclass. ``section`` is used if + ``'part'``, ``'chapter'`` or ``'section'``. The default is ``None``; + the topmost + sectioning unit is switched by documentclass: ``section`` is used if documentclass will be ``howto``, otherwise ``chapter`` will be used. + Note that if LaTeX uses ``\part`` command, then the numbering of sectioning + units one level deep gets off-sync with HTML numbering, because LaTeX + numbers continuously ``\chapter`` (or ``\section`` for ``howto``.) + .. versionadded:: 1.4 .. confval:: latex_appendices From 9a392952917b5bbd560accde1037e4e7c955e96d Mon Sep 17 00:00:00 2001 From: Oliver Jahn Date: Mon, 18 Dec 2017 06:41:50 -0500 Subject: [PATCH 0428/1814] add version --- doc/ext/math.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index fe0baefea..de7ff485b 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -52,6 +52,8 @@ or use Python raw strings (``r"raw"``). be used to reference equation numbers, not the :rst:role:`numref` role. Default is ``True``. + .. versionadded:: 1.7 + :mod:`.mathbase` defines these new markup elements: .. rst:role:: math From a102e8e29b23e08fb779c8153f03beb6fa8fe196 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 12:19:04 +0100 Subject: [PATCH 0429/1814] setup.py: Include 'flake8' in 'test' requirements We are using this in our testing and actually need it for the flake8 plugin, so include this in the list of 'test' requirements. Signed-off-by: Stephen Finucane --- .travis.yml | 1 - setup.py | 1 + tox.ini | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d065b178..a5214057d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,6 @@ install: - pip install -U pip setuptools - pip install docutils==$DOCUTILS - pip install .[test,websupport] - - pip install flake8 - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi script: - flake8 diff --git a/setup.py b/setup.py index 10a513166..5c0b70959 100644 --- a/setup.py +++ b/setup.py @@ -72,6 +72,7 @@ extras_require = { 'pytest', 'pytest-cov', 'html5lib', + 'flake8', ], 'test:python_version<"3"': [ 'enum34', diff --git a/tox.ini b/tox.ini index 00b3c99e2..2ea05641b 100644 --- a/tox.ini +++ b/tox.ini @@ -38,7 +38,6 @@ deps= {[testenv]deps} [testenv:flake8] -deps=flake8 commands=flake8 [testenv:pylint] From 41c19ddf91018e2b9a8c0001a24a78f3ecb893be Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 2 Oct 2017 22:28:22 +0100 Subject: [PATCH 0430/1814] tests: Skip tests with missing binaries While there are already some skips included here, they clearly aren't doing their job and the test fail locally. Resolve this. Signed-off-by: Stephen Finucane --- tests/test_ext_math.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index 92501a3db..4d2fb9836 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -9,11 +9,25 @@ :license: BSD, see LICENSE for details. """ +import os import re +import subprocess import pytest +def has_binary(binary): + try: + subprocess.check_output([binary]) + except OSError as e: + if e.errno == os.errno.ENOENT: + # handle file not found error. + return False + else: + return True + return True + + @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides = {'extensions': ['sphinx.ext.jsmath'], 'jsmath_path': 'dummy.js'}) @@ -34,6 +48,8 @@ def test_jsmath(app, status, warning): assert '

\na + 1 < b
' in content +@pytest.mark.skipif(not has_binary('dvipng'), + reason='Requires dvipng" binary') @pytest.mark.sphinx('html', testroot='ext-math-simple', confoverrides = {'extensions': ['sphinx.ext.imgmath']}) def test_imgmath_png(app, status, warning): @@ -49,6 +65,8 @@ def test_imgmath_png(app, status, warning): assert re.search(html, content, re.S) +@pytest.mark.skipif(not has_binary('dvisvgm'), + reason='Requires dvisvgm" binary') @pytest.mark.sphinx('html', testroot='ext-math-simple', confoverrides={'extensions': ['sphinx.ext.imgmath'], 'imgmath_image_format': 'svg'}) From e243e827236467b67b057b83131248ef1742aacb Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 26 Oct 2017 16:49:44 +0100 Subject: [PATCH 0431/1814] tests: Ignore tests using 'collect_ignore' Per the pytest docs [1], this is the preferred way to ignore tests. This necessitates removing the 'test-async' target as it no longer makes any sense. [1] https://docs.pytest.org/en/latest/example/pythoncollection.html Signed-off-by: Stephen Finucane --- .travis.yml | 2 +- Makefile | 4 ++-- tests/conftest.py | 5 +++++ tox.ini | 15 ++------------- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index a5214057d..1d6694b3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,5 +42,5 @@ install: - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi script: - flake8 - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test-async; fi + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test; fi - if [[ $TRAVIS_PYTHON_VERSION != '3.6' ]]; then make test; fi diff --git a/Makefile b/Makefile index 5b3d5aad4..e4abba088 100644 --- a/Makefile +++ b/Makefile @@ -69,11 +69,11 @@ reindent: .PHONY: test test: - @cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST) + @cd tests; $(PYTHON) run.py -v $(TEST) .PHONY: test-async test-async: - @cd tests; $(PYTHON) run.py -v $(TEST) + @echo "This target no longer does anything and will be removed imminently" .PHONY: covertest covertest: diff --git a/tests/conftest.py b/tests/conftest.py index 28dbd6ed4..c9719bf80 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,12 +8,17 @@ """ import os +import sys import pytest from sphinx.testing.path import path pytest_plugins = 'sphinx.testing.fixtures' +# Disable Python version-specific +if sys.version_info < (3, 5): + collect_ignore = ['py35'] + @pytest.fixture(scope='session') def rootdir(): diff --git a/tox.ini b/tox.ini index 2ea05641b..051b56381 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion=2.0 -envlist=flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} +envlist=docs,flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} [testenv] passenv = https_proxy http_proxy no_proxy @@ -13,9 +13,7 @@ deps = setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= - {envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx \ - --durations 25 {posargs} - sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html + {envpython} -Wall tests/run.py --cov sphinx --durations 25 {posargs} [testenv:du11] deps= @@ -47,15 +45,6 @@ deps= commands= pylint --rcfile utils/pylintrc sphinx -[testenv:py27] -deps= - {[testenv]deps} - -[testenv:py35] -commands= - {envpython} -Wall tests/run.py --cov=sphinx --durations 25 {posargs} - sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html - [testenv:mypy] basepython=python3 deps= From c8d56236c9286adca9664782debf3b1c768ef92d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 26 Oct 2017 16:59:46 +0100 Subject: [PATCH 0432/1814] tests: Ignore roots using 'collect_ignore' This is slightly cleaner than how we're doing this at the moment. Signed-off-by: Stephen Finucane --- tests/conftest.py | 5 ++++- tests/run.py | 11 +---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index c9719bf80..9ea99dbd9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,9 +15,12 @@ from sphinx.testing.path import path pytest_plugins = 'sphinx.testing.fixtures' +# Exclude 'roots' dirs for pytest test collector +collect_ignore = ['roots'] + # Disable Python version-specific if sys.version_info < (3, 5): - collect_ignore = ['py35'] + collect_ignore += ['py35'] @pytest.fixture(scope='session') diff --git a/tests/run.py b/tests/run.py index a8439ba02..2116e345c 100755 --- a/tests/run.py +++ b/tests/run.py @@ -55,14 +55,5 @@ os.makedirs(tempdir) print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0]) sys.stdout.flush() -# exclude 'roots' dirs for pytest test collector -ignore_paths = [ - os.path.relpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), sub)) - for sub in ('roots',) -] -args = sys.argv[1:] -for ignore_path in ignore_paths: - args.extend(['--ignore', ignore_path]) - import pytest # NOQA -sys.exit(pytest.main(args)) +sys.exit(pytest.main(sys.argv[1:])) From 5d812ccefc034e8cc93223454f3e6fa36528546a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 26 Oct 2017 18:11:13 +0100 Subject: [PATCH 0433/1814] tox: Add 'coverage' target Enabling coverage results in an increase in runtime, and while this may be an acceptable compromise for some developers, it's not necessarily something we need to run all the time. Move it to a separate target so it can be run only by those who wish to use it. Signed-off-by: Stephen Finucane --- tox.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 051b56381..05074761e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion=2.0 -envlist=docs,flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} +envlist=docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} [testenv] passenv = https_proxy http_proxy no_proxy @@ -12,8 +12,9 @@ deps = .[test,websupport] setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild + coverage: PYTEST_ADDOPTS = --cov sphinx commands= - {envpython} -Wall tests/run.py --cov sphinx --durations 25 {posargs} + {envpython} -Wall tests/run.py --durations 25 {posargs} [testenv:du11] deps= From fd1df0815b8fd83cd7918a9fcf5eea734161f336 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 27 Oct 2017 10:11:10 +0100 Subject: [PATCH 0434/1814] tox: Make further use of factor-conditional deps This is how we reduce boilerplate [1]. Succinctness FTW. [1] https://tox.readthedocs.io/en/latest/config.html#factors-and-factor-conditional-settings Signed-off-by: Stephen Finucane --- tox.ini | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/tox.ini b/tox.ini index 05074761e..22a34f6f8 100644 --- a/tox.ini +++ b/tox.ini @@ -10,32 +10,16 @@ passenv = https_proxy http_proxy no_proxy # https://tox.readthedocs.io/en/latest/config.html#confval-extras=MULTI-LINE-LIST deps = .[test,websupport] + du11: docutils==0.11 + du12: docutils==0.12 + du13: docutils==0.13.1 + du14: docutils==0.14 setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild coverage: PYTEST_ADDOPTS = --cov sphinx commands= {envpython} -Wall tests/run.py --durations 25 {posargs} -[testenv:du11] -deps= - docutils==0.11 - {[testenv]deps} - -[testenv:du12] -deps= - docutils==0.12 - {[testenv]deps} - -[testenv:du13] -deps= - docutils==0.13.1 - {[testenv]deps} - -[testenv:du14] -deps= - docutils==0.14 - {[testenv]deps} - [testenv:flake8] commands=flake8 From f74b6756ac80e7a07f2b7c8a7f304e245404c116 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 14:19:28 +0100 Subject: [PATCH 0435/1814] setup.cfg: Restructure file Place configuration of the package itself first in the file, followed by configuration of other tools. Signed-off-by: Stephen Finucane --- setup.cfg | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/setup.cfg b/setup.cfg index cb6887fc3..00e7833d3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,11 +1,20 @@ +[metadata] +license_file = LICENSE + [egg_info] tag_build = .dev tag_date = true +[bdist_wheel] +universal = 1 + [aliases] release = egg_info -Db '' upload = upload --sign --identity=36580288 +[build_sphinx] +warning-is-error = 1 + [extract_messages] mapping_file = babel.cfg output_file = sphinx/locale/sphinx.pot @@ -20,12 +29,6 @@ output_dir = sphinx/locale/ domain = sphinx directory = sphinx/locale/ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE - [flake8] max-line-length = 95 ignore = E116,E241,E251,E741 @@ -40,6 +43,3 @@ follow_imports = skip incremental = True check_untyped_defs = True warn_unused_ignores = True - -[build_sphinx] -warning-is-error = 1 From 393f59da004baaac3a4d1f03a0b4585ed71f76f7 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 15:20:21 +0100 Subject: [PATCH 0436/1814] Improve README We're going to be adding additional badges to this but, before we do that, we should improve the README and remove a lot of the duplication that has built up here. The 'long_description' from 'setup.py' is moved into the README as there is serious value in displaying this on GitHub, as much as there is value in including the badges and other content from README. Signed-off-by: Stephen Finucane --- README.rst | 111 +++++++++++++++++++++++++++++------------------------ setup.py | 30 +-------------- 2 files changed, 63 insertions(+), 78 deletions(-) diff --git a/README.rst b/README.rst index 1e027ec8e..54493bb8b 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,7 @@ +======== + Sphinx +======== + .. image:: https://img.shields.io/pypi/v/sphinx.svg :target: https://pypi.python.org/pypi/Sphinx .. image:: https://readthedocs.org/projects/sphinx/badge/ @@ -6,40 +10,81 @@ .. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master :target: https://travis-ci.org/sphinx-doc/sphinx -================= -README for Sphinx -================= +Sphinx is a tool that makes it easy to create intelligent and beautiful +documentation for Python projects (or other documents consisting of multiple +reStructuredText sources), written by Georg Brandl. It was originally created +for the new Python documentation, and has excellent facilities for Python +project documentation, but C/C++ is supported as well, and more languages are +planned. -This is the Sphinx documentation generator, see http://www.sphinx-doc.org/. +Sphinx uses reStructuredText as its markup language, and many of its strengths +come from the power and straightforwardness of reStructuredText and its parsing +and translating suite, the Docutils. +Among its features are the following: -Installing -========== +* Output formats: HTML (including derivative formats such as HTML Help, Epub + and Qt Help), plain text, manual pages and LaTeX or direct PDF output + using rst2pdf +* Extensive cross-references: semantic markup and automatic links + for functions, classes, glossary terms and similar pieces of information +* Hierarchical structure: easy definition of a document tree, with automatic + links to siblings, parents and children +* Automatic indices: general index as well as a module index +* Code handling: automatic highlighting using the Pygments highlighter +* Flexible HTML output using the Jinja 2 templating engine +* Various extensions are available, e.g. for automatic testing of snippets + and inclusion of appropriately formatted docstrings +* Setuptools integration -Install from PyPI to use stable version:: +For more information, refer to the `the documentation`__. + +__ http://www.sphinx-doc.org/ + +Installation +============ + +Sphinx is published on `PyPI`__ and can be installed from there:: pip install -U sphinx -Install from PyPI to use beta version:: +We also publish beta releases:: pip install -U --pre sphinx -Install from newest dev version in stable branch:: +If you wish to install `Sphinx` for development purposes, refer to `the +contributors guide`__. - pip install git+https://github.com/sphinx-doc/sphinx@stable +__ https://pypi.python.org/pypi/Sphinx +__ CONTRIBUTING.rst -Install from newest dev version in master branch:: +Documentation +============= - pip install git+https://github.com/sphinx-doc/sphinx +Documentation is available from `sphinx-doc.org`__. -Install from cloned source:: +__ http://www.sphinx-doc.org/ - pip install . +Testing +======= -Install from cloned source as editable:: +Continuous testing is provided by `Travis`__ (for unit tests and style checks +on Linux), `AppVeyor`__ (for unit tests on Windows), and `CircleCI`__ (for +large processes like TeX compilation). - pip install -e . +For information on running tests locally, refer to `the contributors guide`__. +__ https://travis-ci.org/sphinx-doc/sphinx +__ https://ci.appveyor.com/project/sphinxdoc/sphinx +__ https://circleci.com/gh/sphinx-doc/sphinx +__ CONTRIBUTING.rst + +Contributing +============ + +Refer to `the contributors guide`_. + +__ CONTRIBUTING.rst Release signatures ================== @@ -48,37 +93,3 @@ Releases are signed with following keys: * `498D6B9E `_ * `5EBA0E07 `_ - -Reading the docs -================ - -You can read them online at . - -Or, after installing:: - - cd doc - make html - -Then, direct your browser to ``_build/html/index.html``. - -Testing -======= - -To run the tests with the interpreter available as ``python``, use:: - - make test - -If you want to use a different interpreter, e.g. ``python3``, use:: - - PYTHON=python3 make test - -Continuous testing runs on travis: https://travis-ci.org/sphinx-doc/sphinx - - -Contributing -============ - -See `CONTRIBUTING.rst`__ - -.. __: CONTRIBUTING.rst - diff --git a/setup.py b/setup.py index 5c0b70959..6b7de9129 100644 --- a/setup.py +++ b/setup.py @@ -8,34 +8,8 @@ from distutils.cmd import Command import sphinx -long_desc = ''' -Sphinx is a tool that makes it easy to create intelligent and beautiful -documentation for Python projects (or other documents consisting of multiple -reStructuredText sources), written by Georg Brandl. It was originally created -for the new Python documentation, and has excellent facilities for Python -project documentation, but C/C++ is supported as well, and more languages are -planned. - -Sphinx uses reStructuredText as its markup language, and many of its strengths -come from the power and straightforwardness of reStructuredText and its parsing -and translating suite, the Docutils. - -Among its features are the following: - -* Output formats: HTML (including derivative formats such as HTML Help, Epub - and Qt Help), plain text, manual pages and LaTeX or direct PDF output - using rst2pdf -* Extensive cross-references: semantic markup and automatic links - for functions, classes, glossary terms and similar pieces of information -* Hierarchical structure: easy definition of a document tree, with automatic - links to siblings, parents and children -* Automatic indices: general index as well as a module index -* Code handling: automatic highlighting using the Pygments highlighter -* Flexible HTML output using the Jinja 2 templating engine -* Various extensions are available, e.g. for automatic testing of snippets - and inclusion of appropriately formatted docstrings -* Setuptools integration -''' +with open('README.rst') as f: + long_desc = f.read() if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 4): print('ERROR: Sphinx requires at least Python 2.7 or 3.4 to run.') From a6f0ba0fc95db043a08d4379481d69a9cb917453 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 15:29:35 +0100 Subject: [PATCH 0437/1814] README: Cleanup badges Add AppVeyor badge and include 'alt' attributes for the others. Signed-off-by: Stephen Finucane --- README.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.rst b/README.rst index 54493bb8b..39c58143b 100644 --- a/README.rst +++ b/README.rst @@ -4,11 +4,23 @@ .. image:: https://img.shields.io/pypi/v/sphinx.svg :target: https://pypi.python.org/pypi/Sphinx + :alt: Package on PyPi + .. image:: https://readthedocs.org/projects/sphinx/badge/ :target: http://www.sphinx-doc.org/ :alt: Documentation Status + .. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master :target: https://travis-ci.org/sphinx-doc/sphinx + :alt: Build Status (Travis CI) + +.. image:: https://ci.appveyor.com/api/projects/status/github/sphinx-doc/sphinx?branch=master&svg=true + :target: https://ci.appveyor.com/project/sphinxdoc/sphinx + :alt: Build Status (AppVeyor) + +.. image:: https://circleci.com/gh/sphinx-doc/sphinx.svg?style=shield + :target: https://circleci.com/gh/sphinx-doc/sphinx + :alt: Build Status (CircleCI) Sphinx is a tool that makes it easy to create intelligent and beautiful documentation for Python projects (or other documents consisting of multiple From 04995b703fbf43345ee805a140a64f6bf78b0ff9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Dec 2017 00:05:57 +0900 Subject: [PATCH 0438/1814] Fix typo --- doc/extdev/markupapi.rst | 2 +- sphinx/ext/autodoc/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index 6f289ed9f..97abc17b9 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -138,7 +138,7 @@ Both APIs parse the content into a given node. They are used like this:: .. deprecated:: 1.7 - Since Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this purpose. + Until Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this purpose. For now, it is replaced by ``switch_source_input()``. If you don't need the wrapping node, you can use any concrete node type and diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 150620a62..68f78eeb2 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -116,7 +116,7 @@ class AutodocReporter(object): """ def __init__(self, viewlist, reporter): # type: (ViewList, Reporter) -> None - warnings.warn('AutodocRerporter is now deprecated. ' + warnings.warn('AutodocReporter is now deprecated. ' 'Use sphinx.util.docutils.switch_source_input() instead.', RemovedInSphinx20Warning) self.viewlist = viewlist From 25b96b833d79936734df5f23ee055b59969cd6a2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Dec 2017 00:09:49 +0900 Subject: [PATCH 0439/1814] Revert the changes of directive_helper --- sphinx/util/docutils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 5377e493c..3cd257cba 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -31,7 +31,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/( if False: # For type annotation - from typing import Any, Callable, Dict, Generator, Iterator, List, Tuple # NOQA + from typing import Any, Callable, Generator, Iterator, List, Tuple # NOQA from docutils import nodes # NOQA from docutils.statemachine import State # NOQA from sphinx.environment import BuildEnvironment # NOQA @@ -205,12 +205,12 @@ def is_html5_writer_available(): return __version_info__ > (0, 13, 0) -def directive_helper(obj, has_content=None, argument_spec=None, option_spec=None, **options): - # type: (Any, bool, Tuple[int, int, bool], Dict, Any) -> Any +def directive_helper(obj, has_content=None, argument_spec=None, **option_spec): + # type: (Any, bool, Tuple[int, int, bool], Any) -> Any if isinstance(obj, (types.FunctionType, types.MethodType)): obj.content = has_content # type: ignore obj.arguments = argument_spec or (0, 0, False) # type: ignore - obj.options = option_spec or options # type: ignore + obj.options = option_spec # type: ignore return convert_directive_function(obj) else: if has_content or argument_spec or option_spec: From 242bf9a38a9aa179e4f40c57d4b9a7ff90695127 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Dec 2017 00:11:28 +0900 Subject: [PATCH 0440/1814] Fix typo --- doc/extdev/markupapi.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/extdev/markupapi.rst b/doc/extdev/markupapi.rst index 97abc17b9..ffa08cae7 100644 --- a/doc/extdev/markupapi.rst +++ b/doc/extdev/markupapi.rst @@ -124,7 +124,7 @@ Both APIs parse the content into a given node. They are used like this:: .. note:: ``sphinx.util.docutils.switch_source_input()`` allows to change a target file - during nested_parse. It is useful to mixture contents. For example, ``sphinx. + during nested_parse. It is useful to mixed contents. For example, ``sphinx. ext.autodoc`` uses it to parse docstrings:: from sphinx.util.docutils import switch_source_input From 76bd63187232030b7cff56153e7a648a190eebb6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 26 Oct 2017 18:15:58 +0100 Subject: [PATCH 0441/1814] travis: Start using tox for testing This allows us to validate and reuse the testing tools we use locally for "gate" tests and moves us closer to the eventual goal of deprecating the Makefile targets. This involves adding two new targets to the list of default targets run by tox - docs and mypy. Note that we don't use tox-travis because, wonderful though it may be, configuring it to exclude as many of the tests as we want to exclude is a little convoluted (we have a big test matrix). Signed-off-by: Stephen Finucane --- .travis.yml | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d6694b3d..900853cf7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,45 +2,40 @@ language: python sudo: false dist: trusty cache: pip -python: - - "pypy-5.4.1" - - "3.6" - - "3.5" - - "3.4" - - "2.7" - - "nightly" + env: global: - - TEST='-v --durations 25' - PYTHONFAULTHANDLER=x - PYTHONWARNINGS=all - SKIP_LATEX_BUILD=1 - matrix: - - DOCUTILS=0.13.1 - - DOCUTILS=0.14 + matrix: - exclude: - - python: "3.4" - env: DOCUTILS=0.13.1 - - python: "3.5" - env: DOCUTILS=0.13.1 - - python: "3.6" - env: DOCUTILS=0.13.1 - - python: nightly - env: DOCUTILS=0.13.1 - - python: "pypy-5.4.1" - env: DOCUTILS=0.13.1 + include: + - python: 'pypy' + env: TOXENV=pypy + - python: '2.7' + env: TOXENV=du13 + - python: '3.4' + env: TOXENV=py34 + - python: '3.5' + env: TOXENV=py35 + - python: '3.6' + env: TOXENV=py36 + - python: 'nightly' + env: TOXENV=py37 + - python: '3.6' + env: TOXENV=mypy + - python: '2.7' + env: TOXENV=flake8 + addons: apt: packages: - graphviz - imagemagick + install: - - pip install -U pip setuptools - - pip install docutils==$DOCUTILS - - pip install .[test,websupport] - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi + - pip install -U tox + script: - - flake8 - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test; fi - - if [[ $TRAVIS_PYTHON_VERSION != '3.6' ]]; then make test; fi + - tox -- -v From 638e6467669d5ebc2111a5f7fb2c5612a8bcf1e5 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 3 Oct 2017 10:00:40 +0100 Subject: [PATCH 0442/1814] doc: Rework CONTRIBUTING to encourage use of tox Embrace the tox-ified future. This explicitly asks users to use a virtualenv to stop them shooting themselves in the foot. Signed-off-by: Stephen Finucane --- CONTRIBUTING.rst | 68 +++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 7c8a90c6b..c4b8569b0 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -33,10 +33,10 @@ Bug Reports and Feature Requests If you have encountered a problem with Sphinx or have an idea for a new feature, please submit it to the `issue tracker`_ on GitHub or discuss it -on the sphinx-dev mailing list. +on the `sphinx-dev`_ mailing list. For bug reports, please include the output produced during the build process -and also the log file Sphinx creates after it encounters an un-handled +and also the log file Sphinx creates after it encounters an unhandled exception. The location of this file should be shown towards the end of the error message. @@ -45,6 +45,7 @@ issue. If possible, try to create a minimal project that produces the error and post that instead. .. _`issue tracker`: https://github.com/sphinx-doc/sphinx/issues +.. _`sphinx-dev`: mailto:sphinx-dev@googlegroups.com Contributing to Sphinx @@ -58,7 +59,7 @@ of the core developers before it is merged into the main repository. #. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. #. If you feel uncomfortable or uncertain about an issue or your changes, feel - free to email sphinx-dev@googlegroups.com. + free to email the *sphinx-dev* mailing list. #. Fork `the repository`_ on GitHub to start making your changes to the **master** branch for next major version, or **stable** branch for next minor version. @@ -98,10 +99,14 @@ These are the basic steps needed to start developing on Sphinx. For new features or other substantial changes that should wait until the next major release, use the ``master`` branch. -#. Optional: setup a virtual environment. :: +#. Setup a virtual environment. - virtualenv ~/sphinxenv - . ~/sphinxenv/bin/activate + This is not necessary for unit testing, thanks to ``tox``, but it is + necessary if you wish to run ``sphinx-build`` locally or run unit tests + without the help of ``tox``. :: + + virtualenv ~/.venv + . ~/.venv/bin/activate pip install -e . #. Create a new working branch. Choose any name you like. :: @@ -112,44 +117,53 @@ These are the basic steps needed to start developing on Sphinx. For tips on working with the code, see the `Coding Guide`_. -#. Test, test, test. Possible steps: +#. Test, test, test. - * Run the unit tests:: + Testing is best done through ``tox``, which provides a number of targets and + allows testing against multiple different Python environments: - pip install .[test,websupport] - make test + * To list all possible targets:: - * Again, it's useful to turn on deprecation warnings on so they're shown in - the test output:: + tox -av - PYTHONWARNINGS=all make test + * To run unit tests for a specific Python version, such as 3.6:: - * Arguments to pytest can be passed via tox, e.g. in order to run a + tox -e py36 + + * To run unit tests for a specific Python version and turn on deprecation + warnings on so they're shown in the test output:: + + PYTHONWARNINGS=all tox -e py36 + + * To run code style and type checks:: + + tox -e mypy + tox -e flake8 + + * Arguments to ``pytest`` can be passed via ``tox``, e.g. in order to run a particular test:: - tox -e py27 tests/test_module.py::test_new_feature + tox -e py36 tests/test_module.py::test_new_feature - * Build the documentation and check the output for different builders:: + * To build the documentation:: - make docs target="clean html latexpdf" + tox -e docs - * Run code style checks and type checks (type checks require mypy):: + * To build the documentation in multiple formats:: - make style-check - make type-check + tox -e docs -- -b html,latexpdf - * Run the unit tests under different Python environments using - :program:`tox`:: + You can also test by installing dependencies in your local environment. :: - pip install tox - tox -v + pip install .[test] - * Add a new unit test in the ``tests`` directory if you can. + New unit tests should be included in the ``tests`` directory where + necessary: * For bug fixes, first add a test that fails without your changes and passes after they are applied. - * Tests that need a sphinx-build run should be integrated in one of the + * Tests that need a ``sphinx-build`` run should be integrated in one of the existing test modules if possible. New tests that to ``@with_app`` and then ``build_all`` for a few assertions are not good since *the test suite should not take more than a minute to run*. @@ -266,7 +280,7 @@ Debugging Tips code by running the command ``make clean`` or using the :option:`sphinx-build -E` option. -* Use the :option:`sphinx-build -P` option to run Pdb on exceptions. +* Use the :option:`sphinx-build -P` option to run ``pdb`` on exceptions. * Use ``node.pformat()`` and ``node.asdom().toxml()`` to generate a printable representation of the document structure. From 838f7fc29a0af74d778cb99d235d645716ba02ab Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Dec 2017 00:31:32 +0900 Subject: [PATCH 0443/1814] Add Domain.add_object_type() to update internal caches correctly --- sphinx/domains/__init__.py | 12 ++++++++++++ sphinx/registry.py | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 1b9a7345a..868f56c91 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -188,6 +188,18 @@ class Domain(object): self.objtypes_for_role = self._role2type.get # type: Callable[[unicode], List[unicode]] # NOQA self.role_for_objtype = self._type2role.get # type: Callable[[unicode], unicode] + def add_object_type(self, name, objtype): + # type: (Objtype) -> None + """Add an object type.""" + self.object_types[name] = objtype + if objtype.roles: + self._type2role[name] = objtype.roles[0] + else: + self._type2role[name] = '' + + for role in objtype.roles: + self._role2type.setdefault(role, []).append(name) + def role(self, name): # type: (unicode) -> Callable """Return a role adapter function that always gives the registered diff --git a/sphinx/registry.py b/sphinx/registry.py index 885c7a256..6ec966a6a 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -112,10 +112,11 @@ class SphinxComponentRegistry(object): domain = DomainClass(env) # transplant components added by extensions - domain.object_types.update(self.domain_object_types.get(domain.name, {})) domain.directives.update(self.domain_directives.get(domain.name, {})) domain.roles.update(self.domain_roles.get(domain.name, {})) domain.indices.extend(self.domain_indices.get(domain.name, [])) + for name, objtype in iteritems(self.domain_object_types.get(domain.name, {})): + domain.add_object_type(name, objtype) yield domain From a2a873d58afb91143c3b71c9037384458043c080 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 19 Dec 2017 15:55:10 +0000 Subject: [PATCH 0444/1814] tox: Add documentation for all targets This should make 'tox -av' more helpful. Signed-off-by: Stephen Finucane --- tox.ini | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tox.ini b/tox.ini index 22a34f6f8..4b462d612 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,15 @@ [tox] -minversion=2.0 -envlist=docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} +minversion = 2.0 +envlist = docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} [testenv] -passenv = https_proxy http_proxy no_proxy +passenv = + https_proxy http_proxy no_proxy +description = + py{27,34,35,36,py}: Run unit tests against {envname}. + du{11,12,13,14}: Run unit tests with the given version of docutils. + coverage: Run code coverage checks. + # TODO(stephenfin) Replace this with the 'extras' config option when tox 2.4 is # widely available, likely some time after the Ubuntu 18.04 release # @@ -21,22 +27,30 @@ commands= {envpython} -Wall tests/run.py --durations 25 {posargs} [testenv:flake8] -commands=flake8 +description = + Run style checks. +commands = + flake8 [testenv:pylint] -deps= +description = + Run source code analyzer. +deps = pylint {[testenv]deps} -commands= +commands = pylint --rcfile utils/pylintrc sphinx [testenv:mypy] -basepython=python3 -deps= +description = + Run type checks. +deps = mypy commands= mypy sphinx/ [testenv:docs] -commands= +description = + Build documentation. +commands = python setup.py build_sphinx {posargs} From ac9ae4d54b0ad01dd62d94811046f6e3e9af860a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 19 Dec 2017 16:00:20 +0000 Subject: [PATCH 0445/1814] README: Fix typo Signed-off-by: Stephen Finucane Fixes: 393f59d ("Improve README") --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 39c58143b..79d8d6632 100644 --- a/README.rst +++ b/README.rst @@ -94,7 +94,7 @@ __ CONTRIBUTING.rst Contributing ============ -Refer to `the contributors guide`_. +Refer to `the contributors guide`__. __ CONTRIBUTING.rst From b103b3c24ac8d983498f1170d8e104f8cd72c3df Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Dec 2017 01:28:07 +0900 Subject: [PATCH 0446/1814] doc: Use anonymous link target for README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 79d8d6632..6419503e4 100644 --- a/README.rst +++ b/README.rst @@ -51,7 +51,7 @@ Among its features are the following: For more information, refer to the `the documentation`__. -__ http://www.sphinx-doc.org/ +.. __: http://www.sphinx-doc.org/ Installation ============ From 7a194f52960fe5ace04ef7daa72563e6d3bf094f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 18 Dec 2017 22:09:29 +0900 Subject: [PATCH 0447/1814] autodoc: Use logging module to emit warnings --- CHANGES | 2 ++ sphinx/ext/autodoc/__init__.py | 41 +++++++++++++++------------------ tests/py35/test_autodoc_py35.py | 25 ++++++++------------ tests/test_autodoc.py | 38 +++++++++++++++--------------- 4 files changed, 51 insertions(+), 55 deletions(-) diff --git a/CHANGES b/CHANGES index 2ec7d56bb..cb43a26ae 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,8 @@ Incompatible changes * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc * #4226: apidoc: Generate new style makefile (make-mode) * #4274: sphinx-build returns 2 as an exit code on argument error +* autodoc does not generate warnings messages to the generated document even if + :confval:`keep_warnings` is True. They are only emitted to stderr. Deprecated ---------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ff161565c..48afbcc91 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -354,8 +354,7 @@ class Documenter(object): explicit_modname, path, base, args, retann = \ py_ext_sig_re.match(self.name).groups() # type: ignore except AttributeError: - self.directive.warn('invalid signature for auto%s (%r)' % - (self.objtype, self.name)) + logger.warning('invalid signature for auto%s (%r)' % (self.objtype, self.name)) return False # support explicit module and class name separation via :: @@ -432,8 +431,7 @@ class Documenter(object): if PY2: errmsg = errmsg.decode('utf-8') # type: ignore - logger.debug(errmsg) - self.directive.warn(errmsg) + logger.warning(errmsg) self.env.note_reread() return False @@ -493,8 +491,8 @@ class Documenter(object): try: args = self.format_args() except Exception as err: - self.directive.warn('error while formatting arguments for ' - '%s: %s' % (self.fullname, err)) + logger.warning('error while formatting arguments for %s: %s' % + (self.fullname, err)) args = None retann = self.retann @@ -623,8 +621,8 @@ class Documenter(object): members.append((mname, self.get_attr(self.object, mname))) except AttributeError: if mname not in analyzed_member_names: - self.directive.warn('missing attribute %s in object %s' - % (mname, self.fullname)) + logger.warning('missing attribute %s in object %s' % + (mname, self.fullname)) elif self.options.inherited_members: # safe_getmembers() uses dir() which pulls in members from all # base classes @@ -820,11 +818,11 @@ class Documenter(object): """ if not self.parse_name(): # need a module to import - self.directive.warn( + logger.warning( 'don\'t know which module to import for autodocumenting ' '%r (try placing a "module" or "currentmodule" directive ' - 'in the document, or giving an explicit module name)' - % self.name) + 'in the document, or giving an explicit module name)' % + self.name) return # now, import the module and get object to document @@ -910,15 +908,15 @@ class ModuleDocumenter(Documenter): def resolve_name(self, modname, parents, path, base): # type: (str, Any, str, Any) -> Tuple[str, List[unicode]] if modname is not None: - self.directive.warn('"::" in automodule name doesn\'t make sense') + logger.warning('"::" in automodule name doesn\'t make sense') return (path or '') + base, [] def parse_name(self): # type: () -> bool ret = Documenter.parse_name(self) if self.args or self.retann: - self.directive.warn('signature arguments or return annotation ' - 'given for automodule %s' % self.fullname) + logger.warning('signature arguments or return annotation ' + 'given for automodule %s' % self.fullname) return ret def add_directive_header(self, sig): @@ -949,7 +947,7 @@ class ModuleDocumenter(Documenter): # Sometimes __all__ is broken... if not isinstance(memberlist, (list, tuple)) or not \ all(isinstance(entry, string_types) for entry in memberlist): - self.directive.warn( + logger.warning( '__all__ should be a list of strings, not %r ' '(in module %s) -- ignoring __all__' % (memberlist, self.fullname)) @@ -962,10 +960,10 @@ class ModuleDocumenter(Documenter): try: ret.append((mname, safe_getattr(self.object, mname))) except AttributeError: - self.directive.warn( + logger.warning( 'missing attribute mentioned in :members: or __all__: ' - 'module %s, attribute %s' % ( - safe_getattr(self.object, '__name__', '???'), mname)) + 'module %s, attribute %s' % + (safe_getattr(self.object, '__name__', '???'), mname)) return False, ret @@ -1542,7 +1540,7 @@ class AutoDirective(Directive): def warn(self, msg): # type: (unicode) -> None - self.warnings.append(self.reporter.warning(msg, line=self.lineno)) + logger.warning(msg, line=self.lineno) def run(self): # type: () -> List[nodes.Node] @@ -1550,7 +1548,6 @@ class AutoDirective(Directive): # a set of dependent filenames self.reporter = self.state.document.reporter self.env = self.state.document.settings.env - self.warnings = [] # type: List[unicode] self.result = ViewList() try: @@ -1585,7 +1582,7 @@ class AutoDirective(Directive): documenter = doc_class(self, self.arguments[0]) documenter.generate(more_content=self.content) if not self.result: - return self.warnings + return [] logger.debug('[autodoc] output:\n%s', '\n'.join(self.result)) @@ -1610,7 +1607,7 @@ class AutoDirective(Directive): node.document = self.state.document self.state.nested_parse(self.result, 0, node) self.state.memo.reporter = old_reporter - return self.warnings + node.children + return node.children def add_documenter(cls): diff --git a/tests/py35/test_autodoc_py35.py b/tests/py35/test_autodoc_py35.py index 481374948..9a94dbd27 100644 --- a/tests/py35/test_autodoc_py35.py +++ b/tests/py35/test_autodoc_py35.py @@ -21,6 +21,7 @@ from docutils.statemachine import ViewList from sphinx.ext.autodoc import AutoDirective, add_documenter, \ ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL +from sphinx.util import logging app = None @@ -30,7 +31,7 @@ def setup_module(rootdir, sphinx_test_tempdir): global app srcdir = sphinx_test_tempdir / 'autodoc-root' if not srcdir.exists(): - (rootdir/'test-root').copytree(srcdir) + (rootdir / 'test-root').copytree(srcdir) app = SphinxTestApp(srcdir=srcdir) app.builder.env.app = app app.builder.env.temp_data['docname'] = 'dummy' @@ -47,7 +48,7 @@ directive = options = None @pytest.fixture def setup_test(): global options, directive - global processed_docstrings, processed_signatures, _warnings + global processed_docstrings, processed_signatures options = Struct( inherited_members = False, @@ -70,24 +71,17 @@ def setup_test(): env = app.builder.env, genopt = options, result = ViewList(), - warn = warnfunc, filename_set = set(), ) processed_docstrings = [] processed_signatures = [] - _warnings = [] -_warnings = [] processed_docstrings = [] processed_signatures = [] -def warnfunc(msg): - _warnings.append(msg) - - def process_docstring(app, what, name, obj, options, lines): processed_docstrings.append((what, name)) if name == 'bar': @@ -111,20 +105,21 @@ def skip_member(app, what, name, obj, skip, options): @pytest.mark.usefixtures('setup_test') def test_generate(): + logging.setup(app, app._status, app._warning) + def assert_warns(warn_str, objtype, name, **kw): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) assert len(directive.result) == 0, directive.result - assert len(_warnings) == 1, _warnings - assert warn_str in _warnings[0], _warnings - del _warnings[:] + assert warn_str in app._warning.getvalue() + app._warning.truncate(0) def assert_works(objtype, name, **kw): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) assert directive.result # print '\n'.join(directive.result) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' del directive.result[:] def assert_processes(items, objtype, name, **kw): @@ -137,7 +132,7 @@ def test_generate(): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' assert item in directive.result del directive.result[:] @@ -145,7 +140,7 @@ def test_generate(): inst = AutoDirective._registry[objtype](directive, name) inst.options.member_order = member_order inst.generate(**kw) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' items = list(reversed(items)) lineiter = iter(directive.result) # for line in directive.result: diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 989c367b6..4ab58d891 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -21,6 +21,7 @@ from docutils.statemachine import ViewList from sphinx.ext.autodoc import AutoDirective, add_documenter, \ ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL +from sphinx.util import logging app = None @@ -47,7 +48,7 @@ directive = options = None @pytest.fixture def setup_test(): global options, directive - global processed_docstrings, processed_signatures, _warnings + global processed_docstrings, processed_signatures options = Struct( inherited_members = False, @@ -70,28 +71,24 @@ def setup_test(): env = app.builder.env, genopt = options, result = ViewList(), - warn = warnfunc, filename_set = set(), ) processed_docstrings = [] processed_signatures = [] - _warnings = [] + + app._status.truncate(0) + app._warning.truncate(0) yield AutoDirective._special_attrgetters.clear() -_warnings = [] processed_docstrings = [] processed_signatures = [] -def warnfunc(msg): - _warnings.append(msg) - - def process_docstring(app, what, name, obj, options, lines): processed_docstrings.append((what, name)) if name == 'bar': @@ -115,6 +112,8 @@ def skip_member(app, what, name, obj, skip, options): @pytest.mark.usefixtures('setup_test') def test_parse_name(): + logging.setup(app, app._status, app._warning) + def verify(objtype, name, result): inst = AutoDirective._registry[objtype](directive, name) assert inst.parse_name() @@ -124,8 +123,7 @@ def test_parse_name(): verify('module', 'test_autodoc', ('test_autodoc', [], None, None)) verify('module', 'test.test_autodoc', ('test.test_autodoc', [], None, None)) verify('module', 'test(arg)', ('test', [], 'arg', None)) - assert 'signature arguments' in _warnings[0] - del _warnings[:] + assert 'signature arguments' in app._warning.getvalue() # for functions/classes verify('function', 'test_autodoc.raises', @@ -241,7 +239,6 @@ def test_format_signature(): # test exception handling (exception is caught and args is '') directive.env.config.autodoc_docstring_signature = False assert formatsig('function', 'int', int, None, None) == '' - del _warnings[:] # test processing by event handler assert formatsig('method', 'bar', H.foo1, None, None) == '42' @@ -533,6 +530,8 @@ def test_docstring_property_processing(): @pytest.mark.usefixtures('setup_test') def test_new_documenter(): + logging.setup(app, app._status, app._warning) + class MyDocumenter(ModuleLevelDocumenter): objtype = 'integer' directivetype = 'data' @@ -548,10 +547,11 @@ def test_new_documenter(): add_documenter(MyDocumenter) def assert_result_contains(item, objtype, name, **kw): + app._warning.truncate(0) inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' assert item in directive.result del directive.result[:] @@ -593,20 +593,22 @@ def test_attrgetter_using(): @pytest.mark.usefixtures('setup_test') def test_generate(): + logging.setup(app, app._status, app._warning) + def assert_warns(warn_str, objtype, name, **kw): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) assert len(directive.result) == 0, directive.result - assert len(_warnings) == 1, _warnings - assert warn_str in _warnings[0], _warnings - del _warnings[:] + + assert warn_str in app._warning.getvalue() + app._warning.truncate(0) def assert_works(objtype, name, **kw): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) assert directive.result # print '\n'.join(directive.result) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' del directive.result[:] def assert_processes(items, objtype, name, **kw): @@ -619,7 +621,7 @@ def test_generate(): inst = AutoDirective._registry[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' assert item in directive.result del directive.result[:] @@ -627,7 +629,7 @@ def test_generate(): inst = AutoDirective._registry[objtype](directive, name) inst.options.member_order = member_order inst.generate(**kw) - assert len(_warnings) == 0, _warnings + assert app._warning.getvalue() == '' items = list(reversed(items)) lineiter = iter(directive.result) # for line in directive.result: From 221aa470fa26ae369627b1b301cc16de754a44f5 Mon Sep 17 00:00:00 2001 From: Paul V Craven Date: Tue, 19 Dec 2017 17:28:28 -0600 Subject: [PATCH 0448/1814] Add "Arcade" library documentation to examples --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index fa91b206e..26000cb31 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -111,6 +111,7 @@ Documentation using the sphinxdoc theme Documentation using another builtin theme ----------------------------------------- +* Arcade: https://arcade.academy/ (sphinx_rtd_theme) * ASE: https://wiki.fysik.dtu.dk/ase/ (sphinx_rtd_theme) * C/C++ Development with Eclipse: http://eclipsebook.in/ (agogo) * ESWP3 (http://eswp3.org) (sphinx_rtd_theme) From 7054c0306aafb2cfa8abe4553729385dfb928ffe Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 19 Dec 2017 22:28:54 +0900 Subject: [PATCH 0449/1814] doc: Remove mentions to deprecated options (both are removed at 8c2fabe v1.3) --- doc/config.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index d748f5706..62c4ccc73 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -138,12 +138,10 @@ General configuration - ``'library/xml.rst'`` -- ignores the ``library/xml.rst`` file (replaces entry in :confval:`unused_docs`) - - ``'library/xml'`` -- ignores the ``library/xml`` directory (replaces entry - in :confval:`exclude_trees`) + - ``'library/xml'`` -- ignores the ``library/xml`` directory - ``'library/xml*'`` -- ignores all files and directories starting with ``library/xml`` - - ``'**/.svn'`` -- ignores all ``.svn`` directories (replaces entry in - :confval:`exclude_dirnames`) + - ``'**/.svn'`` -- ignores all ``.svn`` directories :confval:`exclude_patterns` is also consulted when looking for static files in :confval:`html_static_path` and :confval:`html_extra_path`. From 3fe218e759f75f3a1a613dd845ed0db65a6fa196 Mon Sep 17 00:00:00 2001 From: Paul V Craven Date: Tue, 19 Dec 2017 21:14:36 -0600 Subject: [PATCH 0450/1814] Update arcade.academy link Update http://arcade.academy link to use http instead of https. --- EXAMPLES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES b/EXAMPLES index 26000cb31..9d3b24311 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -111,7 +111,7 @@ Documentation using the sphinxdoc theme Documentation using another builtin theme ----------------------------------------- -* Arcade: https://arcade.academy/ (sphinx_rtd_theme) +* Arcade: http://arcade.academy/ (sphinx_rtd_theme) * ASE: https://wiki.fysik.dtu.dk/ase/ (sphinx_rtd_theme) * C/C++ Development with Eclipse: http://eclipsebook.in/ (agogo) * ESWP3 (http://eswp3.org) (sphinx_rtd_theme) From c7a145cc1803787a71654fe052ec9005d6a6f0a9 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Wed, 20 Dec 2017 09:05:34 +0100 Subject: [PATCH 0451/1814] C++, handle defaulted constrained template type parameters --- sphinx/domains/cpp.py | 115 +++++++++++++++++++++++++++++++++++---- tests/test_domain_cpp.py | 4 ++ 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index c77c38413..971d6ad68 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1314,6 +1314,44 @@ class ASTTemplateParamType(ASTBase): self.data.describe_signature(signode, mode, env, symbol) +class ASTTemplateParamConstrainedTypeWithInit(ASTBase): + def __init__(self, type, init): + # type: (Any, Any) -> None + assert type + self.type = type + self.init = init + + @property + def name(self): + # type: () -> ASTNestedName + return self.type.name + + def get_id(self, version, objectType=None, symbol=None): + # type: (int, unicode, Symbol) -> unicode + # this is not part of the normal name mangling in C++ + assert version >= 2 + if symbol: + # the anchor will be our parent + return symbol.parent.declaration.get_id(version, prefixed=False) + else: + return self.type.get_id(version) + + def __unicode__(self): + # type: () -> unicode + res = text_type(self.type) + if self.init: + res += " = " + res += text_type(self.init) + return res + + def describe_signature(self, signode, mode, env, symbol): + # type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None + self.type.describe_signature(signode, mode, env, symbol) + if self.init: + signode += nodes.Text(" = ") + self.init.describe_signature(signode, mode, env, symbol) + + class ASTTemplateParamTemplateType(ASTBase): def __init__(self, nestedParams, data): # type: (Any, Any) -> None @@ -3781,6 +3819,8 @@ class DefinitionParser(object): self.last_match = None # type: Match self._previous_state = (0, None) # type: Tuple[int, Match] self.otherErrors = [] # type: List[DefinitionError] + # in our tests the following is set to False to capture bad parsing + self.allowFallbackExpressionParsing = True self.warnEnv = warnEnv self.config = config @@ -4121,6 +4161,13 @@ class DefinitionParser(object): # TODO: hmm, would we need to try both with operatorCast and with None? prefix = self._parse_type(False, 'operatorCast') prefixType = 'typeOperatorCast' + # | simple-type-specifier "(" expression-list [opt] ")" + # | simple-type-specifier braced-init-list + # | typename-specifier "(" expression-list [opt] ")" + # | typename-specifier braced-init-list + self.skip_ws() + if self.current_char != '(' and self.current_char != '{': + self.fail("Expecting '(' or '{' after type in cast expression.") except DefinitionError as eInner: self.pos = pos header = "Error in postfix expression, expected primary expression or type." @@ -4361,7 +4408,7 @@ class DefinitionParser(object): # TODO: actually parse the second production return self._parse_assignment_expression(inTemplate=inTemplate) - def _parse_expression_fallback(self, end, parser): + def _parse_expression_fallback(self, end, parser, allow=True): # Stupidly "parse" an expression. # 'end' should be a list of characters which ends the expression. @@ -4370,6 +4417,10 @@ class DefinitionParser(object): try: return parser() except DefinitionError as e: + # some places (e.g., template parameters) we really don't want to use fallback, + # and for testing we may want to globally disable it + if not allow or not self.allowFallbackExpressionParsing: + raise self.warn("Parsing of expression failed. Using fallback parser." " Error was:\n%s" % e.description) self.pos = prevPos @@ -4598,7 +4649,7 @@ class DefinitionParser(object): self.fail('Expected ")" after "..." in ' 'parameters_and_qualifiers.') break - # note: it seems that function arguments can always sbe named, + # note: it seems that function arguments can always be named, # even in function pointers and similar. arg = self._parse_type_with_init(outer=None, named='single') # TODO: parse default parameters # TODO: didn't we just do that? @@ -4919,8 +4970,8 @@ class DefinitionParser(object): header = "Error in declarator or parameters and qualifiers" raise self._make_multi_error(prevErrors, header) - def _parse_initializer(self, outer=None): - # type: (unicode) -> ASTInitializer + def _parse_initializer(self, outer=None, allowFallback=True): + # type: (unicode, bool) -> ASTInitializer self.skip_ws() # TODO: support paren and brace initialization for memberObject if not self.skip_string('='): @@ -4929,15 +4980,18 @@ class DefinitionParser(object): if outer == 'member': def parser(): return self._parse_assignment_expression(inTemplate=False) - value = self._parse_expression_fallback([], parser) + value = self._parse_expression_fallback([], parser, + allow=allowFallback) elif outer == 'templateParam': def parser(): return self._parse_assignment_expression(inTemplate=True) - value = self._parse_expression_fallback([',', '>'], parser) + value = self._parse_expression_fallback([',', '>'], parser, + allow=allowFallback) elif outer is None: # function parameter def parser(): return self._parse_assignment_expression(inTemplate=False) - value = self._parse_expression_fallback([',', ')'], parser) + value = self._parse_expression_fallback([',', ')'], parser, + allow=allowFallback) else: self.fail("Internal error, initializer for outer '%s' not " "implemented." % outer) @@ -5027,12 +5081,48 @@ class DefinitionParser(object): return ASTType(declSpecs, decl) def _parse_type_with_init(self, named, outer): - # type: (Union[bool, unicode], unicode) -> ASTTypeWithInit + # type: (Union[bool, unicode], unicode) -> Any if outer: assert outer in ('type', 'member', 'function', 'templateParam') type = self._parse_type(outer=outer, named=named) - init = self._parse_initializer(outer=outer) - return ASTTypeWithInit(type, init) + if outer != 'templateParam': + init = self._parse_initializer(outer=outer) + return ASTTypeWithInit(type, init) + # it could also be a constrained type parameter, e.g., C T = int& + pos = self.pos + eExpr = None + try: + init = self._parse_initializer(outer=outer, allowFallback=False) + # note: init may be None if there is no = + if init is None: + return ASTTypeWithInit(type, None) + # we parsed an expression, so we must have a , or a >, + # otherwise the expression didn't get everything + self.skip_ws() + if self.current_char != ',' and self.current_char != '>': + # pretend it didn't happen + self.pos = pos + init = None + else: + # we assume that it was indeed an expression + return ASTTypeWithInit(type, init) + except DefinitionError as e: + self.pos = pos + eExpr = e + if not self.skip_string("="): + return ASTTypeWithInit(type, None) + try: + typeInit = self._parse_type(named=False, outer=None) + return ASTTemplateParamConstrainedTypeWithInit(type, typeInit) + except DefinitionError as eType: + if eExpr is None: + raise eType + errs = [] + errs.append((eExpr, "If default is an expression")) + errs.append((eType, "If default is a type")) + msg = "Error in non-type template parameter" + msg += " or constrianted template paramter." + raise self._make_multi_error(errs, msg) def _parse_type_using(self): # type: () -> ASTTypeUsing @@ -5156,13 +5246,14 @@ class DefinitionParser(object): param = ASTTemplateParamType(data) templateParams.append(param) else: - # declare a non-type parameter + # declare a non-type parameter, or constrained type parameter pos = self.pos try: param = self._parse_type_with_init('maybe', 'templateParam') templateParams.append(ASTTemplateParamNonType(param)) except DefinitionError as e: - prevErrors.append((e, "If non-type template parameter")) + msg = "If non-type template parameter or constrained template parameter" + prevErrors.append((e, msg)) self.pos = pos self.skip_ws() if self.skip_string('>'): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index f3f0037f5..e4f3a678b 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -25,6 +25,7 @@ def parse(name, string): cpp_id_attributes = ["id_attr"] cpp_paren_attributes = ["paren_attr"] parser = DefinitionParser(string, None, Config()) + parser.allowFallbackExpressionParsing = False ast = parser.parse_declaration(name) parser.assert_end() # The scopedness would usually have been set by CPPEnumObject @@ -569,6 +570,9 @@ def test_templates(): check('member', 'template int A::B::b', {2: 'IEIEN1AIiE1BIiE1bE'}, output='template<> template<> int A::B::b') # same as above + # defaulted constrained type parameters + check('type', 'template A', {2:'I_1CE1A'}) + def test_template_args(): # from breathe#218 From b07de530619d7e26a62540cf75954839f0f712d9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 Dec 2017 00:19:02 +0900 Subject: [PATCH 0452/1814] Fix mypy violation --- sphinx/domains/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 868f56c91..1c80d3a42 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -189,7 +189,7 @@ class Domain(object): self.role_for_objtype = self._type2role.get # type: Callable[[unicode], unicode] def add_object_type(self, name, objtype): - # type: (Objtype) -> None + # type: (unicode, ObjType) -> None """Add an object type.""" self.object_types[name] = objtype if objtype.roles: From e932ff5ad2f9e1241c06506d42b14c2d5ecd8b44 Mon Sep 17 00:00:00 2001 From: Kevin Keating Date: Wed, 20 Dec 2017 15:07:33 -0500 Subject: [PATCH 0453/1814] Closes #947: autodoc now supports ignore-module-all to ignore a module's __all__ --- CHANGES | 1 + doc/ext/autodoc.rst | 8 +++++--- sphinx/ext/autodoc/__init__.py | 7 ++++--- tests/test_autodoc.py | 7 +++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 3023ee8c0..0206e84b5 100644 --- a/CHANGES +++ b/CHANGES @@ -50,6 +50,7 @@ Features added * #3160: html: Use ```` to represent ``:kbd:`` role * #4212: autosummary: catch all exceptions when importing modules * #3991, #4080: Add :confval:`math_numfig` for equation numbering by section +* #947: autodoc now supports ignore-module-all to ignore a module's ``__all__`` Features removed diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index bfd55c81a..09098f39c 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -103,8 +103,10 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, will document all non-private member functions and properties (that is, those whose name doesn't start with ``_``). - For modules, ``__all__`` will be respected when looking for members; the - order of the members will also be the order in ``__all__``. + For modules, ``__all__`` will be respected when looking for members unless + you give the ``ignore-module-all`` flag option. Without + ``ignore-module-all``, the order of the members will also be the order in + ``__all__``. You can also give an explicit list of members; only these will then be documented:: @@ -339,7 +341,7 @@ There are also new config values that you can set: This value is a list of autodoc directive flags that should be automatically applied to all autodoc directives. The supported flags are ``'members'``, ``'undoc-members'``, ``'private-members'``, ``'special-members'``, - ``'inherited-members'`` and ``'show-inheritance'``. + ``'inherited-members'``, ``'show-inheritance'`` and ``'ignore-module-all'``. If you set one of these flags in this config value, you can use a negated form, :samp:`'no-{flag}'`, in an autodoc directive, to disable it once. diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ff161565c..ddf34a211 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -898,7 +898,7 @@ class ModuleDocumenter(Documenter): 'platform': identity, 'deprecated': bool_option, 'member-order': identity, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, - 'imported-members': bool_option, + 'imported-members': bool_option, 'ignore-module-all': bool_option } # type: Dict[unicode, Callable] @classmethod @@ -940,7 +940,8 @@ class ModuleDocumenter(Documenter): def get_object_members(self, want_all): # type: (bool) -> Tuple[bool, List[Tuple[unicode, object]]] if want_all: - if not hasattr(self.object, '__all__'): + if (self.options.ignore_module_all or not + hasattr(self.object, '__all__')): # for implicit module members, check __module__ to avoid # documenting imported objects return True, safe_getmembers(self.object) @@ -1528,7 +1529,7 @@ class AutoDirective(Directive): # flags that can be given in autodoc_default_flags _default_flags = set([ 'members', 'undoc-members', 'inherited-members', 'show-inheritance', - 'private-members', 'special-members', + 'private-members', 'special-members', 'ignore-module-all' ]) # standard docutils directive settings diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 989c367b6..fda1c561e 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -64,6 +64,7 @@ def setup_test(): members = [], member_order = 'alphabetic', exclude_members = set(), + ignore_module_all = False, ) directive = Struct( @@ -736,6 +737,12 @@ def test_generate(): else: assert False, 'documented CustomEx which is not in __all__' + # test ignore-module-all + options.ignore_module_all = True + assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc') + assert_result_contains('.. py:exception:: CustomEx', 'module', + 'test_autodoc') + # test noindex flag options.members = [] options.noindex = True From 1ee2c2fb9543d91f13251a3b818feee121d8a2c9 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Dec 2017 21:30:05 +0100 Subject: [PATCH 0454/1814] Re-use some existing test with extras --- tests/roots/test-latex-toplevel/conf.py | 12 ---- tests/roots/test-latex-toplevel/index.rst | 8 --- .../roots/test-latex-toplevel/indexhowto.rst | 10 --- .../roots/test-latex-toplevel/indexmanual.rst | 13 ---- tests/test_build_latex.py | 64 ++++++++++++------- 5 files changed, 41 insertions(+), 66 deletions(-) delete mode 100644 tests/roots/test-latex-toplevel/conf.py delete mode 100644 tests/roots/test-latex-toplevel/index.rst delete mode 100644 tests/roots/test-latex-toplevel/indexhowto.rst delete mode 100644 tests/roots/test-latex-toplevel/indexmanual.rst diff --git a/tests/roots/test-latex-toplevel/conf.py b/tests/roots/test-latex-toplevel/conf.py deleted file mode 100644 index 88efc87ed..000000000 --- a/tests/roots/test-latex-toplevel/conf.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- - -master_doc = 'index' - -latex_toplevel_sectioning = 'part' - -latex_documents = [ - ('indexmanual', 'SphinxManual.tex', 'Test toplevel manual', - 'Sphinx', 'manual'), - ('indexhowto', 'SphinxHowTo.tex', 'Test toplevel howto', - 'Sphinx', 'howto'), -] diff --git a/tests/roots/test-latex-toplevel/index.rst b/tests/roots/test-latex-toplevel/index.rst deleted file mode 100644 index 833bc67bb..000000000 --- a/tests/roots/test-latex-toplevel/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -=================== -test-latex-toplevel -=================== - -.. toctree:: - - indexmanual - indexhowto diff --git a/tests/roots/test-latex-toplevel/indexhowto.rst b/tests/roots/test-latex-toplevel/indexhowto.rst deleted file mode 100644 index 7c0c92d1a..000000000 --- a/tests/roots/test-latex-toplevel/indexhowto.rst +++ /dev/null @@ -1,10 +0,0 @@ -========================= -test-latex-toplevel-howto -========================= - -This is a part -============== - -This is a section ------------------ - diff --git a/tests/roots/test-latex-toplevel/indexmanual.rst b/tests/roots/test-latex-toplevel/indexmanual.rst deleted file mode 100644 index 2181b1426..000000000 --- a/tests/roots/test-latex-toplevel/indexmanual.rst +++ /dev/null @@ -1,13 +0,0 @@ -========================== -test-latex-toplevel-manual -========================== - -First part -========== - -This is chapter ---------------- - -This is section -~~~~~~~~~~~~~~~ - diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index edaf107c4..faa2f46a7 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -713,20 +713,16 @@ def test_latex_logo_if_not_found(app, status, warning): assert isinstance(exc, SphinxError) -@pytest.mark.sphinx('latex', testroot='toctree-maxdepth', - confoverrides={'latex_documents': [ - ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation', - 'Georg Brandl', 'manual'), - ]}) +@pytest.mark.sphinx('latex', testroot='toctree-maxdepth') def test_toctree_maxdepth_manual(app, status, warning): app.builder.build_all() - result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') + result = (app.outdir / 'Python.tex').text(encoding='utf8') print(result) print(status.getvalue()) print(warning.getvalue()) assert '\\setcounter{tocdepth}{1}' in result assert '\\setcounter{secnumdepth}' not in result - + assert '\\chapter{Foo}' in result @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', @@ -742,7 +738,7 @@ def test_toctree_maxdepth_howto(app, status, warning): print(warning.getvalue()) assert '\\setcounter{tocdepth}{2}' in result assert '\\setcounter{secnumdepth}' not in result - + assert '\\section{Foo}' in result @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', @@ -755,7 +751,7 @@ def test_toctree_not_found(app, status, warning): print(warning.getvalue()) assert '\\setcounter{tocdepth}' not in result assert '\\setcounter{secnumdepth}' not in result - + assert '\\chapter{Foo A}' in result @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', @@ -805,6 +801,26 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning): print(status.getvalue()) print(warning.getvalue()) assert '\\part{Foo}' in result + assert '\\chapter{Foo A}' in result + assert '\\chapter{Foo B}' in result + + +@pytest.mark.sphinx( + 'latex', testroot='toctree-maxdepth', + confoverrides={'latex_toplevel_sectioning': 'part', + 'latex_documents': [ + ('index', 'Python.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'howto') + ]}) +def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'Python.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\part{Foo}' in result + assert '\\section{Foo A}' in result + assert '\\section{Foo B}' in result @pytest.mark.sphinx( @@ -819,6 +835,22 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning): assert '\\chapter{Foo}' in result +@pytest.mark.sphinx( + 'latex', testroot='toctree-maxdepth', + confoverrides={'latex_toplevel_sectioning': 'chapter', + 'latex_documents': [ + ('index', 'Python.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'howto') + ]}) +def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'Python.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\section{Foo}' in result + + @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', confoverrides={'latex_toplevel_sectioning': 'section'}) @@ -1039,17 +1071,3 @@ def test_latex_image_in_parsed_literal(app, status, warning): assert ('{\\sphinxunactivateextrasandspace \\raisebox{-0.5\\height}' '{\\scalebox{2.000000}{\\sphinxincludegraphics[height=1cm]{{pic}.png}}}' '}AFTER') in result - - -@pytest.mark.sphinx('latex', testroot='latex-toplevel') -def test_latex_toplevel_is_part(app, status, warning): - app.builder.build_all() - - result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') - assert ('\\part{First part}') in result - assert ('\\chapter{This is chapter}') in result - assert ('\\section{This is section}') in result - - result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') - assert ('\\part{This is a part}') in result - assert ('\\section{This is a section}') in result From dab7b49cd95c97d3efc5d6fd09ffdefc6155aad3 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Dec 2017 22:19:35 +0100 Subject: [PATCH 0455/1814] Correct merge error in writers/latex.py --- sphinx/writers/latex.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 26a1b904e..54f288d61 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -552,8 +552,6 @@ class LaTeXTranslator(nodes.NodeVisitor): self.elements.update({ 'releasename': _('Release'), }) - if builder.config.latex_keep_old_macro_names: - self.elements['sphinxpkgoptions'] = '' # we assume LaTeX class provides \chapter command except in case # of non-Japanese 'howto' case From 8c72f98c784328ffa3d400b5fc4b119449585d2d Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Dec 2017 22:45:22 +0100 Subject: [PATCH 0456/1814] Update CHANGES for PR #4316 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 1b8289784..271e935f2 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,8 @@ Bugs fixed remote image * #1421: Respect the quiet flag in sphinx-quickstart * #4281: Race conditions when creating output directory +* #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates + ``\chapter`` commands Testing -------- From 7ea4fa535a0e40a3ca16d78b706e376dea275030 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 17 Dec 2017 00:23:54 +0100 Subject: [PATCH 0457/1814] Make LaTeX obey numfig_secnum_depth for figures, tables, code-blocks Notes: - also fixes #4314 - although numbering of figures, tables and code-blocks will be same as in html, due to issue #4318 the numbering of enclosing sectioning units themselves may go deeper in html than PDF via latex. But this commit makes sure numbering goes to minimal depth needed by numfig_secnum_depth --- doc/config.rst | 11 ++--- sphinx/texinputs/sphinx.sty | 99 ++++++++++++++++++++++++++++++++----- sphinx/writers/latex.py | 34 +++++++++++-- 3 files changed, 123 insertions(+), 21 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 2ca622211..881387b48 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -341,20 +341,19 @@ General configuration starting at ``1``. - if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x`` the section number (top level sectioning; no ``x.`` if no section). - This naturally applies only if section numbering has been activated via + This naturally applies only if section numbering has been activated via the ``:numbered:`` option of the :rst:dir:`toctree` directive. - ``2`` means that numbers will be ``x.y.1``, ``x.y.2``, ... if located in a sub-section (but still ``x.1``, ``x.2``, ... if located directly under a section and ``1``, ``2``, ... if not in any top level section.) - etc... - .. note:: - - The LaTeX builder currently ignores this configuration setting. It will - obey it at Sphinx 1.7. - .. versionadded:: 1.3 + .. versionchanged:: 1.7 + The LaTeX builder obeys this setting (if :confval:`numfig` is set to + ``True``). + .. confval:: tls_verify If true, Sphinx verifies server certifications. Default is ``True``. diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 80b81f6d6..f890b40f8 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -183,7 +183,7 @@ % control caption around literal-block \RequirePackage{capt-of} \RequirePackage{needspace} - +\RequirePackage{remreset}% provides \@removefromreset % to make pdf with correct encoded bookmarks in Japanese % this should precede the hyperref package \ifx\kanjiskip\@undefined @@ -247,7 +247,9 @@ \fi \DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0} - +\DeclareStringOption[-1]{numfigreset} +\DeclareBoolOption[false]{nonumfigreset} +% \DeclareBoolOption[false]{usespart}% not used % dimensions, we declare the \dimen registers here. \newdimen\sphinxverbatimsep \newdimen\sphinxverbatimborder @@ -349,6 +351,8 @@ \ProcessKeyvalOptions* % don't allow use of maxlistdepth via \sphinxsetup. \DisableKeyvalOption{sphinx}{maxlistdepth} +\DisableKeyvalOption{sphinx}{numfigreset} +\DisableKeyvalOption{sphinx}{nonumfigreset} % user interface: options can be changed midway in a document! \newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}} @@ -657,6 +661,7 @@ {\abovecaptionskip\smallskipamount \belowcaptionskip\smallskipamount} + %% FOOTNOTES % % Support large numbered footnotes in minipage @@ -665,6 +670,87 @@ \def\thempfootnote{\arabic{mpfootnote}} +%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS +\ltx@ifundefined{c@chapter} + {\newcounter{literalblock}}% + {\newcounter{literalblock}[chapter]% + \def\theliteralblock{\ifnum\c@chapter>\z@\arabic{chapter}.\fi + \arabic{literalblock}}% + }% +\ifspx@opt@nonumfigreset + \ltx@ifundefined{c@chapter}{}{% + \@removefromreset{figure}{chapter}% + \@removefromreset{table}{chapter}% + \@removefromreset{literalblock}{chapter}% + }% + \def\thefigure{\arabic{figure}}% + \def\thetable {\arabic{table}}% + \def\theliteralblock{\arabic{literalblock}}% + %\let\theHliteralblock\theliteralblock +\else +\let\spx@preAthefigure\@empty +\let\spx@preBthefigure\@empty +% \ifspx@opt@usespart % <-- LaTeX writer could pass such a 'usespart' boolean +% % as sphinx.sty package option +% If document uses \part, (triggered in Sphinx by latex_toplevel_sectioning) +% LaTeX core per default does not reset chapter or section +% counters at each part. +% But if we modify this, we need to redefine \thechapter, \thesection to +% include the part number and this will cause problems in table of contents +% because of too wide numbering. Simplest is to do nothing. +% \fi +\ifnum\spx@opt@numfigreset>0 + \ltx@ifundefined{c@chapter} + {} + {\g@addto@macro\spx@preAthefigure{\ifnum\c@chapter>\z@\arabic{chapter}.}% + \g@addto@macro\spx@preBthefigure{\fi}}% +\fi +\ifnum\spx@opt@numfigreset>1 + \@addtoreset{figure}{section}% + \@addtoreset{table}{section}% + \@addtoreset{literalblock}{section}% + \g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>2 + \@addtoreset{figure}{subsection}% + \@addtoreset{table}{subsection}% + \@addtoreset{literalblock}{subsection}% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>3 + \@addtoreset{figure}{subsubsection}% + \@addtoreset{table}{subsubsection}% + \@addtoreset{literalblock}{subsubsection}% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>4 + \@addtoreset{figure}{paragraph}% + \@addtoreset{table}{paragraph}% + \@addtoreset{literalblock}{paragraph}% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\ifnum\spx@opt@numfigreset>5 + \@addtoreset{figure}{subparagraph}% + \@addtoreset{table}{subparagraph}% + \@addtoreset{literalblock}{subparagraph}% + \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}.}% + \g@addto@macro\spx@preBthefigure{\fi}% +\fi +\expandafter\g@addto@macro +\expandafter\spx@preAthefigure\expandafter{\spx@preBthefigure}% +\let\thefigure\spx@preAthefigure +\let\thetable\spx@preAthefigure +\let\theliteralblock\spx@preAthefigure +\g@addto@macro\thefigure{\arabic{figure}}% +\g@addto@macro\thetable{\arabic{table}}% +\g@addto@macro\theliteralblock{\arabic{literalblock}}% +\fi + + %% LITERAL BLOCKS % % Based on use of "fancyvrb.sty"'s Verbatim. @@ -680,15 +766,6 @@ \let\endOriginalVerbatim\endVerbatim % for captions of literal blocks -% also define `\theH...` macros for hyperref -\newcounter{literalblock} -\ltx@ifundefined{c@chapter} - {\@addtoreset{literalblock}{section} - \def\theliteralblock {\ifnum\c@section>\z@ \thesection.\fi\arabic{literalblock}} - \def\theHliteralblock {\theHsection.\arabic{literalblock}}} - {\@addtoreset{literalblock}{chapter} - \def\theliteralblock {\ifnum\c@chapter>\z@ \thechapter.\fi\arabic{literalblock}} - \def\theHliteralblock {\theHchapter.\arabic{literalblock}}} % at start of caption title \newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock} % this will be overwritten in document preamble by Babel translation diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 54f288d61..95938cc50 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -48,7 +48,6 @@ BEGIN_DOC = r''' URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:') -SECNUMDEPTH = 3 LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection", "subsubsection", "paragraph", "subparagraph"] @@ -504,6 +503,8 @@ def rstdim_to_latexdim(width_str): class LaTeXTranslator(nodes.NodeVisitor): + secnumdepth = 2 # legacy sphinxhowto.cls uses this, whereas article.cls + # default is originally 3. For book/report, 2 is already LaTeX default. ignore_missing_images = False # sphinx specific document classes @@ -581,6 +582,24 @@ class LaTeXTranslator(nodes.NodeVisitor): else: self.elements['date'] = format_date(builder.config.today_fmt or _('%b %d, %Y'), # type: ignore # NOQA language=builder.config.language) + + if builder.config.numfig: + self.numfig_secnum_depth = builder.config.numfig_secnum_depth + if self.numfig_secnum_depth > 0: # default is 1 + # numfig_secnum_depth as passed to sphinx.sty indices same names as in + # LATEXSECTIONNAMES but with -1 for part, 0 for chapter, 1 for section... + if len(self.sectionnames) < 7 and self.top_sectionlevel > 0: + self.numfig_secnum_depth += self.top_sectionlevel + else: + self.numfig_secnum_depth += self.top_sectionlevel - 1 + if self.numfig_secnum_depth >= len(self.sectionnames): + self.numfig_secnum_depth = len(self.sectionnames) - 1 + # if passed key value is < 1 LaTeX will act as if 0; see sphinx.sty + self.elements['sphinxpkgoptions'] += \ + (',numfigreset=%s' % self.numfig_secnum_depth) + else: + self.elements['sphinxpkgoptions'] += ',nonumfigreset' + if builder.config.latex_logo: # no need for \\noindent here, used in flushright self.elements['logo'] = '\\sphinxincludegraphics{%s}\\par' % \ @@ -637,6 +656,8 @@ class LaTeXTranslator(nodes.NodeVisitor): return '\\usepackage{%s}' % (packagename,) usepackages = (declare_package(*p) for p in builder.usepackages) self.elements['usepackages'] += "\n".join(usepackages) + + minsecnumdepth = self.secnumdepth # 2 from legacy sphinx manual/howto if document.get('tocdepth'): # reduce tocdepth if `part` or `chapter` is used for top_sectionlevel # tocdepth = -1: show only parts @@ -653,9 +674,14 @@ class LaTeXTranslator(nodes.NodeVisitor): tocdepth = 5 self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth - if tocdepth >= SECNUMDEPTH: - # Increase secnumdepth if tocdepth is deeper than default SECNUMDEPTH - self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' % tocdepth + minsecnumdepth = max(minsecnumdepth, tocdepth) + + if builder.config.numfig and (builder.config.numfig_secnum_depth > 0): + minsecnumdepth = max(minsecnumdepth, self.numfig_secnum_depth - 1) + + if minsecnumdepth > self.secnumdepth: + self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' %\ + minsecnumdepth if getattr(document.settings, 'contentsname', None): self.elements['contentsname'] = \ From 43bed034cd1b19340125388f5e2d5b81f28d9345 Mon Sep 17 00:00:00 2001 From: jfbu Date: Mon, 18 Dec 2017 13:02:09 +0100 Subject: [PATCH 0458/1814] Add test for latex obey numfig_secnum_depth feature --- tests/roots/test-latex-numfig/conf.py | 10 +++++ tests/roots/test-latex-numfig/index.rst | 9 +++++ tests/roots/test-latex-numfig/indexhowto.rst | 10 +++++ tests/roots/test-latex-numfig/indexmanual.rst | 13 +++++++ tests/test_build_latex.py | 37 +++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 tests/roots/test-latex-numfig/conf.py create mode 100644 tests/roots/test-latex-numfig/index.rst create mode 100644 tests/roots/test-latex-numfig/indexhowto.rst create mode 100644 tests/roots/test-latex-numfig/indexmanual.rst diff --git a/tests/roots/test-latex-numfig/conf.py b/tests/roots/test-latex-numfig/conf.py new file mode 100644 index 000000000..61ea52b42 --- /dev/null +++ b/tests/roots/test-latex-numfig/conf.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' + +latex_documents = [ + ('indexmanual', 'SphinxManual.tex', 'Test numfig manual', + 'Sphinx', 'manual'), + ('indexhowto', 'SphinxHowTo.tex', 'Test numfig howto', + 'Sphinx', 'howto'), +] diff --git a/tests/roots/test-latex-numfig/index.rst b/tests/roots/test-latex-numfig/index.rst new file mode 100644 index 000000000..6b8b9688c --- /dev/null +++ b/tests/roots/test-latex-numfig/index.rst @@ -0,0 +1,9 @@ +================= +test-latex-numfig +================= + +.. toctree:: + :numbered: + + indexmanual + indexhowto diff --git a/tests/roots/test-latex-numfig/indexhowto.rst b/tests/roots/test-latex-numfig/indexhowto.rst new file mode 100644 index 000000000..4749f1ecd --- /dev/null +++ b/tests/roots/test-latex-numfig/indexhowto.rst @@ -0,0 +1,10 @@ +======================= +test-latex-numfig-howto +======================= + +This is a part +============== + +This is a section +----------------- + diff --git a/tests/roots/test-latex-numfig/indexmanual.rst b/tests/roots/test-latex-numfig/indexmanual.rst new file mode 100644 index 000000000..8bab4fbfd --- /dev/null +++ b/tests/roots/test-latex-numfig/indexmanual.rst @@ -0,0 +1,13 @@ +======================== +test-latex-numfig-manual +======================== + +First part +========== + +This is chapter +--------------- + +This is section +~~~~~~~~~~~~~~~ + diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index bf6082705..ca96d10ec 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -335,6 +335,43 @@ def test_numref_with_language_ja(app, status, warning): '\\nameref{\\detokenize{foo:foo}}}') in result +@pytest.mark.sphinx('latex', testroot='latex-numfig') +def test_latex_obey_numfig_is_false(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') + assert '\\usepackage{sphinx}' in result + + result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') + assert '\\usepackage{sphinx}' in result + + +@pytest.mark.sphinx( + 'latex', testroot='latex-numfig', + confoverrides={'numfig': True, 'numfig_secnum_depth': 0}) +def test_latex_obey_numfig_secnum_depth_is_zero(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') + assert '\\usepackage[,nonumfigreset]{sphinx}' in result + + result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') + assert '\\usepackage[,nonumfigreset]{sphinx}' in result + + +@pytest.mark.sphinx( + 'latex', testroot='latex-numfig', + confoverrides={'numfig': True, 'numfig_secnum_depth': 2}) +def test_latex_obey_numfig_secnum_depth_is_two(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') + assert '\\usepackage[,numfigreset=2]{sphinx}' in result + + result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') + assert '\\usepackage[,numfigreset=3]{sphinx}' in result + + @pytest.mark.sphinx('latex') def test_latex_add_latex_package(app, status, warning): app.add_latex_package('foo') From 91350f35faa4761aae04f11b5505cecaaf9560e5 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 20 Dec 2017 23:55:56 +0100 Subject: [PATCH 0459/1814] Remove hard-coded numbers to let LATEXSECTIONNAMES become patchable --- sphinx/writers/latex.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 95938cc50..70d394623 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -588,12 +588,14 @@ class LaTeXTranslator(nodes.NodeVisitor): if self.numfig_secnum_depth > 0: # default is 1 # numfig_secnum_depth as passed to sphinx.sty indices same names as in # LATEXSECTIONNAMES but with -1 for part, 0 for chapter, 1 for section... - if len(self.sectionnames) < 7 and self.top_sectionlevel > 0: + if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \ + self.top_sectionlevel > 0: self.numfig_secnum_depth += self.top_sectionlevel else: self.numfig_secnum_depth += self.top_sectionlevel - 1 - if self.numfig_secnum_depth >= len(self.sectionnames): - self.numfig_secnum_depth = len(self.sectionnames) - 1 + # this (minus one) will serve as minimum to LaTeX's secnumdepth + self.numfig_secnum_depth = min(self.numfig_secnum_depth, + len(LATEXSECTIONNAMES) - 1) # if passed key value is < 1 LaTeX will act as if 0; see sphinx.sty self.elements['sphinxpkgoptions'] += \ (',numfigreset=%s' % self.numfig_secnum_depth) @@ -665,13 +667,13 @@ class LaTeXTranslator(nodes.NodeVisitor): # tocdepth = 1: show parts, chapters and sections # tocdepth = 2: show parts, chapters, sections and subsections # ... - tocdepth = document['tocdepth'] + self.top_sectionlevel - 2 - if len(self.sectionnames) < 7 and self.top_sectionlevel > 0: + if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \ + self.top_sectionlevel > 0: tocdepth += 1 # because top_sectionlevel is shifted by -1 - if tocdepth > 5: # 5 corresponds to subparagraph + if tocdepth > len(LATEXSECTIONNAMES) - 2: # default is 5 <-> subparagraph logger.warning('too large :maxdepth:, ignored.') - tocdepth = 5 + tocdepth = len(LATEXSECTIONNAMES) - 2 self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth minsecnumdepth = max(minsecnumdepth, tocdepth) From c7a4283ff7fd906035405b4cf99810b3a2bc4862 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 00:04:40 +0100 Subject: [PATCH 0460/1814] Update CHANGES for PR #4311 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index a5701f4fc..d4e08333d 100644 --- a/CHANGES +++ b/CHANGES @@ -50,6 +50,7 @@ Features added * #3160: html: Use ```` to represent ``:kbd:`` role * #4212: autosummary: catch all exceptions when importing modules * #3991, #4080: Add :confval:`math_numfig` for equation numbering by section +* #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, ... Features removed @@ -91,6 +92,8 @@ Bugs fixed * #4094: C++, allow empty template argument lists. * C++, also hyperlink types in the name of declarations with qualified names. * C++, do not add index entries for declarations inside concepts. +* #4314: For PDF 'howto' documents, numbering of code-blocks differs from the + one of figures and tables Testing -------- From 24c9103a2cfb58da19362689f39f649e46027f45 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 00:19:23 +0100 Subject: [PATCH 0461/1814] Update CHANGES --- CHANGES | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index d4e08333d..1d6c3994f 100644 --- a/CHANGES +++ b/CHANGES @@ -49,7 +49,8 @@ Features added * HTML themes can set up default sidebars through ``theme.conf`` * #3160: html: Use ```` to represent ``:kbd:`` role * #4212: autosummary: catch all exceptions when importing modules -* #3991, #4080: Add :confval:`math_numfig` for equation numbering by section +* #4166: Add :confval:`math_numfig` for equation numbering by section (refs: + #3991, #4080). Thanks to Oliver Jahn. * #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, ... From ec240614d9d47546f8640afb922753ca15f5e9e4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 Dec 2017 10:35:51 +0900 Subject: [PATCH 0462/1814] test_autodoc: Separate testdata (python objects) and testcases --- .../roots/test-ext-autodoc/target/__init__.py | 225 ++++++++++ tests/roots/test-root/autodoc.txt | 4 +- tests/roots/test-root/autodoc_target.py | 225 ++++++++++ tests/test_autodoc.py | 399 ++++-------------- tests/test_build_html.py | 4 +- tests/test_build_html5.py | 4 +- tests/test_ext_coverage.py | 16 +- 7 files changed, 557 insertions(+), 320 deletions(-) create mode 100644 tests/roots/test-ext-autodoc/target/__init__.py create mode 100644 tests/roots/test-root/autodoc_target.py diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py new file mode 100644 index 000000000..bd00bf183 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/__init__.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +import enum +from six import StringIO, add_metaclass +from sphinx.ext.autodoc import add_documenter # NOQA + + +__all__ = ['Class'] + +#: documentation for the integer +integer = 1 + + +def raises(exc, func, *args, **kwds): + """Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.""" + pass + + +class CustomEx(Exception): + """My custom exception.""" + + def f(self): + """Exception method.""" + + +class CustomDataDescriptor(object): + """Descriptor class docstring.""" + + def __init__(self, doc): + self.__doc__ = doc + + def __get__(self, obj, type=None): + if obj is None: + return self + return 42 + + def meth(self): + """Function.""" + return "The Answer" + + +class CustomDataDescriptorMeta(type): + """Descriptor metaclass docstring.""" + + +@add_metaclass(CustomDataDescriptorMeta) +class CustomDataDescriptor2(CustomDataDescriptor): + """Descriptor class with custom metaclass docstring.""" + + +def _funky_classmethod(name, b, c, d, docstring=None): + """Generates a classmethod for a class from a template by filling out + some arguments.""" + def template(cls, a, b, c, d=4, e=5, f=6): + return a, b, c, d, e, f + from functools import partial + function = partial(template, b=b, c=c, d=d) + function.__name__ = name + function.__doc__ = docstring + return classmethod(function) + + +class Base(object): + def inheritedmeth(self): + """Inherited function.""" + + +class Derived(Base): + def inheritedmeth(self): + # no docstring here + pass + + +class Class(Base): + """Class to document.""" + + descr = CustomDataDescriptor("Descriptor instance docstring.") + + def meth(self): + """Function.""" + + def undocmeth(self): + pass + + def skipmeth(self): + """Method that should be skipped.""" + + def excludemeth(self): + """Method that should be excluded.""" + + # should not be documented + skipattr = 'foo' + + #: should be documented -- süß + attr = 'bar' + + @property + def prop(self): + """Property.""" + + docattr = 'baz' + """should likewise be documented -- süß""" + + udocattr = 'quux' + u"""should be documented as well - süß""" + + # initialized to any class imported from another module + mdocattr = StringIO() + """should be documented as well - süß""" + + roger = _funky_classmethod("roger", 2, 3, 4) + + moore = _funky_classmethod("moore", 9, 8, 7, + docstring="moore(a, e, f) -> happiness") + + def __init__(self, arg): + self.inst_attr_inline = None #: an inline documented instance attr + #: a documented instance attribute + self.inst_attr_comment = None + self.inst_attr_string = None + """a documented instance attribute""" + self._private_inst_attr = None #: a private instance attribute + + def __special1__(self): + """documented special method""" + + def __special2__(self): + # undocumented special method + pass + + +class CustomDict(dict): + """Docstring.""" + + +def function(foo, *args, **kwds): + """ + Return spam. + """ + pass + + +class Outer(object): + """Foo""" + + class Inner(object): + """Foo""" + + def meth(self): + """Foo""" + + # should be documented as an alias + factory = dict + + +class DocstringSig(object): + def meth(self): + """meth(FOO, BAR=1) -> BAZ +First line of docstring + + rest of docstring + """ + + def meth2(self): + """First line, no signature + Second line followed by indentation:: + + indented line + """ + + @property + def prop1(self): + """DocstringSig.prop1(self) + First line of docstring + """ + return 123 + + @property + def prop2(self): + """First line of docstring + Second line of docstring + """ + return 456 + + +class StrRepr(str): + def __repr__(self): + return self + + +class AttCls(object): + a1 = StrRepr('hello\nworld') + a2 = None + + +class InstAttCls(object): + """Class with documented class and instance attributes.""" + + #: Doc comment for class attribute InstAttCls.ca1. + #: It can have multiple lines. + ca1 = 'a' + + ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only. + + ca3 = 'c' + """Docstring for class attribute InstAttCls.ca3.""" + + def __init__(self): + #: Doc comment for instance attribute InstAttCls.ia1 + self.ia1 = 'd' + + self.ia2 = 'e' + """Docstring for instance attribute InstAttCls.ia2.""" + + +class EnumCls(enum.Enum): + """ + this is enum class + """ + + #: doc for val1 + val1 = 12 + val2 = 23 #: doc for val2 + val3 = 34 + """doc for val3""" diff --git a/tests/roots/test-root/autodoc.txt b/tests/roots/test-root/autodoc.txt index aa0dffba1..3c83ebf6e 100644 --- a/tests/roots/test-root/autodoc.txt +++ b/tests/roots/test-root/autodoc.txt @@ -5,7 +5,7 @@ Just testing a few autodoc possibilities... .. automodule:: util -.. automodule:: test_autodoc +.. automodule:: autodoc_target :members: .. autofunction:: function @@ -34,7 +34,7 @@ Just testing a few autodoc possibilities... .. autoclass:: MarkupError -.. currentmodule:: test_autodoc +.. currentmodule:: autodoc_target .. autoclass:: InstAttCls :members: diff --git a/tests/roots/test-root/autodoc_target.py b/tests/roots/test-root/autodoc_target.py new file mode 100644 index 000000000..bd00bf183 --- /dev/null +++ b/tests/roots/test-root/autodoc_target.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +import enum +from six import StringIO, add_metaclass +from sphinx.ext.autodoc import add_documenter # NOQA + + +__all__ = ['Class'] + +#: documentation for the integer +integer = 1 + + +def raises(exc, func, *args, **kwds): + """Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.""" + pass + + +class CustomEx(Exception): + """My custom exception.""" + + def f(self): + """Exception method.""" + + +class CustomDataDescriptor(object): + """Descriptor class docstring.""" + + def __init__(self, doc): + self.__doc__ = doc + + def __get__(self, obj, type=None): + if obj is None: + return self + return 42 + + def meth(self): + """Function.""" + return "The Answer" + + +class CustomDataDescriptorMeta(type): + """Descriptor metaclass docstring.""" + + +@add_metaclass(CustomDataDescriptorMeta) +class CustomDataDescriptor2(CustomDataDescriptor): + """Descriptor class with custom metaclass docstring.""" + + +def _funky_classmethod(name, b, c, d, docstring=None): + """Generates a classmethod for a class from a template by filling out + some arguments.""" + def template(cls, a, b, c, d=4, e=5, f=6): + return a, b, c, d, e, f + from functools import partial + function = partial(template, b=b, c=c, d=d) + function.__name__ = name + function.__doc__ = docstring + return classmethod(function) + + +class Base(object): + def inheritedmeth(self): + """Inherited function.""" + + +class Derived(Base): + def inheritedmeth(self): + # no docstring here + pass + + +class Class(Base): + """Class to document.""" + + descr = CustomDataDescriptor("Descriptor instance docstring.") + + def meth(self): + """Function.""" + + def undocmeth(self): + pass + + def skipmeth(self): + """Method that should be skipped.""" + + def excludemeth(self): + """Method that should be excluded.""" + + # should not be documented + skipattr = 'foo' + + #: should be documented -- süß + attr = 'bar' + + @property + def prop(self): + """Property.""" + + docattr = 'baz' + """should likewise be documented -- süß""" + + udocattr = 'quux' + u"""should be documented as well - süß""" + + # initialized to any class imported from another module + mdocattr = StringIO() + """should be documented as well - süß""" + + roger = _funky_classmethod("roger", 2, 3, 4) + + moore = _funky_classmethod("moore", 9, 8, 7, + docstring="moore(a, e, f) -> happiness") + + def __init__(self, arg): + self.inst_attr_inline = None #: an inline documented instance attr + #: a documented instance attribute + self.inst_attr_comment = None + self.inst_attr_string = None + """a documented instance attribute""" + self._private_inst_attr = None #: a private instance attribute + + def __special1__(self): + """documented special method""" + + def __special2__(self): + # undocumented special method + pass + + +class CustomDict(dict): + """Docstring.""" + + +def function(foo, *args, **kwds): + """ + Return spam. + """ + pass + + +class Outer(object): + """Foo""" + + class Inner(object): + """Foo""" + + def meth(self): + """Foo""" + + # should be documented as an alias + factory = dict + + +class DocstringSig(object): + def meth(self): + """meth(FOO, BAR=1) -> BAZ +First line of docstring + + rest of docstring + """ + + def meth2(self): + """First line, no signature + Second line followed by indentation:: + + indented line + """ + + @property + def prop1(self): + """DocstringSig.prop1(self) + First line of docstring + """ + return 123 + + @property + def prop2(self): + """First line of docstring + Second line of docstring + """ + return 456 + + +class StrRepr(str): + def __repr__(self): + return self + + +class AttCls(object): + a1 = StrRepr('hello\nworld') + a2 = None + + +class InstAttCls(object): + """Class with documented class and instance attributes.""" + + #: Doc comment for class attribute InstAttCls.ca1. + #: It can have multiple lines. + ca1 = 'a' + + ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only. + + ca3 = 'c' + """Docstring for class attribute InstAttCls.ca3.""" + + def __init__(self): + #: Doc comment for instance attribute InstAttCls.ia1 + self.ia1 = 'd' + + self.ia2 = 'e' + """Docstring for instance attribute InstAttCls.ia2.""" + + +class EnumCls(enum.Enum): + """ + this is enum class + """ + + #: doc for val1 + val1 = 12 + val2 = 23 #: doc for val2 + val3 = 34 + """doc for val3""" diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 989c367b6..6bd22df86 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -10,13 +10,12 @@ :license: BSD, see LICENSE for details. """ +import sys from six import PY3 from sphinx.testing.util import SphinxTestApp, Struct # NOQA import pytest -import enum -from six import StringIO, add_metaclass from docutils.statemachine import ViewList from sphinx.ext.autodoc import AutoDirective, add_documenter, \ @@ -27,18 +26,23 @@ app = None @pytest.fixture(scope='module', autouse=True) def setup_module(rootdir, sphinx_test_tempdir): - global app - srcdir = sphinx_test_tempdir / 'autodoc-root' - if not srcdir.exists(): - (rootdir/'test-root').copytree(srcdir) - app = SphinxTestApp(srcdir=srcdir) - app.builder.env.app = app - app.builder.env.temp_data['docname'] = 'dummy' - app.connect('autodoc-process-docstring', process_docstring) - app.connect('autodoc-process-signature', process_signature) - app.connect('autodoc-skip-member', skip_member) - yield - app.cleanup() + try: + global app + srcdir = sphinx_test_tempdir / 'autodoc-root' + if not srcdir.exists(): + (rootdir / 'test-root').copytree(srcdir) + testroot = rootdir / 'test-ext-autodoc' + sys.path.append(testroot) + app = SphinxTestApp(srcdir=srcdir) + app.builder.env.app = app + app.builder.env.temp_data['docname'] = 'dummy' + app.connect('autodoc-process-docstring', process_docstring) + app.connect('autodoc-process-signature', process_signature) + app.connect('autodoc-skip-member', skip_member) + yield + finally: + app.cleanup() + sys.path.remove(testroot) directive = options = None @@ -431,6 +435,8 @@ def test_get_doc(): directive.env.config.autoclass_content = 'both' assert getdocl('class', I) == ['Class docstring', '', 'New docstring'] + from target import Base, Derived + # NOTE: inspect.getdoc seems not to work with locally defined classes directive.env.config.autodoc_inherit_docstrings = False assert getdocl('method', Base.inheritedmeth) == ['Inherited function.'] @@ -508,24 +514,24 @@ def test_docstring_property_processing(): directive.env.config.autodoc_docstring_signature = False results, docstrings = \ - genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') + genarate_docstring('attribute', 'target.DocstringSig.prop1') assert '.. py:attribute:: DocstringSig.prop1' in results assert 'First line of docstring' in docstrings assert 'DocstringSig.prop1(self)' in docstrings results, docstrings = \ - genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') + genarate_docstring('attribute', 'target.DocstringSig.prop2') assert '.. py:attribute:: DocstringSig.prop2' in results assert 'First line of docstring' in docstrings assert 'Second line of docstring' in docstrings directive.env.config.autodoc_docstring_signature = True results, docstrings = \ - genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') + genarate_docstring('attribute', 'target.DocstringSig.prop1') assert '.. py:attribute:: DocstringSig.prop1' in results assert 'First line of docstring' in docstrings assert 'DocstringSig.prop1(self)' not in docstrings results, docstrings = \ - genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') + genarate_docstring('attribute', 'target.DocstringSig.prop2') assert '.. py:attribute:: DocstringSig.prop2' in results assert 'First line of docstring' in docstrings assert 'Second line of docstring' in docstrings @@ -556,11 +562,13 @@ def test_new_documenter(): del directive.result[:] options.members = ['integer'] - assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc') + assert_result_contains('.. py:data:: integer', 'module', 'target') @pytest.mark.usefixtures('setup_test') def test_attrgetter_using(): + from target import Class + def assert_getter_works(objtype, name, obj, attrs=[], **kw): getattr_spy = [] @@ -585,10 +593,10 @@ def test_attrgetter_using(): options.members = ALL options.inherited_members = False - assert_getter_works('class', 'test_autodoc.Class', Class, ['meth']) + assert_getter_works('class', 'target.Class', Class, ['meth']) options.inherited_members = True - assert_getter_works('class', 'test_autodoc.Class', Class, ['meth', 'inheritedmeth']) + assert_getter_works('class', 'target.Class', Class, ['meth', 'inheritedmeth']) @pytest.mark.usefixtures('setup_test') @@ -655,11 +663,11 @@ def test_generate(): assert_warns("failed to import function 'foobar' from module 'util'", 'function', 'util.foobar', more_content=None) # method missing - assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc';", - 'method', 'test_autodoc.Class.foobar', more_content=None) + assert_warns("failed to import method 'Class.foobar' from module 'target';", + 'method', 'target.Class.foobar', more_content=None) # test auto and given content mixing - directive.env.ref_context['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'target' assert_result_contains(' Function.', 'method', 'Class.meth') add_content = ViewList() add_content.append('Content.', '', 0) @@ -674,63 +682,63 @@ def test_generate(): assert len(directive.result) == 0 # assert that exceptions can be documented - assert_works('exception', 'test_autodoc.CustomEx', all_members=True) - assert_works('exception', 'test_autodoc.CustomEx') + assert_works('exception', 'target.CustomEx', all_members=True) + assert_works('exception', 'target.CustomEx') # test diverse inclusion settings for members - should = [('class', 'test_autodoc.Class')] + should = [('class', 'target.Class')] assert_processes(should, 'class', 'Class') - should.extend([('method', 'test_autodoc.Class.meth')]) + should.extend([('method', 'target.Class.meth')]) options.members = ['meth'] options.exclude_members = set(['excludemeth']) assert_processes(should, 'class', 'Class') - should.extend([('attribute', 'test_autodoc.Class.prop'), - ('attribute', 'test_autodoc.Class.descr'), - ('attribute', 'test_autodoc.Class.attr'), - ('attribute', 'test_autodoc.Class.docattr'), - ('attribute', 'test_autodoc.Class.udocattr'), - ('attribute', 'test_autodoc.Class.mdocattr'), - ('attribute', 'test_autodoc.Class.inst_attr_comment'), - ('attribute', 'test_autodoc.Class.inst_attr_inline'), - ('attribute', 'test_autodoc.Class.inst_attr_string'), - ('method', 'test_autodoc.Class.moore'), + should.extend([('attribute', 'target.Class.prop'), + ('attribute', 'target.Class.descr'), + ('attribute', 'target.Class.attr'), + ('attribute', 'target.Class.docattr'), + ('attribute', 'target.Class.udocattr'), + ('attribute', 'target.Class.mdocattr'), + ('attribute', 'target.Class.inst_attr_comment'), + ('attribute', 'target.Class.inst_attr_inline'), + ('attribute', 'target.Class.inst_attr_string'), + ('method', 'target.Class.moore'), ]) options.members = ALL assert_processes(should, 'class', 'Class') options.undoc_members = True - should.extend((('attribute', 'test_autodoc.Class.skipattr'), - ('method', 'test_autodoc.Class.undocmeth'), - ('method', 'test_autodoc.Class.roger'))) + should.extend((('attribute', 'target.Class.skipattr'), + ('method', 'target.Class.undocmeth'), + ('method', 'target.Class.roger'))) assert_processes(should, 'class', 'Class') options.inherited_members = True - should.append(('method', 'test_autodoc.Class.inheritedmeth')) + should.append(('method', 'target.Class.inheritedmeth')) assert_processes(should, 'class', 'Class') # test special members options.special_members = ['__special1__'] - should.append(('method', 'test_autodoc.Class.__special1__')) + should.append(('method', 'target.Class.__special1__')) assert_processes(should, 'class', 'Class') options.special_members = ALL - should.append(('method', 'test_autodoc.Class.__special2__')) + should.append(('method', 'target.Class.__special2__')) assert_processes(should, 'class', 'Class') options.special_members = False options.members = [] # test module flags - assert_result_contains('.. py:module:: test_autodoc', - 'module', 'test_autodoc') + assert_result_contains('.. py:module:: target', + 'module', 'target') options.synopsis = 'Synopsis' - assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc') + assert_result_contains(' :synopsis: Synopsis', 'module', 'target') options.deprecated = True - assert_result_contains(' :deprecated:', 'module', 'test_autodoc') + assert_result_contains(' :deprecated:', 'module', 'target') options.platform = 'Platform' - assert_result_contains(' :platform: Platform', 'module', 'test_autodoc') + assert_result_contains(' :platform: Platform', 'module', 'target') # test if __all__ is respected for modules options.members = ALL - assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc') + assert_result_contains('.. py:class:: Class(arg)', 'module', 'target') try: assert_result_contains('.. py:exception:: CustomEx', - 'module', 'test_autodoc') + 'module', 'target') except AssertionError: pass else: @@ -739,7 +747,7 @@ def test_generate(): # test noindex flag options.members = [] options.noindex = True - assert_result_contains(' :noindex:', 'module', 'test_autodoc') + assert_result_contains(' :noindex:', 'module', 'target') assert_result_contains(' :noindex:', 'class', 'Base') # okay, now let's get serious about mixing Python and C signature stuff @@ -747,14 +755,14 @@ def test_generate(): all_members=True) # test inner class handling - assert_processes([('class', 'test_autodoc.Outer'), - ('class', 'test_autodoc.Outer.Inner'), - ('method', 'test_autodoc.Outer.Inner.meth')], + assert_processes([('class', 'target.Outer'), + ('class', 'target.Outer.Inner'), + ('method', 'target.Outer.Inner.meth')], 'class', 'Outer', all_members=True) # test descriptor docstrings assert_result_contains(' Descriptor instance docstring.', - 'attribute', 'test_autodoc.Class.descr') + 'attribute', 'target.Class.descr') # test generation for C modules (which have no source file) directive.env.ref_context['py:module'] = 'time' @@ -762,7 +770,7 @@ def test_generate(): assert_processes([('function', 'time.asctime')], 'function', 'asctime') # test autodoc_member_order == 'source' - directive.env.ref_context['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'target' options.private_members = True if PY3: roger_line = ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)' @@ -788,7 +796,7 @@ def test_generate(): del directive.env.ref_context['py:module'] # test attribute initialized to class instance from other module - directive.env.temp_data['autodoc:class'] = 'test_autodoc.Class' + directive.env.temp_data['autodoc:class'] = 'target.Class' assert_result_contains(u' should be documented as well - s\xfc\xdf', 'attribute', 'mdocattr') del directive.env.temp_data['autodoc:class'] @@ -796,25 +804,25 @@ def test_generate(): # test autodoc_docstring_signature assert_result_contains( '.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method', - 'test_autodoc.DocstringSig.meth') + 'target.DocstringSig.meth') assert_result_contains( - ' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth') + ' rest of docstring', 'method', 'target.DocstringSig.meth') assert_result_contains( '.. py:method:: DocstringSig.meth2()', 'method', - 'test_autodoc.DocstringSig.meth2') + 'target.DocstringSig.meth2') assert_result_contains( ' indented line', 'method', - 'test_autodoc.DocstringSig.meth2') + 'target.DocstringSig.meth2') assert_result_contains( '.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method', - 'test_autodoc.Class.moore') + 'target.Class.moore') # test new attribute documenter behavior - directive.env.ref_context['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'target' options.undoc_members = True - assert_processes([('class', 'test_autodoc.AttCls'), - ('attribute', 'test_autodoc.AttCls.a1'), - ('attribute', 'test_autodoc.AttCls.a2'), + assert_processes([('class', 'target.AttCls'), + ('attribute', 'target.AttCls.a1'), + ('attribute', 'target.AttCls.a2'), ], 'class', 'AttCls') assert_result_contains( ' :annotation: = hello world', 'attribute', 'AttCls.a1') @@ -824,40 +832,40 @@ def test_generate(): # test explicit members with instance attributes del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:module'] - directive.env.ref_context['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'target' options.inherited_members = False options.undoc_members = False options.members = ALL assert_processes([ - ('class', 'test_autodoc.InstAttCls'), - ('attribute', 'test_autodoc.InstAttCls.ca1'), - ('attribute', 'test_autodoc.InstAttCls.ca2'), - ('attribute', 'test_autodoc.InstAttCls.ca3'), - ('attribute', 'test_autodoc.InstAttCls.ia1'), - ('attribute', 'test_autodoc.InstAttCls.ia2'), + ('class', 'target.InstAttCls'), + ('attribute', 'target.InstAttCls.ca1'), + ('attribute', 'target.InstAttCls.ca2'), + ('attribute', 'target.InstAttCls.ca3'), + ('attribute', 'target.InstAttCls.ia1'), + ('attribute', 'target.InstAttCls.ia2'), ], 'class', 'InstAttCls') del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:module'] options.members = ['ca1', 'ia1'] assert_processes([ - ('class', 'test_autodoc.InstAttCls'), - ('attribute', 'test_autodoc.InstAttCls.ca1'), - ('attribute', 'test_autodoc.InstAttCls.ia1'), + ('class', 'target.InstAttCls'), + ('attribute', 'target.InstAttCls.ca1'), + ('attribute', 'target.InstAttCls.ia1'), ], 'class', 'InstAttCls') del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:module'] del directive.env.ref_context['py:module'] # test members with enum attributes - directive.env.ref_context['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'target' options.inherited_members = False options.undoc_members = False options.members = ALL assert_processes([ - ('class', 'test_autodoc.EnumCls'), - ('attribute', 'test_autodoc.EnumCls.val1'), - ('attribute', 'test_autodoc.EnumCls.val2'), - ('attribute', 'test_autodoc.EnumCls.val3'), + ('class', 'target.EnumCls'), + ('attribute', 'target.EnumCls.val1'), + ('attribute', 'target.EnumCls.val2'), + ('attribute', 'target.EnumCls.val3'), ], 'class', 'EnumCls') assert_result_contains( ' :annotation: = 12', 'attribute', 'EnumCls.val1') @@ -871,11 +879,11 @@ def test_generate(): # test descriptor class documentation options.members = ['CustomDataDescriptor', 'CustomDataDescriptor2'] assert_result_contains('.. py:class:: CustomDataDescriptor(doc)', - 'module', 'test_autodoc') + 'module', 'target') assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()', - 'module', 'test_autodoc') + 'module', 'target') assert_result_contains('.. py:class:: CustomDataDescriptor2(doc)', - 'module', 'test_autodoc') + 'module', 'target') # test mocked module imports options.members = ['TestAutodoc'] @@ -887,224 +895,3 @@ def test_generate(): options.members = ['decoratedFunction'] assert_result_contains('.. py:function:: decoratedFunction()', 'module', 'autodoc_missing_imports') - - -# --- generate fodder ------------ -__all__ = ['Class'] - -#: documentation for the integer -integer = 1 - - -def raises(exc, func, *args, **kwds): - """Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*.""" - pass - - -class CustomEx(Exception): - """My custom exception.""" - - def f(self): - """Exception method.""" - - -class CustomDataDescriptor(object): - """Descriptor class docstring.""" - - def __init__(self, doc): - self.__doc__ = doc - - def __get__(self, obj, type=None): - if obj is None: - return self - return 42 - - def meth(self): - """Function.""" - return "The Answer" - - -class CustomDataDescriptorMeta(type): - """Descriptor metaclass docstring.""" - - -@add_metaclass(CustomDataDescriptorMeta) -class CustomDataDescriptor2(CustomDataDescriptor): - """Descriptor class with custom metaclass docstring.""" - - -def _funky_classmethod(name, b, c, d, docstring=None): - """Generates a classmethod for a class from a template by filling out - some arguments.""" - def template(cls, a, b, c, d=4, e=5, f=6): - return a, b, c, d, e, f - from functools import partial - function = partial(template, b=b, c=c, d=d) - function.__name__ = name - function.__doc__ = docstring - return classmethod(function) - - -class Base(object): - def inheritedmeth(self): - """Inherited function.""" - - -class Derived(Base): - def inheritedmeth(self): - # no docstring here - pass - - -class Class(Base): - """Class to document.""" - - descr = CustomDataDescriptor("Descriptor instance docstring.") - - def meth(self): - """Function.""" - - def undocmeth(self): - pass - - def skipmeth(self): - """Method that should be skipped.""" - - def excludemeth(self): - """Method that should be excluded.""" - - # should not be documented - skipattr = 'foo' - - #: should be documented -- süß - attr = 'bar' - - @property - def prop(self): - """Property.""" - - docattr = 'baz' - """should likewise be documented -- süß""" - - udocattr = 'quux' - u"""should be documented as well - süß""" - - # initialized to any class imported from another module - mdocattr = StringIO() - """should be documented as well - süß""" - - roger = _funky_classmethod("roger", 2, 3, 4) - - moore = _funky_classmethod("moore", 9, 8, 7, - docstring="moore(a, e, f) -> happiness") - - def __init__(self, arg): - self.inst_attr_inline = None #: an inline documented instance attr - #: a documented instance attribute - self.inst_attr_comment = None - self.inst_attr_string = None - """a documented instance attribute""" - self._private_inst_attr = None #: a private instance attribute - - def __special1__(self): - """documented special method""" - - def __special2__(self): - # undocumented special method - pass - - -class CustomDict(dict): - """Docstring.""" - - -def function(foo, *args, **kwds): - """ - Return spam. - """ - pass - - -class Outer(object): - """Foo""" - - class Inner(object): - """Foo""" - - def meth(self): - """Foo""" - - # should be documented as an alias - factory = dict - - -class DocstringSig(object): - def meth(self): - """meth(FOO, BAR=1) -> BAZ -First line of docstring - - rest of docstring - """ - - def meth2(self): - """First line, no signature - Second line followed by indentation:: - - indented line - """ - - @property - def prop1(self): - """DocstringSig.prop1(self) - First line of docstring - """ - return 123 - - @property - def prop2(self): - """First line of docstring - Second line of docstring - """ - return 456 - - -class StrRepr(str): - def __repr__(self): - return self - - -class AttCls(object): - a1 = StrRepr('hello\nworld') - a2 = None - - -class InstAttCls(object): - """Class with documented class and instance attributes.""" - - #: Doc comment for class attribute InstAttCls.ca1. - #: It can have multiple lines. - ca1 = 'a' - - ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only. - - ca3 = 'c' - """Docstring for class attribute InstAttCls.ca3.""" - - def __init__(self): - #: Doc comment for instance attribute InstAttCls.ia1 - self.ia1 = 'd' - - self.ia2 = 'e' - """Docstring for instance attribute InstAttCls.ia2.""" - - -class EnumCls(enum.Enum): - """ - this is enum class - """ - - #: doc for val1 - val1 = 12 - val2 = 23 #: doc for val2 - val3 = 34 - """doc for val3""" diff --git a/tests/test_build_html.py b/tests/test_build_html.py index b4fec18ba..2d56ba5c6 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -182,8 +182,8 @@ def test_html_warnings(app, warning): r'-| |-'), ], 'autodoc.html': [ - (".//dt[@id='test_autodoc.Class']", ''), - (".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'), + (".//dt[@id='autodoc_target.Class']", ''), + (".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'), (".//dd/p", r'Return spam\.'), ], 'extapi.html': [ diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py index 39b064b1c..6128af843 100644 --- a/tests/test_build_html5.py +++ b/tests/test_build_html5.py @@ -90,8 +90,8 @@ def cached_etree_parse(): r'-| |-'), ], 'autodoc.html': [ - (".//dt[@id='test_autodoc.Class']", ''), - (".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'), + (".//dt[@id='autodoc_target.Class']", ''), + (".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'), (".//dd/p", r'Return spam\.'), ], 'extapi.html': [ diff --git a/tests/test_ext_coverage.py b/tests/test_ext_coverage.py index ff3fb4c02..ed1f2e787 100644 --- a/tests/test_ext_coverage.py +++ b/tests/test_ext_coverage.py @@ -21,9 +21,9 @@ def test_build(app, status, warning): py_undoc = (app.outdir / 'python.txt').text() assert py_undoc.startswith('Undocumented Python objects\n' '===========================\n') - assert 'test_autodoc\n------------\n' in py_undoc + assert 'autodoc_target\n--------------\n' in py_undoc assert ' * Class -- missing methods:\n' in py_undoc - assert ' * process_docstring\n' in py_undoc + assert ' * raises\n' in py_undoc assert ' * function\n' not in py_undoc # these two are documented assert ' * Class\n' not in py_undoc # in autodoc.txt @@ -40,9 +40,9 @@ def test_build(app, status, warning): # the key is the full path to the header file, which isn't testable assert list(undoc_c.values())[0] == set([('function', 'Py_SphinxTest')]) - assert 'test_autodoc' in undoc_py - assert 'funcs' in undoc_py['test_autodoc'] - assert 'process_docstring' in undoc_py['test_autodoc']['funcs'] - assert 'classes' in undoc_py['test_autodoc'] - assert 'Class' in undoc_py['test_autodoc']['classes'] - assert 'undocmeth' in undoc_py['test_autodoc']['classes']['Class'] + assert 'autodoc_target' in undoc_py + assert 'funcs' in undoc_py['autodoc_target'] + assert 'raises' in undoc_py['autodoc_target']['funcs'] + assert 'classes' in undoc_py['autodoc_target'] + assert 'Class' in undoc_py['autodoc_target']['classes'] + assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class'] From 201c59126fc7e4083f83acdcffd4c4ca7ceeddc0 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 09:21:07 +0100 Subject: [PATCH 0463/1814] Set LaTeX default tocdepth to 2 for howto documents (fixes #4330) Memo: for Japanese documents, jreport.cls already does that, so this commit changes nothing. However as the class uses ``\chapter``, this means that by default howto documents table of contents in PDF have three levels, whereas manual documents only have two. --- sphinx/texinputs/sphinxhowto.cls | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/texinputs/sphinxhowto.cls b/sphinx/texinputs/sphinxhowto.cls index 90680fdee..11a49a205 100644 --- a/sphinx/texinputs/sphinxhowto.cls +++ b/sphinx/texinputs/sphinxhowto.cls @@ -25,6 +25,7 @@ % reset these counters in your preamble. % \setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2}% i.e. section and subsection % Change the title page to look a bit better, and fit in with the fncychap % ``Bjarne'' style a bit better. From 3bb61e909476798bbbf303a8e957b4f1a0a5a87c Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 12:23:20 +0100 Subject: [PATCH 0464/1814] Let LaTeX obey :confval:`math_numfig` for equation numbering --- doc/ext/math.rst | 6 +++++- sphinx/texinputs/sphinx.sty | 28 ++++++++++++++++++++++++++- sphinx/writers/latex.py | 5 +++++ tests/roots/test-latex-numfig/conf.py | 2 ++ tests/test_build_latex.py | 21 ++++++++++++++++---- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 10a26ccf4..635d48a3e 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -47,12 +47,16 @@ or use Python raw strings (``r"raw"``). .. confval:: math_numfig If ``True``, displayed math equations are numbered across pages in html and - related (epub, ...) output when :confval:`numfig` is enabled. + related (epub, ...) output (also with latex) when :confval:`numfig` is enabled. :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` role must be used to reference equation numbers, not the :rst:role:`numref` role. Default is ``True``. .. versionadded:: 1.7 + If ``False``, latex behaves as in former releases i.e. for ``'manual'`` + docclass (and ``'howto'`` for Japanese) it resets by default the + equation numbers per each toplevel section, and for ``'howto'`` it uses + continuous numbering across entire PDF. :mod:`.mathbase` defines these new markup elements: diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index f890b40f8..890ef60f7 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -249,6 +249,7 @@ \DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0} \DeclareStringOption[-1]{numfigreset} \DeclareBoolOption[false]{nonumfigreset} +\DeclareBoolOption[false]{mathnumfig} % \DeclareBoolOption[false]{usespart}% not used % dimensions, we declare the \dimen registers here. \newdimen\sphinxverbatimsep @@ -353,6 +354,7 @@ \DisableKeyvalOption{sphinx}{maxlistdepth} \DisableKeyvalOption{sphinx}{numfigreset} \DisableKeyvalOption{sphinx}{nonumfigreset} +\DisableKeyvalOption{sphinx}{mathnumfig} % user interface: options can be changed midway in a document! \newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}} @@ -682,11 +684,16 @@ \@removefromreset{figure}{chapter}% \@removefromreset{table}{chapter}% \@removefromreset{literalblock}{chapter}% + \ifspx@opt@mathnumfig + \@removefromreset{equation}{chapter}% + \fi }% \def\thefigure{\arabic{figure}}% \def\thetable {\arabic{table}}% \def\theliteralblock{\arabic{literalblock}}% - %\let\theHliteralblock\theliteralblock + \ifspx@opt@mathnumfig + \def\theequation{\arabic{equation}}% + \fi \else \let\spx@preAthefigure\@empty \let\spx@preBthefigure\@empty @@ -709,6 +716,9 @@ \@addtoreset{figure}{section}% \@addtoreset{table}{section}% \@addtoreset{literalblock}{section}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{section}% + \fi \g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -716,6 +726,9 @@ \@addtoreset{figure}{subsection}% \@addtoreset{table}{subsection}% \@addtoreset{literalblock}{subsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsection}% + \fi \g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -723,6 +736,9 @@ \@addtoreset{figure}{subsubsection}% \@addtoreset{table}{subsubsection}% \@addtoreset{literalblock}{subsubsection}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subsubsection}% + \fi \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -730,6 +746,9 @@ \@addtoreset{figure}{paragraph}% \@addtoreset{table}{paragraph}% \@addtoreset{literalblock}{paragraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{paragraph}% + \fi \g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -737,6 +756,9 @@ \@addtoreset{figure}{subparagraph}% \@addtoreset{table}{subparagraph}% \@addtoreset{literalblock}{subparagraph}% + \ifspx@opt@mathnumfig + \@addtoreset{equation}{subparagraph}% + \fi \g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}.}% \g@addto@macro\spx@preBthefigure{\fi}% \fi @@ -748,6 +770,10 @@ \g@addto@macro\thefigure{\arabic{figure}}% \g@addto@macro\thetable{\arabic{table}}% \g@addto@macro\theliteralblock{\arabic{literalblock}}% + \ifspx@opt@mathnumfig + \let\theequation\spx@preAthefigure + \g@addto@macro\theequation{\arabic{equation}}% + \fi \fi diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 70d394623..3ef336520 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -601,6 +601,11 @@ class LaTeXTranslator(nodes.NodeVisitor): (',numfigreset=%s' % self.numfig_secnum_depth) else: self.elements['sphinxpkgoptions'] += ',nonumfigreset' + try: + if builder.config.math_numfig: + self.elements['sphinxpkgoptions'] += ',mathnumfig' + except: + pass if builder.config.latex_logo: # no need for \\noindent here, used in flushright diff --git a/tests/roots/test-latex-numfig/conf.py b/tests/roots/test-latex-numfig/conf.py index 61ea52b42..506186b26 100644 --- a/tests/roots/test-latex-numfig/conf.py +++ b/tests/roots/test-latex-numfig/conf.py @@ -2,6 +2,8 @@ master_doc = 'index' +extensions = ['sphinx.ext.imgmath'] # for math_numfig + latex_documents = [ ('indexmanual', 'SphinxManual.tex', 'Test numfig manual', 'Sphinx', 'manual'), diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index ca96d10ec..bf0e84c57 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -353,10 +353,10 @@ def test_latex_obey_numfig_secnum_depth_is_zero(app, status, warning): app.builder.build_all() result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') - assert '\\usepackage[,nonumfigreset]{sphinx}' in result + assert '\\usepackage[,nonumfigreset,mathnumfig]{sphinx}' in result result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') - assert '\\usepackage[,nonumfigreset]{sphinx}' in result + assert '\\usepackage[,nonumfigreset,mathnumfig]{sphinx}' in result @pytest.mark.sphinx( @@ -366,10 +366,23 @@ def test_latex_obey_numfig_secnum_depth_is_two(app, status, warning): app.builder.build_all() result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') - assert '\\usepackage[,numfigreset=2]{sphinx}' in result + assert '\\usepackage[,numfigreset=2,mathnumfig]{sphinx}' in result result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') - assert '\\usepackage[,numfigreset=3]{sphinx}' in result + assert '\\usepackage[,numfigreset=3,mathnumfig]{sphinx}' in result + + +@pytest.mark.sphinx( + 'latex', testroot='latex-numfig', + confoverrides={'numfig': True, 'math_numfig': False}) +def test_latex_obey_numfig_but_math_numfig_false(app, status, warning): + app.builder.build_all() + + result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8') + assert '\\usepackage[,numfigreset=1]{sphinx}' in result + + result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8') + assert '\\usepackage[,numfigreset=2]{sphinx}' in result @pytest.mark.sphinx('latex') From 7ec3a237628675b8421a57b7c87106d8c10e098c Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 12:43:53 +0100 Subject: [PATCH 0465/1814] Avoid using bare except --- sphinx/writers/latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 3ef336520..c93fd197e 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -604,7 +604,7 @@ class LaTeXTranslator(nodes.NodeVisitor): try: if builder.config.math_numfig: self.elements['sphinxpkgoptions'] += ',mathnumfig' - except: + except AttributeError: pass if builder.config.latex_logo: From e2e907b3ee68baada5d47aabe3f507cc0b8fa6df Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 22 Dec 2017 00:53:53 +0900 Subject: [PATCH 0466/1814] Fix broken test_autodoc --- tests/test_autodoc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index cf3eb3926..d3c0a1f50 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -747,9 +747,8 @@ def test_generate(): # test ignore-module-all options.ignore_module_all = True - assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc') - assert_result_contains('.. py:exception:: CustomEx', 'module', - 'test_autodoc') + assert_result_contains('.. py:class:: Class(arg)', 'module', 'target') + assert_result_contains('.. py:exception:: CustomEx', 'module', 'target') # test noindex flag options.members = [] From 5ca9d0578b726a9c4a921a448e5c114f5cd446ab Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 18:37:45 +0100 Subject: [PATCH 0467/1814] Update CHANGES for PR #4331 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 9cddb98e0..b617835f5 100644 --- a/CHANGES +++ b/CHANGES @@ -96,6 +96,8 @@ Bugs fixed * C++, do not add index entries for declarations inside concepts. * #4314: For PDF 'howto' documents, numbering of code-blocks differs from the one of figures and tables +* #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter + setting Testing -------- From 8cbd66f8221cb1e8c5a93059631baf09c82e58c7 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 18:47:35 +0100 Subject: [PATCH 0468/1814] Trim docs about math_numfig --- doc/ext/math.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/doc/ext/math.rst b/doc/ext/math.rst index 635d48a3e..4097bb29e 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -46,17 +46,12 @@ or use Python raw strings (``r"raw"``). .. confval:: math_numfig - If ``True``, displayed math equations are numbered across pages in html and - related (epub, ...) output (also with latex) when :confval:`numfig` is enabled. - :confval:`numfig_secnum_depth` is respected. The :rst:role:`eq` role must - be used to reference equation numbers, not the :rst:role:`numref` role. - Default is ``True``. + If ``True``, displayed math equations are numbered across pages when + :confval:`numfig` is enabled. The :confval:`numfig_secnum_depth` setting + is respected. The :rst:role:`eq`, not :rst:role:`numref`, role + must be used to reference equation numbers. Default is ``True``. .. versionadded:: 1.7 - If ``False``, latex behaves as in former releases i.e. for ``'manual'`` - docclass (and ``'howto'`` for Japanese) it resets by default the - equation numbers per each toplevel section, and for ``'howto'`` it uses - continuous numbering across entire PDF. :mod:`.mathbase` defines these new markup elements: From 2d99648e9982325bbd670da11df5f809e3134284 Mon Sep 17 00:00:00 2001 From: Christer Bystrom Date: Thu, 21 Dec 2017 19:06:17 +0100 Subject: [PATCH 0469/1814] Closes #4334: sphinx-apidoc: Don't generate references to non-existing files in TOC --- CHANGES | 1 + sphinx/apidoc.py | 7 +- .../test-apidoc-toc/mypackage/__init__.py | 0 tests/roots/test-apidoc-toc/mypackage/main.py | 16 ++++ .../test-apidoc-toc/mypackage/no_init/foo.py | 1 + .../mypackage/resource/__init__.py | 0 .../mypackage/resource/resource.txt | 1 + .../mypackage/something/__init__.py | 1 + tests/test_apidoc.py | 77 +++++++++++++++++++ 9 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/roots/test-apidoc-toc/mypackage/__init__.py create mode 100755 tests/roots/test-apidoc-toc/mypackage/main.py create mode 100644 tests/roots/test-apidoc-toc/mypackage/no_init/foo.py create mode 100644 tests/roots/test-apidoc-toc/mypackage/resource/__init__.py create mode 100644 tests/roots/test-apidoc-toc/mypackage/resource/resource.txt create mode 100644 tests/roots/test-apidoc-toc/mypackage/something/__init__.py diff --git a/CHANGES b/CHANGES index b7a16af4f..5b3600d1d 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ Features added Bugs fixed ---------- +* #4334: sphinx-apidoc: Don't generate references to non-existing files in TOC * #4206: latex: reST label between paragraphs loses paragraph break * #4231: html: Apply fixFirefoxAnchorBug only under Firefox * #4221: napoleon depends on autodoc, but users need to load it manually diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index 24ed874b0..335abe344 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -116,7 +116,12 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_ text += '\n' # build a list of directories that are szvpackages (contain an INITPY file) - subs = [sub for sub in subs if path.isfile(path.join(root, sub, INITPY))] + # and also checks the INITPY file is not empty, or there are other python + # source files in that folder. + # (depending on settings - but shall_skip() takes care of that) + subs = [sub for sub in subs if not + shall_skip(path.join(root, sub, INITPY), opts)] + # if there are some package directories, add a TOC for theses subpackages if subs: text += format_heading(2, 'Subpackages') diff --git a/tests/roots/test-apidoc-toc/mypackage/__init__.py b/tests/roots/test-apidoc-toc/mypackage/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-apidoc-toc/mypackage/main.py b/tests/roots/test-apidoc-toc/mypackage/main.py new file mode 100755 index 000000000..5d3da04b9 --- /dev/null +++ b/tests/roots/test-apidoc-toc/mypackage/main.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +import os + +import mod_resource + +import mod_something + + +if __name__ == "__main__": + print("Hello, world! -> something returns: {}".format(mod_something.something())) + + res_path = \ + os.path.join(os.path.dirname(mod_resource.__file__), 'resource.txt') + with open(res_path) as f: + text = f.read() + print("From mod_resource:resource.txt -> {}".format(text)) diff --git a/tests/roots/test-apidoc-toc/mypackage/no_init/foo.py b/tests/roots/test-apidoc-toc/mypackage/no_init/foo.py new file mode 100644 index 000000000..ce059b276 --- /dev/null +++ b/tests/roots/test-apidoc-toc/mypackage/no_init/foo.py @@ -0,0 +1 @@ +MESSAGE="There's no __init__.py in this folder, hence we should be left out" diff --git a/tests/roots/test-apidoc-toc/mypackage/resource/__init__.py b/tests/roots/test-apidoc-toc/mypackage/resource/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-apidoc-toc/mypackage/resource/resource.txt b/tests/roots/test-apidoc-toc/mypackage/resource/resource.txt new file mode 100644 index 000000000..5b64c924d --- /dev/null +++ b/tests/roots/test-apidoc-toc/mypackage/resource/resource.txt @@ -0,0 +1 @@ +This is a text resource to be included in this otherwise empty module. No python contents here. \ No newline at end of file diff --git a/tests/roots/test-apidoc-toc/mypackage/something/__init__.py b/tests/roots/test-apidoc-toc/mypackage/something/__init__.py new file mode 100644 index 000000000..259184ba3 --- /dev/null +++ b/tests/roots/test-apidoc-toc/mypackage/something/__init__.py @@ -0,0 +1 @@ +"Subpackage Something" \ No newline at end of file diff --git a/tests/test_apidoc.py b/tests/test_apidoc.py index 20582e9fc..faceb715f 100644 --- a/tests/test_apidoc.py +++ b/tests/test_apidoc.py @@ -188,3 +188,80 @@ def test_extension_parsed(make_app, apidoc): with open(outdir / 'conf.py') as f: rst = f.read() assert "sphinx.ext.mathjax" in rst + + +@pytest.mark.apidoc( + coderoot='test-apidoc-toc', + options=["--implicit-namespaces"], +) +def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc): + """All references in toc should exist. This test doesn't say if + directories with empty __init__.py and and nothing else should be + skipped, just ensures consistency between what's referenced in the toc + and what is created. This is the variant with pep420 enabled. + """ + outdir = apidoc.outdir + assert (outdir / 'conf.py').isfile() + + toc = extract_toc(outdir / 'mypackage.rst') + + refs = [l.strip() for l in toc.splitlines() if l.strip()] + found_refs = [] + missing_files = [] + for ref in refs: + if ref and ref[0] in (':', '#'): + continue + found_refs.append(ref) + filename = "{}.rst".format(ref) + if not (outdir / filename).isfile(): + missing_files.append(filename) + + assert len(missing_files) == 0, \ + 'File(s) referenced in TOC not found: {}\n' \ + 'TOC:\n{}'.format(", ".join(missing_files), toc) + + +@pytest.mark.apidoc( + coderoot='test-apidoc-toc', +) +def test_toc_all_references_should_exist_pep420_disabled(make_app, apidoc): + """All references in toc should exist. This test doesn't say if + directories with empty __init__.py and and nothing else should be + skipped, just ensures consistency between what's referenced in the toc + and what is created. This is the variant with pep420 disabled. + """ + outdir = apidoc.outdir + assert (outdir / 'conf.py').isfile() + + toc = extract_toc(outdir / 'mypackage.rst') + + refs = [l.strip() for l in toc.splitlines() if l.strip()] + found_refs = [] + missing_files = [] + for ref in refs: + if ref and ref[0] in (':', '#'): + continue + filename = "{}.rst".format(ref) + found_refs.append(ref) + if not (outdir / filename).isfile(): + missing_files.append(filename) + + assert len(missing_files) == 0, \ + 'File(s) referenced in TOC not found: {}\n' \ + 'TOC:\n{}'.format(", ".join(missing_files), toc) + + +def extract_toc(path): + """Helper: Extract toc section from package rst file""" + with open(path) as f: + rst = f.read() + + # Read out the part containing the toctree + toctree_start = "\n.. toctree::\n" + toctree_end = "\nSubmodules" + + start_idx = rst.index(toctree_start) + end_idx = rst.index(toctree_end, start_idx) + toctree = rst[start_idx + len(toctree_start):end_idx] + + return toctree From 2e04c2a0588d1b9e7b1cf0d1b67e1a5496704960 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 21 Dec 2017 19:33:47 +0100 Subject: [PATCH 0470/1814] Update CHANGES for PR #4332 --- CHANGES | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index b617835f5..3b3bb7c17 100644 --- a/CHANGES +++ b/CHANGES @@ -51,8 +51,10 @@ Features added * #4212: autosummary: catch all exceptions when importing modules * #4166: Add :confval:`math_numfig` for equation numbering by section (refs: #3991, #4080). Thanks to Oliver Jahn. -* #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, ... +* #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, and + code-blocks * #947: autodoc now supports ignore-module-all to ignore a module's ``__all__`` +* #4332: Let LaTeX obey :confval:`math_numfig` for equation numbering Features removed From a9efb2517a0ccbd932f7e6be3e8984d78dc763b8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 23 Dec 2017 21:20:32 +0900 Subject: [PATCH 0471/1814] Fix flake8 violations --- tests/test_autodoc.py | 2 +- tests/test_build.py | 4 +- tests/test_build_epub.py | 2 - tests/test_build_html.py | 1 - tests/test_build_latex.py | 11 +- tests/test_docutilsconf.py | 2 +- tests/test_domain_cpp.py | 438 +++++++++++++++++----------------- tests/test_environment.py | 2 +- tests/test_ext_autosummary.py | 3 +- tests/test_ext_graphviz.py | 2 + tests/test_ext_intersphinx.py | 1 - tests/test_ext_todo.py | 4 +- tests/test_intl.py | 1 + tests/test_quickstart.py | 1 - tests/test_util.py | 1 - tests/test_util_images.py | 16 +- tests/test_util_inspect.py | 1 - tests/test_versioning.py | 2 +- 18 files changed, 247 insertions(+), 247 deletions(-) diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index d3c0a1f50..8d67cdb6f 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -425,7 +425,7 @@ def test_get_doc(): # class has __init__ method without docstring and # __new__ method with docstring # class docstring: depends on config value which one is taken - class I: + class I: # NOQA """Class docstring""" def __new__(cls): """New docstring""" diff --git a/tests/test_build.py b/tests/test_build.py index 387e308a8..6892ddfad 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -34,8 +34,8 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir): basedir = sphinx_test_tempdir / request.node.originalname # Windows with versions prior to 3.2 (I think) doesn't support unicode on system path # so we force a non-unicode path in that case - if sys.platform == "win32" and \ - not (sys.version_info.major >= 3 and sys.version_info.minor >= 2): + if (sys.platform == "win32" and + not (sys.version_info.major >= 3 and sys.version_info.minor >= 2)): return basedir / 'all' try: srcdir = basedir / test_name diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py index 397547734..e5d86b0ed 100644 --- a/tests/test_build_epub.py +++ b/tests/test_build_epub.py @@ -245,5 +245,3 @@ def test_epub_writing_mode(app): # vertical / writing-mode (CSS) css = (app.outdir / '_static' / 'epub.css').text() assert 'writing-mode: vertical-rl;' in css - - diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 2d56ba5c6..dafc1f09f 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -15,7 +15,6 @@ from itertools import cycle, chain from six import PY3 -from sphinx import __display_version__ from sphinx.util.inventory import InventoryFile from sphinx.testing.util import remove_unicode_literals, strip_escseq import xml.etree.cElementTree as ElementTree diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index bf0e84c57..5c0450810 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -773,6 +773,7 @@ def test_toctree_maxdepth_manual(app, status, warning): assert '\\setcounter{secnumdepth}' not in result assert '\\chapter{Foo}' in result + @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', confoverrides={'latex_documents': [ @@ -789,6 +790,7 @@ def test_toctree_maxdepth_howto(app, status, warning): assert '\\setcounter{secnumdepth}' not in result assert '\\section{Foo}' in result + @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', confoverrides={'master_doc': 'foo'}) @@ -802,6 +804,7 @@ def test_toctree_not_found(app, status, warning): assert '\\setcounter{secnumdepth}' not in result assert '\\chapter{Foo A}' in result + @pytest.mark.sphinx( 'latex', testroot='toctree-maxdepth', confoverrides={'master_doc': 'bar'}) @@ -858,8 +861,8 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning): 'latex', testroot='toctree-maxdepth', confoverrides={'latex_toplevel_sectioning': 'part', 'latex_documents': [ - ('index', 'Python.tex', 'Sphinx Tests Documentation', - 'Georg Brandl', 'howto') + ('index', 'Python.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'howto') ]}) def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning): app.builder.build_all() @@ -888,8 +891,8 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning): 'latex', testroot='toctree-maxdepth', confoverrides={'latex_toplevel_sectioning': 'chapter', 'latex_documents': [ - ('index', 'Python.tex', 'Sphinx Tests Documentation', - 'Georg Brandl', 'howto') + ('index', 'Python.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'howto') ]}) def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning): app.builder.build_all() diff --git a/tests/test_docutilsconf.py b/tests/test_docutilsconf.py index fd5cf7a61..bca41feea 100644 --- a/tests/test_docutilsconf.py +++ b/tests/test_docutilsconf.py @@ -72,7 +72,7 @@ def test_texinfo(app, status, warning): @pytest.mark.sphinx('html', testroot='docutilsconf', docutilsconf='[general]\nsource_link=true\n') -@pytest.mark.skip(sys.platform == "win32" and \ +@pytest.mark.skip(sys.platform == "win32" and not (sys.version_info.major >= 3 and sys.version_info.minor >= 2), reason="Python < 3.2 on Win32 doesn't handle non-ASCII paths right") def test_docutils_source_link_with_nonascii_file(app, status, warning): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index e4f3a678b..aed574daf 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -101,13 +101,13 @@ def test_fundamental_types(): if t == "std::nullptr_t": id = "NSt9nullptr_tE" return "1f%s" % id - check("function", "void f(%s arg)" % t, {1: makeIdV1(), 2:makeIdV2()}) + check("function", "void f(%s arg)" % t, {1: makeIdV1(), 2: makeIdV2()}) def test_expressions(): def exprCheck(expr, id): ids = 'IE1CIA%s_1aE' - check('class', 'template<> C' % expr, {2:ids % expr, 3:ids % id}) + check('class', 'template<> C' % expr, {2: ids % expr, 3: ids % id}) # primary exprCheck('nullptr', 'LDnE') exprCheck('true', 'L1E') @@ -118,9 +118,9 @@ def test_expressions(): for i in ints: for u in unsignedSuffix: for l in longSuffix: - expr = i + u + l; + expr = i + u + l exprCheck(expr, 'L' + expr + 'E') - expr = i + l + u; + expr = i + l + u exprCheck(expr, 'L' + expr + 'E') for suffix in ['', 'f', 'F', 'l', 'L']: expr = '5.0' + suffix @@ -200,55 +200,55 @@ def test_expressions(): # a < expression that starts with something that could be a template exprCheck('A < 42', 'lt1AL42E') check('function', 'template<> void f(A &v)', - {2:"IE1fR1AI1BX2EE", 3:"IE1fR1AI1BXL2EEE"}) + {2: "IE1fR1AI1BX2EE", 3: "IE1fR1AI1BXL2EEE"}) exprCheck('A<1>::value', 'N1AIXL1EEE5valueE') - check('class', "template A", {2:"I_iE1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2:"1A"}) + check('class', "template A", {2: "I_iE1A"}) + check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) def test_type_definitions(): - check("type", "public bool b", {1:"b", 2:"1b"}, "bool b") - check("type", "bool A::b", {1:"A::b", 2:"N1A1bE"}) - check("type", "bool *b", {1:"b", 2:"1b"}) - check("type", "bool *const b", {1:"b", 2:"1b"}) - check("type", "bool *volatile const b", {1:"b", 2:"1b"}) - check("type", "bool *volatile const b", {1:"b", 2:"1b"}) - check("type", "bool *volatile const *b", {1:"b", 2:"1b"}) - check("type", "bool &b", {1:"b", 2:"1b"}) - check("type", "bool b[]", {1:"b", 2:"1b"}) - check("type", "std::pair coord", {1:"coord", 2:"5coord"}) - check("type", "long long int foo", {1:"foo", 2:"3foo"}) + check("type", "public bool b", {1: "b", 2: "1b"}, "bool b") + check("type", "bool A::b", {1: "A::b", 2: "N1A1bE"}) + check("type", "bool *b", {1: "b", 2: "1b"}) + check("type", "bool *const b", {1: "b", 2: "1b"}) + check("type", "bool *volatile const b", {1: "b", 2: "1b"}) + check("type", "bool *volatile const b", {1: "b", 2: "1b"}) + check("type", "bool *volatile const *b", {1: "b", 2: "1b"}) + check("type", "bool &b", {1: "b", 2: "1b"}) + check("type", "bool b[]", {1: "b", 2: "1b"}) + check("type", "std::pair coord", {1: "coord", 2: "5coord"}) + check("type", "long long int foo", {1: "foo", 2: "3foo"}) check("type", 'std::vector> module::blah', - {1:"module::blah", 2:"N6module4blahE"}) - check("type", "std::function F", {1:"F", 2:"1F"}) - check("type", "std::function F", {1:"F", 2:"1F"}) - check("type", "std::function F", {1:"F", 2:"1F"}) - check("type", "std::function F", {1:"F", 2:"1F"}) + {1: "module::blah", 2: "N6module4blahE"}) + check("type", "std::function F", {1: "F", 2: "1F"}) + check("type", "std::function F", {1: "F", 2: "1F"}) + check("type", "std::function F", {1: "F", 2: "1F"}) + check("type", "std::function F", {1: "F", 2: "1F"}) check("type", "MyContainer::const_iterator", - {1:"MyContainer::const_iterator", 2:"N11MyContainer14const_iteratorE"}) + {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}) check("type", "public MyContainer::const_iterator", - {1:"MyContainer::const_iterator", 2:"N11MyContainer14const_iteratorE"}, + {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}, output="MyContainer::const_iterator") # test decl specs on right - check("type", "bool const b", {1:"b", 2:"1b"}) + check("type", "bool const b", {1: "b", 2: "1b"}) # test name in global scope - check("type", "bool ::B::b", {1:"B::b", 2:"N1B1bE"}) + check("type", "bool ::B::b", {1: "B::b", 2: "N1B1bE"}) - check('type', 'A = B', {2:'1A'}) - check('type', 'A = decltype(b)', {2:'1A'}) + check('type', 'A = B', {2: '1A'}) + check('type', 'A = decltype(b)', {2: '1A'}) # from breathe#267 (named function parameters for function pointers check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', - {1:'gpio_callback_t', 2:'15gpio_callback_t'}) - check('type', 'void (*f)(std::function g)', {1:'f', 2:'1f'}) + {1: 'gpio_callback_t', 2: '15gpio_callback_t'}) + check('type', 'void (*f)(std::function g)', {1: 'f', 2: '1f'}) def test_concept_definitions(): check('concept', 'template A::B::Concept', - {2:'I0EN1A1B7ConceptE'}) + {2: 'I0EN1A1B7ConceptE'}) check('concept', 'template Foo', - {2:'I00DpE3Foo'}) + {2: 'I00DpE3Foo'}) with pytest.raises(DefinitionError): parse('concept', 'Foo') with pytest.raises(DefinitionError): @@ -257,269 +257,270 @@ def test_concept_definitions(): def test_member_definitions(): check('member', ' const std::string & name = 42', - {1:"name__ssCR", 2:"4name"}, output='const std::string &name = 42') - check('member', ' const std::string & name', {1:"name__ssCR", 2:"4name"}, + {1: "name__ssCR", 2: "4name"}, output='const std::string &name = 42') + check('member', ' const std::string & name', {1: "name__ssCR", 2: "4name"}, output='const std::string &name') check('member', ' const std::string & name [ n ]', - {1:"name__ssCRA", 2:"4name"}, output='const std::string &name[n]') + {1: "name__ssCRA", 2: "4name"}, output='const std::string &name[n]') check('member', 'const std::vector< unsigned int, long> &name', - {1:"name__std::vector:unsigned-i.l:CR", 2:"4name"}, + {1: "name__std::vector:unsigned-i.l:CR", 2: "4name"}, output='const std::vector &name') - check('member', 'module::myclass foo[n]', {1:"foo__module::myclassA", 2:"3foo"}) - check('member', 'int *const p', {1:'p__iPC', 2:'1p'}) - check('member', 'extern int myInt', {1:'myInt__i', 2:'5myInt'}) - check('member', 'thread_local int myInt', {1:'myInt__i', 2:'5myInt'}) - check('member', 'extern thread_local int myInt', {1:'myInt__i', 2:'5myInt'}) - check('member', 'thread_local extern int myInt', {1:'myInt__i', 2:'5myInt'}, + check('member', 'module::myclass foo[n]', {1: "foo__module::myclassA", 2: "3foo"}) + check('member', 'int *const p', {1: 'p__iPC', 2: '1p'}) + check('member', 'extern int myInt', {1: 'myInt__i', 2: '5myInt'}) + check('member', 'thread_local int myInt', {1: 'myInt__i', 2: '5myInt'}) + check('member', 'extern thread_local int myInt', {1: 'myInt__i', 2: '5myInt'}) + check('member', 'thread_local extern int myInt', {1: 'myInt__i', 2: '5myInt'}, 'extern thread_local int myInt') def test_function_definitions(): - check('function', 'operator bool() const', {1:"castto-b-operatorC", 2:"NKcvbEv"}) + check('function', 'operator bool() const', {1: "castto-b-operatorC", 2: "NKcvbEv"}) check('function', 'A::operator bool() const', - {1:"A::castto-b-operatorC", 2:"NK1AcvbEv"}) + {1: "A::castto-b-operatorC", 2: "NK1AcvbEv"}) check('function', 'A::operator bool() volatile const &', - {1:"A::castto-b-operatorVCR", 2:"NVKR1AcvbEv"}) + {1: "A::castto-b-operatorVCR", 2: "NVKR1AcvbEv"}) check('function', 'A::operator bool() volatile const &&', - {1:"A::castto-b-operatorVCO", 2:"NVKO1AcvbEv"}) + {1: "A::castto-b-operatorVCO", 2: "NVKO1AcvbEv"}) check('function', 'bool namespaced::theclass::method(arg1, arg2)', - {1:"namespaced::theclass::method__arg1.arg2", - 2:"N10namespaced8theclass6methodE4arg14arg2"}) + {1: "namespaced::theclass::method__arg1.arg2", + 2: "N10namespaced8theclass6methodE4arg14arg2"}) x = 'std::vector> &module::test(register int ' \ 'foo, bar, std::string baz = "foobar, blah, bleh") const = 0' - check('function', x, {1:"module::test__i.bar.ssC", - 2:"NK6module4testEi3barNSt6stringE"}) + check('function', x, {1: "module::test__i.bar.ssC", + 2: "NK6module4testEi3barNSt6stringE"}) check('function', 'void f(std::pair)', - {1:"f__std::pair:A.B:", 2:"1fNSt4pairI1A1BEE"}) + {1: "f__std::pair:A.B:", 2: "1fNSt4pairI1A1BEE"}) check('function', 'explicit module::myclass::foo::foo()', - {1:"module::myclass::foo::foo", 2:"N6module7myclass3foo3fooEv"}) + {1: "module::myclass::foo::foo", 2: "N6module7myclass3foo3fooEv"}) check('function', 'module::myclass::foo::~foo()', - {1:"module::myclass::foo::~foo", 2:"N6module7myclass3fooD0Ev"}) + {1: "module::myclass::foo::~foo", 2: "N6module7myclass3fooD0Ev"}) check('function', 'int printf(const char *fmt, ...)', - {1:"printf__cCP.z", 2:"6printfPKcz"}) + {1: "printf__cCP.z", 2: "6printfPKcz"}) check('function', 'int foo(const unsigned int j)', - {1:"foo__unsigned-iC", 2:"3fooKj"}) + {1: "foo__unsigned-iC", 2: "3fooKj"}) check('function', 'int foo(const int *const ptr)', - {1:"foo__iCPC", 2:"3fooPCKi"}) + {1: "foo__iCPC", 2: "3fooPCKi"}) check('function', 'module::myclass::operator std::vector()', - {1:"module::myclass::castto-std::vector:ss:-operator", - 2:"N6module7myclasscvNSt6vectorINSt6stringEEEEv"}) + {1: "module::myclass::castto-std::vector:ss:-operator", + 2: "N6module7myclasscvNSt6vectorINSt6stringEEEEv"}) check('function', 'void operator()(const boost::array &v) const', - {1:"call-operator__boost::array:VertexID.2:CRC", - 2:"NKclERKN5boost5arrayI8VertexIDX2EEE", - 3:"NKclERKN5boost5arrayI8VertexIDXL2EEEE"}) + {1: "call-operator__boost::array:VertexID.2:CRC", + 2: "NKclERKN5boost5arrayI8VertexIDX2EEE", + 3: "NKclERKN5boost5arrayI8VertexIDXL2EEEE"}) check('function', 'void operator()(const boost::array &v) const', - {1:'call-operator__boost::array:VertexID.2."foo,--bar":CRC', - 2:'NKclERKN5boost5arrayI8VertexIDX2EX"foo, bar"EEE', - 3:'NKclERKN5boost5arrayI8VertexIDXL2EEXLA9_KcEEEE'}) + {1: 'call-operator__boost::array:VertexID.2."foo,--bar":CRC', + 2: 'NKclERKN5boost5arrayI8VertexIDX2EX"foo, bar"EEE', + 3: 'NKclERKN5boost5arrayI8VertexIDXL2EEXLA9_KcEEEE'}) check('function', 'MyClass::MyClass(MyClass::MyClass&&)', - {1:"MyClass::MyClass__MyClass::MyClassRR", - 2:"N7MyClass7MyClassERRN7MyClass7MyClassE"}) - check('function', 'constexpr int get_value()', {1:"get_valueCE", 2:"9get_valuev"}) + {1: "MyClass::MyClass__MyClass::MyClassRR", + 2: "N7MyClass7MyClassERRN7MyClass7MyClassE"}) + check('function', 'constexpr int get_value()', {1: "get_valueCE", 2: "9get_valuev"}) check('function', 'static constexpr int get_value()', - {1:"get_valueCE", 2:"9get_valuev"}) + {1: "get_valueCE", 2: "9get_valuev"}) check('function', 'int get_value() const noexcept', - {1:"get_valueC", 2:"NK9get_valueEv"}) + {1: "get_valueC", 2: "NK9get_valueEv"}) check('function', 'int get_value() const noexcept = delete', - {1:"get_valueC", 2:"NK9get_valueEv"}) + {1: "get_valueC", 2: "NK9get_valueEv"}) check('function', 'int get_value() volatile const', - {1:"get_valueVC", 2:"NVK9get_valueEv"}) + {1: "get_valueVC", 2: "NVK9get_valueEv"}) check('function', 'MyClass::MyClass(MyClass::MyClass&&) = default', - {1:"MyClass::MyClass__MyClass::MyClassRR", - 2:"N7MyClass7MyClassERRN7MyClass7MyClassE"}) + {1: "MyClass::MyClass__MyClass::MyClassRR", + 2: "N7MyClass7MyClassERRN7MyClass7MyClassE"}) check('function', 'virtual MyClass::a_virtual_function() const override', - {1:"MyClass::a_virtual_functionC", 2:"NK7MyClass18a_virtual_functionEv"}) - check('function', 'A B() override', {1:"B", 2:"1Bv"}) - check('function', 'A B() final', {1:"B", 2:"1Bv"}) - check('function', 'A B() final override', {1:"B", 2:"1Bv"}) - check('function', 'A B() override final', {1:"B", 2:"1Bv"}, + {1: "MyClass::a_virtual_functionC", 2: "NK7MyClass18a_virtual_functionEv"}) + check('function', 'A B() override', {1: "B", 2: "1Bv"}) + check('function', 'A B() final', {1: "B", 2: "1Bv"}) + check('function', 'A B() final override', {1: "B", 2: "1Bv"}) + check('function', 'A B() override final', {1: "B", 2: "1Bv"}, output='A B() final override') check('function', 'MyClass::a_member_function() volatile', - {1:"MyClass::a_member_functionV", 2:"NV7MyClass17a_member_functionEv"}) + {1: "MyClass::a_member_functionV", 2: "NV7MyClass17a_member_functionEv"}) check('function', 'MyClass::a_member_function() volatile const', - {1:"MyClass::a_member_functionVC", 2:"NVK7MyClass17a_member_functionEv"}) + {1: "MyClass::a_member_functionVC", 2: "NVK7MyClass17a_member_functionEv"}) check('function', 'MyClass::a_member_function() &&', - {1:"MyClass::a_member_functionO", 2:"NO7MyClass17a_member_functionEv"}) + {1: "MyClass::a_member_functionO", 2: "NO7MyClass17a_member_functionEv"}) check('function', 'MyClass::a_member_function() &', - {1:"MyClass::a_member_functionR", 2:"NR7MyClass17a_member_functionEv"}) + {1: "MyClass::a_member_functionR", 2: "NR7MyClass17a_member_functionEv"}) check('function', 'MyClass::a_member_function() const &', - {1:"MyClass::a_member_functionCR", 2:"NKR7MyClass17a_member_functionEv"}) + {1: "MyClass::a_member_functionCR", 2: "NKR7MyClass17a_member_functionEv"}) check('function', 'int main(int argc, char *argv[])', - {1:"main__i.cPA", 2:"4mainiA_Pc"}) + {1: "main__i.cPA", 2: "4mainiA_Pc"}) check('function', 'MyClass &MyClass::operator++()', - {1:"MyClass::inc-operator", 2:"N7MyClassppEv"}) + {1: "MyClass::inc-operator", 2: "N7MyClassppEv"}) check('function', 'MyClass::pointer MyClass::operator->()', - {1:"MyClass::pointer-operator", 2:"N7MyClassptEv"}) + {1: "MyClass::pointer-operator", 2: "N7MyClassptEv"}) x = 'std::vector> &module::test(register int ' \ 'foo, bar[n], std::string baz = "foobar, blah, bleh") const = 0' - check('function', x, {1:"module::test__i.barA.ssC", - 2:"NK6module4testEiAn_3barNSt6stringE", - 3:"NK6module4testEiA1n_3barNSt6stringE"}) + check('function', x, {1: "module::test__i.barA.ssC", + 2: "NK6module4testEiAn_3barNSt6stringE", + 3: "NK6module4testEiA1n_3barNSt6stringE"}) check('function', 'int foo(Foo f = Foo(double(), std::make_pair(int(2), double(3.4))))', - {1:"foo__Foo", 2:"3foo3Foo"}) - check('function', 'int foo(A a = x(a))', {1:"foo__A", 2:"3foo1A"}) + {1: "foo__Foo", 2: "3foo3Foo"}) + check('function', 'int foo(A a = x(a))', {1: "foo__A", 2: "3foo1A"}) with pytest.raises(DefinitionError): parse('function', 'int foo(B b=x(a)') with pytest.raises(DefinitionError): parse('function', 'int foo)C c=x(a))') with pytest.raises(DefinitionError): parse('function', 'int foo(D d=x(a') - check('function', 'int foo(const A&... a)', {1:"foo__ACRDp", 2:"3fooDpRK1A"}) - check('function', 'virtual void f()', {1:"f", 2:"1fv"}) + check('function', 'int foo(const A&... a)', {1: "foo__ACRDp", 2: "3fooDpRK1A"}) + check('function', 'virtual void f()', {1: "f", 2: "1fv"}) # test for ::nestedName, from issue 1738 check("function", "result(int val, ::std::error_category const &cat)", - {1:"result__i.std::error_categoryCR", 2:"6resultiRNSt14error_categoryE"}) - check("function", "int *f()", {1:"f", 2:"1fv"}) + {1: "result__i.std::error_categoryCR", 2: "6resultiRNSt14error_categoryE"}) + check("function", "int *f()", {1: "f", 2: "1fv"}) # tests derived from issue #1753 (skip to keep sanity) - check("function", "f(int (&array)[10])", {2:"1fRA10_i", 3:"1fRAL10E_i"}) - check("function", "void f(int (&array)[10])", {2:"1fRA10_i", 3:"1fRAL10E_i"}) - check("function", "void f(float *q(double))", {2:"1fFPfdE"}) - check("function", "void f(float *(*q)(double))", {2:"1fPFPfdE"}) - check("function", "void f(float (*q)(double))", {2:"1fPFfdE"}) - check("function", "int (*f(double d))(float)", {1:"f__double", 2:"1fd"}) - check("function", "int (*f(bool b))[5]", {1:"f__b", 2:"1fb"}) + check("function", "f(int (&array)[10])", {2: "1fRA10_i", 3: "1fRAL10E_i"}) + check("function", "void f(int (&array)[10])", {2: "1fRA10_i", 3: "1fRAL10E_i"}) + check("function", "void f(float *q(double))", {2: "1fFPfdE"}) + check("function", "void f(float *(*q)(double))", {2: "1fPFPfdE"}) + check("function", "void f(float (*q)(double))", {2: "1fPFfdE"}) + check("function", "int (*f(double d))(float)", {1: "f__double", 2: "1fd"}) + check("function", "int (*f(bool b))[5]", {1: "f__b", 2: "1fb"}) check("function", "int (*A::f(double d) const)(float)", - {1:"A::f__doubleC", 2:"NK1A1fEd"}) + {1: "A::f__doubleC", 2: "NK1A1fEd"}) check("function", "void f(std::shared_ptr ptr)", - {2:"1fNSt10shared_ptrIFidEEE"}) - check("function", "void f(int *const p)", {1:"f__iPC", 2:"1fPCi"}) - check("function", "void f(int *volatile const p)", {1:"f__iPVC", 2:"1fPVCi"}) + {2: "1fNSt10shared_ptrIFidEEE"}) + check("function", "void f(int *const p)", {1: "f__iPC", 2: "1fPCi"}) + check("function", "void f(int *volatile const p)", {1: "f__iPVC", 2: "1fPVCi"}) - check('function', 'extern int f()', {1:'f', 2:'1fv'}) + check('function', 'extern int f()', {1: 'f', 2: '1fv'}) - check('function', 'decltype(auto) f()', {1: 'f', 2:"1fv"}) + check('function', 'decltype(auto) f()', {1: 'f', 2: "1fv"}) # TODO: make tests for functions in a template, e.g., Test # such that the id generation for function type types is correct. check('function', 'friend std::ostream &f(std::ostream&, int)', - {1:'f__osR.i', 2:'1fRNSt7ostreamEi'}) + {1: 'f__osR.i', 2: '1fRNSt7ostreamEi'}) # from breathe#223 - check('function', 'void f(struct E e)', {1:'f__E', 2:'1f1E'}) - check('function', 'void f(class E e)', {1:'f__E', 2:'1f1E'}) - check('function', 'void f(typename E e)', {1:'f__E', 2:'1f1E'}) - check('function', 'void f(enum E e)', {1:'f__E', 2:'1f1E'}) - check('function', 'void f(union E e)', {1:'f__E', 2:'1f1E'}) + check('function', 'void f(struct E e)', {1: 'f__E', 2: '1f1E'}) + check('function', 'void f(class E e)', {1: 'f__E', 2: '1f1E'}) + check('function', 'void f(typename E e)', {1: 'f__E', 2: '1f1E'}) + check('function', 'void f(enum E e)', {1: 'f__E', 2: '1f1E'}) + check('function', 'void f(union E e)', {1: 'f__E', 2: '1f1E'}) # pointer to member (function) - check('function', 'void f(int C::*)', {2:'1fM1Ci'}) - check('function', 'void f(int C::* p)', {2:'1fM1Ci'}) - check('function', 'void f(int ::C::* p)', {2:'1fM1Ci'}) - check('function', 'void f(int C::* const)', {2:'1fKM1Ci'}) - check('function', 'void f(int C::* const&)', {2:'1fRKM1Ci'}) - check('function', 'void f(int C::* volatile)', {2:'1fVM1Ci'}) - check('function', 'void f(int C::* const volatile)', {2:'1fVKM1Ci'}, + check('function', 'void f(int C::*)', {2: '1fM1Ci'}) + check('function', 'void f(int C::* p)', {2: '1fM1Ci'}) + check('function', 'void f(int ::C::* p)', {2: '1fM1Ci'}) + check('function', 'void f(int C::* const)', {2: '1fKM1Ci'}) + check('function', 'void f(int C::* const&)', {2: '1fRKM1Ci'}) + check('function', 'void f(int C::* volatile)', {2: '1fVM1Ci'}) + check('function', 'void f(int C::* const volatile)', {2: '1fVKM1Ci'}, output='void f(int C::* volatile const)') - check('function', 'void f(int C::* volatile const)', {2:'1fVKM1Ci'}) - check('function', 'void f(int (C::*)(float, double))', {2:'1fM1CFifdE'}) - check('function', 'void f(int (C::* p)(float, double))', {2:'1fM1CFifdE'}) - check('function', 'void f(int (::C::* p)(float, double))', {2:'1fM1CFifdE'}) - check('function', 'void f(void (C::*)() const &)', {2:'1fM1CKRFvvE'}) - check('function', 'int C::* f(int, double)', {2:'1fid'}) - check('function', 'void f(int C::* *)', {2:'1fPM1Ci'}) + check('function', 'void f(int C::* volatile const)', {2: '1fVKM1Ci'}) + check('function', 'void f(int (C::*)(float, double))', {2: '1fM1CFifdE'}) + check('function', 'void f(int (C::* p)(float, double))', {2: '1fM1CFifdE'}) + check('function', 'void f(int (::C::* p)(float, double))', {2: '1fM1CFifdE'}) + check('function', 'void f(void (C::*)() const &)', {2: '1fM1CKRFvvE'}) + check('function', 'int C::* f(int, double)', {2: '1fid'}) + check('function', 'void f(int C::* *)', {2: '1fPM1Ci'}) def test_operators(): check('function', 'void operator new [ ] ()', - {1:"new-array-operator", 2:"nav"}, output='void operator new[]()') + {1: "new-array-operator", 2: "nav"}, output='void operator new[]()') check('function', 'void operator delete ()', - {1:"delete-operator", 2:"dlv"}, output='void operator delete()') + {1: "delete-operator", 2: "dlv"}, output='void operator delete()') check('function', 'operator bool() const', - {1:"castto-b-operatorC", 2:"NKcvbEv"}, output='operator bool() const') + {1: "castto-b-operatorC", 2: "NKcvbEv"}, output='operator bool() const') check('function', 'void operator * ()', - {1:"mul-operator", 2:"mlv"}, output='void operator*()') + {1: "mul-operator", 2: "mlv"}, output='void operator*()') check('function', 'void operator - ()', - {1:"sub-operator", 2:"miv"}, output='void operator-()') + {1: "sub-operator", 2: "miv"}, output='void operator-()') check('function', 'void operator + ()', - {1:"add-operator", 2:"plv"}, output='void operator+()') + {1: "add-operator", 2: "plv"}, output='void operator+()') check('function', 'void operator = ()', - {1:"assign-operator", 2:"aSv"}, output='void operator=()') + {1: "assign-operator", 2: "aSv"}, output='void operator=()') check('function', 'void operator / ()', - {1:"div-operator", 2:"dvv"}, output='void operator/()') + {1: "div-operator", 2: "dvv"}, output='void operator/()') check('function', 'void operator % ()', - {1:"mod-operator", 2:"rmv"}, output='void operator%()') + {1: "mod-operator", 2: "rmv"}, output='void operator%()') check('function', 'void operator ! ()', - {1:"not-operator", 2:"ntv"}, output='void operator!()') + {1: "not-operator", 2: "ntv"}, output='void operator!()') check('function', 'void operator "" _udl()', - {2:'li4_udlv'}, output='void operator""_udl()') + {2: 'li4_udlv'}, output='void operator""_udl()') def test_class_definitions(): - check('class', 'public A', {1:"A", 2:"1A"}, output='A') - check('class', 'private A', {1:"A", 2:"1A"}) - check('class', 'A final', {1:'A', 2:'1A'}) + check('class', 'public A', {1: "A", 2: "1A"}, output='A') + check('class', 'private A', {1: "A", 2: "1A"}) + check('class', 'A final', {1: 'A', 2: '1A'}) # test bases - check('class', 'A', {1:"A", 2:"1A"}) - check('class', 'A::B::C', {1:"A::B::C", 2:"N1A1B1CE"}) - check('class', 'A : B', {1:"A", 2:"1A"}) - check('class', 'A : private B', {1:"A", 2:"1A"}, output='A : B') - check('class', 'A : public B', {1:"A", 2:"1A"}) - check('class', 'A : B, C', {1:"A", 2:"1A"}) - check('class', 'A : B, protected C, D', {1:"A", 2:"1A"}) - check('class', 'A : virtual private B', {1:'A', 2:'1A'}, output='A : virtual B') - check('class', 'A : B, virtual C', {1:'A', 2:'1A'}) - check('class', 'A : public virtual B', {1:'A', 2:'1A'}) - check('class', 'A : B, C...', {1:'A', 2:'1A'}) - check('class', 'A : B..., C', {1:'A', 2:'1A'}) + check('class', 'A', {1: "A", 2: "1A"}) + check('class', 'A::B::C', {1: "A::B::C", 2: "N1A1B1CE"}) + check('class', 'A : B', {1: "A", 2: "1A"}) + check('class', 'A : private B', {1: "A", 2: "1A"}, output='A : B') + check('class', 'A : public B', {1: "A", 2: "1A"}) + check('class', 'A : B, C', {1: "A", 2: "1A"}) + check('class', 'A : B, protected C, D', {1: "A", 2: "1A"}) + check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='A : virtual B') + check('class', 'A : B, virtual C', {1: 'A', 2: '1A'}) + check('class', 'A : public virtual B', {1: 'A', 2: '1A'}) + check('class', 'A : B, C...', {1: 'A', 2: '1A'}) + check('class', 'A : B..., C', {1: 'A', 2: '1A'}) # from #4094 - check('class', 'template> has_var', {2:'I00E7has_var'}) - check('class', 'template has_var>', {2:'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) + check('class', 'template> has_var', {2: 'I00E7has_var'}) + check('class', 'template has_var>', + {2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) def test_enum_definitions(): - check('enum', 'A', {2:"1A"}) - check('enum', 'A : std::underlying_type::type', {2:"1A"}) - check('enum', 'A : unsigned int', {2:"1A"}) - check('enum', 'public A', {2:"1A"}, output='A') - check('enum', 'private A', {2:"1A"}) + check('enum', 'A', {2: "1A"}) + check('enum', 'A : std::underlying_type::type', {2: "1A"}) + check('enum', 'A : unsigned int', {2: "1A"}) + check('enum', 'public A', {2: "1A"}, output='A') + check('enum', 'private A', {2: "1A"}) - check('enumerator', 'A', {2:"1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2:"1A"}) + check('enumerator', 'A', {2: "1A"}) + check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) def test_templates(): - check('class', "A", {2:"IE1AI1TE"}, output="template<> A") + check('class', "A", {2: "IE1AI1TE"}, output="template<> A") # first just check which objects support templating - check('class', "template<> A", {2:"IE1A"}) - check('function', "template<> void A()", {2:"IE1Av"}) - check('member', "template<> A a", {2:"IE1a"}) - check('type', "template<> a = A", {2:"IE1a"}) + check('class', "template<> A", {2: "IE1A"}) + check('function', "template<> void A()", {2: "IE1Av"}) + check('member', "template<> A a", {2: "IE1a"}) + check('type', "template<> a = A", {2: "IE1a"}) with pytest.raises(DefinitionError): parse('enum', "template<> A") with pytest.raises(DefinitionError): parse('enumerator', "template<> A") # then all the real tests - check('class', "template A", {2:"I00E1A"}) - check('type', "template<> a", {2:"IE1a"}) + check('class', "template A", {2: "I00E1A"}) + check('type', "template<> a", {2: "IE1a"}) - check('class', "template A", {2:"I0E1A"}) - check('class', "template A", {2:"I0E1A"}) - check('class', "template A", {2:"IDpE1A"}) - check('class', "template A", {2:"IDpE1A"}) - check('class', "template A", {2:"I0E1A"}) - check('class', "template A", {2:"I0E1A"}) + check('class', "template A", {2: "I0E1A"}) + check('class', "template A", {2: "I0E1A"}) + check('class', "template A", {2: "IDpE1A"}) + check('class', "template A", {2: "IDpE1A"}) + check('class', "template A", {2: "I0E1A"}) + check('class', "template A", {2: "I0E1A"}) - check('class', "template typename T> A", {2:"II0E0E1A"}) + check('class', "template typename T> A", {2: "II0E0E1A"}) check('class', "template typename> A", {2: "II0E0E1A"}) - check('class', "template typename ...T> A", {2:"II0EDpE1A"}) + check('class', "template typename ...T> A", {2: "II0EDpE1A"}) check('class', "template typename...> A", {2: "II0EDpE1A"}) - check('class', "template A", {2:"I_iE1A"}) - check('class', "template A", {2:"I_iE1A"}) - check('class', "template A", {2:"I_DpiE1A"}) - check('class', "template A", {2:"I_iE1A"}) - check('class', "template A", {2:"I_iE1A"}) + check('class', "template A", {2: "I_iE1A"}) + check('class', "template A", {2: "I_iE1A"}) + check('class', "template A", {2: "I_DpiE1A"}) + check('class', "template A", {2: "I_iE1A"}) + check('class', "template A", {2: "I_iE1A"}) - check('class', "template<> A>", {2:"IE1AIN2NS1BIEEE"}) + check('class', "template<> A>", {2: "IE1AIN2NS1BIEEE"}) # from #2058 check('function', @@ -527,8 +528,8 @@ def test_templates(): "inline std::basic_ostream &operator<<(" "std::basic_ostream &os, " "const c_string_view_base &str)", - {2:"I00ElsRNSt13basic_ostreamI4Char6TraitsEE" - "RK18c_string_view_baseIK4Char6TraitsE"}) + {2: "I00ElsRNSt13basic_ostreamI4Char6TraitsEE" + "RK18c_string_view_baseIK4Char6TraitsE"}) # template introductions with pytest.raises(DefinitionError): @@ -536,42 +537,42 @@ def test_templates(): with pytest.raises(DefinitionError): parse('enumerator', 'abc::ns::foo{id_0, id_1, id_2} A') check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', - {2:'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', - {2:'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', - {2:'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barI4id_04id_14id_2EE'}) + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barI4id_04id_14id_2EE'}) check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', - {2:'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barI4id_04id_1Dp4id_2EE'}) + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barI4id_04id_1Dp4id_2EE'}) - check('class', 'template<> Concept{U} A::B', {2:'IEI0EX7ConceptI1UEEN1AIiE1BE'}) + check('class', 'template<> Concept{U} A::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'}) check('type', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar = ghi::qux', - {2:'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) check('type', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar = ghi::qux', - {2:'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) check('function', 'abc::ns::foo{id_0, id_1, id_2} void xyz::bar()', - {2:'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv'}) + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv'}) check('function', 'abc::ns::foo{id_0, id_1, ...id_2} void xyz::bar()', - {2:'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barEv'}) + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barEv'}) check('member', 'abc::ns::foo{id_0, id_1, id_2} ghi::qux xyz::bar', - {2:'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) check('member', 'abc::ns::foo{id_0, id_1, ...id_2} ghi::qux xyz::bar', - {2:'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) - check('concept', 'Iterator{T, U} Another', {2:'I00EX8IteratorI1T1UEE7Another'}) + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) + check('concept', 'Iterator{T, U} Another', {2: 'I00EX8IteratorI1T1UEE7Another'}) check('concept', 'template Numerics = (... && Numeric)', - {2:'IDpE8Numerics'}) + {2: 'IDpE8Numerics'}) # explicit specializations of members - check('member', 'template<> int A::a', {2:'IEN1AIiE1aE'}) + check('member', 'template<> int A::a', {2: 'IEN1AIiE1aE'}) check('member', 'template int A::a', {2: 'IEN1AIiE1aE'}, output='template<> int A::a') # same as above - check('member', 'template<> template<> int A::B::b', {2:'IEIEN1AIiE1BIiE1bE'}) + check('member', 'template<> template<> int A::B::b', {2: 'IEIEN1AIiE1BIiE1bE'}) check('member', 'template int A::B::b', {2: 'IEIEN1AIiE1BIiE1bE'}, output='template<> template<> int A::B::b') # same as above # defaulted constrained type parameters - check('type', 'template A', {2:'I_1CE1A'}) + check('type', 'template A', {2: 'I_1CE1A'}) def test_template_args(): @@ -579,33 +580,32 @@ def test_template_args(): check('function', "template " "void allow(F *f, typename func::type tt)", - {2:"I0E5allowP1FN4funcI1F1BXG != 1EE4typeE", - 3:"I0E5allowP1FN4funcI1F1BXne1GL1EEE4typeE"}) + {2: "I0E5allowP1FN4funcI1F1BXG != 1EE4typeE", + 3: "I0E5allowP1FN4funcI1F1BXne1GL1EEE4typeE"}) # from #3542 check('type', "template " "enable_if_not_array_t = std::enable_if_t::value, int>", - {2:"I0E21enable_if_not_array_t"}) - + {2: "I0E21enable_if_not_array_t"}) def test_attributes(): # style: C++ - check('member', '[[]] int f', {1:'f__i', 2:'1f'}) - check('member', '[ [ ] ] int f', {1:'f__i', 2:'1f'}, + check('member', '[[]] int f', {1: 'f__i', 2: '1f'}) + check('member', '[ [ ] ] int f', {1: 'f__i', 2: '1f'}, # this will fail when the proper grammar is implemented output='[[ ]] int f') - check('member', '[[a]] int f', {1:'f__i', 2:'1f'}) + check('member', '[[a]] int f', {1: 'f__i', 2: '1f'}) # style: GNU - check('member', '__attribute__(()) int f', {1:'f__i', 2:'1f'}) - check('member', '__attribute__((a)) int f', {1:'f__i', 2:'1f'}) - check('member', '__attribute__((a, b)) int f', {1:'f__i', 2:'1f'}) + check('member', '__attribute__(()) int f', {1: 'f__i', 2: '1f'}) + check('member', '__attribute__((a)) int f', {1: 'f__i', 2: '1f'}) + check('member', '__attribute__((a, b)) int f', {1: 'f__i', 2: '1f'}) # style: user-defined id - check('member', 'id_attr int f', {1:'f__i', 2:'1f'}) + check('member', 'id_attr int f', {1: 'f__i', 2: '1f'}) # style: user-defined paren - check('member', 'paren_attr() int f', {1:'f__i', 2:'1f'}) - check('member', 'paren_attr(a) int f', {1:'f__i', 2:'1f'}) - check('member', 'paren_attr("") int f', {1:'f__i', 2:'1f'}) - check('member', 'paren_attr(()[{}][]{}) int f', {1:'f__i', 2:'1f'}) + check('member', 'paren_attr() int f', {1: 'f__i', 2: '1f'}) + check('member', 'paren_attr(a) int f', {1: 'f__i', 2: '1f'}) + check('member', 'paren_attr("") int f', {1: 'f__i', 2: '1f'}) + check('member', 'paren_attr(()[{}][]{}) int f', {1: 'f__i', 2: '1f'}) with pytest.raises(DefinitionError): parse('member', 'paren_attr(() int f') with pytest.raises(DefinitionError): @@ -621,7 +621,7 @@ def test_attributes(): # position: decl specs check('function', 'static inline __attribute__(()) void f()', - {1:'f', 2:'1fv'}, + {1: 'f', 2: '1fv'}, output='__attribute__(()) static inline void f()') diff --git a/tests/test_environment.py b/tests/test_environment.py index 611d34577..64089b7c8 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -22,7 +22,7 @@ def setup_module(rootdir, sphinx_test_tempdir): global app, env srcdir = sphinx_test_tempdir / 'root-envtest' if not srcdir.exists(): - (rootdir/'test-root').copytree(srcdir) + (rootdir / 'test-root').copytree(srcdir) app = SphinxTestApp(srcdir=srcdir) env = app.env yield diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index b59f0cbc8..b0b34f8f1 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -163,7 +163,8 @@ def test_import_by_name(): assert parent is sphinx.ext.autosummary assert modname == 'sphinx.ext.autosummary' - prefixed_name, obj, parent, modname = import_by_name('sphinx.ext.autosummary.Autosummary.get_items') + prefixed_name, obj, parent, modname = \ + import_by_name('sphinx.ext.autosummary.Autosummary.get_items') assert prefixed_name == 'sphinx.ext.autosummary.Autosummary.get_items' assert obj == sphinx.ext.autosummary.Autosummary.get_items assert parent is sphinx.ext.autosummary.Autosummary diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py index 1d2a3ab2f..118e6abe2 100644 --- a/tests/test_ext_graphviz.py +++ b/tests/test_ext_graphviz.py @@ -40,6 +40,7 @@ def test_graphviz_png_html(app, status, warning): r'}\" />\n
') assert re.search(html, content, re.S) + @pytest.mark.sphinx('html', testroot='ext-graphviz', confoverrides={'graphviz_output_format': 'svg'}) @pytest.mark.usefixtures('if_graphviz_found') @@ -80,6 +81,7 @@ def test_graphviz_svg_html(app, status, warning): r'') assert re.search(html, content, re.S) + @pytest.mark.sphinx('latex', testroot='ext-graphviz') @pytest.mark.usefixtures('if_graphviz_found') def test_graphviz_latex(app, status, warning): diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 594aa81b8..c1e1dae93 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -240,7 +240,6 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): ' title="(in foo v2.0)">bartype' in html) - def test_missing_reference_jsdomain(tempdir, app, status, warning): inv_file = tempdir / 'inventory' inv_file.write_bytes(inventory_v2) diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index 4f01a07ab..19225bea8 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -85,6 +85,7 @@ def test_todo_not_included(app, status, warning): assert len(todos) == 2 assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar']) + @pytest.mark.sphinx('latex', testroot='ext-todo', freshenv=True, confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True}) def test_todo_valid_link(app, status, warning): @@ -107,8 +108,7 @@ def test_todo_valid_link(app, status, warning): target = m[0] # Look for the targets of this link. - labels = [m for m in re.findall(r'\\label\{([^}]*)}', content) - if m == target] + labels = [m for m in re.findall(r'\\label\{([^}]*)}', content) if m == target] # If everything is correct we should have exactly one target. assert len(labels) == 1 diff --git a/tests/test_intl.py b/tests/test_intl.py index 6b72438bd..fd2bcd5b5 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -222,6 +222,7 @@ def test_text_inconsistency_warnings(app, warning): u'.*/refs_inconsistency.txt:\\d+: WARNING: citation not found: ref3') assert_re_search(expected_citation_warning_expr, warnings) + @sphinx_intl @pytest.mark.sphinx('text') @pytest.mark.test_params(shared_result='test_intl_basic') diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index f69a0a58e..160e2df32 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -96,7 +96,6 @@ def test_do_prompt_inputstrip(): def test_do_prompt_with_nonascii(): - d = {} answers = { 'Q1': u'\u30c9\u30a4\u30c4', } diff --git a/tests/test_util.py b/tests/test_util.py index aae54eaf0..db1a28869 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -95,7 +95,6 @@ def test_parselinenos(): parselinenos('3-1', 10) - def test_xmlname_check(): checker = xmlname_checker() assert checker.match('id-pub') diff --git a/tests/test_util_images.py b/tests/test_util_images.py index 6f67dcc82..fbee12a61 100644 --- a/tests/test_util_images.py +++ b/tests/test_util_images.py @@ -44,22 +44,22 @@ def test_guess_mimetype(testroot): assert guess_mimetype('IMG.PNG') == 'image/png' # guess by content - assert guess_mimetype(content=(testroot/GIF_FILENAME).bytes()) == 'image/gif' - assert guess_mimetype(content=(testroot/PNG_FILENAME).bytes()) == 'image/png' - assert guess_mimetype(content=(testroot/PDF_FILENAME).bytes()) is None - assert guess_mimetype(content=(testroot/TXT_FILENAME).bytes()) is None - assert guess_mimetype(content=(testroot/TXT_FILENAME).bytes(), + assert guess_mimetype(content=(testroot / GIF_FILENAME).bytes()) == 'image/gif' + assert guess_mimetype(content=(testroot / PNG_FILENAME).bytes()) == 'image/png' + assert guess_mimetype(content=(testroot / PDF_FILENAME).bytes()) is None + assert guess_mimetype(content=(testroot / TXT_FILENAME).bytes()) is None + assert guess_mimetype(content=(testroot / TXT_FILENAME).bytes(), default='text/plain') == 'text/plain' # the priority of params: filename > content > default assert guess_mimetype('img.png', - content=(testroot/GIF_FILENAME).bytes(), + content=(testroot / GIF_FILENAME).bytes(), default='text/plain') == 'image/png' assert guess_mimetype('no_extension', - content=(testroot/GIF_FILENAME).bytes(), + content=(testroot / GIF_FILENAME).bytes(), default='text/plain') == 'image/gif' assert guess_mimetype('no_extension', - content=(testroot/TXT_FILENAME).bytes(), + content=(testroot / TXT_FILENAME).bytes(), default='text/plain') == 'text/plain' diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 63e04ee76..e5a9ed730 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -113,7 +113,6 @@ def test_getargspec_bound_methods(): assert expected_bound == inspect.getargspec(wrapped_bound_method) - def test_Signature(): # literals with pytest.raises(TypeError): diff --git a/tests/test_versioning.py b/tests/test_versioning.py index b73c00fa6..2832a12e4 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -28,7 +28,7 @@ def setup_module(rootdir, sphinx_test_tempdir): global app, original, original_uids srcdir = sphinx_test_tempdir / 'test-versioning' if not srcdir.exists(): - (rootdir/'test-versioning').copytree(srcdir) + (rootdir / 'test-versioning').copytree(srcdir) app = SphinxTestApp(srcdir=srcdir) app.builder.env.app = app app.connect('doctree-resolved', on_doctree_resolved) From 411055905cd0a24ad21ee4701770f362d341ea8d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 24 Dec 2017 14:47:31 +0000 Subject: [PATCH 0472/1814] tox: Add 'PERL5LIB' to 'passenv' list This is required by 'makeinfo'. Signed-off-by: Stephen Finucane Fixes #4339 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 4b462d612..b7934f8fd 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ envlist = docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} [testenv] passenv = - https_proxy http_proxy no_proxy + https_proxy http_proxy no_proxy PERL PERL5LIB description = py{27,34,35,36,py}: Run unit tests against {envname}. du{11,12,13,14}: Run unit tests with the given version of docutils. From 9766c2f339b2f5f16e1e66458d35651c8a7d6272 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 24 Dec 2017 16:31:10 +0100 Subject: [PATCH 0473/1814] C++, support the template disambiguator for dependent names. --- CHANGES | 1 + sphinx/domains/cpp.py | 56 +++++++++++++++++++++++++++------------- tests/test_domain_cpp.py | 2 ++ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 3b3bb7c17..100831a3f 100644 --- a/CHANGES +++ b/CHANGES @@ -96,6 +96,7 @@ Bugs fixed * #4094: C++, allow empty template argument lists. * C++, also hyperlink types in the name of declarations with qualified names. * C++, do not add index entries for declarations inside concepts. +* C++, support the template disambiguator for dependent names. * #4314: For PDF 'howto' documents, numbering of code-blocks differs from the one of figures and tables * #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index a1d8fe909..271832908 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1285,7 +1285,7 @@ class ASTTemplateParamType(ASTBase): def name(self): # type: () -> ASTNestedName id = self.get_identifier() - return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False) @property def isPack(self): @@ -1364,7 +1364,7 @@ class ASTTemplateParamTemplateType(ASTBase): def name(self): # type: () -> ASTNestedName id = self.get_identifier() - return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False) def get_identifier(self): # type: () -> unicode @@ -1401,7 +1401,7 @@ class ASTTemplateParamNonType(ASTBase): def name(self): # type: () -> ASTNestedName id = self.get_identifier() - return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False) def get_identifier(self): # type: () -> unicode @@ -1494,7 +1494,7 @@ class ASTTemplateIntroductionParameter(ASTBase): def name(self): # type: () -> ASTNestedName id = self.get_identifier() - return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False) + return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False) @property def isPack(self): @@ -1820,10 +1820,12 @@ class ASTNestedNameElement(ASTBase): class ASTNestedName(ASTBase): - def __init__(self, names, rooted): - # type: (List[Any], bool) -> None + def __init__(self, names, templates, rooted): + # type: (List[Any], List[bool], bool) -> None assert len(names) > 0 self.names = names + self.templates = templates + assert len(self.names) == len(self.templates) self.rooted = rooted @property @@ -1864,8 +1866,13 @@ class ASTNestedName(ASTBase): res = [] # type: List[unicode] if self.rooted: res.append('') - for n in self.names: - res.append(text_type(n)) + for i in range(len(self.names)): + n = self.names[i] + t = self.templates[i] + if t: + res.append("template " + text_type(n)) + else: + res.append(text_type(n)) return '::'.join(res) def describe_signature(self, signode, mode, env, symbol): @@ -1892,10 +1899,14 @@ class ASTNestedName(ASTBase): prefix = '' # type: unicode first = True names = self.names[:-1] if mode == 'lastIsName' else self.names - for name in names: + for i in range(len(names)): + name = names[i] + template = self.templates[i] if not first: signode += nodes.Text('::') prefix += '::' + if template: + signode += nodes.Text("template ") first = False if name != '': if (name.templateArgs and # type: ignore @@ -1908,6 +1919,8 @@ class ASTNestedName(ASTBase): if mode == 'lastIsName': if len(self.names) > 1: signode += addnodes.desc_addname('::', '::') + if self.templates[-1]: + signode += nodes.Text("template ") self.names[-1].describe_signature(signode, mode, env, '', symbol) else: raise Exception('Unknown description mode: %s' % mode) @@ -3338,7 +3351,7 @@ class Symbol(object): else: decl = None nne = ASTNestedNameElement(p.get_identifier(), None) - nn = ASTNestedName([nne], rooted=False) + nn = ASTNestedName([nne], [False], rooted=False) self._add_symbols(nn, [], decl, docname) # add symbols for function parameters, if any if declaration is not None and declaration.function_params is not None: @@ -3413,9 +3426,11 @@ class Symbol(object): def get_full_nested_name(self): # type: () -> ASTNestedName names = [] + templates = [] for nne, templateParams in self.get_lookup_key(): names.append(nne) - return ASTNestedName(names, rooted=False) + templates.append(False) + return ASTNestedName(names, templates, rooted=False) def _find_named_symbol(self, identifier, templateParams, templateArgs, operator, @@ -4531,7 +4546,8 @@ class DefinitionParser(object): def _parse_nested_name(self, memberPointer=False): # type: (bool) -> ASTNestedName - names = [] + names = [] # type: List[Any] + templates = [] # type: List[bool] self.skip_ws() rooted = False @@ -4539,14 +4555,18 @@ class DefinitionParser(object): rooted = True while 1: self.skip_ws() - if self.skip_word_and_ws('template'): - self.fail("'template' in nested name not implemented.") - elif self.skip_word_and_ws('operator'): + if len(names) > 0: + template = self.skip_word_and_ws('template') + else: + template = False + templates.append(template) + if self.skip_word_and_ws('operator'): op = self._parse_operator() names.append(op) else: if not self.match(_identifier_re): if memberPointer and len(names) > 0: + templates.pop() break self.fail("Expected identifier in nested name.") identifier = self.matched_text @@ -4571,7 +4591,7 @@ class DefinitionParser(object): if memberPointer: self.fail("Expected '::' in pointer to member (function).") break - return ASTNestedName(names, rooted) + return ASTNestedName(names, templates, rooted) def _parse_trailing_type_spec(self): # type: () -> Any @@ -4836,7 +4856,7 @@ class DefinitionParser(object): if self.match(_identifier_re): identifier = ASTIdentifier(self.matched_text) nne = ASTNestedNameElement(identifier, None) - declId = ASTNestedName([nne], rooted=False) + declId = ASTNestedName([nne], [False], rooted=False) # if it's a member pointer, we may have '::', which should be an error self.skip_ws() if self.current_char == ':': @@ -5477,7 +5497,7 @@ class DefinitionParser(object): def _make_phony_error_name(): # type: () -> ASTNestedName nne = ASTNestedNameElement(ASTIdentifier("PhonyNameDueToError"), None) - return ASTNestedName([nne], rooted=False) + return ASTNestedName([nne], [False], rooted=False) class CPPObject(ObjectDescription): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index aed574daf..aa398370d 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -243,6 +243,8 @@ def test_type_definitions(): {1: 'gpio_callback_t', 2: '15gpio_callback_t'}) check('type', 'void (*f)(std::function g)', {1: 'f', 2: '1f'}) + check('type', 'T = A::template B::template C', {2: '1T'}) + def test_concept_definitions(): check('concept', 'template A::B::Concept', From a3f9935d958197a3c0963cec97755db1ff32a3a3 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sat, 21 Oct 2017 15:52:46 +0100 Subject: [PATCH 0474/1814] travis: Enable codecov coverage This necessitates adding some basic coverage-py configuration [1] and making sure the pytest-cov plugin uses said configuration [2]. Badges are included. Note that we do not run the 'coverage' tox target, which is reserved for users. [1] https://github.com/codecov/example-python [2] https://bitbucket.org/ned/coveragepy/issues/512/ Signed-off-by: Stephen Finucane --- .travis.yml | 13 ++++++++++--- README.rst | 4 ++++ setup.cfg | 14 ++++++++++++++ tox.ini | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 900853cf7..f05d6a3b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,17 @@ matrix: - python: 'pypy' env: TOXENV=pypy - python: '2.7' - env: TOXENV=du13 + env: + - TOXENV=du13 + - PYTEST_ADDOPTS = --cov sphinx --cov-append --cov-config setup.cfg - python: '3.4' env: TOXENV=py34 - python: '3.5' env: TOXENV=py35 - python: '3.6' - env: TOXENV=py36 + env: + - TOXENV=py36 + - PYTEST_ADDOPTS = --cov sphinx --cov-append --cov-config setup.cfg - python: 'nightly' env: TOXENV=py37 - python: '3.6' @@ -35,7 +39,10 @@ addons: - imagemagick install: - - pip install -U tox + - pip install -U tox codecov script: - tox -- -v + +after_success: + - codecov diff --git a/README.rst b/README.rst index 6419503e4..2d841f78e 100644 --- a/README.rst +++ b/README.rst @@ -22,6 +22,10 @@ :target: https://circleci.com/gh/sphinx-doc/sphinx :alt: Build Status (CircleCI) +.. image:: https://codecov.io/gh/sphinx-doc/sphinx/branch/master/graph/badge.svg + :target: https://codecov.io/gh/sphinx-doc/sphinx + :alt: Code Coverage Status (Codecov) + Sphinx is a tool that makes it easy to create intelligent and beautiful documentation for Python projects (or other documents consisting of multiple reStructuredText sources), written by Georg Brandl. It was originally created diff --git a/setup.cfg b/setup.cfg index 00e7833d3..0ce6282dc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,3 +43,17 @@ follow_imports = skip incremental = True check_untyped_defs = True warn_unused_ignores = True + +[coverage:run] +branch = True +source = sphinx + +[coverage:report] +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + # Don't complain if tests don't hit defensive assertion code: + raise NotImplementedError + # Don't complain if non-runnable code isn't run: + if __name__ == .__main__.: +ignore_errors = True diff --git a/tox.ini b/tox.ini index 4b462d612..5ff3e9f33 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ deps = du14: docutils==0.14 setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild - coverage: PYTEST_ADDOPTS = --cov sphinx + coverage: PYTEST_ADDOPTS = --cov sphinx --cov-config {toxinidir}/setup.cfg commands= {envpython} -Wall tests/run.py --durations 25 {posargs} From 77ca8947236c1b8e42c0bd47567c87ddede9b1b3 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:00:25 +0000 Subject: [PATCH 0475/1814] tox: Report coverage to user Run 'coverage report' after a successful coverage run. There's enough coverage-related stuff here at this point to warrant its own section. Signed-off-by: Stephen Finucane --- tox.ini | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 5ff3e9f33..a4497a5c8 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,6 @@ passenv = description = py{27,34,35,36,py}: Run unit tests against {envname}. du{11,12,13,14}: Run unit tests with the given version of docutils. - coverage: Run code coverage checks. # TODO(stephenfin) Replace this with the 'extras' config option when tox 2.4 is # widely available, likely some time after the Ubuntu 18.04 release @@ -22,7 +21,6 @@ deps = du14: docutils==0.14 setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild - coverage: PYTEST_ADDOPTS = --cov sphinx --cov-config {toxinidir}/setup.cfg commands= {envpython} -Wall tests/run.py --durations 25 {posargs} @@ -41,6 +39,15 @@ deps = commands = pylint --rcfile utils/pylintrc sphinx +[testenv:coverage] +description = + Run code coverage checks. +setenv = + PYTEST_ADDOPTS = --cov sphinx --cov-config {toxinidir}/setup.cfg +commands = + {[testenv]commands} + coverage report + [testenv:mypy] description = Run type checks. From f06862717663fe19c651c8fadbf8037cbb7d5b03 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:01:51 +0000 Subject: [PATCH 0476/1814] gitignore: Ignore 'htmlcov' directory This is generated if you run 'coverage html'. Hide it from Git. Signed-off-by: Stephen Finucane --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f1dc3167c..5d1026c5e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ TAGS .tox .venv .coverage +htmlcov .DS_Store sphinx/pycode/Grammar*pickle distribute-* From b094c401de702e5811c8a195db3a5f7a9d6ed435 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 27 Dec 2017 14:59:59 +0900 Subject: [PATCH 0477/1814] docs: make explicitly :meth: reference (refs: #4344) --- doc/markup/inline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index 8be34f22c..4d14a653d 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -63,7 +63,7 @@ Cross-referencing anything by :rst:role:`doc`, :rst:role:`ref` or :rst:role:`option`. Custom objects added to the standard domain by extensions (see - :meth:`.add_object_type`) are also searched. + :meth:`Sphinx.add_object_type`) are also searched. * Then, it looks for objects (targets) in all loaded domains. It is up to the domains how specific a match must be. For example, in the Python From 90acaa82f64ca2a3665a9fd560dd3a9b04dd8312 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 27 Dec 2017 15:04:30 +0900 Subject: [PATCH 0478/1814] Diet tests on appveyor --- .appveyor.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a3f83394f..cfc8d884f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,19 +6,12 @@ environment: matrix: - PYTHON: 27 - DOCUTILS: 0.13.1 - TEST_IGNORE: --ignore py35 - - PYTHON: 27 - DOCUTILS: 0.14 TEST_IGNORE: --ignore py35 - PYTHON: 36 - DOCUTILS: 0.14 - PYTHON: 36-x64 - DOCUTILS: 0.14 install: - C:\Python%PYTHON%\python.exe -m pip install -U pip setuptools - - C:\Python%PYTHON%\python.exe -m pip install docutils==%DOCUTILS% mock - C:\Python%PYTHON%\python.exe -m pip install .[test,websupport] # No automatic build, just run python tests From 0cc6cdd7cce9418b27e46ae9d1238aea932e15a5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 28 Dec 2017 10:48:29 +0900 Subject: [PATCH 0479/1814] travis: Build own docs as a test --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index f05d6a3b8..2bd437436 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,8 @@ matrix: - PYTEST_ADDOPTS = --cov sphinx --cov-append --cov-config setup.cfg - python: 'nightly' env: TOXENV=py37 + - python: '3.6' + env: TOXENV=docs - python: '3.6' env: TOXENV=mypy - python: '2.7' From f3c05adebc6f42eed3ccdc498f5deb45bf4f9885 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 28 Dec 2017 16:50:32 +0100 Subject: [PATCH 0480/1814] C++, fix handling of (templated) operators --- sphinx/domains/cpp.py | 181 +++++++++----------------- tests/roots/test-domain-cpp/index.rst | 6 + tests/test_domain_cpp.py | 7 + 3 files changed, 77 insertions(+), 117 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 271832908..5f644255a 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1408,9 +1408,9 @@ class ASTTemplateParamNonType(ASTBase): name = self.param.name if name: assert len(name.names) == 1 - assert name.names[0].identifier + assert name.names[0].identOrOp assert not name.names[0].templateArgs - return name.names[0].identifier + return name.names[0].identOrOp else: return None @@ -1650,8 +1650,8 @@ class ASTOperatorBuildIn(ASTBase): else: return u'operator' + self.op - def describe_signature(self, signode, mode, env, prefix, symbol): - # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None + def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): + # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None _verify_description_mode(mode) identifier = text_type(self) if mode == 'lastIsName': @@ -1684,7 +1684,7 @@ class ASTOperatorType(ASTBase): # type: () -> unicode return text_type(self) - def describe_signature(self, signode, mode, env, prefix, symbol): + def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None _verify_description_mode(mode) identifier = text_type(self) @@ -1714,7 +1714,7 @@ class ASTOperatorLiteral(ASTBase): # type: () -> unicode return u'operator""' + text_type(self.identifier) - def describe_signature(self, signode, mode, env, prefix, symbol): + def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None _verify_description_mode(mode) identifier = text_type(self) @@ -1788,9 +1788,9 @@ class ASTTemplateArgs(ASTBase): class ASTNestedNameElement(ASTBase): - def __init__(self, identifier, templateArgs): + def __init__(self, identOrOp, templateArgs): # type: (Any, Any) -> None - self.identifier = identifier + self.identOrOp = identOrOp self.templateArgs = templateArgs def is_operator(self): @@ -1799,14 +1799,14 @@ class ASTNestedNameElement(ASTBase): def get_id(self, version): # type: (int) -> unicode - res = self.identifier.get_id(version) + res = self.identOrOp.get_id(version) if self.templateArgs: res += self.templateArgs.get_id(version) return res def __unicode__(self): # type: () -> unicode - res = text_type(self.identifier) + res = text_type(self.identOrOp) if self.templateArgs: res += text_type(self.templateArgs) return res @@ -1814,7 +1814,7 @@ class ASTNestedNameElement(ASTBase): def describe_signature(self, signode, mode, env, prefix, symbol): # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None tArgs = text_type(self.templateArgs) if self.templateArgs is not None else '' - self.identifier.describe_signature(signode, mode, env, prefix, tArgs, symbol) + self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol) if self.templateArgs is not None: self.templateArgs.describe_signature(signode, mode, env, symbol) @@ -3310,23 +3310,20 @@ class Symbol(object): # type: () -> None if not self.parent: # parent == None means global scope, so declaration means a parent - assert not self.identifier + assert not self.identOrOp assert not self.templateParams assert not self.templateArgs assert not self.declaration assert not self.docname else: - if not self.identifier: - # in case it's an operator - assert self.declaration if self.declaration: assert self.docname - def __init__(self, parent, identifier, + def __init__(self, parent, identOrOp, templateParams, templateArgs, declaration, docname): # type: (Any, Any, Any, Any, Any, unicode) -> None self.parent = parent - self.identifier = identifier + self.identOrOp = identOrOp self.templateParams = templateParams # template self.templateArgs = templateArgs # identifier self.declaration = declaration @@ -3365,8 +3362,8 @@ class Symbol(object): decl = ASTDeclaration('functionParam', None, None, p) assert not nn.rooted assert len(nn.names) == 1 - identifier = nn.names[0].identifier - Symbol(parent=self, identifier=identifier, + identOrOp = nn.names[0].identOrOp + Symbol(parent=self, identOrOp=identOrOp, templateParams=None, templateArgs=None, declaration=decl, docname=docname) @@ -3390,12 +3387,7 @@ class Symbol(object): if sChild.declaration and sChild.docname == docname: sChild.declaration = None sChild.docname = None - # Just remove operators, because there is no identification if - # they got removed. - # Don't remove other symbols because they may be used in namespace - # directives. - if sChild.identifier or sChild.declaration: - newChildren.append(sChild) + newChildren.append(sChild) self.children = newChildren def get_all_symbols(self): @@ -3415,11 +3407,7 @@ class Symbol(object): symbols.reverse() key = [] for s in symbols: - if s.identifier: - nne = ASTNestedNameElement(s.identifier, s.templateArgs) - else: - assert s.declaration - nne = s.declaration.name.names[-1] + nne = ASTNestedNameElement(s.identOrOp, s.templateArgs) key.append((nne, s.templateParams)) return key @@ -3432,11 +3420,9 @@ class Symbol(object): templates.append(False) return ASTNestedName(names, templates, rooted=False) - def _find_named_symbol(self, identifier, templateParams, - templateArgs, operator, + def _find_named_symbol(self, identOrOp, templateParams, templateArgs, templateShorthand, matchSelf): - # type: (Any, Any, Any, Any, Any, bool) -> Symbol - assert (identifier is None) != (operator is None) + # type: (Any, Any, Any, Any, bool) -> Symbol def isSpecialization(): # the names of the template parameters must be given exactly as args @@ -3464,17 +3450,8 @@ class Symbol(object): templateArgs = None def matches(s): - if s.identifier != identifier: + if s.identOrOp != identOrOp: return False - if not s.identifier: - if not s.declaration: - return False - assert operator - name = s.declaration.name.names[-1] - if not name.is_operator(): - return False - if text_type(name) != text_type(operator): - return False if (s.templateParams is None) != (templateParams is None): if templateParams is not None: # we query with params, they must match params @@ -3515,10 +3492,7 @@ class Symbol(object): names = nestedName.names iTemplateDecl = 0 for name in names[:-1]: - # there shouldn't be anything inside an operator - # (other than template parameters, which are not added this way, right?) - assert not name.is_operator() - identifier = name.identifier + identOrOp = name.identOrOp templateArgs = name.templateArgs if templateArgs: assert iTemplateDecl < len(templateDecls) @@ -3526,27 +3500,20 @@ class Symbol(object): iTemplateDecl += 1 else: templateParams = None - symbol = parentSymbol._find_named_symbol(identifier, + symbol = parentSymbol._find_named_symbol(identOrOp, templateParams, templateArgs, - operator=None, templateShorthand=False, matchSelf=False) if symbol is None: - symbol = Symbol(parent=parentSymbol, identifier=identifier, + symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp, templateParams=templateParams, templateArgs=templateArgs, declaration=None, docname=None) parentSymbol = symbol name = names[-1] - if name.is_operator(): - identifier = None - templateArgs = None - operator = name - else: - identifier = name.identifier - templateArgs = name.templateArgs - operator = None + identOrOp = name.identOrOp + templateArgs = name.templateArgs if iTemplateDecl < len(templateDecls): if iTemplateDecl + 1 != len(templateDecls): print(text_type(templateDecls)) @@ -3556,10 +3523,9 @@ class Symbol(object): else: assert iTemplateDecl == len(templateDecls) templateParams = None - symbol = parentSymbol._find_named_symbol(identifier, + symbol = parentSymbol._find_named_symbol(identOrOp, templateParams, templateArgs, - operator, templateShorthand=False, matchSelf=False) if symbol: @@ -3576,7 +3542,7 @@ class Symbol(object): return symbol # It may simply be a function overload, so let's compare ids. isRedeclaration = True - candSymbol = Symbol(parent=parentSymbol, identifier=identifier, + candSymbol = Symbol(parent=parentSymbol, identOrOp=identOrOp, templateParams=templateParams, templateArgs=templateArgs, declaration=declaration, @@ -3596,7 +3562,7 @@ class Symbol(object): candSymbol.isRedeclaration = True raise _DuplicateSymbolError(symbol, declaration) else: - symbol = Symbol(parent=parentSymbol, identifier=identifier, + symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp, templateParams=templateParams, templateArgs=templateArgs, declaration=declaration, @@ -3667,12 +3633,12 @@ class Symbol(object): templateDecls = [] return self._add_symbols(nestedName, templateDecls, declaration, docname) - def find_identifier(self, identifier, matchSelf): + def find_identifier(self, identOrOp, matchSelf): # type: (Any, bool) -> Symbol - if matchSelf and self.identifier and self.identifier == identifier: + if matchSelf and self.identOrOp == identOrOp: return self for s in self.children: - if s.identifier and s.identifier == identifier: + if s.identOrOp == identOrOp: return s return None @@ -3680,16 +3646,10 @@ class Symbol(object): # type: (List[Tuple[Any, Any]]) -> Symbol s = self for name, templateParams in key: - if name.is_operator(): - identifier = None - templateArgs = None - operator = name - else: - identifier = name.identifier - templateArgs = name.templateArgs - operator = None - s = s._find_named_symbol(identifier, templateParams, - templateArgs, operator, + identOrOp = name.identOrOp + templateArgs = name.templateArgs + s = s._find_named_symbol(identOrOp, + templateParams, templateArgs, templateShorthand=False, matchSelf=False) if not s: @@ -3713,13 +3673,13 @@ class Symbol(object): firstName = names[0] if not firstName.is_operator(): while parentSymbol.parent: - if parentSymbol.find_identifier(firstName.identifier, + if parentSymbol.find_identifier(firstName.identOrOp, matchSelf=matchSelf): # if we are in the scope of a constructor but wants to reference the class # we need to walk one extra up if (len(names) == 1 and typ == 'class' and matchSelf and - parentSymbol.parent and parentSymbol.parent.identifier and - parentSymbol.parent.identifier == firstName.identifier): + parentSymbol.parent and + parentSymbol.parent.identOrOp == firstName.identOrOp): pass else: break @@ -3728,48 +3688,36 @@ class Symbol(object): for iName in range(len(names)): name = names[iName] if iName + 1 == len(names): - if name.is_operator(): - identifier = None - templateArgs = None - operator = name - else: - identifier = name.identifier - templateArgs = name.templateArgs - operator = None + identOrOp = name.identOrOp + templateArgs = name.templateArgs if iTemplateDecl < len(templateDecls): assert iTemplateDecl + 1 == len(templateDecls) templateParams = templateDecls[iTemplateDecl] else: assert iTemplateDecl == len(templateDecls) templateParams = None - symbol = parentSymbol._find_named_symbol(identifier, + symbol = parentSymbol._find_named_symbol(identOrOp, templateParams, templateArgs, - operator, templateShorthand=templateShorthand, matchSelf=matchSelf) if symbol is not None: return symbol # try without template params and args - symbol = parentSymbol._find_named_symbol(identifier, + symbol = parentSymbol._find_named_symbol(identOrOp, None, None, - operator, templateShorthand=templateShorthand, matchSelf=matchSelf) return symbol else: - # there shouldn't be anything inside an operator - assert not name.is_operator() - identifier = name.identifier + identOrOp = name.identOrOp templateArgs = name.templateArgs if templateArgs and iTemplateDecl < len(templateDecls): templateParams = templateDecls[iTemplateDecl] iTemplateDecl += 1 else: templateParams = None - symbol = parentSymbol._find_named_symbol(identifier, - templateParams, - templateArgs, - operator=None, + symbol = parentSymbol._find_named_symbol(identOrOp, + templateParams, templateArgs, templateShorthand=templateShorthand, matchSelf=matchSelf) if symbol is None: @@ -3792,8 +3740,8 @@ class Symbol(object): res.append(text_type(self.templateParams)) res.append('\n') res.append('\t' * indent) - if self.identifier: - res.append(text_type(self.identifier)) + if self.identOrOp: + res.append(text_type(self.identOrOp)) else: res.append(text_type(self.declaration)) if self.templateArgs: @@ -4561,8 +4509,7 @@ class DefinitionParser(object): template = False templates.append(template) if self.skip_word_and_ws('operator'): - op = self._parse_operator() - names.append(op) + identOrOp = self._parse_operator() else: if not self.match(_identifier_re): if memberPointer and len(names) > 0: @@ -4574,17 +4521,17 @@ class DefinitionParser(object): if identifier in _keywords: self.fail("Expected identifier in nested name, " "got keyword: %s" % identifier) - # try greedily to get template parameters, - # but otherwise a < might be because we are in an expression - pos = self.pos - try: - templateArgs = self._parse_template_argument_list() - except DefinitionError as ex: - self.pos = pos - templateArgs = None - self.otherErrors.append(ex) - identifier = ASTIdentifier(identifier) # type: ignore - names.append(ASTNestedNameElement(identifier, templateArgs)) + identOrOp = ASTIdentifier(identifier) # type: ignore + # try greedily to get template arguments, + # but otherwise a < might be because we are in an expression + pos = self.pos + try: + templateArgs = self._parse_template_argument_list() + except DefinitionError as ex: + self.pos = pos + templateArgs = None + self.otherErrors.append(ex) + names.append(ASTNestedNameElement(identOrOp, templateArgs)) self.skip_ws() if not self.skip_string('::'): @@ -5532,7 +5479,7 @@ class CPPObject(ObjectDescription): # then add the name to the parent scope symbol = ast.symbol assert symbol - assert symbol.identifier is not None + assert symbol.identOrOp is not None assert symbol.templateParams is None assert symbol.templateArgs is None parentSymbol = symbol.parent @@ -5545,7 +5492,7 @@ class CPPObject(ObjectDescription): if parentDecl is None: # the parent is not explicitly declared # TODO: we could warn, but it could be a style to just assume - # enumerator parnets to be scoped + # enumerator parents to be scoped return if parentDecl.objectType != 'enum': # TODO: maybe issue a warning, enumerators in non-enums is weird, @@ -5555,13 +5502,13 @@ class CPPObject(ObjectDescription): return targetSymbol = parentSymbol.parent - s = targetSymbol.find_identifier(symbol.identifier, matchSelf=False) + s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False) if s is not None: # something is already declared with that name return declClone = symbol.declaration.clone() declClone.enumeratorScopedSymbol = symbol - Symbol(parent=targetSymbol, identifier=symbol.identifier, + Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp, templateParams=None, templateArgs=None, declaration=declClone, docname=self.env.docname) diff --git a/tests/roots/test-domain-cpp/index.rst b/tests/roots/test-domain-cpp/index.rst index 618e51037..2df5ec848 100644 --- a/tests/roots/test-domain-cpp/index.rst +++ b/tests/roots/test-domain-cpp/index.rst @@ -28,14 +28,20 @@ directives An unscoped enum. + .. cpp:enumerator:: A + .. cpp:enum-class:: MyScopedEnum A scoped enum. + .. cpp:enumerator:: B + .. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type A scoped enum with non-default visibility, and with a specified underlying type. + .. cpp:enumerator:: B + .. cpp:function:: void paren_1(int, float) .. cpp:function:: void paren_2(int, float) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index aa398370d..0b31d8aed 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -205,6 +205,9 @@ def test_expressions(): check('class', "template A", {2: "I_iE1A"}) check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) + exprCheck('operator()()', 'clclE') + exprCheck('operator()()', 'clclIiEE') + def test_type_definitions(): check("type", "public bool b", {1: "b", 2: "1b"}, "bool b") @@ -245,6 +248,10 @@ def test_type_definitions(): check('type', 'T = A::template B::template C', {2: '1T'}) + check('type', 'T = Q', {2: '1T'}) + check('type', 'T = Q>', {2: '1T'}) + check('type', 'T = Q', {2: '1T'}) + def test_concept_definitions(): check('concept', 'template A::B::Concept', From 217c5f385635e4aa965bf6e8de37953219336704 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 28 Dec 2017 17:04:21 +0100 Subject: [PATCH 0481/1814] Fixes for previous commit --- sphinx/domains/cpp.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 5f644255a..c6e87fd7a 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1685,7 +1685,7 @@ class ASTOperatorType(ASTBase): return text_type(self) def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): - # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None + # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None _verify_description_mode(mode) identifier = text_type(self) if mode == 'lastIsName': @@ -1715,7 +1715,7 @@ class ASTOperatorLiteral(ASTBase): return u'operator""' + text_type(self.identifier) def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol): - # type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None + # type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None _verify_description_mode(mode) identifier = text_type(self) if mode == 'lastIsName': @@ -3573,22 +3573,9 @@ class Symbol(object): # type: (Any, List[unicode], BuildEnvironment) -> None assert other is not None for otherChild in other.children: - if not otherChild.identifier: - if not otherChild.declaration: - print("Problem in symbol tree merging") - print("OtherChild.dump:") - print(otherChild.dump(0)) - print("Other.dump:") - print(other.dump(0)) - assert otherChild.declaration - operator = otherChild.declaration.name.names[-1] - assert operator.is_operator() - else: - operator = None - ourChild = self._find_named_symbol(otherChild.identifier, + ourChild = self._find_named_symbol(otherChild.identOrOp, otherChild.templateParams, otherChild.templateArgs, - operator, templateShorthand=False, matchSelf=False) if ourChild is None: @@ -4521,7 +4508,7 @@ class DefinitionParser(object): if identifier in _keywords: self.fail("Expected identifier in nested name, " "got keyword: %s" % identifier) - identOrOp = ASTIdentifier(identifier) # type: ignore + identOrOp = ASTIdentifier(identifier) # try greedily to get template arguments, # but otherwise a < might be because we are in an expression pos = self.pos From e5ba527dd5d5d2620ab03b0bdd552f380242fafa Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 28 Dec 2017 17:16:53 +0100 Subject: [PATCH 0482/1814] Fix missing metainfo for sphinx.io --- sphinx/io.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sphinx/io.py b/sphinx/io.py index 804932863..cfdaafb9c 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -285,3 +285,9 @@ def read_doc(app, env, filename): def setup(app): app.registry.add_source_input('*', SphinxFileInput) app.registry.add_source_input('restructuredtext', SphinxRSTFileInput) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } From f4f677c8f714a68f1152afcc40e3441a79f8913c Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 21:18:23 +0000 Subject: [PATCH 0483/1814] templates: Remove 'epub3' targets This appears to have been missed in commit 69d1dfaa. One could add an alias for this to restore behavior, but no one has reported the issue since Sphinx meaning this seems unnecessary. Signed-off-by: Stephen Finucane --- sphinx/templates/quickstart/Makefile_t | 7 ------- sphinx/templates/quickstart/make.bat_t | 9 --------- 2 files changed, 16 deletions(-) diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 4639a982b..2858d9bf7 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -27,7 +27,6 @@ help: @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" - @echo " epub3 to make an epub3" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @@ -122,12 +121,6 @@ epub: @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." -.PHONY: epub3 -epub3: - $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 - @echo - @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." - .PHONY: latex latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 8438b5f7e..230977488 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -29,7 +29,6 @@ if "%1" == "help" ( echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub - echo. epub3 to make an epub3 echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages @@ -153,14 +152,6 @@ if "%1" == "epub" ( goto end ) -if "%1" == "epub3" ( - %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. - goto end -) - if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 From f048d668e558f1674ebed6547b71968b47763444 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 21:28:55 +0000 Subject: [PATCH 0484/1814] doc: Remove invalid note for epub3 builder This doesn't appear to be true any more, based on the code. Signed-off-by: Stephen Finucane --- doc/config.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 881387b48..1ef455803 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -1458,10 +1458,6 @@ the `Dublin Core metadata `_. a chapter, but can be confusing because it mixes entries of different depth in one list. The default value is ``True``. - .. note:: - - ``epub3`` builder ignores ``epub_tocdup`` option(always ``False``) - .. confval:: epub_tocscope This setting control the scope of the epub table of contents. The setting From 35ad6910a9bb1d8f80c3d12cd3dfd1ebc06ba6dc Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 21:37:07 +0000 Subject: [PATCH 0485/1814] epub: Remove dead templates These are no longer used since 'f2c93b31'. Signed-off-by: Stephen Finucane --- sphinx/templates/epub2/container.xml | 6 ----- sphinx/templates/epub2/content.opf_t | 37 ---------------------------- sphinx/templates/epub2/mimetype | 1 - sphinx/templates/epub2/toc.ncx_t | 15 ----------- 4 files changed, 59 deletions(-) delete mode 100644 sphinx/templates/epub2/container.xml delete mode 100644 sphinx/templates/epub2/content.opf_t delete mode 100644 sphinx/templates/epub2/mimetype delete mode 100644 sphinx/templates/epub2/toc.ncx_t diff --git a/sphinx/templates/epub2/container.xml b/sphinx/templates/epub2/container.xml deleted file mode 100644 index 326cf15fa..000000000 --- a/sphinx/templates/epub2/container.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/sphinx/templates/epub2/content.opf_t b/sphinx/templates/epub2/content.opf_t deleted file mode 100644 index 5169d0551..000000000 --- a/sphinx/templates/epub2/content.opf_t +++ /dev/null @@ -1,37 +0,0 @@ - - - - {{ lang }} - {{ title }} - {{ author }} - {{ publisher }} - {{ copyright }} - {{ id }} - {{ date }} - {%- if cover %} - - {%- endif %} - - - - {%- for item in manifest_items %} - - {%- endfor %} - - - {%- for spine in spines %} - {%- if spine.linear %} - - {%- else %} - - {%- endif %} - {%- endfor %} - - - {%- for guide in guides %} - - {%- endfor %} - - diff --git a/sphinx/templates/epub2/mimetype b/sphinx/templates/epub2/mimetype deleted file mode 100644 index 57ef03f24..000000000 --- a/sphinx/templates/epub2/mimetype +++ /dev/null @@ -1 +0,0 @@ -application/epub+zip \ No newline at end of file diff --git a/sphinx/templates/epub2/toc.ncx_t b/sphinx/templates/epub2/toc.ncx_t deleted file mode 100644 index 9bb701908..000000000 --- a/sphinx/templates/epub2/toc.ncx_t +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - {{ title }} - - -{{ navpoints }} - - From 9f7f5f2a44436d0c0779d8417781882b189263a7 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 22:54:23 +0000 Subject: [PATCH 0486/1814] doc: Add missing sphinx-apidocs opt, envvar Add docs for '--module-first' option and 'SPHINX_APIDOC_OPTIONS' environment variable. Per the closest thing we have to official man page guidelines [1]: ENVIRONMENT lists all environment variables that affect the program or function and how they affect it. [1] https://linux.die.net/man/7/man-pages Signed-off-by: Stephen Finucane Fixes #2250 --- doc/man/sphinx-apidoc.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst index 803466040..9a13f1401 100644 --- a/doc/man/sphinx-apidoc.rst +++ b/doc/man/sphinx-apidoc.rst @@ -91,7 +91,7 @@ Options Interpret paths recursively according to PEP-0420. -.. option:: -M +.. option:: -M, --module-first Put module documentation before submodule documentation. @@ -118,6 +118,14 @@ These options are used when :option:`--full` is specified: Sets the project release to put in generated files (see :confval:`release`). +Environment +----------- + +.. envvar:: SPHINX_APIDOC_OPTIONS + + A comma-separated list of option to append to generated ``automodule`` + directives. Defaults to ``members,undoc-members,show-inheritance``. + See also -------- From 4fd217ce88c596093887895197ccf75a7e99368c Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 24 Dec 2017 15:24:10 +0000 Subject: [PATCH 0487/1814] circleci: Install packages ourselves Start installing Python dependencies and Sphinx itself as part of the CircleCI job rather than expecting it to be done in the Docker container. This ensures we will use the version of the packages for a given commit. This is the other half of sphinx-doc/docker-ci#1. Signed-off-by: Stephen Finucane --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1bbcb4884..f4d4415f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,4 +6,6 @@ jobs: working_directory: /sphinx steps: - checkout + - run: /python3.4/bin/pip install -U pip setuptools + - run: /python3.4/bin/pip install -U .[test,websupport] - run: make test PYTHON=/python3.4/bin/python From 9348c4bea1bf75184bb4fe2af25c5990d6dcf2c1 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:50:47 +0000 Subject: [PATCH 0488/1814] tests: Stop explicitly checking for modules This will have already been handled by setuptools. If the user isn't using this then they've dug their own grave. Signed-off-by: Stephen Finucane --- tests/run.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/run.py b/tests/run.py index 2116e345c..217f8bea2 100755 --- a/tests/run.py +++ b/tests/run.py @@ -27,19 +27,6 @@ warnings.filterwarnings('ignore', category=ImportWarning, module='pkgutil') warnings.filterwarnings('ignore', category=ImportWarning, module='pytest_cov') warnings.filterwarnings('ignore', category=PendingDeprecationWarning, module=r'_pytest\..*') -# check dependencies before testing -print('Checking dependencies...') -for modname in ('pytest', 'mock', 'six', 'docutils', 'jinja2', 'pygments', - 'snowballstemmer', 'babel', 'html5lib'): - try: - __import__(modname) - except ImportError as err: - if modname == 'mock' and sys.version_info[0] == 3: - continue - traceback.print_exc() - print('The %r package is needed to run the Sphinx test suite.' % modname) - sys.exit(1) - # find a temp dir for testing and clean it up now os.environ['SPHINX_TEST_TEMPDIR'] = \ os.path.abspath(os.path.join(testroot, 'build')) \ From c33ecd1f8f1ea6eb7e410e91aec754bdd1d1f20a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:50:49 +0000 Subject: [PATCH 0489/1814] tests: Use 'pytest_report_header' This is the recommended way to print extra headers [1]. [1] https://docs.pytest.org/en/latest/example/simple.html#adding-info-to-test-report-header Signed-off-by: Stephen Finucane --- tests/conftest.py | 5 +++++ tests/run.py | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9ea99dbd9..d50d76df0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,3 +26,8 @@ if sys.version_info < (3, 5): @pytest.fixture(scope='session') def rootdir(): return path(os.path.dirname(__file__) or '.').abspath() / 'roots' + + +def pytest_report_header(config): + return 'Running Sphinx test suite (with Python %s)...' % ( + sys.version.split()[0]) diff --git a/tests/run.py b/tests/run.py index 217f8bea2..aa797dbdb 100755 --- a/tests/run.py +++ b/tests/run.py @@ -39,8 +39,5 @@ if os.path.exists(tempdir): shutil.rmtree(tempdir) os.makedirs(tempdir) -print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0]) -sys.stdout.flush() - import pytest # NOQA sys.exit(pytest.main(sys.argv[1:])) From 529c96a3c991d167edd3f7181284b1f21315a486 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 24 Dec 2017 20:28:46 +0000 Subject: [PATCH 0490/1814] tests: Use 'pytest_sessionstart' This is the recommended way to do pre-session configuration in pytest if not using session fixtures [1]. With this, we're able to remove the custom 'test/run.py' script in its entirety and run 'pytest' like everyone else does. We'll do this separately to keep things simple. [1] https://stackoverflow.com/a/12600154/613428 Signed-off-by: Stephen Finucane --- tests/conftest.py | 31 +++++++++++++++++++++++++++++++ tests/run.py | 29 +---------------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index d50d76df0..336484bcc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,9 @@ """ import os +import shutil import sys +import warnings import pytest from sphinx.testing.path import path @@ -31,3 +33,32 @@ def rootdir(): def pytest_report_header(config): return 'Running Sphinx test suite (with Python %s)...' % ( sys.version.split()[0]) + + +def _filter_warnings(): + def ignore(**kwargs): warnings.filterwarnings('ignore', **kwargs) + + ignore(category=DeprecationWarning, module='site') # virtualenv + ignore(category=PendingDeprecationWarning, module=r'_pytest\..*') + ignore(category=ImportWarning, module='backports') + ignore(category=ImportWarning, module='pkgutil') + ignore(category=ImportWarning, module='pytest_cov') + + +def _initialize_test_directory(session): + testroot = os.path.join(str(session.config.rootdir), 'tests') + tempdir = os.path.abspath(os.getenv('SPHINX_TEST_TEMPDIR', + os.path.join(testroot, 'build'))) + os.environ['SPHINX_TEST_TEMPDIR'] = tempdir + + print('Temporary files will be placed in %s.' % tempdir) + + if os.path.exists(tempdir): + shutil.rmtree(tempdir) + + os.makedirs(tempdir) + + +def pytest_sessionstart(session): + _filter_warnings() + _initialize_test_directory(session) diff --git a/tests/run.py b/tests/run.py index aa797dbdb..6c82db782 100755 --- a/tests/run.py +++ b/tests/run.py @@ -9,35 +9,8 @@ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ -from __future__ import print_function - -import os import sys -import warnings -import traceback -import shutil -testroot = os.path.dirname(__file__) or '.' -sys.path.insert(0, os.path.abspath(os.path.join(testroot, os.path.pardir))) +import pytest -# filter warnings of test dependencies -warnings.filterwarnings('ignore', category=DeprecationWarning, module='site') # virtualenv -warnings.filterwarnings('ignore', category=ImportWarning, module='backports') -warnings.filterwarnings('ignore', category=ImportWarning, module='pkgutil') -warnings.filterwarnings('ignore', category=ImportWarning, module='pytest_cov') -warnings.filterwarnings('ignore', category=PendingDeprecationWarning, module=r'_pytest\..*') - -# find a temp dir for testing and clean it up now -os.environ['SPHINX_TEST_TEMPDIR'] = \ - os.path.abspath(os.path.join(testroot, 'build')) \ - if 'SPHINX_TEST_TEMPDIR' not in os.environ \ - else os.path.abspath(os.environ['SPHINX_TEST_TEMPDIR']) - -tempdir = os.environ['SPHINX_TEST_TEMPDIR'] -print('Temporary files will be placed in %s.' % tempdir) -if os.path.exists(tempdir): - shutil.rmtree(tempdir) -os.makedirs(tempdir) - -import pytest # NOQA sys.exit(pytest.main(sys.argv[1:])) From 7c0723fd46825ea44a98ae22ac45d08ca0ddd88b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:50:51 +0000 Subject: [PATCH 0491/1814] tests: Remove 'tests/run.py' This is no longer necessary. One test needs to be modified to deal with how 'python -m pytest' modifies the PATH. Signed-off-by: Stephen Finucane --- .appveyor.yml | 2 +- CONTRIBUTING.rst | 19 +++++++++++-------- Makefile | 4 ++-- tests/run.py | 16 ---------------- tests/test_pycode.py | 3 ++- tox.ini | 2 +- 6 files changed, 17 insertions(+), 29 deletions(-) delete mode 100755 tests/run.py diff --git a/.appveyor.yml b/.appveyor.yml index a3f83394f..d2c5d0d95 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,7 +39,7 @@ test_script: if (-not $test_ignore) { $test_ignore = '' } $tests = $env:TEST if (-not $tests) { $tests = '' } - & "C:\Python$($env:PYTHON)\python.exe" run.py $test_ignore.Split(' ') --junitxml .junit.xml $tests.Split(' ') + & "C:\Python$($env:PYTHON)\python.exe" -m pytest $test_ignore.Split(' ') --junitxml .junit.xml $tests.Split(' ') Pop-Location if ($LastExitCode -eq 1) { Write-Host "Test Failures Occurred, leaving for test result parsing" } elseif ($LastExitCode -ne 0) { Write-Host "Other Error Occurred, aborting"; exit $LastExitCode } diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c4b8569b0..03d26c001 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -317,14 +317,17 @@ There are a couple reasons that code in Sphinx might be deprecated: no longer needs to support the older version of Python that doesn't include the library, the library will be deprecated in Sphinx. -As the :ref:`deprecation-policy` describes, -the first release of Sphinx that deprecates a feature (``A.B``) should raise a -``RemovedInSphinxXXWarning`` (where XX is the Sphinx version where the feature -will be removed) when the deprecated feature is invoked. Assuming we have good -test coverage, these warnings are converted to errors when running the test -suite with warnings enabled: ``python -Wall tests/run.py``. Thus, when adding -a ``RemovedInSphinxXXWarning`` you need to eliminate or silence any warnings -generated when running the tests. +As the :ref:`deprecation-policy` describes, the first release of Sphinx that +deprecates a feature (``A.B``) should raise a ``RemovedInSphinxXXWarning`` +(where ``XX`` is the Sphinx version where the feature will be removed) when the +deprecated feature is invoked. Assuming we have good test coverage, these +warnings are converted to errors when running the test suite with warnings +enabled:: + + pytest -Wall + +Thus, when adding a ``RemovedInSphinxXXWarning`` you need to eliminate or +silence any warnings generated when running the tests. .. _deprecation-policy: diff --git a/Makefile b/Makefile index e4abba088..67699363f 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ reindent: .PHONY: test test: - @cd tests; $(PYTHON) run.py -v $(TEST) + @$(PYTHON) -m pytest -v $(TEST) .PHONY: test-async test-async: @@ -77,7 +77,7 @@ test-async: .PHONY: covertest covertest: - @cd tests; $(PYTHON) run.py -v --cov=sphinx --junitxml=.junit.xml $(TEST) + @$(PYTHON) -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST) .PHONY: build build: diff --git a/tests/run.py b/tests/run.py deleted file mode 100755 index 6c82db782..000000000 --- a/tests/run.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - Sphinx unit test driver - ~~~~~~~~~~~~~~~~~~~~~~~ - - This script runs the Sphinx unit test suite. - - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" -import sys - -import pytest - -sys.exit(pytest.main(sys.argv[1:])) diff --git a/tests/test_pycode.py b/tests/test_pycode.py index 2b5ae1514..400c47dc5 100644 --- a/tests/test_pycode.py +++ b/tests/test_pycode.py @@ -41,7 +41,8 @@ def test_ModuleAnalyzer_for_file(): def test_ModuleAnalyzer_for_module(): analyzer = ModuleAnalyzer.for_module('sphinx') assert analyzer.modname == 'sphinx' - assert analyzer.srcname == SPHINX_MODULE_PATH + assert analyzer.srcname in (SPHINX_MODULE_PATH, + os.path.abspath(SPHINX_MODULE_PATH)) assert analyzer.encoding == 'utf-8' diff --git a/tox.ini b/tox.ini index 36fdf83f4..0d19225f8 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ deps = setenv = SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= - {envpython} -Wall tests/run.py --durations 25 {posargs} + pytest -Wall --durations 25 {posargs} [testenv:flake8] description = From 9a3ebaaff5a24ed9f9ae9481acc0dbfd46281096 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Dec 2017 18:50:53 +0000 Subject: [PATCH 0492/1814] Resolve warning filter issues There's an issue with 'pkgutils' and namespace packages. This has been reported against setuptools [1], but until this is resolved, we simply need to live with it. Ensure said warnings are filtered from tox too and remove some unnecessary ones. [1] https://github.com/pypa/setuptools/issues/1111 Signed-off-by: Stephen Finucane --- tests/conftest.py | 2 -- tox.ini | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 336484bcc..0d6b39681 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,9 +40,7 @@ def _filter_warnings(): ignore(category=DeprecationWarning, module='site') # virtualenv ignore(category=PendingDeprecationWarning, module=r'_pytest\..*') - ignore(category=ImportWarning, module='backports') ignore(category=ImportWarning, module='pkgutil') - ignore(category=ImportWarning, module='pytest_cov') def _initialize_test_directory(session): diff --git a/tox.ini b/tox.ini index 0d19225f8..99e243ad6 100644 --- a/tox.ini +++ b/tox.ini @@ -20,6 +20,7 @@ deps = du13: docutils==0.13.1 du14: docutils==0.14 setenv = + PYTHONWARNINGS = all,ignore::ImportWarning:pkgutil SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= pytest -Wall --durations 25 {posargs} From 60e25090a3d40f2883701df22aa778a2623d50a2 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 24 Dec 2017 20:05:13 +0000 Subject: [PATCH 0493/1814] tox: Enable 'skipsdist' Given that we install Sphinx as part of the dependencies, there's no reason to do it twice. Skip that step. Signed-off-by: Stephen Finucane --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 99e243ad6..ae6b2a4b3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] minversion = 2.0 envlist = docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} +skipsdist = True [testenv] passenv = From 54699dd263950527b55cfafc115b8d5ee7cfeacf Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 30 Dec 2017 00:38:17 +0900 Subject: [PATCH 0494/1814] Fix parallel_write_safe check was wrong --- sphinx/extension.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/extension.py b/sphinx/extension.py index 0520bf564..acbe0d865 100644 --- a/sphinx/extension.py +++ b/sphinx/extension.py @@ -38,7 +38,7 @@ class Extension(object): # The extension supports parallel write or not. The default value # is ``True``. Sphinx writes parallelly documents even if # the extension does not tell its status. - self.parallel_write_safe = kwargs.pop('parallel_read_safe', True) + self.parallel_write_safe = kwargs.pop('parallel_write_safe', True) def verify_required_extensions(app, requirements): From 1d3362425b95151d8ecfacbd53667b2663013580 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 30 Dec 2017 00:54:55 +0900 Subject: [PATCH 0495/1814] Add app.is_parallel_allowed() --- sphinx/application.py | 30 +++++++++++++++- sphinx/builders/__init__.py | 11 ++---- sphinx/environment/__init__.py | 17 ++------- tests/roots/test-extensions/conf.py | 4 +++ tests/roots/test-extensions/read_parallel.py | 4 +++ tests/roots/test-extensions/read_serial.py | 4 +++ tests/roots/test-extensions/write_parallel.py | 4 +++ tests/roots/test-extensions/write_serial.py | 4 +++ tests/test_application.py | 36 +++++++++++++++++++ 9 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 tests/roots/test-extensions/conf.py create mode 100644 tests/roots/test-extensions/read_parallel.py create mode 100644 tests/roots/test-extensions/read_serial.py create mode 100644 tests/roots/test-extensions/write_parallel.py create mode 100644 tests/roots/test-extensions/write_serial.py diff --git a/sphinx/application.py b/sphinx/application.py index b6fd7feef..2a084ff0c 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -19,7 +19,7 @@ import posixpath from os import path from collections import deque -from six import iteritems +from six import iteritems, itervalues from six.moves import cStringIO from docutils import nodes @@ -673,6 +673,34 @@ class Sphinx(object): logger.debug('[app] adding HTML theme: %r, %r', name, theme_path) self.html_themes[name] = theme_path + # ---- other methods ------------------------------------------------- + def is_parallel_allowed(self, typ): + # type: (unicode) -> bool + """Check parallel processing is allowed or not. + + ``typ`` is a type of processing; ``'read'`` or ``'write'``. + """ + if typ == 'read': + attrname = 'parallel_read_safe' + elif typ == 'write': + attrname = 'parallel_write_safe' + else: + raise ValueError('parallel type %s is not supported' % typ) + + for ext in itervalues(self.extensions): + allowed = getattr(ext, attrname, None) + if allowed is None: + logger.warning(__("the %s extension does not declare if it is safe " + "for parallel %sing, assuming it isn't - please " + "ask the extension author to check and make it " + "explicit"), ext.name, typ) + logger.warning('doing serial %s', typ) + return False + elif not allowed: + return False + + return True + class TemplateBridge(object): """ diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 8acd91729..d096ee4d7 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -371,15 +371,10 @@ class Builder(object): docnames = set(docnames) & self.env.found_docs # determine if we can write in parallel - self.parallel_ok = False if parallel_available and self.app.parallel > 1 and self.allow_parallel: - self.parallel_ok = True - for extension in itervalues(self.app.extensions): - if not extension.parallel_write_safe: - logger.warning('the %s extension is not safe for parallel ' - 'writing, doing serial write', extension.name) - self.parallel_ok = False - break + self.parallel_ok = self.app.is_parallel_allowed('write') + else: + self.parallel_ok = False # create a task executor to use for misc. "finish-up" tasks # if self.parallel_ok: diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index b4c40b608..583d41c1a 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -558,21 +558,10 @@ class BuildEnvironment(object): self.app.emit('env-before-read-docs', self, docnames) # check if we should do parallel or serial read - par_ok = False if parallel_available and len(docnames) > 5 and self.app.parallel > 1: - for ext in itervalues(self.app.extensions): - if ext.parallel_read_safe is None: - logger.warning(__('the %s extension does not declare if it is safe ' - 'for parallel reading, assuming it isn\'t - please ' - 'ask the extension author to check and make it ' - 'explicit'), ext.name) - logger.warning('doing serial read') - break - elif ext.parallel_read_safe is False: - break - else: - # all extensions support parallel-read - par_ok = True + par_ok = self.app.is_parallel_allowed('read') + else: + par_ok = False if par_ok: self._read_parallel(docnames, self.app, nproc=self.app.parallel) diff --git a/tests/roots/test-extensions/conf.py b/tests/roots/test-extensions/conf.py new file mode 100644 index 000000000..9a3cbc844 --- /dev/null +++ b/tests/roots/test-extensions/conf.py @@ -0,0 +1,4 @@ +import os +import sys + +sys.path.insert(0, os.path.abspath('.')) diff --git a/tests/roots/test-extensions/read_parallel.py b/tests/roots/test-extensions/read_parallel.py new file mode 100644 index 000000000..a3e052f95 --- /dev/null +++ b/tests/roots/test-extensions/read_parallel.py @@ -0,0 +1,4 @@ +def setup(app): + return { + 'parallel_read_safe': True + } diff --git a/tests/roots/test-extensions/read_serial.py b/tests/roots/test-extensions/read_serial.py new file mode 100644 index 000000000..c55570a5c --- /dev/null +++ b/tests/roots/test-extensions/read_serial.py @@ -0,0 +1,4 @@ +def setup(app): + return { + 'parallel_read_safe': False + } diff --git a/tests/roots/test-extensions/write_parallel.py b/tests/roots/test-extensions/write_parallel.py new file mode 100644 index 000000000..ebc48ef9b --- /dev/null +++ b/tests/roots/test-extensions/write_parallel.py @@ -0,0 +1,4 @@ +def setup(app): + return { + 'parallel_write_safe': True, + } diff --git a/tests/roots/test-extensions/write_serial.py b/tests/roots/test-extensions/write_serial.py new file mode 100644 index 000000000..75494ce77 --- /dev/null +++ b/tests/roots/test-extensions/write_serial.py @@ -0,0 +1,4 @@ +def setup(app): + return { + 'parallel_write_safe': False + } diff --git a/tests/test_application.py b/tests/test_application.py index 785a78878..1a4b22e3e 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -12,6 +12,7 @@ from docutils import nodes from sphinx.application import ExtensionError from sphinx.domains import Domain +from sphinx.util import logging from sphinx.testing.util import strip_escseq import pytest @@ -86,3 +87,38 @@ def test_add_source_parser(app, status, warning): assert set(app.registry.get_source_parsers().keys()) == set(['*', '.md', '.test']) assert app.registry.get_source_parsers()['.md'].__name__ == 'DummyMarkdownParser' assert app.registry.get_source_parsers()['.test'].__name__ == 'TestSourceParser' + + +@pytest.mark.sphinx(testroot='extensions') +def test_add_is_parallel_allowed(app, status, warning): + logging.setup(app, status, warning) + + assert app.is_parallel_allowed('read') is True + assert app.is_parallel_allowed('write') is True + assert warning.getvalue() == '' + + app.setup_extension('read_parallel') + assert app.is_parallel_allowed('read') is True + assert app.is_parallel_allowed('write') is True + assert warning.getvalue() == '' + app.extensions.pop('read_parallel') + + app.setup_extension('write_parallel') + assert app.is_parallel_allowed('read') is False + assert app.is_parallel_allowed('write') is True + assert 'the write_parallel extension does not declare' in warning.getvalue() + app.extensions.pop('write_parallel') + warning.truncate(0) # reset warnings + + app.setup_extension('read_serial') + assert app.is_parallel_allowed('read') is False + assert app.is_parallel_allowed('write') is True + assert warning.getvalue() == '' + app.extensions.pop('read_serial') + + app.setup_extension('write_serial') + assert app.is_parallel_allowed('read') is False + assert app.is_parallel_allowed('write') is False + assert 'the write_serial extension does not declare' in warning.getvalue() + app.extensions.pop('write_serial') + warning.truncate(0) # reset warnings From d7aa98aed7d5e5f361d76768c1abf12f912c3609 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 30 Dec 2017 01:21:22 +0900 Subject: [PATCH 0496/1814] Fix flake8 violations --- sphinx/builders/__init__.py | 1 - sphinx/environment/__init__.py | 1 - 2 files changed, 2 deletions(-) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index d096ee4d7..6bba5c788 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -17,7 +17,6 @@ try: except ImportError: multiprocessing = None -from six import itervalues from docutils import nodes from sphinx.deprecation import RemovedInSphinx20Warning diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 583d41c1a..2cbee2523 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -40,7 +40,6 @@ from sphinx.util.matching import compile_matchers from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError -from sphinx.locale import __ from sphinx.transforms import SphinxTransformer from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.environment.adapters.indexentries import IndexEntries From 0059c05a857f4144e4eea8b3d2908e906cf7de49 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 30 Dec 2017 11:03:43 +0100 Subject: [PATCH 0497/1814] Rename smartquotable to notsmartquotable for intelligibility --- sphinx/transforms/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 0ceced214..c5fe7864e 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -346,5 +346,5 @@ class SphinxSmartQuotes(SmartQuotes): texttype = {True: 'literal', # "literal" text is not changed: False: 'plain'} for txtnode in txtnodes: - smartquotable = not is_smartquotable(txtnode) - yield (texttype[smartquotable], txtnode.astext()) + notsmartquotable = not is_smartquotable(txtnode) + yield (texttype[notsmartquotable], txtnode.astext()) From 2426cedb8b12b7a59270e55f2f26d63d0014a28f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 Jan 2018 01:06:58 +0900 Subject: [PATCH 0498/1814] A happy new year! --- LICENSE | 2 +- doc/_themes/sphinx13/layout.html | 2 +- doc/_themes/sphinx13/static/sphinx13.css | 2 +- doc/conf.py | 2 +- sphinx-apidoc.py | 2 +- sphinx-autogen.py | 2 +- sphinx-build.py | 2 +- sphinx-quickstart.py | 2 +- sphinx/__init__.py | 2 +- sphinx/__main__.py | 2 +- sphinx/addnodes.py | 2 +- sphinx/apidoc.py | 2 +- sphinx/application.py | 2 +- sphinx/builders/__init__.py | 2 +- sphinx/builders/_epub_base.py | 2 +- sphinx/builders/applehelp.py | 2 +- sphinx/builders/changes.py | 2 +- sphinx/builders/devhelp.py | 2 +- sphinx/builders/gettext.py | 2 +- sphinx/builders/html.py | 2 +- sphinx/builders/htmlhelp.py | 2 +- sphinx/builders/latex.py | 2 +- sphinx/builders/linkcheck.py | 2 +- sphinx/builders/manpage.py | 2 +- sphinx/builders/qthelp.py | 2 +- sphinx/builders/texinfo.py | 2 +- sphinx/builders/text.py | 2 +- sphinx/builders/websupport.py | 2 +- sphinx/builders/xml.py | 2 +- sphinx/cmdline.py | 2 +- sphinx/config.py | 2 +- sphinx/deprecation.py | 2 +- sphinx/directives/__init__.py | 2 +- sphinx/directives/code.py | 2 +- sphinx/directives/other.py | 2 +- sphinx/directives/patches.py | 2 +- sphinx/domains/__init__.py | 2 +- sphinx/domains/c.py | 2 +- sphinx/domains/cpp.py | 2 +- sphinx/domains/javascript.py | 2 +- sphinx/domains/python.py | 2 +- sphinx/domains/rst.py | 2 +- sphinx/domains/std.py | 2 +- sphinx/environment/__init__.py | 2 +- sphinx/environment/adapters/__init__.py | 2 +- sphinx/environment/adapters/asset.py | 2 +- sphinx/environment/adapters/indexentries.py | 2 +- sphinx/environment/adapters/toctree.py | 2 +- sphinx/environment/collectors/__init__.py | 2 +- sphinx/environment/collectors/asset.py | 2 +- sphinx/environment/collectors/dependencies.py | 2 +- sphinx/environment/collectors/indexentries.py | 2 +- sphinx/environment/collectors/metadata.py | 2 +- sphinx/environment/collectors/title.py | 2 +- sphinx/environment/collectors/toctree.py | 2 +- sphinx/errors.py | 2 +- sphinx/events.py | 2 +- sphinx/ext/__init__.py | 2 +- sphinx/ext/autodoc.py | 2 +- sphinx/ext/autosectionlabel.py | 2 +- sphinx/ext/autosummary/__init__.py | 2 +- sphinx/ext/autosummary/generate.py | 2 +- sphinx/ext/coverage.py | 2 +- sphinx/ext/doctest.py | 2 +- sphinx/ext/extlinks.py | 2 +- sphinx/ext/githubpages.py | 2 +- sphinx/ext/graphviz.py | 2 +- sphinx/ext/ifconfig.py | 2 +- sphinx/ext/imgconverter.py | 2 +- sphinx/ext/imgmath.py | 2 +- sphinx/ext/inheritance_diagram.py | 2 +- sphinx/ext/intersphinx.py | 2 +- sphinx/ext/jsmath.py | 2 +- sphinx/ext/linkcode.py | 2 +- sphinx/ext/mathbase.py | 2 +- sphinx/ext/mathjax.py | 2 +- sphinx/ext/napoleon/__init__.py | 2 +- sphinx/ext/napoleon/docstring.py | 2 +- sphinx/ext/napoleon/iterators.py | 2 +- sphinx/ext/pngmath.py | 2 +- sphinx/ext/todo.py | 2 +- sphinx/ext/viewcode.py | 2 +- sphinx/extension.py | 2 +- sphinx/highlighting.py | 2 +- sphinx/io.py | 2 +- sphinx/jinja2glue.py | 2 +- sphinx/make_mode.py | 2 +- sphinx/parsers.py | 2 +- sphinx/pycode/__init__.py | 2 +- sphinx/pycode/nodes.py | 2 +- sphinx/pygments_styles.py | 2 +- sphinx/quickstart.py | 2 +- sphinx/roles.py | 2 +- sphinx/search/__init__.py | 2 +- sphinx/search/en.py | 2 +- sphinx/search/ja.py | 2 +- sphinx/search/jssplitter.py | 2 +- sphinx/search/zh.py | 2 +- sphinx/setup_command.py | 2 +- sphinx/testing/__init__.py | 2 +- sphinx/testing/fixtures.py | 2 +- sphinx/testing/path.py | 2 +- sphinx/testing/util.py | 2 +- sphinx/themes/agogo/layout.html | 2 +- sphinx/themes/agogo/static/agogo.css_t | 2 +- sphinx/themes/basic/defindex.html | 2 +- sphinx/themes/basic/domainindex.html | 2 +- sphinx/themes/basic/genindex-single.html | 2 +- sphinx/themes/basic/genindex-split.html | 2 +- sphinx/themes/basic/genindex.html | 2 +- sphinx/themes/basic/globaltoc.html | 2 +- sphinx/themes/basic/layout.html | 2 +- sphinx/themes/basic/localtoc.html | 2 +- sphinx/themes/basic/page.html | 2 +- sphinx/themes/basic/relations.html | 2 +- sphinx/themes/basic/search.html | 2 +- sphinx/themes/basic/searchbox.html | 2 +- sphinx/themes/basic/searchresults.html | 2 +- sphinx/themes/basic/sourcelink.html | 2 +- sphinx/themes/basic/static/basic.css_t | 2 +- sphinx/themes/basic/static/doctools.js_t | 2 +- sphinx/themes/basic/static/searchtools.js_t | 2 +- sphinx/themes/basic/static/websupport.js | 2 +- sphinx/themes/classic/layout.html | 2 +- sphinx/themes/classic/static/classic.css_t | 2 +- sphinx/themes/classic/static/sidebar.js_t | 2 +- sphinx/themes/epub/epub-cover.html | 2 +- sphinx/themes/epub/layout.html | 2 +- sphinx/themes/epub/static/epub.css_t | 2 +- sphinx/themes/haiku/layout.html | 2 +- sphinx/themes/haiku/static/haiku.css_t | 2 +- sphinx/themes/nature/static/nature.css_t | 2 +- sphinx/themes/nonav/layout.html | 2 +- sphinx/themes/nonav/static/nonav.css | 2 +- sphinx/themes/pyramid/static/epub.css | 2 +- sphinx/themes/pyramid/static/pyramid.css_t | 2 +- sphinx/themes/scrolls/layout.html | 2 +- sphinx/themes/scrolls/static/scrolls.css_t | 2 +- sphinx/themes/sphinxdoc/layout.html | 2 +- sphinx/themes/sphinxdoc/static/sphinxdoc.css_t | 2 +- sphinx/themes/traditional/static/traditional.css_t | 2 +- sphinx/theming.py | 2 +- sphinx/transforms/__init__.py | 2 +- sphinx/transforms/compact_bullet_list.py | 2 +- sphinx/transforms/i18n.py | 2 +- sphinx/transforms/post_transforms/__init__.py | 2 +- sphinx/transforms/post_transforms/images.py | 2 +- sphinx/util/__init__.py | 2 +- sphinx/util/compat.py | 2 +- sphinx/util/console.py | 2 +- sphinx/util/docfields.py | 2 +- sphinx/util/docstrings.py | 2 +- sphinx/util/docutils.py | 2 +- sphinx/util/fileutil.py | 2 +- sphinx/util/i18n.py | 2 +- sphinx/util/images.py | 2 +- sphinx/util/inspect.py | 2 +- sphinx/util/inventory.py | 2 +- sphinx/util/jsdump.py | 2 +- sphinx/util/jsonimpl.py | 2 +- sphinx/util/logging.py | 2 +- sphinx/util/matching.py | 2 +- sphinx/util/nodes.py | 2 +- sphinx/util/osutil.py | 2 +- sphinx/util/parallel.py | 2 +- sphinx/util/png.py | 2 +- sphinx/util/pycompat.py | 2 +- sphinx/util/requests.py | 2 +- sphinx/util/rst.py | 2 +- sphinx/util/stemmer/__init__.py | 2 +- sphinx/util/tags.py | 2 +- sphinx/util/template.py | 2 +- sphinx/util/texescape.py | 2 +- sphinx/util/typing.py | 2 +- sphinx/util/websupport.py | 2 +- sphinx/versioning.py | 2 +- sphinx/websupport/__init__.py | 2 +- sphinx/websupport/errors.py | 2 +- sphinx/websupport/search/__init__.py | 2 +- sphinx/websupport/search/nullsearch.py | 2 +- sphinx/websupport/search/whooshsearch.py | 2 +- sphinx/websupport/search/xapiansearch.py | 2 +- sphinx/websupport/storage/__init__.py | 2 +- sphinx/websupport/storage/differ.py | 2 +- sphinx/websupport/storage/sqlalchemy_db.py | 2 +- sphinx/websupport/storage/sqlalchemystorage.py | 2 +- sphinx/writers/__init__.py | 2 +- sphinx/writers/html.py | 2 +- sphinx/writers/html5.py | 2 +- sphinx/writers/latex.py | 2 +- sphinx/writers/manpage.py | 2 +- sphinx/writers/texinfo.py | 2 +- sphinx/writers/text.py | 2 +- sphinx/writers/websupport.py | 2 +- sphinx/writers/xml.py | 2 +- tests/conftest.py | 2 +- tests/py35/test_autodoc_py35.py | 2 +- tests/run.py | 2 +- tests/test_api_translator.py | 2 +- tests/test_apidoc.py | 2 +- tests/test_application.py | 2 +- tests/test_autodoc.py | 2 +- tests/test_build.py | 2 +- tests/test_build_applehelp.py | 2 +- tests/test_build_gettext.py | 2 +- tests/test_build_html.py | 2 +- tests/test_build_html5.py | 2 +- tests/test_build_latex.py | 2 +- tests/test_build_linkcheck.py | 2 +- tests/test_build_manpage.py | 2 +- tests/test_build_texinfo.py | 2 +- tests/test_build_text.py | 2 +- tests/test_catalogs.py | 2 +- tests/test_config.py | 2 +- tests/test_correct_year.py | 2 +- tests/test_directive_code.py | 2 +- tests/test_directive_only.py | 2 +- tests/test_docutilsconf.py | 2 +- tests/test_domain_cpp.py | 2 +- tests/test_domain_js.py | 2 +- tests/test_domain_py.py | 2 +- tests/test_domain_rst.py | 2 +- tests/test_domain_std.py | 2 +- tests/test_environment.py | 2 +- tests/test_environment_indexentries.py | 2 +- tests/test_environment_toctree.py | 2 +- tests/test_ext_autodoc.py | 2 +- tests/test_ext_autosectionlabel.py | 2 +- tests/test_ext_autosummary.py | 2 +- tests/test_ext_coverage.py | 2 +- tests/test_ext_doctest.py | 2 +- tests/test_ext_githubpages.py | 2 +- tests/test_ext_graphviz.py | 2 +- tests/test_ext_ifconfig.py | 2 +- tests/test_ext_imgconverter.py | 2 +- tests/test_ext_inheritance_diagram.py | 2 +- tests/test_ext_intersphinx.py | 2 +- tests/test_ext_math.py | 2 +- tests/test_ext_napoleon.py | 2 +- tests/test_ext_napoleon_docstring.py | 2 +- tests/test_ext_napoleon_iterators.py | 2 +- tests/test_ext_todo.py | 2 +- tests/test_ext_viewcode.py | 2 +- tests/test_highlighting.py | 2 +- tests/test_intl.py | 2 +- tests/test_markup.py | 2 +- tests/test_metadata.py | 2 +- tests/test_quickstart.py | 2 +- tests/test_search.py | 2 +- tests/test_setup_command.py | 2 +- tests/test_templating.py | 2 +- tests/test_theming.py | 2 +- tests/test_toctree.py | 2 +- tests/test_util.py | 2 +- tests/test_util_fileutil.py | 2 +- tests/test_util_i18n.py | 2 +- tests/test_util_images.py | 2 +- tests/test_util_inspect.py | 2 +- tests/test_util_logging.py | 2 +- tests/test_util_matching.py | 2 +- tests/test_util_nodes.py | 2 +- tests/test_util_rst.py | 2 +- tests/test_versioning.py | 2 +- tests/test_websupport.py | 2 +- tests/test_writer_latex.py | 2 +- utils/check_sources.py | 2 +- utils/jssplitter_generator.py | 2 +- 267 files changed, 267 insertions(+), 267 deletions(-) diff --git a/LICENSE b/LICENSE index a2783ab3f..19f1090fd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ License for Sphinx ================== -Copyright (c) 2007-2017 by the Sphinx team (see AUTHORS file). +Copyright (c) 2007-2018 by the Sphinx team (see AUTHORS file). All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/doc/_themes/sphinx13/layout.html b/doc/_themes/sphinx13/layout.html index fdac6d0a2..cd870fe7b 100644 --- a/doc/_themes/sphinx13/layout.html +++ b/doc/_themes/sphinx13/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the sphinxdoc theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/doc/_themes/sphinx13/static/sphinx13.css b/doc/_themes/sphinx13/static/sphinx13.css index d15fbaea4..6bdc5a96c 100644 --- a/doc/_themes/sphinx13/static/sphinx13.css +++ b/doc/_themes/sphinx13/static/sphinx13.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- sphinx13 theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/doc/conf.py b/doc/conf.py index 62c5c13d5..1f19b53a2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -15,7 +15,7 @@ templates_path = ['_templates'] exclude_patterns = ['_build'] project = 'Sphinx' -copyright = '2007-2017, Georg Brandl and the Sphinx team' +copyright = '2007-2018, Georg Brandl and the Sphinx team' version = sphinx.__display_version__ release = version show_authors = True diff --git a/sphinx-apidoc.py b/sphinx-apidoc.py index 0290d6c50..8279feaaa 100755 --- a/sphinx-apidoc.py +++ b/sphinx-apidoc.py @@ -4,7 +4,7 @@ Sphinx - Python documentation toolchain ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx-autogen.py b/sphinx-autogen.py index 8320b2c14..6c10f0e64 100755 --- a/sphinx-autogen.py +++ b/sphinx-autogen.py @@ -4,7 +4,7 @@ Sphinx - Python documentation toolchain ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx-build.py b/sphinx-build.py index ae60c0724..1b8d14082 100755 --- a/sphinx-build.py +++ b/sphinx-build.py @@ -4,7 +4,7 @@ Sphinx - Python documentation toolchain ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx-quickstart.py b/sphinx-quickstart.py index bf8423fa6..81d6b6696 100755 --- a/sphinx-quickstart.py +++ b/sphinx-quickstart.py @@ -4,7 +4,7 @@ Sphinx - Python documentation toolchain ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 4facec53e..b8a62f9e8 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -5,7 +5,7 @@ The Sphinx documentation toolchain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/__main__.py b/sphinx/__main__.py index 544505a6c..06b1812f2 100644 --- a/sphinx/__main__.py +++ b/sphinx/__main__.py @@ -5,7 +5,7 @@ The Sphinx documentation toolchain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import sys diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 762dc9bbb..e6999bd16 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -5,7 +5,7 @@ Additional docutils nodes. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py index b764cfc35..8f9694cdd 100644 --- a/sphinx/apidoc.py +++ b/sphinx/apidoc.py @@ -11,7 +11,7 @@ Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/application.py b/sphinx/application.py index b5705face..d23d97fbd 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -7,7 +7,7 @@ Gracefully adapted from the TextPress system by Armin. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index a1d5c5d22..4b977cbc2 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -5,7 +5,7 @@ Builder superclass for all builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index b68fdbacc..411ea7067 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -5,7 +5,7 @@ Base class of epub2/epub3 builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index f8df9310c..52ba2ce5c 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -5,7 +5,7 @@ Build Apple help books. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 5c3072059..f18076700 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -5,7 +5,7 @@ Changelog builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index 9dbbf3c17..88a9be219 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -7,7 +7,7 @@ .. _Devhelp: http://live.gnome.org/devhelp - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index b684104c1..464d574cc 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -5,7 +5,7 @@ The MessageCatalogBuilder class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index e50d2abe4..68f38320b 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -5,7 +5,7 @@ Several HTML builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index c2e3bbe2c..0b45601e3 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -6,7 +6,7 @@ Build HTML help support files. Parts adapted from Python's Doc/tools/prechm.py. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py index 03a75caab..d93b0ab99 100644 --- a/sphinx/builders/latex.py +++ b/sphinx/builders/latex.py @@ -5,7 +5,7 @@ LaTeX builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index c52b808cd..ca62b9fe1 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -5,7 +5,7 @@ The CheckExternalLinksBuilder class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index 83e354601..b57a756ee 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -5,7 +5,7 @@ Manual pages builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 12a50d140..07efd02ab 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -5,7 +5,7 @@ Build input files for the Qt collection generator. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 3e6816507..82c6f1b9d 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -5,7 +5,7 @@ Texinfo builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index 29ceaa855..7b977b1b9 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -5,7 +5,7 @@ Plain-text Sphinx builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/websupport.py b/sphinx/builders/websupport.py index 2e416b287..1fe9e2001 100644 --- a/sphinx/builders/websupport.py +++ b/sphinx/builders/websupport.py @@ -5,7 +5,7 @@ Builder for the web support package. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py index d4ebb47ef..599530ac1 100644 --- a/sphinx/builders/xml.py +++ b/sphinx/builders/xml.py @@ -5,7 +5,7 @@ Docutils-native XML and pseudo-XML builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 79a69cd7b..c9a0dd4c6 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -5,7 +5,7 @@ sphinx-build command-line handling. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/config.py b/sphinx/config.py index cc5f57e8e..d3468b0a5 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -5,7 +5,7 @@ Build configuration file handling. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 608b23c1b..93395fa7d 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -5,7 +5,7 @@ Sphinx deprecation classes and utilities. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index dc0cc4f6c..dc51810d3 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -5,7 +5,7 @@ Handlers for additional ReST directives. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 41a593aa3..9758cbbe8 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -3,7 +3,7 @@ sphinx.directives.code ~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 626218ca2..4ce709a63 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -3,7 +3,7 @@ sphinx.directives.other ~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py index 880377ff7..c97340a81 100644 --- a/sphinx/directives/patches.py +++ b/sphinx/directives/patches.py @@ -3,7 +3,7 @@ sphinx.directives.patches ~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 6edc3cdb0..a6d28a06d 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -6,7 +6,7 @@ Support for domains, which are groupings of description directives and roles describing e.g. constructs of one programming language. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index b9afd10c2..3030cff8a 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -5,7 +5,7 @@ The C language domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index aa97481ab..fa9eaa5e8 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -5,7 +5,7 @@ The C++ language domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 9ecf4a4b0..81f86f754 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -5,7 +5,7 @@ The JavaScript domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 6aa00a8b0..432e9b542 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -5,7 +5,7 @@ The Python domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 2a7dffc4d..936dd1b9f 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -5,7 +5,7 @@ The reStructuredText domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index bfaa57c4f..27bb88c96 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -5,7 +5,7 @@ The standard domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 522414ea6..65a73b019 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -5,7 +5,7 @@ Global creation environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/adapters/__init__.py b/sphinx/environment/adapters/__init__.py index 9171ac0be..f945c4250 100644 --- a/sphinx/environment/adapters/__init__.py +++ b/sphinx/environment/adapters/__init__.py @@ -5,6 +5,6 @@ Sphinx environment adapters - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/adapters/asset.py b/sphinx/environment/adapters/asset.py index 02557a8c4..91f2cf8eb 100644 --- a/sphinx/environment/adapters/asset.py +++ b/sphinx/environment/adapters/asset.py @@ -5,7 +5,7 @@ Assets adapter for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py index 946e635ef..4a39b1bd0 100644 --- a/sphinx/environment/adapters/indexentries.py +++ b/sphinx/environment/adapters/indexentries.py @@ -5,7 +5,7 @@ Index entries adapters for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index 03c1d8aa9..bf725b619 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -5,7 +5,7 @@ Toctree adapter for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py index 917b34afb..9d9f5347c 100644 --- a/sphinx/environment/collectors/__init__.py +++ b/sphinx/environment/collectors/__init__.py @@ -5,7 +5,7 @@ The data collector components for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py index 3a0e1fefd..0d7a193e3 100644 --- a/sphinx/environment/collectors/asset.py +++ b/sphinx/environment/collectors/asset.py @@ -5,7 +5,7 @@ The image collector for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py index 5e20d1245..bf42b12e9 100644 --- a/sphinx/environment/collectors/dependencies.py +++ b/sphinx/environment/collectors/dependencies.py @@ -5,7 +5,7 @@ The dependencies collector components for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/indexentries.py b/sphinx/environment/collectors/indexentries.py index 0b1c35934..f9fa8bab7 100644 --- a/sphinx/environment/collectors/indexentries.py +++ b/sphinx/environment/collectors/indexentries.py @@ -5,7 +5,7 @@ Index entries collector for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/metadata.py b/sphinx/environment/collectors/metadata.py index ae8a8cb4c..7d54d2fe6 100644 --- a/sphinx/environment/collectors/metadata.py +++ b/sphinx/environment/collectors/metadata.py @@ -5,7 +5,7 @@ The metadata collector components for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/title.py b/sphinx/environment/collectors/title.py index 3335c2cc7..eb23b975f 100644 --- a/sphinx/environment/collectors/title.py +++ b/sphinx/environment/collectors/title.py @@ -5,7 +5,7 @@ The title collector components for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index 91aa21f2e..53e1045d9 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -5,7 +5,7 @@ Toctree collector for sphinx.environment. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/errors.py b/sphinx/errors.py index 7662c95a3..eef1a157a 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -6,7 +6,7 @@ Contains SphinxError and a few subclasses (in an extra module to avoid circular import problems). - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/events.py b/sphinx/events.py index 99decfff5..097f61fc6 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -7,7 +7,7 @@ Gracefully adapted from the TextPress system by Armin. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/ext/__init__.py b/sphinx/ext/__init__.py index e529ee9e5..440c01a15 100644 --- a/sphinx/ext/__init__.py +++ b/sphinx/ext/__init__.py @@ -5,6 +5,6 @@ Contains Sphinx features not activated by default. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 3cc87904a..e04b4a09d 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -7,7 +7,7 @@ the doctree, thus avoiding duplication between docstrings and documentation for those who like elaborate docstrings. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 69b8c6873..fbb7d037f 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -5,7 +5,7 @@ Allow reference sections by :ref: role using its title. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 67bbf6d91..08776badc 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -49,7 +49,7 @@ resolved to a Python object, and otherwise it becomes simple emphasis. This can be used as the default role to make links 'smart'. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 775490471..99d5d5796 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -14,7 +14,7 @@ generate: sphinx-autogen -o source/generated source/*.rst - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 02843ac83..476a0ed46 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -6,7 +6,7 @@ Check Python modules and C API for coverage. Mostly written by Josip Dzolonga for the Google Highly Open Participation contest. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 4110d9c90..e0ce050f7 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -6,7 +6,7 @@ Mimic doctest by automatically executing code snippets and checking their results. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py index 00180b35c..c247e6722 100644 --- a/sphinx/ext/extlinks.py +++ b/sphinx/ext/extlinks.py @@ -20,7 +20,7 @@ You can also give an explicit caption, e.g. :exmpl:`Foo `. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/githubpages.py b/sphinx/ext/githubpages.py index 028b65622..7d673a72d 100644 --- a/sphinx/ext/githubpages.py +++ b/sphinx/ext/githubpages.py @@ -5,7 +5,7 @@ To publish HTML docs at GitHub Pages, create .nojekyll file. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index 2a83474ce..546594843 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -6,7 +6,7 @@ Allow graphviz-formatted graphs to be included in Sphinx-generated documents inline. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py index c700649dd..16042ac3f 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -16,7 +16,7 @@ namespace of the project configuration (that is, all variables from ``conf.py`` are available.) - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/imgconverter.py b/sphinx/ext/imgconverter.py index d2894b2a3..95f579e36 100644 --- a/sphinx/ext/imgconverter.py +++ b/sphinx/ext/imgconverter.py @@ -5,7 +5,7 @@ Image converter extension for Sphinx - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import subprocess diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 8bf4fcad5..f4a144403 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -5,7 +5,7 @@ Render math in HTML via dvipng or dvisvgm. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index f5b0228a5..34fe7bea6 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -32,7 +32,7 @@ r""" The graph is inserted as a PNG+image map into HTML and a PDF in LaTeX. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index ad50542a3..ccd2c9321 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -20,7 +20,7 @@ also be specified individually, e.g. if the docs should be buildable without Internet access. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index dc57c13c6..21ec3cd23 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -6,7 +6,7 @@ Set up everything for use of JSMath to display math in HTML via JavaScript. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/linkcode.py b/sphinx/ext/linkcode.py index e74ee8529..a42dab528 100644 --- a/sphinx/ext/linkcode.py +++ b/sphinx/ext/linkcode.py @@ -5,7 +5,7 @@ Add external links to module code in Python object descriptions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index baa4df176..549ca30cd 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -5,7 +5,7 @@ Set up math support in source files and LaTeX/text output. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index f25f91e74..7fb3b17ad 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -7,7 +7,7 @@ Sphinx's HTML writer -- requires the MathJax JavaScript library on your webserver/computer. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 7aca9b629..b65f7f2a1 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -5,7 +5,7 @@ Support for NumPy and Google style docstrings. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index d3a64049b..b349c761f 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -7,7 +7,7 @@ Classes for docstring parsing and formatting. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py index b03bcf047..b4bba8863 100644 --- a/sphinx/ext/napoleon/iterators.py +++ b/sphinx/ext/napoleon/iterators.py @@ -7,7 +7,7 @@ A collection of helpful iterators. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py index 85010b799..eb1c82e8f 100644 --- a/sphinx/ext/pngmath.py +++ b/sphinx/ext/pngmath.py @@ -6,7 +6,7 @@ Render math in HTML via dvipng. This extension has been deprecated; please use sphinx.ext.imgmath instead. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index badfbc35f..e60620b5b 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -8,7 +8,7 @@ all todos of your project and lists them along with a backlink to the original location. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 25e5fe82a..2fd4479f8 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -5,7 +5,7 @@ Add links to module code in Python object descriptions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/extension.py b/sphinx/extension.py index 0520bf564..8a2f945ae 100644 --- a/sphinx/extension.py +++ b/sphinx/extension.py @@ -5,7 +5,7 @@ Utilities for Sphinx extensions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index eb309d82a..eef24ee95 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -5,7 +5,7 @@ Highlight code blocks using Pygments. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/io.py b/sphinx/io.py index 8f048c7fc..8365e22e0 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -5,7 +5,7 @@ Input/Output files - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from docutils.io import FileInput diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 41d48ad34..8839e48fa 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -5,7 +5,7 @@ Glue code for the jinja2 templating engine. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py index e7962db2e..f22a63b09 100644 --- a/sphinx/make_mode.py +++ b/sphinx/make_mode.py @@ -11,7 +11,7 @@ This is in its own module so that importing it is fast. It should not import the main Sphinx modules (like sphinx.applications, sphinx.builders). - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 33556e487..b58eefa23 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -5,7 +5,7 @@ A Base class for additional parsers. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index eabcc8188..92d96cecf 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -5,7 +5,7 @@ Utilities parsing and analyzing Python code. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/pycode/nodes.py b/sphinx/pycode/nodes.py index ea3b3e9ad..52bba1a35 100644 --- a/sphinx/pycode/nodes.py +++ b/sphinx/pycode/nodes.py @@ -5,7 +5,7 @@ Parse tree node implementations. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/pygments_styles.py b/sphinx/pygments_styles.py index a70005d7c..d29d825d5 100644 --- a/sphinx/pygments_styles.py +++ b/sphinx/pygments_styles.py @@ -5,7 +5,7 @@ Sphinx theme specific highlighting styles. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 5d8738996..a36c57528 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -5,7 +5,7 @@ Quickly setup documentation source to work with Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/roles.py b/sphinx/roles.py index 4007b9f88..223c6c21f 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -5,7 +5,7 @@ Handlers for additional ReST roles. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index 17560213d..d56b9e626 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -5,7 +5,7 @@ Create a full-text search index for offline search. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re diff --git a/sphinx/search/en.py b/sphinx/search/en.py index f7ce43350..fe9b7d8da 100644 --- a/sphinx/search/en.py +++ b/sphinx/search/en.py @@ -5,7 +5,7 @@ English search language: includes the JS porter stemmer. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index d1d922dd4..0cdc14a11 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -5,7 +5,7 @@ Japanese search language: includes routine to split words. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/jssplitter.py b/sphinx/search/jssplitter.py index 56b91c1d0..7166565f1 100644 --- a/sphinx/search/jssplitter.py +++ b/sphinx/search/jssplitter.py @@ -7,7 +7,7 @@ DO NOT EDIT. This is generated by utils/jssplitter_generator.py - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index bf01812e0..c9ae890ed 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -5,7 +5,7 @@ Chinese search language: includes routine to split words. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py index 8c00a2ff8..cd89fe7f7 100644 --- a/sphinx/setup_command.py +++ b/sphinx/setup_command.py @@ -8,7 +8,7 @@ :author: Sebastian Wiesner :contact: basti.wiesner@gmx.net - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/testing/__init__.py b/sphinx/testing/__init__.py index e246be8c0..c551da36f 100644 --- a/sphinx/testing/__init__.py +++ b/sphinx/testing/__init__.py @@ -10,6 +10,6 @@ pytest_plugins = 'sphinx.testing.fixtures' - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index 624adc03a..be0037b70 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -5,7 +5,7 @@ Sphinx test fixtures for pytest - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/testing/path.py b/sphinx/testing/path.py index 634d61332..30c4b49f3 100644 --- a/sphinx/testing/path.py +++ b/sphinx/testing/path.py @@ -3,7 +3,7 @@ sphinx.testing.path ~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index c1b2ae2b2..d8d06d3d4 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -5,7 +5,7 @@ Sphinx test suite utilities - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os diff --git a/sphinx/themes/agogo/layout.html b/sphinx/themes/agogo/layout.html index dcf5b0ed7..8bd476cad 100644 --- a/sphinx/themes/agogo/layout.html +++ b/sphinx/themes/agogo/layout.html @@ -5,7 +5,7 @@ Sphinx layout template for the agogo theme, originally written by Andi Albrecht. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t index f9e0d1637..0b5bbe16b 100644 --- a/sphinx/themes/agogo/static/agogo.css_t +++ b/sphinx/themes/agogo/static/agogo.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- agogo theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/basic/defindex.html b/sphinx/themes/basic/defindex.html index 303f9668b..5c92348b9 100644 --- a/sphinx/themes/basic/defindex.html +++ b/sphinx/themes/basic/defindex.html @@ -4,7 +4,7 @@ Default template for the "index" page. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #}{{ warn('Now base template defindex.html is deprecated.') }} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/domainindex.html b/sphinx/themes/basic/domainindex.html index dafbf72dc..58f0fc990 100644 --- a/sphinx/themes/basic/domainindex.html +++ b/sphinx/themes/basic/domainindex.html @@ -4,7 +4,7 @@ Template for domain indices (module index, ...). - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/genindex-single.html b/sphinx/themes/basic/genindex-single.html index bbdbfd0d0..1f61fa0f5 100644 --- a/sphinx/themes/basic/genindex-single.html +++ b/sphinx/themes/basic/genindex-single.html @@ -4,7 +4,7 @@ Template for a "single" page of a split index. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {% macro indexentries(firstname, links) %} diff --git a/sphinx/themes/basic/genindex-split.html b/sphinx/themes/basic/genindex-split.html index 12887c10e..42a7a4be3 100644 --- a/sphinx/themes/basic/genindex-split.html +++ b/sphinx/themes/basic/genindex-split.html @@ -4,7 +4,7 @@ Template for a "split" index overview page. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/genindex.html b/sphinx/themes/basic/genindex.html index fd96ba642..c852f25e8 100644 --- a/sphinx/themes/basic/genindex.html +++ b/sphinx/themes/basic/genindex.html @@ -4,7 +4,7 @@ Template for an "all-in-one" index. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {% macro indexentries(firstname, links) %} diff --git a/sphinx/themes/basic/globaltoc.html b/sphinx/themes/basic/globaltoc.html index 3b3a9201a..dc6fea373 100644 --- a/sphinx/themes/basic/globaltoc.html +++ b/sphinx/themes/basic/globaltoc.html @@ -4,7 +4,7 @@ Sphinx sidebar template: global table of contents. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #}

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

diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index bae7db7b5..cb89921fd 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -4,7 +4,7 @@ Master layout template for Sphinx themes. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- block doctype -%}{%- if html5_doctype %} diff --git a/sphinx/themes/basic/localtoc.html b/sphinx/themes/basic/localtoc.html index ca1a73ac0..5d3c7f4fd 100644 --- a/sphinx/themes/basic/localtoc.html +++ b/sphinx/themes/basic/localtoc.html @@ -4,7 +4,7 @@ Sphinx sidebar template: local table of contents. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if display_toc %} diff --git a/sphinx/themes/basic/page.html b/sphinx/themes/basic/page.html index e96f667ba..d2f0bd3f3 100644 --- a/sphinx/themes/basic/page.html +++ b/sphinx/themes/basic/page.html @@ -4,7 +4,7 @@ Master template for simple pages. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/relations.html b/sphinx/themes/basic/relations.html index d7fb6f0a4..7c0f4e711 100644 --- a/sphinx/themes/basic/relations.html +++ b/sphinx/themes/basic/relations.html @@ -4,7 +4,7 @@ Sphinx sidebar template: relation links. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if prev %} diff --git a/sphinx/themes/basic/search.html b/sphinx/themes/basic/search.html index ce8fa8924..32432a1e3 100644 --- a/sphinx/themes/basic/search.html +++ b/sphinx/themes/basic/search.html @@ -4,7 +4,7 @@ Template for the search page. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html index 17d84a02b..a8ea03cc8 100644 --- a/sphinx/themes/basic/searchbox.html +++ b/sphinx/themes/basic/searchbox.html @@ -4,7 +4,7 @@ Sphinx sidebar template: quick search box. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if pagename != "search" and builder != "singlehtml" %} diff --git a/sphinx/themes/basic/searchresults.html b/sphinx/themes/basic/searchresults.html index e04ec15d6..1371bf93c 100644 --- a/sphinx/themes/basic/searchresults.html +++ b/sphinx/themes/basic/searchresults.html @@ -4,7 +4,7 @@ Template for the body of the search results page. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #}

{{ _('Search') }}

diff --git a/sphinx/themes/basic/sourcelink.html b/sphinx/themes/basic/sourcelink.html index 3d4f76ddb..ecde6d3c5 100644 --- a/sphinx/themes/basic/sourcelink.html +++ b/sphinx/themes/basic/sourcelink.html @@ -4,7 +4,7 @@ Sphinx sidebar template: "show source" link. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- if show_source and has_source and sourcename %} diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index d16c760cb..745864e28 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/basic/static/doctools.js_t b/sphinx/themes/basic/static/doctools.js_t index 326856cfc..b261a44f3 100644 --- a/sphinx/themes/basic/static/doctools.js_t +++ b/sphinx/themes/basic/static/doctools.js_t @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for all documentation. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/basic/static/searchtools.js_t b/sphinx/themes/basic/static/searchtools.js_t index 306fdf55f..e707bb1ea 100644 --- a/sphinx/themes/basic/static/searchtools.js_t +++ b/sphinx/themes/basic/static/searchtools.js_t @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for the full-text search. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/basic/static/websupport.js b/sphinx/themes/basic/static/websupport.js index 53f6a4525..79b18e389 100644 --- a/sphinx/themes/basic/static/websupport.js +++ b/sphinx/themes/basic/static/websupport.js @@ -4,7 +4,7 @@ * * sphinx.websupport utilities for all documentation. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/classic/layout.html b/sphinx/themes/classic/layout.html index 50b6dc9e0..19f3d0279 100644 --- a/sphinx/themes/classic/layout.html +++ b/sphinx/themes/classic/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the classic theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/classic/static/classic.css_t b/sphinx/themes/classic/static/classic.css_t index 25e1c0261..a84ef8696 100644 --- a/sphinx/themes/classic/static/classic.css_t +++ b/sphinx/themes/classic/static/classic.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- classic theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/classic/static/sidebar.js_t b/sphinx/themes/classic/static/sidebar.js_t index 494df24f9..ce8361d9b 100644 --- a/sphinx/themes/classic/static/sidebar.js_t +++ b/sphinx/themes/classic/static/sidebar.js_t @@ -16,7 +16,7 @@ * Once the browser is closed the cookie is deleted and the position * reset to the default (expanded). * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/epub/epub-cover.html b/sphinx/themes/epub/epub-cover.html index 763be11ff..436c36aa0 100644 --- a/sphinx/themes/epub/epub-cover.html +++ b/sphinx/themes/epub/epub-cover.html @@ -4,7 +4,7 @@ Sample template for the html cover page. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "layout.html" %} diff --git a/sphinx/themes/epub/layout.html b/sphinx/themes/epub/layout.html index f27e4daa1..84d4bf31c 100644 --- a/sphinx/themes/epub/layout.html +++ b/sphinx/themes/epub/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the epub theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/epub/static/epub.css_t b/sphinx/themes/epub/static/epub.css_t index f8ef61e7c..0e8808f4a 100644 --- a/sphinx/themes/epub/static/epub.css_t +++ b/sphinx/themes/epub/static/epub.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- epub theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/haiku/layout.html b/sphinx/themes/haiku/layout.html index a6e42d2d2..c93c52dbd 100644 --- a/sphinx/themes/haiku/layout.html +++ b/sphinx/themes/haiku/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the haiku theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/haiku/static/haiku.css_t b/sphinx/themes/haiku/static/haiku.css_t index cb4a2fb62..16d49fea4 100644 --- a/sphinx/themes/haiku/static/haiku.css_t +++ b/sphinx/themes/haiku/static/haiku.css_t @@ -16,7 +16,7 @@ * Braden Ewing * Humdinger * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index bb0c83bac..5751bf940 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- nature theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/nonav/layout.html b/sphinx/themes/nonav/layout.html index 4d79446c4..5e79b2a7a 100644 --- a/sphinx/themes/nonav/layout.html +++ b/sphinx/themes/nonav/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the any help system theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/nonav/static/nonav.css b/sphinx/themes/nonav/static/nonav.css index 554b4b912..b41bd2044 100644 --- a/sphinx/themes/nonav/static/nonav.css +++ b/sphinx/themes/nonav/static/nonav.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- nonav theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/pyramid/static/epub.css b/sphinx/themes/pyramid/static/epub.css index a0cffc066..0df0eaeeb 100644 --- a/sphinx/themes/pyramid/static/epub.css +++ b/sphinx/themes/pyramid/static/epub.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- default theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t index ca36ef6ac..93799111e 100644 --- a/sphinx/themes/pyramid/static/pyramid.css_t +++ b/sphinx/themes/pyramid/static/pyramid.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- pylons theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/scrolls/layout.html b/sphinx/themes/scrolls/layout.html index 893ae17d3..9ebe3b35d 100644 --- a/sphinx/themes/scrolls/layout.html +++ b/sphinx/themes/scrolls/layout.html @@ -5,7 +5,7 @@ Sphinx layout template for the scrolls theme, originally written by Armin Ronacher. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t index 996a6d22a..3edd869af 100644 --- a/sphinx/themes/scrolls/static/scrolls.css_t +++ b/sphinx/themes/scrolls/static/scrolls.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- scrolls theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/sphinxdoc/layout.html b/sphinx/themes/sphinxdoc/layout.html index b37567bf8..91349c970 100644 --- a/sphinx/themes/sphinxdoc/layout.html +++ b/sphinx/themes/sphinxdoc/layout.html @@ -4,7 +4,7 @@ Sphinx layout template for the sphinxdoc theme. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t index 3b88e888e..2f4275a6c 100644 --- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t @@ -5,7 +5,7 @@ * Sphinx stylesheet -- sphinxdoc theme. Originally created by * Armin Ronacher for Werkzeug. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t index fb0ab54c9..e5fda3bab 100644 --- a/sphinx/themes/traditional/static/traditional.css_t +++ b/sphinx/themes/traditional/static/traditional.css_t @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- traditional docs.python.org theme. * - * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/sphinx/theming.py b/sphinx/theming.py index f787e8120..64cd67126 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -5,7 +5,7 @@ Theming support for HTML builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index c5fe7864e..acfff6a4d 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -5,7 +5,7 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py index 8c930c8bc..0121dd12f 100644 --- a/sphinx/transforms/compact_bullet_list.py +++ b/sphinx/transforms/compact_bullet_list.py @@ -5,7 +5,7 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 4c1fbc2a7..12f143302 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -5,7 +5,7 @@ Docutils transforms used by Sphinx when reading documents. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 4c4e094d1..42e7307be 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -5,7 +5,7 @@ Docutils transforms used by Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index df207f8ad..bffba8516 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -5,7 +5,7 @@ Docutils transforms used by Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 55fb9fcc1..4201c9462 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -5,7 +5,7 @@ Utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 988d41744..402e4bf9f 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -5,7 +5,7 @@ Stuff for docutils compatibility. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/console.py b/sphinx/util/console.py index 63a619f55..8069dd9c9 100644 --- a/sphinx/util/console.py +++ b/sphinx/util/console.py @@ -5,7 +5,7 @@ Format colored console output. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 4bce071c0..2f952d7cc 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -6,7 +6,7 @@ "Doc fields" are reST field lists in object descriptions that will be domain-specifically transformed to a more appealing presentation. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/docstrings.py b/sphinx/util/docstrings.py index c2ef91a66..bc4b96a56 100644 --- a/sphinx/util/docstrings.py +++ b/sphinx/util/docstrings.py @@ -5,7 +5,7 @@ Utilities for docstring processing. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 92e6c8c22..bbf32da1d 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -5,7 +5,7 @@ Utility functions for docutils. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py index fe98117d2..3fd570273 100644 --- a/sphinx/util/fileutil.py +++ b/sphinx/util/fileutil.py @@ -5,7 +5,7 @@ File utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 09b53b4a0..75a8506fa 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -5,7 +5,7 @@ Builder superclass for all builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import gettext diff --git a/sphinx/util/images.py b/sphinx/util/images.py index 1c2b4033a..46187775d 100644 --- a/sphinx/util/images.py +++ b/sphinx/util/images.py @@ -5,7 +5,7 @@ Image utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index f29cd9a78..704225359 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -5,7 +5,7 @@ Helpers for inspecting Python modules. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py index 40c0dc648..837188b5a 100644 --- a/sphinx/util/inventory.py +++ b/sphinx/util/inventory.py @@ -5,7 +5,7 @@ Inventory utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re diff --git a/sphinx/util/jsdump.py b/sphinx/util/jsdump.py index 73aa2ce03..6776691cf 100644 --- a/sphinx/util/jsdump.py +++ b/sphinx/util/jsdump.py @@ -6,7 +6,7 @@ This module implements a simple JavaScript serializer. Uses the basestring encode function from simplejson by Bob Ippolito. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py index 09c04dc6a..fbaa72978 100644 --- a/sphinx/util/jsonimpl.py +++ b/sphinx/util/jsonimpl.py @@ -5,7 +5,7 @@ JSON serializer implementation wrapper. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 00c12ec4f..ec81f02d7 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -5,7 +5,7 @@ Logging utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index 401f5f002..bddf84f5c 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -5,7 +5,7 @@ Pattern-matching utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 5d9ac78c6..97e5b7f30 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -5,7 +5,7 @@ Docutils node-related utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import absolute_import diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index a8bff11c4..b38e58e5d 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -5,7 +5,7 @@ Operating system-related utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py index 9bc3c36e1..6340e4dfc 100644 --- a/sphinx/util/parallel.py +++ b/sphinx/util/parallel.py @@ -5,7 +5,7 @@ Parallel building utilities. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/png.py b/sphinx/util/png.py index cc4447e4e..d22839fbf 100644 --- a/sphinx/util/png.py +++ b/sphinx/util/png.py @@ -5,7 +5,7 @@ PNG image manipulation helpers. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 7f7ee4e9b..e1a2bad9a 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -5,7 +5,7 @@ Stuff for Python version compatibility. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index 3dc1a30b2..9dee6e694 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -5,7 +5,7 @@ Simple requests package loader - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index 8186130cf..efc1ca76d 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -5,7 +5,7 @@ reST helper functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/stemmer/__init__.py b/sphinx/util/stemmer/__init__.py index 6f17d6cdf..8cefee6d2 100644 --- a/sphinx/util/stemmer/__init__.py +++ b/sphinx/util/stemmer/__init__.py @@ -5,7 +5,7 @@ Word stemming utilities for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py index 24f64bece..2c4855e91 100644 --- a/sphinx/util/tags.py +++ b/sphinx/util/tags.py @@ -3,7 +3,7 @@ sphinx.util.tags ~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/template.py b/sphinx/util/template.py index 87e81d823..a78871349 100644 --- a/sphinx/util/template.py +++ b/sphinx/util/template.py @@ -5,7 +5,7 @@ Templates utility functions for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/texescape.py b/sphinx/util/texescape.py index 07f5390c4..8d37e0f60 100644 --- a/sphinx/util/texescape.py +++ b/sphinx/util/texescape.py @@ -5,7 +5,7 @@ TeX escaping helper. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index d30cc230a..793504b77 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -5,7 +5,7 @@ The composit types for Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/util/websupport.py b/sphinx/util/websupport.py index 4d91cb77c..59133b9e1 100644 --- a/sphinx/util/websupport.py +++ b/sphinx/util/websupport.py @@ -3,7 +3,7 @@ sphinx.util.websupport ~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 97a013135..d911085c3 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -6,7 +6,7 @@ Implements the low-level algorithms Sphinx uses for the versioning of doctrees. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from uuid import uuid4 diff --git a/sphinx/websupport/__init__.py b/sphinx/websupport/__init__.py index 528343f8c..51d906fa6 100644 --- a/sphinx/websupport/__init__.py +++ b/sphinx/websupport/__init__.py @@ -5,7 +5,7 @@ Base Module for web support functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/errors.py b/sphinx/websupport/errors.py index 587d7e7e7..7456659ec 100644 --- a/sphinx/websupport/errors.py +++ b/sphinx/websupport/errors.py @@ -5,7 +5,7 @@ Contains Error classes for the web support package. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/search/__init__.py b/sphinx/websupport/search/__init__.py index 0f90e009b..e1e871ba0 100644 --- a/sphinx/websupport/search/__init__.py +++ b/sphinx/websupport/search/__init__.py @@ -5,7 +5,7 @@ Server side search support for the web support package. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/search/nullsearch.py b/sphinx/websupport/search/nullsearch.py index afae1ca57..422b398c9 100644 --- a/sphinx/websupport/search/nullsearch.py +++ b/sphinx/websupport/search/nullsearch.py @@ -5,7 +5,7 @@ The default search adapter, does nothing. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/search/whooshsearch.py b/sphinx/websupport/search/whooshsearch.py index f007c3cdc..94cce8ed7 100644 --- a/sphinx/websupport/search/whooshsearch.py +++ b/sphinx/websupport/search/whooshsearch.py @@ -5,7 +5,7 @@ Whoosh search adapter. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/search/xapiansearch.py b/sphinx/websupport/search/xapiansearch.py index 23be038e5..4df4769e2 100644 --- a/sphinx/websupport/search/xapiansearch.py +++ b/sphinx/websupport/search/xapiansearch.py @@ -5,7 +5,7 @@ Xapian search adapter. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/storage/__init__.py b/sphinx/websupport/storage/__init__.py index adfdec4a5..727e86da4 100644 --- a/sphinx/websupport/storage/__init__.py +++ b/sphinx/websupport/storage/__init__.py @@ -5,7 +5,7 @@ Storage for the websupport package. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/storage/differ.py b/sphinx/websupport/storage/differ.py index 449d038da..1358d8645 100644 --- a/sphinx/websupport/storage/differ.py +++ b/sphinx/websupport/storage/differ.py @@ -5,7 +5,7 @@ A differ for creating an HTML representations of proposal diffs - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/storage/sqlalchemy_db.py b/sphinx/websupport/storage/sqlalchemy_db.py index a2dfc35b9..e1c86dd9d 100644 --- a/sphinx/websupport/storage/sqlalchemy_db.py +++ b/sphinx/websupport/storage/sqlalchemy_db.py @@ -6,7 +6,7 @@ SQLAlchemy table and mapper definitions used by the :class:`sphinx.websupport.storage.sqlalchemystorage.SQLAlchemyStorage`. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/websupport/storage/sqlalchemystorage.py b/sphinx/websupport/storage/sqlalchemystorage.py index dc5e9400b..b018ea0a3 100644 --- a/sphinx/websupport/storage/sqlalchemystorage.py +++ b/sphinx/websupport/storage/sqlalchemystorage.py @@ -5,7 +5,7 @@ An SQLAlchemy storage backend. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/__init__.py b/sphinx/writers/__init__.py index 6b157a83a..79eacbbfb 100644 --- a/sphinx/writers/__init__.py +++ b/sphinx/writers/__init__.py @@ -5,6 +5,6 @@ Custom docutils writers. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 8d02793e3..30631f560 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -5,7 +5,7 @@ docutils writers handling Sphinx' custom nodes. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 51c4e8ecb..533235f62 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -5,7 +5,7 @@ Experimental docutils writers for HTML5 handling Sphinx' custom nodes. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 39c7bc81e..98fec811c 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -8,7 +8,7 @@ Much of this code is adapted from Dave Kuhlman's "docpy" writer from his docutils sandbox. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 71c2aac0b..1d645ce5f 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -5,7 +5,7 @@ Manual page writer, extended for Sphinx custom nodes. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index d7e08510e..b73557f86 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -5,7 +5,7 @@ Custom docutils writer for Texinfo. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index d2b2f9045..b6e3f4cec 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -5,7 +5,7 @@ Custom docutils writer for plain text. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os diff --git a/sphinx/writers/websupport.py b/sphinx/writers/websupport.py index 1e7f4babd..a962faf4d 100644 --- a/sphinx/writers/websupport.py +++ b/sphinx/writers/websupport.py @@ -5,7 +5,7 @@ sphinx.websupport writer that adds comment-related annotations. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/writers/xml.py b/sphinx/writers/xml.py index 9cb64216a..f94fe847c 100644 --- a/sphinx/writers/xml.py +++ b/sphinx/writers/xml.py @@ -5,7 +5,7 @@ Docutils-native XML and pseudo-XML writers. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/conftest.py b/tests/conftest.py index 28dbd6ed4..4de67c7d6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ pytest config for sphinx/tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/py35/test_autodoc_py35.py b/tests/py35/test_autodoc_py35.py index 481374948..ecb0a96af 100644 --- a/tests/py35/test_autodoc_py35.py +++ b/tests/py35/test_autodoc_py35.py @@ -6,7 +6,7 @@ Test the autodoc extension. This tests mainly the Documenters; the auto directives are tested in a test source file translated by test_build. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/run.py b/tests/run.py index a8439ba02..f84926fb6 100755 --- a/tests/run.py +++ b/tests/run.py @@ -6,7 +6,7 @@ This script runs the Sphinx unit test suite. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_api_translator.py b/tests/test_api_translator.py index 35b24732b..4e4230ba3 100644 --- a/tests/test_api_translator.py +++ b/tests/test_api_translator.py @@ -5,7 +5,7 @@ Test the Sphinx API for translator. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_apidoc.py b/tests/test_apidoc.py index 20582e9fc..fd0049c8f 100644 --- a/tests/test_apidoc.py +++ b/tests/test_apidoc.py @@ -5,7 +5,7 @@ Test the sphinx.apidoc module. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_application.py b/tests/test_application.py index 785a78878..8535cc9dc 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -5,7 +5,7 @@ Test the Sphinx class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from docutils import nodes diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 6eb087567..462f65698 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -6,7 +6,7 @@ Test the autodoc extension. This tests mainly the Documenters; the auto directives are tested in a test source file translated by test_build. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build.py b/tests/test_build.py index c61fbb5c2..6533a1763 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -5,7 +5,7 @@ Test all builders. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_applehelp.py b/tests/test_build_applehelp.py index 4418cb265..31d4ca4df 100644 --- a/tests/test_build_applehelp.py +++ b/tests/test_build_applehelp.py @@ -7,7 +7,7 @@ test the HTML itself; that's already handled by :file:`test_build_html.py`. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_gettext.py b/tests/test_build_gettext.py index f256140fe..c14013f9a 100644 --- a/tests/test_build_gettext.py +++ b/tests/test_build_gettext.py @@ -5,7 +5,7 @@ Test the build process with gettext builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 0ccd4da01..6fc024d35 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -5,7 +5,7 @@ Test the HTML builder and check output against XPath. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py index 4ad282973..217050ec7 100644 --- a/tests/test_build_html5.py +++ b/tests/test_build_html5.py @@ -10,7 +10,7 @@ https://github.com/sphinx-doc/sphinx/pull/2805/files - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index faa2f46a7..0c95a0cdb 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -5,7 +5,7 @@ Test the build process with LaTeX builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index cc3d6e24f..839a15628 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -5,7 +5,7 @@ Test the build process with manpage builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_build_manpage.py b/tests/test_build_manpage.py index 953332c73..3448d6eeb 100644 --- a/tests/test_build_manpage.py +++ b/tests/test_build_manpage.py @@ -5,7 +5,7 @@ Test the build process with manpage builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py index 14c6028bc..50f42542d 100644 --- a/tests/test_build_texinfo.py +++ b/tests/test_build_texinfo.py @@ -5,7 +5,7 @@ Test the build process with Texinfo builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_build_text.py b/tests/test_build_text.py index 1732b3187..382e62b34 100644 --- a/tests/test_build_text.py +++ b/tests/test_build_text.py @@ -5,7 +5,7 @@ Test the build process with Text builder with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index b3e17a0a1..4bfbb18a3 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -5,7 +5,7 @@ Test the base build process. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import shutil diff --git a/tests/test_config.py b/tests/test_config.py index f9300c30e..965f46c3e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,7 +6,7 @@ Test the sphinx.config.Config class and its handling in the Application class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from six import PY3, iteritems diff --git a/tests/test_correct_year.py b/tests/test_correct_year.py index a8058f08c..e7501bb6a 100644 --- a/tests/test_correct_year.py +++ b/tests/test_correct_year.py @@ -5,7 +5,7 @@ Test copyright year adjustment - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py index e3069061b..f62f44f13 100644 --- a/tests/test_directive_code.py +++ b/tests/test_directive_code.py @@ -5,7 +5,7 @@ Test the code-block directive. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_directive_only.py b/tests/test_directive_only.py index d70585774..79544975b 100644 --- a/tests/test_directive_only.py +++ b/tests/test_directive_only.py @@ -5,7 +5,7 @@ Test the only directive with the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_docutilsconf.py b/tests/test_docutilsconf.py index 572660d69..d2b56d30d 100644 --- a/tests/test_docutilsconf.py +++ b/tests/test_docutilsconf.py @@ -5,7 +5,7 @@ Test docutils.conf support for several writers. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 2932f356f..7437b4c05 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -5,7 +5,7 @@ Tests the C++ Domain - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_js.py b/tests/test_domain_js.py index 22faf4458..a609dcefe 100644 --- a/tests/test_domain_js.py +++ b/tests/test_domain_js.py @@ -5,7 +5,7 @@ Tests the JavaScript Domain - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 5596950df..b917540d8 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -5,7 +5,7 @@ Tests the Python Domain - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_rst.py b/tests/test_domain_rst.py index 1e55e92a1..8cfe7e284 100644 --- a/tests/test_domain_rst.py +++ b/tests/test_domain_rst.py @@ -5,7 +5,7 @@ Tests the reStructuredText domain. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py index edd5a0ebf..06573fa38 100644 --- a/tests/test_domain_std.py +++ b/tests/test_domain_std.py @@ -5,7 +5,7 @@ Tests the std domain - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_environment.py b/tests/test_environment.py index 611d34577..adc1e306b 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -5,7 +5,7 @@ Test the BuildEnvironment class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index b9de151cc..03e4d9662 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -5,7 +5,7 @@ Test the sphinx.environment.managers.indexentries. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py index f7a24d1fc..26334858b 100644 --- a/tests/test_environment_toctree.py +++ b/tests/test_environment_toctree.py @@ -5,7 +5,7 @@ Test the sphinx.environment.managers.toctree. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 1c1ebf7a0..e7057df0f 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -5,7 +5,7 @@ Test the autodoc extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_autosectionlabel.py b/tests/test_ext_autosectionlabel.py index 4726a2378..1266edbc3 100644 --- a/tests/test_ext_autosectionlabel.py +++ b/tests/test_ext_autosectionlabel.py @@ -5,7 +5,7 @@ Test sphinx.ext.autosectionlabel extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 81fd35762..a4cd9e03b 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -5,7 +5,7 @@ Test the autosummary extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_coverage.py b/tests/test_ext_coverage.py index ff3fb4c02..d1b4b55c4 100644 --- a/tests/test_ext_coverage.py +++ b/tests/test_ext_coverage.py @@ -5,7 +5,7 @@ Test the coverage builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_doctest.py b/tests/test_ext_doctest.py index fa3ad6bc4..020357879 100644 --- a/tests/test_ext_doctest.py +++ b/tests/test_ext_doctest.py @@ -5,7 +5,7 @@ Test the doctest extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_ext_githubpages.py b/tests/test_ext_githubpages.py index 56ce7b775..18ee51480 100644 --- a/tests/test_ext_githubpages.py +++ b/tests/test_ext_githubpages.py @@ -5,7 +5,7 @@ Test sphinx.ext.githubpages extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py index 1d2a3ab2f..e59b697be 100644 --- a/tests/test_ext_graphviz.py +++ b/tests/test_ext_graphviz.py @@ -5,7 +5,7 @@ Test sphinx.ext.graphviz extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_ifconfig.py b/tests/test_ext_ifconfig.py index 5c59caaaf..b4c941512 100644 --- a/tests/test_ext_ifconfig.py +++ b/tests/test_ext_ifconfig.py @@ -5,7 +5,7 @@ Test sphinx.ext.ifconfig extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_imgconverter.py b/tests/test_ext_imgconverter.py index cc84001df..8f610377c 100644 --- a/tests/test_ext_imgconverter.py +++ b/tests/test_ext_imgconverter.py @@ -5,7 +5,7 @@ Test sphinx.ext.imgconverter extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py index 6a2652514..1b168e622 100644 --- a/tests/test_ext_inheritance_diagram.py +++ b/tests/test_ext_inheritance_diagram.py @@ -5,7 +5,7 @@ Test sphinx.ext.inheritance_diagram extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 96210dc6c..371f296ea 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -5,7 +5,7 @@ Test the intersphinx extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py index 552be96f3..2b8a68f9c 100644 --- a/tests/test_ext_math.py +++ b/tests/test_ext_math.py @@ -5,7 +5,7 @@ Test math extensions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_napoleon.py b/tests/test_ext_napoleon.py index b2ca7fe7a..d8d6adc65 100644 --- a/tests/test_ext_napoleon.py +++ b/tests/test_ext_napoleon.py @@ -6,7 +6,7 @@ Tests for :mod:`sphinx.ext.napoleon.__init__` module. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py index e71d517fe..1865b004c 100644 --- a/tests/test_ext_napoleon_docstring.py +++ b/tests/test_ext_napoleon_docstring.py @@ -6,7 +6,7 @@ Tests for :mod:`sphinx.ext.napoleon.docstring` module. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_napoleon_iterators.py b/tests/test_ext_napoleon_iterators.py index 5258d9b79..bf144275d 100644 --- a/tests/test_ext_napoleon_iterators.py +++ b/tests/test_ext_napoleon_iterators.py @@ -6,7 +6,7 @@ Tests for :mod:`sphinx.ext.napoleon.iterators` module. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py index cee59fe9d..99eb7b801 100644 --- a/tests/test_ext_todo.py +++ b/tests/test_ext_todo.py @@ -5,7 +5,7 @@ Test sphinx.ext.todo extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_ext_viewcode.py b/tests/test_ext_viewcode.py index 4dceaa488..3f6612c76 100644 --- a/tests/test_ext_viewcode.py +++ b/tests/test_ext_viewcode.py @@ -5,7 +5,7 @@ Test sphinx.ext.viewcode extension. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_highlighting.py b/tests/test_highlighting.py index 938181fe1..5660869bd 100644 --- a/tests/test_highlighting.py +++ b/tests/test_highlighting.py @@ -5,7 +5,7 @@ Test the Pygments highlighting bridge. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_intl.py b/tests/test_intl.py index 6b72438bd..920def588 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -6,7 +6,7 @@ Test message patching for internationalization purposes. Runs the text builder in the test root. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_markup.py b/tests/test_markup.py index 9c41845fc..34ab1405d 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -5,7 +5,7 @@ Test various Sphinx-specific markup extensions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 58f573b0a..a00d76f87 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -5,7 +5,7 @@ Test our handling of metadata in files with bibliographic metadata. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index b95356aaa..a4f12a551 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -5,7 +5,7 @@ Test the sphinx.quickstart module. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_search.py b/tests/test_search.py index f1825dfa4..fc5fb7e04 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -5,7 +5,7 @@ Test the search index builder. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_setup_command.py b/tests/test_setup_command.py index 562b0a715..e1f976b8a 100644 --- a/tests/test_setup_command.py +++ b/tests/test_setup_command.py @@ -5,7 +5,7 @@ Test setup_command for distutils. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_templating.py b/tests/test_templating.py index b0070f06a..341b33f51 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -5,7 +5,7 @@ Test templating. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_theming.py b/tests/test_theming.py index 176c9eebc..48a4e1865 100644 --- a/tests/test_theming.py +++ b/tests/test_theming.py @@ -5,7 +5,7 @@ Test the Theme class. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_toctree.py b/tests/test_toctree.py index 18910197f..42ec0ce89 100644 --- a/tests/test_toctree.py +++ b/tests/test_toctree.py @@ -5,7 +5,7 @@ Test the HTML builder and check output against XPath. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import pytest diff --git a/tests/test_util.py b/tests/test_util.py index 84ce44007..d55de7f5c 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -5,7 +5,7 @@ Tests util functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_util_fileutil.py b/tests/test_util_fileutil.py index 849ccce22..69f51f52c 100644 --- a/tests/test_util_fileutil.py +++ b/tests/test_util_fileutil.py @@ -5,7 +5,7 @@ Tests sphinx.util.fileutil functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from sphinx.util.fileutil import copy_asset, copy_asset_file diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py index 53e0e4cf1..bec4e91e9 100644 --- a/tests/test_util_i18n.py +++ b/tests/test_util_i18n.py @@ -5,7 +5,7 @@ Test i18n util. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_util_images.py b/tests/test_util_images.py index 6f67dcc82..a9c023b09 100644 --- a/tests/test_util_images.py +++ b/tests/test_util_images.py @@ -5,7 +5,7 @@ Test images util. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 87b4d5186..a463f4f6a 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -5,7 +5,7 @@ Tests util.inspect functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from unittest import TestCase diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py index 7ae086872..e909c2dcf 100644 --- a/tests/test_util_logging.py +++ b/tests/test_util_logging.py @@ -5,7 +5,7 @@ Test logging util. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/tests/test_util_matching.py b/tests/test_util_matching.py index 3b84f4735..fc38470d3 100644 --- a/tests/test_util_matching.py +++ b/tests/test_util_matching.py @@ -5,7 +5,7 @@ Tests sphinx.util.matching functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from sphinx.util.matching import compile_matchers, Matcher diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index c392c2bc7..c58ecc205 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -5,7 +5,7 @@ Tests uti.nodes functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from textwrap import dedent diff --git a/tests/test_util_rst.py b/tests/test_util_rst.py index 5fce6e3eb..406ea710e 100644 --- a/tests/test_util_rst.py +++ b/tests/test_util_rst.py @@ -5,7 +5,7 @@ Tests sphinx.util.rst functions. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from sphinx.util.rst import escape diff --git a/tests/test_versioning.py b/tests/test_versioning.py index b73c00fa6..7956b6710 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -5,7 +5,7 @@ Test the versioning implementation. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_websupport.py b/tests/test_websupport.py index 51cb2b287..10942798c 100644 --- a/tests/test_websupport.py +++ b/tests/test_websupport.py @@ -5,7 +5,7 @@ Test the Web Support Package - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_writer_latex.py b/tests/test_writer_latex.py index b026f8d17..5c73469ec 100644 --- a/tests/test_writer_latex.py +++ b/tests/test_writer_latex.py @@ -5,7 +5,7 @@ Test the LaTeX writer - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/utils/check_sources.py b/utils/check_sources.py index 3895ee1d6..30f1fb93c 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -7,7 +7,7 @@ Make sure each Python file has a correct file header including copyright and license information. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/utils/jssplitter_generator.py b/utils/jssplitter_generator.py index 75f0353af..073b7c7ae 100644 --- a/utils/jssplitter_generator.py +++ b/utils/jssplitter_generator.py @@ -122,7 +122,7 @@ python_src = '''# -*- coding: utf-8 -*- DO NOT EDIT. This is generated by utils/jssplitter_generator.py - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ From 5562e76585611928ad8628cb9a40a0eb2b3d87fe Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 Jan 2018 01:10:10 +0900 Subject: [PATCH 0499/1814] A happy new year! --- sphinx/cmd/__init__.py | 2 +- sphinx/cmd/build.py | 2 +- sphinx/cmd/quickstart.py | 2 +- sphinx/ext/apidoc.py | 2 +- sphinx/ext/autodoc/importer.py | 2 +- sphinx/ext/autodoc/inspector.py | 2 +- sphinx/pycode/parser.py | 2 +- tests/test_build_qthelp.py | 2 +- tests/test_io.py | 2 +- utils/checks.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sphinx/cmd/__init__.py b/sphinx/cmd/__init__.py index 9ffb9e612..a559306d6 100644 --- a/sphinx/cmd/__init__.py +++ b/sphinx/cmd/__init__.py @@ -5,6 +5,6 @@ Modules for command line executables. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/cmd/build.py b/sphinx/cmd/build.py index 6c9d6e3e9..c0c31ae67 100644 --- a/sphinx/cmd/build.py +++ b/sphinx/cmd/build.py @@ -5,7 +5,7 @@ Build documentation from a provided source. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 3051520cb..fd9b15649 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -5,7 +5,7 @@ Quickly setup documentation source to work with Sphinx. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index d99f852f1..f44bc0b85 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -11,7 +11,7 @@ Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/ - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 5c28f490d..75e045c21 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -5,7 +5,7 @@ Importer utilities for autodoc - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/ext/autodoc/inspector.py b/sphinx/ext/autodoc/inspector.py index 50c5a9082..6e07c9547 100644 --- a/sphinx/ext/autodoc/inspector.py +++ b/sphinx/ext/autodoc/inspector.py @@ -5,7 +5,7 @@ Inspect utilities for autodoc - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index 7460dcfce..9aed7f7f4 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -5,7 +5,7 @@ Utilities parsing and analyzing Python code. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ import re diff --git a/tests/test_build_qthelp.py b/tests/test_build_qthelp.py index 3e4815fbe..de676e6e0 100644 --- a/tests/test_build_qthelp.py +++ b/tests/test_build_qthelp.py @@ -7,7 +7,7 @@ test the HTML itself; that's already handled by :file:`test_build_html.py`. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/tests/test_io.py b/tests/test_io.py index ecd4a1009..1c8fee86b 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -5,7 +5,7 @@ Tests io modules. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/utils/checks.py b/utils/checks.py index 03104d78a..90d89439e 100644 --- a/utils/checks.py +++ b/utils/checks.py @@ -5,7 +5,7 @@ Custom, Sphinx-only flake8 plugins. - :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ From 1d64ade74911c9a9d3178d4f215fe4d75c2eddda Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 18 Jun 2017 00:39:23 +0900 Subject: [PATCH 0500/1814] Refactor: Add import_object() --- sphinx/ext/autodoc/__init__.py | 58 +++++----------------------------- sphinx/ext/autodoc/importer.py | 52 +++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 5c1a71ea9..f9f7c5edc 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -14,9 +14,8 @@ import re import sys import inspect -import traceback -from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types +from six import iterkeys, iteritems, itervalues, text_type, class_types, string_types from docutils import nodes from docutils.utils import assemble_option_dict @@ -24,7 +23,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx -from sphinx.ext.autodoc.importer import mock, import_module +from sphinx.ext.autodoc.importer import mock, import_object from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA from sphinx.util import rpartition, force_decode @@ -384,56 +383,15 @@ class Documenter(object): Returns True if successful, False if an error occurred. """ - if self.objpath: - logger.debug('[autodoc] from %s import %s', - self.modname, '.'.join(self.objpath)) - # always enable mock import hook - # it will do nothing if autodoc_mock_imports is empty with mock(self.env.config.autodoc_mock_imports): try: - logger.debug('[autodoc] import %s', self.modname) - obj = import_module(self.modname, self.env.config.autodoc_warningiserror) - parent = None - self.module = obj - logger.debug('[autodoc] => %r', obj) - for part in self.objpath: - parent = obj - logger.debug('[autodoc] getattr(_, %r)', part) - obj = self.get_attr(obj, part) - logger.debug('[autodoc] => %r', obj) - self.object_name = part - self.parent = parent - self.object = obj + ret = import_object(self.modname, self.objpath, self.objtype, + attrgetter=self.get_attr, + warningiserror=self.env.config.autodoc_warningiserror) + self.module, self.parent, self.object_name, self.object = ret return True - except (AttributeError, ImportError) as exc: - if self.objpath: - errmsg = 'autodoc: failed to import %s %r from module %r' % \ - (self.objtype, '.'.join(self.objpath), self.modname) - else: - errmsg = 'autodoc: failed to import %s %r' % \ - (self.objtype, self.fullname) - - if isinstance(exc, ImportError): - # import_module() raises ImportError having real exception obj and - # traceback - real_exc, traceback_msg = exc.args - if isinstance(real_exc, SystemExit): - errmsg += ('; the module executes module level statement ' + - 'and it might call sys.exit().') - elif isinstance(real_exc, ImportError): - errmsg += ('; the following exception was raised:\n%s' % - real_exc.args[0]) - else: - errmsg += ('; the following exception was raised:\n%s' % - traceback_msg) - else: - errmsg += ('; the following exception was raised:\n%s' % - traceback.format_exc()) - - if PY2: - errmsg = errmsg.decode('utf-8') # type: ignore - logger.debug(errmsg) - self.directive.warn(errmsg) + except ImportError as exc: + self.directive.warn(exc.args[0]) self.env.note_reread() return False diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 75e045c21..95ca58d0b 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -15,11 +15,14 @@ import traceback import contextlib from types import FunctionType, MethodType, ModuleType +from six import PY2 + from sphinx.util import logging +from sphinx.util.inspect import safe_getattr if False: # For type annotation - from typing import Any, Generator, List, Set # NOQA + from typing import Any, Callable, Generator, List, Set # NOQA logger = logging.getLogger(__name__) @@ -144,3 +147,50 @@ def import_module(modname, warningiserror=False): # Importing modules may cause any side effects, including # SystemExit, so we need to catch all errors. raise ImportError(exc, traceback.format_exc()) + + +def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warningiserror=False): + # type: (str, List[unicode], str, Callable[[Any, unicode], Any]) -> Any + if objpath: + logger.debug('[autodoc] from %s import %s', modname, '.'.join(objpath)) + else: + logger.debug('[autodoc] import %s', modname) + + try: + module = import_module(modname, warningiserror=warningiserror) + logger.debug('[autodoc] => %r', module) + obj = module + parent = None + object_name = None + for attrname in objpath: + parent = obj + logger.debug('[autodoc] getattr(_, %r)', attrname) + obj = attrgetter(obj, attrname) + logger.debug('[autodoc] => %r', obj) + object_name = attrname + return [module, parent, object_name, obj] + except (AttributeError, ImportError) as exc: + if objpath: + errmsg = ('autodoc: failed to import %s %r from module %r' % + (objtype, '.'.join(objpath), modname)) + else: + errmsg = 'autodoc: failed to import %s %r' % (objtype, modname) + + if isinstance(exc, ImportError): + # import_module() raises ImportError having real exception obj and + # traceback + real_exc, traceback_msg = exc.args + if isinstance(real_exc, SystemExit): + errmsg += ('; the module executes module level statement ' + 'and it might call sys.exit().') + elif isinstance(real_exc, ImportError): + errmsg += '; the following exception was raised:\n%s' % real_exc.args[0] + else: + errmsg += '; the following exception was raised:\n%s' % traceback_msg + else: + errmsg += '; the following exception was raised:\n%s' % traceback.format_exc() + + if PY2: + errmsg = errmsg.decode('utf-8') # type: ignore + logger.debug(errmsg) + raise ImportError(errmsg) From 5d6413b7120cfc6d3d0cc9367cfe8b6f7ee87523 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 18 Jun 2017 10:25:34 +0900 Subject: [PATCH 0501/1814] Deprecate sphinx.ext.autodoc.add_documenter() and AutoDirective._register --- CHANGES | 2 ++ sphinx/application.py | 6 ++-- sphinx/ext/autodoc/__init__.py | 55 ++++++++++++++++++++++++++---- sphinx/ext/autosummary/__init__.py | 18 +++++----- sphinx/ext/autosummary/generate.py | 38 ++++++++++++--------- sphinx/registry.py | 6 ++++ tests/py35/test_autodoc_py35.py | 8 ++--- tests/test_autodoc.py | 22 ++++++------ tests/test_ext_autosummary.py | 10 ++++-- tests/test_templating.py | 11 ++++-- 10 files changed, 121 insertions(+), 55 deletions(-) diff --git a/CHANGES b/CHANGES index bd6a92728..c0934c396 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,8 @@ Deprecated values will be accepted at 2.0. * ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use ``sphinx.util.inspect.Signature`` instead. +* ``sphinx.ext.autodoc.add_documenter()`` and ``AutoDirective._register`` is now + deprecated. Please use ``app.add_autodocumenter()`` Features added -------------- diff --git a/sphinx/application.py b/sphinx/application.py index 9195f11af..3bfea910f 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -642,9 +642,9 @@ class Sphinx(object): def add_autodocumenter(self, cls): # type: (Any) -> None logger.debug('[app] adding autodocumenter: %r', cls) - from sphinx.ext import autodoc - autodoc.add_documenter(cls) - self.add_directive('auto' + cls.objtype, autodoc.AutoDirective) + from sphinx.ext.autodoc import AutoDirective + self.add_directive('auto' + cls.objtype, AutoDirective) + self.registry.add_documenter(cls.objtype, cls) def add_autodoc_attrgetter(self, type, getter): # type: (Any, Callable) -> None diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index f9f7c5edc..a6afe4f4c 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -14,6 +14,7 @@ import re import sys import inspect +import warnings from six import iterkeys, iteritems, itervalues, text_type, class_types, string_types @@ -23,6 +24,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList import sphinx +from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.ext.autodoc.importer import mock, import_object from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA @@ -323,6 +325,14 @@ class Documenter(object): # the module analyzer to get at attribute docs, or None self.analyzer = None # type: Any + @property + def documenters(self): + # type: () -> Dict[unicode, Type[Documenter]] + """Returns registered Documenter classes""" + classes = dict(AutoDirective._registry) # registered directly + classes.update(self.env.app.registry.documenters) # registered by API + return classes + def add_line(self, line, source, *lineno): # type: (unicode, unicode, int) -> None """Append one line of generated reST to the output.""" @@ -727,7 +737,7 @@ class Documenter(object): # document non-skipped members memberdocumenters = [] # type: List[Tuple[Documenter, bool]] for (mname, member, isattr) in self.filter_members(members, want_all): - classes = [cls for cls in itervalues(AutoDirective._registry) + classes = [cls for cls in itervalues(self.documenters) if cls.can_document_member(member, mname, isattr, self)] if not classes: # don't know how to document this member @@ -1463,11 +1473,28 @@ class InstanceAttributeDocumenter(AttributeDocumenter): AttributeDocumenter.add_content(self, more_content, no_docstring=True) +class DeprecatedDict(dict): + def __init__(self, message): + self.message = message + super(DeprecatedDict, self).__init__() + + def __setitem__(self, key, value): + warnings.warn(self.message, RemovedInSphinx20Warning) + super(DeprecatedDict, self).__setitem__(key, value) + + def setdefault(self, key, default=None): + warnings.warn(self.message, RemovedInSphinx20Warning) + super(DeprecatedDict, self).setdefault(key, default) + + def update(self, other=None): + warnings.warn(self.message, RemovedInSphinx20Warning) + super(DeprecatedDict, self).update(other) + + class AutoDirective(Directive): """ The AutoDirective class is used for all autodoc directives. It dispatches - most of the work to one of the Documenters, which it selects through its - *_registry* dictionary. + most of the work to one of the Documenters. The *_special_attrgetters* attribute is used to customize ``getattr()`` calls that the Documenters make; its entries are of the form ``type: @@ -1478,8 +1505,11 @@ class AutoDirective(Directive): dictionary should include all necessary functions for accessing attributes of the parents. """ - # a registry of objtype -> documenter class - _registry = {} # type: Dict[unicode, Type[Documenter]] + # a registry of objtype -> documenter class (Deprecated) + _registry = DeprecatedDict( + 'AutoDirective._registry has been deprecated. ' + 'Please use app.add_autodocumenter() instead.' + ) # type: Dict[unicode, Type[Documenter]] # a registry of type -> getattr function _special_attrgetters = {} # type: Dict[Type, Callable] @@ -1521,7 +1551,7 @@ class AutoDirective(Directive): # find out what documenter to call objtype = self.name[4:] - doc_class = self._registry[objtype] + doc_class = get_documenters(self.env.app)[objtype] # add default flags for flag in self._default_flags: if flag not in doc_class.option_spec: @@ -1575,6 +1605,10 @@ class AutoDirective(Directive): def add_documenter(cls): # type: (Type[Documenter]) -> None """Register a new Documenter.""" + warnings.warn('sphinx.ext.autodoc.add_documenter() has been deprecated. ' + 'Please use app.add_autodocumenter() instead.', + RemovedInSphinx20Warning) + if not issubclass(cls, Documenter): raise ExtensionError('autodoc documenter %r must be a subclass ' 'of Documenter' % cls) @@ -1585,6 +1619,15 @@ def add_documenter(cls): AutoDirective._registry[cls.objtype] = cls +def get_documenters(app): + # type: (Sphinx) -> Dict[unicode, Type[Documenter]] + """Returns registered Documenter classes""" + classes = dict(AutoDirective._registry) # registered directly + if app: + classes.update(app.registry.documenters) # registered by API + return classes + + def setup(app): # type: (Sphinx) -> Dict[unicode, Any] app.add_autodocumenter(ModuleDocumenter) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 3dded11ff..af7da3b1e 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -72,8 +72,8 @@ from sphinx import addnodes from sphinx.environment.adapters.toctree import TocTree from sphinx.util import import_object, rst, logging from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.ext.autodoc import Options from sphinx.ext.autodoc.importer import import_module +from sphinx.ext.autodoc import Options, get_documenters if False: # For type annotation @@ -158,8 +158,8 @@ class FakeDirective(object): genopt = Options() -def get_documenter(obj, parent): - # type: (Any, Any) -> Type[Documenter] +def get_documenter(app, obj, parent): + # type: (Sphinx, Any, Any) -> Type[Documenter] """Get an autodoc.Documenter class suitable for documenting the given object. @@ -167,8 +167,7 @@ def get_documenter(obj, parent): another Python object (e.g. a module or a class) to which *obj* belongs to. """ - from sphinx.ext.autodoc import AutoDirective, DataDocumenter, \ - ModuleDocumenter + from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter if inspect.ismodule(obj): # ModuleDocumenter.can_document_member always returns False @@ -176,7 +175,7 @@ def get_documenter(obj, parent): # Construct a fake documenter for *parent* if parent is not None: - parent_doc_cls = get_documenter(parent, None) + parent_doc_cls = get_documenter(app, parent, None) else: parent_doc_cls = ModuleDocumenter @@ -186,7 +185,7 @@ def get_documenter(obj, parent): parent_doc = parent_doc_cls(FakeDirective(), "") # Get the corrent documenter class for *obj* - classes = [cls for cls in AutoDirective._registry.values() + classes = [cls for cls in get_documenters(app).values() if cls.can_document_member(obj, '', False, parent_doc)] if classes: classes.sort(key=lambda cls: cls.priority) @@ -289,7 +288,7 @@ class Autosummary(Directive): full_name = modname + '::' + full_name[len(modname) + 1:] # NB. using full_name here is important, since Documenters # handle module prefixes slightly differently - documenter = get_documenter(obj, parent)(self, full_name) + documenter = get_documenter(self.env.app, obj, parent)(self, full_name) if not documenter.parse_name(): self.warn('failed to parse name %s' % real_name) items.append((display_name, '', '', real_name)) @@ -615,7 +614,8 @@ def process_generate_options(app): generate_autosummary_docs(genfiles, builder=app.builder, warn=logger.warning, info=logger.info, - suffix=suffix, base_path=app.srcdir) + suffix=suffix, base_path=app.srcdir, + app=app) def setup(app): diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 4db1a93e9..2873b6082 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -31,26 +31,13 @@ from jinja2.sandbox import SandboxedEnvironment from sphinx import __display_version__ from sphinx import package_dir +from sphinx.ext.autodoc import add_documenter from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.util.osutil import ensuredir from sphinx.util.inspect import safe_getattr from sphinx.util.rst import escape as rst_escape -# Add documenters to AutoDirective registry -from sphinx.ext.autodoc import add_documenter, \ - ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, \ - FunctionDocumenter, MethodDocumenter, AttributeDocumenter, \ - InstanceAttributeDocumenter -add_documenter(ModuleDocumenter) -add_documenter(ClassDocumenter) -add_documenter(ExceptionDocumenter) -add_documenter(DataDocumenter) -add_documenter(FunctionDocumenter) -add_documenter(MethodDocumenter) -add_documenter(AttributeDocumenter) -add_documenter(InstanceAttributeDocumenter) - if False: # For type annotation from typing import Any, Callable, Dict, Tuple, List # NOQA @@ -60,6 +47,22 @@ if False: from sphinx.environment import BuildEnvironment # NOQA +def setup_documenters(): + from sphinx.ext.autodoc import ( + ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, + FunctionDocumenter, MethodDocumenter, AttributeDocumenter, + InstanceAttributeDocumenter + ) + add_documenter(ModuleDocumenter) + add_documenter(ClassDocumenter) + add_documenter(ExceptionDocumenter) + add_documenter(DataDocumenter) + add_documenter(FunctionDocumenter) + add_documenter(MethodDocumenter) + add_documenter(AttributeDocumenter) + add_documenter(InstanceAttributeDocumenter) + + def _simple_info(msg): # type: (unicode) -> None print(msg) @@ -81,7 +84,7 @@ def _underline(title, line='='): def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', warn=_simple_warn, info=_simple_info, base_path=None, builder=None, template_dir=None, - imported_members=False): + imported_members=False, app=None): # type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool) -> None # NOQA showed_sources = list(sorted(sources)) @@ -148,7 +151,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', new_files.append(fn) with open(fn, 'w') as f: - doc = get_documenter(obj, parent) + doc = get_documenter(app, obj, parent) if template_name is not None: template = template_env.get_template(template_name) @@ -167,7 +170,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', value = safe_getattr(obj, name) except AttributeError: continue - documenter = get_documenter(value, obj) + documenter = get_documenter(app, value, obj) if documenter.objtype == typ: if typ == 'method': items.append(name) @@ -392,6 +395,7 @@ The format of the autosummary directive is documented in the def main(argv=sys.argv[1:]): # type: (List[str]) -> None + setup_documenters() args = get_parser().parse_args(argv) generate_autosummary_docs(args.source_file, args.output_dir, '.' + args.suffix, diff --git a/sphinx/registry.py b/sphinx/registry.py index 6ec966a6a..38fe9caf3 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -38,6 +38,7 @@ if False: from sphinx.builders import Builder # NOQA from sphinx.domains import Domain, Index # NOQA from sphinx.environment import BuildEnvironment # NOQA + from sphinx.ext.autodoc import Documenter # NOQA from sphinx.util.typing import RoleFunction # NOQA logger = logging.getLogger(__name__) @@ -52,6 +53,7 @@ EXTENSION_BLACKLIST = { class SphinxComponentRegistry(object): def __init__(self): self.builders = {} # type: Dict[unicode, Type[Builder]] + self.documenters = {} # type: Dict[unicode, Type[Documenter]] self.domains = {} # type: Dict[unicode, Type[Domain]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] self.domain_indices = {} # type: Dict[unicode, List[Type[Index]]] @@ -284,6 +286,10 @@ class SphinxComponentRegistry(object): # type: () -> List[Type[Transform]] return self.post_transforms + def add_documenter(self, objtype, documenter): + # type: (unicode, Type[Documenter]) -> None + self.documenters[objtype] = documenter + def load_extension(self, app, extname): # type: (Sphinx, unicode) -> None """Load a Sphinx extension.""" diff --git a/tests/py35/test_autodoc_py35.py b/tests/py35/test_autodoc_py35.py index ecb0a96af..d13e50d9c 100644 --- a/tests/py35/test_autodoc_py35.py +++ b/tests/py35/test_autodoc_py35.py @@ -112,7 +112,7 @@ def skip_member(app, what, name, obj, skip, options): @pytest.mark.usefixtures('setup_test') def test_generate(): def assert_warns(warn_str, objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) assert len(directive.result) == 0, directive.result assert len(_warnings) == 1, _warnings @@ -120,7 +120,7 @@ def test_generate(): del _warnings[:] def assert_works(objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) assert directive.result # print '\n'.join(directive.result) @@ -134,7 +134,7 @@ def test_generate(): assert set(processed_docstrings) | set(processed_signatures) == set(items) def assert_result_contains(item, objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) assert len(_warnings) == 0, _warnings @@ -142,7 +142,7 @@ def test_generate(): del directive.result[:] def assert_order(items, objtype, name, member_order, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.options.member_order = member_order inst.generate(**kw) assert len(_warnings) == 0, _warnings diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 61152ba02..1abd01b5f 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -121,7 +121,7 @@ def skip_member(app, what, name, obj, skip, options): @pytest.mark.usefixtures('setup_test') def test_parse_name(): def verify(objtype, name, result): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) assert inst.parse_name() assert (inst.modname, inst.objpath, inst.args, inst.retann) == result @@ -164,7 +164,7 @@ def test_parse_name(): @pytest.mark.usefixtures('setup_test') def test_format_signature(): def formatsig(objtype, name, obj, args, retann): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.fullname = name inst.doc_as_attr = False # for class objtype inst.object = obj @@ -270,7 +270,7 @@ def test_format_signature(): @pytest.mark.usefixtures('setup_test') def test_get_doc(): def getdocl(objtype, obj, encoding=None): - inst = AutoDirective._registry[objtype](directive, 'tmp') + inst = app.registry.documenters[objtype](directive, 'tmp') inst.object = obj inst.objpath = [obj.__name__] inst.doc_as_attr = False @@ -449,7 +449,7 @@ def test_get_doc(): @pytest.mark.usefixtures('setup_test') def test_docstring_processing(): def process(objtype, name, obj): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.object = obj inst.fullname = name return list(inst.process_doc(inst.get_doc())) @@ -506,7 +506,7 @@ def test_docstring_property_processing(): def genarate_docstring(objtype, name, **kw): del processed_docstrings[:] del processed_signatures[:] - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) results = list(directive.result) docstrings = inst.get_doc()[0] @@ -555,7 +555,7 @@ def test_new_documenter(): add_documenter(MyDocumenter) def assert_result_contains(item, objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) assert len(_warnings) == 0, _warnings @@ -581,7 +581,7 @@ def test_attrgetter_using(): AutoDirective._special_attrgetters[type] = special_getattr del getattr_spy[:] - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) hooked_members = [s[1] for s in getattr_spy] @@ -603,7 +603,7 @@ def test_attrgetter_using(): @pytest.mark.usefixtures('setup_test') def test_generate(): def assert_warns(warn_str, objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) assert len(directive.result) == 0, directive.result assert len(_warnings) == 1, _warnings @@ -611,7 +611,7 @@ def test_generate(): del _warnings[:] def assert_works(objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) assert directive.result # print '\n'.join(directive.result) @@ -625,7 +625,7 @@ def test_generate(): assert set(processed_docstrings) | set(processed_signatures) == set(items) def assert_result_contains(item, objtype, name, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.generate(**kw) # print '\n'.join(directive.result) assert len(_warnings) == 0, _warnings @@ -633,7 +633,7 @@ def test_generate(): del directive.result[:] def assert_order(items, objtype, name, member_order, **kw): - inst = AutoDirective._registry[objtype](directive, name) + inst = app.registry.documenters[objtype](directive, name) inst.options.member_order = member_order inst.generate(**kw) assert len(_warnings) == 0, _warnings diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 0aea99df6..1035d3b3b 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -57,10 +57,14 @@ def test_mangle_signature(): @pytest.mark.sphinx('dummy', **default_kw) -def test_get_items_summary(app, status, warning): +def test_get_items_summary(make_app, app_params): + import sphinx.ext.autosummary + import sphinx.ext.autosummary.generate + sphinx.ext.autosummary.generate.setup_documenters() + args, kwargs = app_params + app = make_app(*args, **kwargs) # monkey-patch Autosummary.get_items so we can easily get access to it's # results.. - import sphinx.ext.autosummary orig_get_items = sphinx.ext.autosummary.Autosummary.get_items autosummary_items = {} @@ -81,7 +85,7 @@ def test_get_items_summary(app, status, warning): finally: sphinx.ext.autosummary.Autosummary.get_items = orig_get_items - html_warnings = warning.getvalue() + html_warnings = app._warning.getvalue() assert html_warnings == '' expected_values = { diff --git a/tests/test_templating.py b/tests/test_templating.py index 341b33f51..88a196e77 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -10,10 +10,14 @@ """ import pytest +from sphinx.ext.autosummary.generate import setup_documenters @pytest.mark.sphinx('html', testroot='templating') -def test_layout_overloading(app, status, warning): +def test_layout_overloading(make_app, app_params): + setup_documenters() + args, kwargs = app_params + app = make_app(*args, **kwargs) app.builder.build_update() result = (app.outdir / 'contents.html').text(encoding='utf-8') @@ -22,7 +26,10 @@ def test_layout_overloading(app, status, warning): @pytest.mark.sphinx('html', testroot='templating') -def test_autosummary_class_template_overloading(app, status, warning): +def test_autosummary_class_template_overloading(make_app, app_params): + setup_documenters() + args, kwargs = app_params + app = make_app(*args, **kwargs) app.builder.build_update() result = (app.outdir / 'generated' / 'sphinx.application.TemplateBridge.html').text( From 4b51ed4aa9170265d682d120bb900e9fd94a21bc Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 18 Jun 2017 19:21:46 +0900 Subject: [PATCH 0502/1814] Deprecate AutoDirective._special_attrgetters --- CHANGES | 4 +++- sphinx/application.py | 9 ++++----- sphinx/ext/autodoc/__init__.py | 31 ++++++++++++++++++++----------- sphinx/registry.py | 5 +++++ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index c0934c396..ca0f3220a 100644 --- a/CHANGES +++ b/CHANGES @@ -22,7 +22,9 @@ Deprecated * ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use ``sphinx.util.inspect.Signature`` instead. * ``sphinx.ext.autodoc.add_documenter()`` and ``AutoDirective._register`` is now - deprecated. Please use ``app.add_autodocumenter()`` + deprecated. Please use ``app.add_autodocumenter()`` instead. +* ``AutoDirective._special_attrgetters`` is now deprecated. Please use + ``app.add_autodoc_attrgetter()`` instead. Features added -------------- diff --git a/sphinx/application.py b/sphinx/application.py index 3bfea910f..07b8539a9 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -646,11 +646,10 @@ class Sphinx(object): self.add_directive('auto' + cls.objtype, AutoDirective) self.registry.add_documenter(cls.objtype, cls) - def add_autodoc_attrgetter(self, type, getter): - # type: (Any, Callable) -> None - logger.debug('[app] adding autodoc attrgetter: %r', (type, getter)) - from sphinx.ext import autodoc - autodoc.AutoDirective._special_attrgetters[type] = getter + def add_autodoc_attrgetter(self, typ, getter): + # type: (Type, Callable[[Any, unicode, Any], Any]) -> None + logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter)) + self.registy.add_autodoc_attrgetter(typ, getter) def add_search_language(self, cls): # type: (Any) -> None diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index a6afe4f4c..14572e283 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -285,14 +285,10 @@ class Documenter(object): option_spec = {'noindex': bool_option} # type: Dict[unicode, Callable] - @staticmethod - def get_attr(obj, name, *defargs): + def get_attr(self, obj, name, *defargs): # type: (Any, unicode, Any) -> Any """getattr() override for types such as Zope interfaces.""" - for typ, func in iteritems(AutoDirective._special_attrgetters): - if isinstance(obj, typ): - return func(obj, name, *defargs) - return safe_getattr(obj, name, *defargs) + return autodoc_attrgetter(self.env.app, obj, name, *defargs) @classmethod def can_document_member(cls, member, membername, isattr, parent): @@ -1496,10 +1492,6 @@ class AutoDirective(Directive): The AutoDirective class is used for all autodoc directives. It dispatches most of the work to one of the Documenters. - The *_special_attrgetters* attribute is used to customize ``getattr()`` - calls that the Documenters make; its entries are of the form ``type: - getattr_function``. - Note: When importing an object, all items along the import chain are accessed using the descendant's *_special_attrgetters*, thus this dictionary should include all necessary functions for accessing @@ -1512,7 +1504,10 @@ class AutoDirective(Directive): ) # type: Dict[unicode, Type[Documenter]] # a registry of type -> getattr function - _special_attrgetters = {} # type: Dict[Type, Callable] + _special_attrgetters = DeprecatedDict( + 'AutoDirective._special_attrgetters has been deprecated. ' + 'Please use app.add_autodoc_attrgetter() instead.' + ) # type: Dict[Type, Callable] # flags that can be given in autodoc_default_flags _default_flags = set([ @@ -1628,6 +1623,20 @@ def get_documenters(app): return classes +def autodoc_attrgetter(app, obj, name, *defargs): + # type: (Sphinx, Any, unicode, Any) -> Any + """Alternative getattr() for types""" + candidates = dict(AutoDirective._special_attrgetters) + if app: + candidates.update(app.registry.autodoc_attrgettrs) + + for typ, func in iteritems(candidates): + if isinstance(obj, typ): + return func(obj, name, *defargs) + + return safe_getattr(obj, name, *defargs) + + def setup(app): # type: (Sphinx) -> Dict[unicode, Any] app.add_autodocumenter(ModuleDocumenter) diff --git a/sphinx/registry.py b/sphinx/registry.py index 38fe9caf3..e48c12f96 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -52,6 +52,7 @@ EXTENSION_BLACKLIST = { class SphinxComponentRegistry(object): def __init__(self): + self.autodoc_attrgettrs = {} # type: Dict[Type, Callable[[Any, unicode, Any], Any]] self.builders = {} # type: Dict[unicode, Type[Builder]] self.documenters = {} # type: Dict[unicode, Type[Documenter]] self.domains = {} # type: Dict[unicode, Type[Domain]] @@ -290,6 +291,10 @@ class SphinxComponentRegistry(object): # type: (unicode, Type[Documenter]) -> None self.documenters[objtype] = documenter + def add_autodoc_attrgetter(self, typ, attrgetter): + # type: (Type, Callable[[Any, unicode, Any], Any]) -> None + self.autodoc_attrgettrs[typ] = attrgetter + def load_extension(self, app, extname): # type: (Sphinx, unicode) -> None """Load a Sphinx extension.""" From bf0153d74850cc9d498a0ed152a0d3d6e7e49f96 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 22 Jun 2017 01:20:18 +0900 Subject: [PATCH 0503/1814] autodoc: Refactor get_object_members() --- sphinx/ext/autodoc/__init__.py | 63 ++++++++-------------------------- sphinx/ext/autodoc/importer.py | 33 +++++++++++++++++- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 14572e283..16abb8c71 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -16,7 +16,7 @@ import sys import inspect import warnings -from six import iterkeys, iteritems, itervalues, text_type, class_types, string_types +from six import iteritems, itervalues, text_type, class_types, string_types from docutils import nodes from docutils.utils import assemble_option_dict @@ -25,7 +25,7 @@ from docutils.statemachine import ViewList import sphinx from sphinx.deprecation import RemovedInSphinx20Warning -from sphinx.ext.autodoc.importer import mock, import_object +from sphinx.ext.autodoc.importer import mock, import_object, get_object_members from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA from sphinx.util import rpartition, force_decode @@ -36,7 +36,7 @@ from sphinx.util import logging from sphinx.util.nodes import nested_parse_with_titles from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \ safe_getattr, object_description, is_builtin_class_method, \ - isenumclass, isenumattribute, getdoc + isenumattribute, getdoc from sphinx.util.docstrings import prepare_docstring if False: @@ -570,57 +570,24 @@ class Documenter(object): If *want_all* is True, return all members. Else, only return those members given by *self.options.members* (which may also be none). """ - analyzed_member_names = set() - if self.analyzer: - attr_docs = self.analyzer.find_attr_docs() - namespace = '.'.join(self.objpath) - for item in iteritems(attr_docs): - if item[0][0] == namespace: - analyzed_member_names.add(item[0][1]) + members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer) if not want_all: if not self.options.members: return False, [] # specific members given - members = [] - for mname in self.options.members: - try: - members.append((mname, self.get_attr(self.object, mname))) - except AttributeError: - if mname not in analyzed_member_names: - self.directive.warn('missing attribute %s in object %s' - % (mname, self.fullname)) + selected = [] + for name in self.options.members: + if name in members: + selected.append((name, members[name].value)) + else: + self.directive.warn('missing attribute %s in object %s' % + (name, self.fullname)) + return False, sorted(selected) elif self.options.inherited_members: - # safe_getmembers() uses dir() which pulls in members from all - # base classes - members = safe_getmembers(self.object, attr_getter=self.get_attr) + return False, sorted((m.name, m.value) for m in itervalues(members)) else: - # __dict__ contains only the members directly defined in - # the class (but get them via getattr anyway, to e.g. get - # unbound method objects instead of function objects); - # using list(iterkeys()) because apparently there are objects for which - # __dict__ changes while getting attributes - try: - obj_dict = self.get_attr(self.object, '__dict__') - except AttributeError: - members = [] - else: - members = [(mname, self.get_attr(self.object, mname, None)) - for mname in list(iterkeys(obj_dict))] - - # Py34 doesn't have enum members in __dict__. - if isenumclass(self.object): - members.extend( - item for item in self.object.__members__.items() - if item not in members - ) - - membernames = set(m[0] for m in members) - # add instance attributes from the analyzer - for aname in analyzed_member_names: - if aname not in membernames and \ - (want_all or aname in self.options.members): - members.append((aname, INSTANCEATTR)) - return False, sorted(members) + return False, sorted((m.name, m.value) for m in itervalues(members) + if m.directly_defined) def filter_members(self, members, want_all): # type: (List[Tuple[unicode, Any]], bool) -> List[Tuple[unicode, Any, bool]] diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 95ca58d0b..b22af9ff5 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -13,6 +13,7 @@ import sys import warnings import traceback import contextlib +from collections import namedtuple from types import FunctionType, MethodType, ModuleType from six import PY2 @@ -22,7 +23,7 @@ from sphinx.util.inspect import safe_getattr if False: # For type annotation - from typing import Any, Callable, Generator, List, Set # NOQA + from typing import Any, Callable, Dict, Generator, List, Optional, Set # NOQA logger = logging.getLogger(__name__) @@ -194,3 +195,33 @@ def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warning errmsg = errmsg.decode('utf-8') # type: ignore logger.debug(errmsg) raise ImportError(errmsg) + + +Attribute = namedtuple('Attribute', ['name', 'directly_defined', 'value']) + + +def get_object_members(subject, objpath, attrgetter, analyzer=None): + # type: (Any, List[unicode], Callable, Any) -> Dict[str, Attribute] # NOQA + """Get members and attributes of target object.""" + # the members directly defined in the class + obj_dict = attrgetter(subject, '__dict__', {}) + + members = {} + for name in dir(subject): + try: + value = attrgetter(subject, name) + directly_defined = name in obj_dict + members[name] = Attribute(name, directly_defined, value) + except AttributeError: + continue + + if analyzer: + # append instance attributes (cf. self.attr1) if analyzer knows + from sphinx.ext.autodoc import INSTANCEATTR + + namespace = '.'.join(objpath) + for (ns, name) in analyzer.find_attr_docs(): + if namespace == ns and name not in members: + members[name] = Attribute(name, True, INSTANCEATTR) + + return members From 69f39e44d91c0eb10596448f38fb1aafcbf2054a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 24 Dec 2017 20:05:13 +0000 Subject: [PATCH 0504/1814] tox: Enable 'skipsdist' Given that we install Sphinx as part of the dependencies, there's no reason to do it twice. Skip that step. Signed-off-by: Stephen Finucane --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 530e5b941..9c0f2d2f3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,6 @@ [tox] envlist=flake8,py27,py34,py35,py36,pypy,du13,du12,du11 +skipsdist = True [testenv] deps= From f21fe6f24f879fcb640e9d9711eeb777a57b10a9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 Jan 2018 23:03:15 +0900 Subject: [PATCH 0505/1814] Revert "tox: Enable 'skipsdist'" This reverts commit 69f39e44d91c0eb10596448f38fb1aafcbf2054a. --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9c0f2d2f3..530e5b941 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,5 @@ [tox] envlist=flake8,py27,py34,py35,py36,pypy,du13,du12,du11 -skipsdist = True [testenv] deps= From 850e9a9c5cbd18163eaa8861c7fecbdfb9921a2b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 Jan 2018 23:29:10 +0900 Subject: [PATCH 0506/1814] Fix links to external option docs with intersphinx (refs: #3769) --- CHANGES | 1 + sphinx/domains/std.py | 16 +++++++++++----- sphinx/ext/intersphinx.py | 1 + tests/test_ext_intersphinx.py | 8 +++++++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index bb11d643d..39288bea7 100644 --- a/CHANGES +++ b/CHANGES @@ -38,6 +38,7 @@ Bugs fixed * #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates ``\chapter`` commands * #4214: Two todolist directives break sphinx-1.6.5 +* Fix links to external option docs with intersphinx (refs: #3769) Testing -------- diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 27bb88c96..68baa04aa 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -959,12 +959,18 @@ class StandardDomain(Domain): def get_full_qualified_name(self, node): # type: (nodes.Node) -> unicode - progname = node.get('std:program') - target = node.get('reftarget') - if progname is None or target is None: - return None + if node.get('reftype') == 'option': + progname = node.get('std:program') + command = ws_re.split(node.get('reftarget')) + if progname: + command.insert(0, progname) + option = command.pop() + if command: + return '.'.join(['-'.join(command), option]) + else: + return None else: - return '.'.join([progname, target]) + return None def setup(app): diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index ccd2c9321..9336c4b53 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -304,6 +304,7 @@ def missing_reference(app, env, node, contnode): in_set = setname to_try.append((inventories.named_inventory[setname], newtarget)) if domain: + node['reftarget'] = newtarget full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) if full_qualified_name: to_try.append((inventories.named_inventory[setname], full_qualified_name)) diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 371f296ea..a978928d4 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -194,7 +194,7 @@ def test_missing_reference_stddomain(tempdir, app, status, warning): inv_file = tempdir / 'inventory' inv_file.write_bytes(inventory_v2) app.config.intersphinx_mapping = { - 'https://docs.python.org/': inv_file, + 'cmd': ('https://docs.python.org/', inv_file), } app.config.intersphinx_cache_limit = 0 @@ -213,6 +213,12 @@ def test_missing_reference_stddomain(tempdir, app, status, warning): rn = missing_reference(app, app.env, node, contnode) assert rn.astext() == 'ls -l' + # refers inventory by name + kwargs = {} + node, contnode = fake_node('std', 'option', 'cmd:ls -l', '-l', **kwargs) + rn = missing_reference(app, app.env, node, contnode) + assert rn.astext() == '-l' + @pytest.mark.sphinx('html', testroot='ext-intersphinx-cppdomain') def test_missing_reference_cppdomain(tempdir, app, status, warning): From cb860f0d306b3dc5a8688e3c88035b060fc0882f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 2 Jan 2018 01:57:41 +0900 Subject: [PATCH 0507/1814] Fix #4091: Private members not documented without :undoc-members: --- CHANGES | 1 + sphinx/ext/autodoc.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 39288bea7..1e1379178 100644 --- a/CHANGES +++ b/CHANGES @@ -39,6 +39,7 @@ Bugs fixed ``\chapter`` commands * #4214: Two todolist directives break sphinx-1.6.5 * Fix links to external option docs with intersphinx (refs: #3769) +* #4091: Private members not documented without :undoc-members: Testing -------- diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index e04b4a09d..bd686644c 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -965,8 +965,7 @@ class Documenter(object): elif (namespace, membername) in attr_docs: if want_all and membername.startswith('_'): # ignore members whose name starts with _ by default - keep = self.options.private_members and \ - (has_doc or self.options.undoc_members) + keep = self.options.private_members else: # keep documented attributes keep = True From 309f38a91fcbb8405a7f3d8c13fe4bce65b0b230 Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 2 Jan 2018 23:11:19 +0100 Subject: [PATCH 0508/1814] Split out fancy LaTeX macros from ``\sphinxcode`` into ``\sphinxupquote`` Since #2627 (1.4.4), `\code`, and then again at #3116 (1.5) `\sphinxcode` which is the new name has become more complicated than the original `\texttt{#1}`. This was to obtain straight quotes in PDF output, and to allow long inline literals to break across lines. This means though that users who want to customize `\sphinxcode`, for example to not only do `\texttt` but to use some colour, have to copy about 10 lines of complicated LaTeX macros which should be not modified in any way. This commit moves all the code out of `\sphinxcode` into a separate macro `\sphinxupquote`. The LaTeX writer will output `\sphinxcode{\sphinxupquote{foo}}` in place of former `\sphinxcode{foo}`. Moving the `\texttt` from innermost to outermost level is with no consequence. --- sphinx/texinputs/sphinx.sty | 15 ++++++++------- sphinx/writers/latex.py | 26 +++++++++++++------------- tests/test_markup.py | 12 ++++++------ 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 890ef60f7..8de263a52 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1459,8 +1459,8 @@ % \newenvironment{productionlist}{% % \def\sphinxoptional##1{{\Large[}##1{\Large]}} - \def\production##1##2{\\\sphinxcode{##1}&::=&\sphinxcode{##2}}% - \def\productioncont##1{\\& &\sphinxcode{##1}}% + \def\production##1##2{\\\sphinxcode{\sphinxupquote{##1}}&::=&\sphinxcode{\sphinxupquote{##2}}}% + \def\productioncont##1{\\& &\sphinxcode{\sphinxupquote{##1}}}% \parindent=2em \indent \setlength{\LTpre}{0pt}% @@ -1541,15 +1541,13 @@ %% TEXT STYLING % -% Some custom font markup commands. -\protected\def\sphinxstrong#1{{\textbf{#1}}} % to obtain straight quotes we execute \@noligs as patched by upquote, and % \scantokens is needed in cases where it would be too late for the macro to % first set catcodes and then fetch its argument. We also make the contents % breakable at non-escaped . , ; ? ! / using \sphinxbreaksviaactive. % the macro must be protected if it ends up used in moving arguments, % in 'alltt' \@noligs is done already, and the \scantokens must be avoided. -\protected\def\sphinxcode#1{{\def\@tempa{alltt}% +\protected\def\sphinxupquote#1{{\def\@tempa{alltt}% \ifx\@tempa\@currenvir\else \ifspx@opt@inlineliteralwraps \sphinxbreaksviaactive\let\sphinxafterbreak\empty @@ -1560,12 +1558,15 @@ \let\do@noligs\sphinx@do@noligs \@noligs\endlinechar\m@ne\everyeof{}% (<- in case inside \sphinxhref) \expandafter\scantokens - \fi {\texttt{#1}}}} + \fi {#1}}} \def\sphinx@do@noligs #1{\catcode`#1\active\begingroup\lccode`\~`#1\relax \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1 }}} \def\sphinx@literal@nolig@list {\do\`\do\<\do\>\do\'\do\-}% -\protected\def\sphinxbfcode#1{\sphinxcode{\bfseries{}#1}} +% Some custom font markup commands. +\protected\def\sphinxstrong#1{\textbf{#1}} +\protected\def\sphinxcode#1{\texttt{#1}} +\protected\def\sphinxbfcode#1{\textbf{\sphinxcode{#1}}} \protected\def\sphinxemail#1{\textsf{#1}} \protected\def\sphinxtablecontinued#1{\textsf{#1}} \protected\def\sphinxtitleref#1{\emph{#1}} diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 9a3c0e5cd..de472b36c 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1216,12 +1216,12 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_desc_addname(self, node): # type: (nodes.Node) -> None - self.body.append(r'\sphinxcode{') + self.body.append(r'\sphinxcode{\sphinxupquote{') self.literal_whitespace += 1 def depart_desc_addname(self, node): # type: (nodes.Node) -> None - self.body.append('}') + self.body.append('}}') self.literal_whitespace -= 1 def visit_desc_type(self, node): @@ -1242,13 +1242,13 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_desc_name(self, node): # type: (nodes.Node) -> None - self.body.append(r'\sphinxbfcode{') + self.body.append(r'\sphinxbfcode{\sphinxupquote{') self.no_contractions += 1 self.literal_whitespace += 1 def depart_desc_name(self, node): # type: (nodes.Node) -> None - self.body.append('}') + self.body.append('}}') self.literal_whitespace -= 1 self.no_contractions -= 1 @@ -1287,11 +1287,11 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_desc_annotation(self, node): # type: (nodes.Node) -> None - self.body.append(r'\sphinxbfcode{') + self.body.append(r'\sphinxbfcode{\sphinxupquote{') def depart_desc_annotation(self, node): # type: (nodes.Node) -> None - self.body.append('}') + self.body.append('}}') def visit_desc_content(self, node): # type: (nodes.Node) -> None @@ -2177,12 +2177,12 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_literal_emphasis(self, node): # type: (nodes.Node) -> None - self.body.append(r'\sphinxstyleliteralemphasis{') + self.body.append(r'\sphinxstyleliteralemphasis{\sphinxupquote{') self.no_contractions += 1 def depart_literal_emphasis(self, node): # type: (nodes.Node) -> None - self.body.append('}') + self.body.append('}}') self.no_contractions -= 1 def visit_strong(self, node): @@ -2195,12 +2195,12 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_literal_strong(self, node): # type: (nodes.Node) -> None - self.body.append(r'\sphinxstyleliteralstrong{') + self.body.append(r'\sphinxstyleliteralstrong{\sphinxupquote{') self.no_contractions += 1 def depart_literal_strong(self, node): # type: (nodes.Node) -> None - self.body.append('}') + self.body.append('}}') self.no_contractions -= 1 def visit_abbreviation(self, node): @@ -2259,14 +2259,14 @@ class LaTeXTranslator(nodes.NodeVisitor): # type: (nodes.Node) -> None self.no_contractions += 1 if self.in_title: - self.body.append(r'\sphinxstyleliteralintitle{') + self.body.append(r'\sphinxstyleliteralintitle{\sphinxupquote{') else: - self.body.append(r'\sphinxcode{') + self.body.append(r'\sphinxcode{\sphinxupquote{') def depart_literal(self, node): # type: (nodes.Node) -> None self.no_contractions -= 1 - self.body.append('}') + self.body.append('}}') def visit_footnote_reference(self, node): # type: (nodes.Node) -> None diff --git a/tests/test_markup.py b/tests/test_markup.py index 34ab1405d..c48096e34 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -135,7 +135,7 @@ def get_verifier(verify, verify_re): '``code sample``', ('

' 'code   sample

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

' 'code   sample

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

a' 'b' 'c

'), - '\\sphinxcode{a\\sphinxstyleemphasis{b}c}', + '\\sphinxcode{\\sphinxupquote{a\\sphinxstyleemphasis{b}c}}', ), ( # interpolation of arrows in menuselection @@ -175,7 +175,7 @@ def get_verifier(verify, verify_re): ':option:`--with-option`', ('

' '--with-option

$'), - r'\\sphinxcode{-{-}with-option}$', + r'\\sphinxcode{\\sphinxupquote{-{-}with-option}}$', ), ( # verify smarty-pants quotes @@ -190,14 +190,14 @@ def get_verifier(verify, verify_re): '``"John"``', ('

' '"John"

'), - '\\sphinxcode{"John"}', + '\\sphinxcode{\\sphinxupquote{"John"}}', ), ( # verify classes for inline roles 'verify', ':manpage:`mp(1)`', '

mp(1)

', - '\\sphinxstyleliteralemphasis{mp(1)}', + '\\sphinxstyleliteralemphasis{\\sphinxupquote{mp(1)}}', ), ( # correct escaping in normal mode From 680d6766bb556bb31bedac7847120b7ecc7465dd Mon Sep 17 00:00:00 2001 From: jfbu Date: Tue, 2 Jan 2018 23:28:46 +0100 Subject: [PATCH 0509/1814] Make LaTeX macro definitions more readable This make clearer to average LaTeX user the format which is expected for these macros, in case of redefinitions. --- sphinx/texinputs/sphinx.sty | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 8de263a52..61192d628 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1580,21 +1580,21 @@ % additional customizable styling % FIXME: convert this to package options ? -\protected\def\sphinxstyleindexentry {\texttt} -\protected\def\sphinxstyleindexextra #1{ \emph{(#1)}} -\protected\def\sphinxstyleindexpageref {, \pageref} -\protected\def\sphinxstyletopictitle #1{\textbf{#1}\par\medskip} +\protected\def\sphinxstyleindexentry #1{\texttt{#1}} +\protected\def\sphinxstyleindexextra #1{ \emph{(#1)}} +\protected\def\sphinxstyleindexpageref #1{, \pageref{#1}} +\protected\def\sphinxstyletopictitle #1{\textbf{#1}\par\medskip} \let\sphinxstylesidebartitle\sphinxstyletopictitle -\protected\def\sphinxstyleothertitle {\textbf} +\protected\def\sphinxstyleothertitle #1{\textbf{#1}} \protected\def\sphinxstylesidebarsubtitle #1{~\\\textbf{#1} \smallskip} % \text.. commands do not allow multiple paragraphs \protected\def\sphinxstyletheadfamily {\sffamily} -\protected\def\sphinxstyleemphasis {\emph} +\protected\def\sphinxstyleemphasis #1{\emph{#1}} \protected\def\sphinxstyleliteralemphasis#1{\emph{\sphinxcode{#1}}} -\protected\def\sphinxstylestrong {\textbf} -\protected\def\sphinxstyleliteralstrong {\sphinxbfcode} -\protected\def\sphinxstyleabbreviation {\textsc} -\protected\def\sphinxstyleliteralintitle {\sphinxcode} +\protected\def\sphinxstylestrong #1{\textbf{#1}} +\protected\def\sphinxstyleliteralstrong#1{\sphinxbfcode{#1}} +\protected\def\sphinxstyleabbreviation #1{\textsc{#1}} +\protected\def\sphinxstyleliteralintitle#1{\sphinxcode{#1}} \newcommand*\sphinxstylecodecontinued[1]{\footnotesize(#1)}% \newcommand*\sphinxstylecodecontinues[1]{\footnotesize(#1)}% % figure legend comes after caption and may contain arbitrary body elements From c892fe98f7a311dc51340f8d98e63d9790b7f820 Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 3 Jan 2018 10:50:18 +0100 Subject: [PATCH 0510/1814] Fix space gobbling issue from PR #4370 This is subtle LaTeX thing. Prior to merge of #4370 there was a `\texttt` which was hiding the potential problem. The fix is to leave a brace pair in place. --- sphinx/texinputs/sphinx.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 61192d628..2b41673db 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1558,7 +1558,7 @@ \let\do@noligs\sphinx@do@noligs \@noligs\endlinechar\m@ne\everyeof{}% (<- in case inside \sphinxhref) \expandafter\scantokens - \fi {#1}}} + \fi {{#1}}}}% extra brace pair to fix end-space gobbling issue... \def\sphinx@do@noligs #1{\catcode`#1\active\begingroup\lccode`\~`#1\relax \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1 }}} \def\sphinx@literal@nolig@list {\do\`\do\<\do\>\do\'\do\-}% From 6fa344c951a8c9c67c4fd7492a758f8e70ee3c4f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 3 Jan 2018 20:15:20 +0900 Subject: [PATCH 0511/1814] Show traceback if conf.py raises an exception (refs: #4369) --- CHANGES | 1 + sphinx/config.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 39288bea7..a6caf7031 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ Features added * ``VerbatimHighlightColor`` is a new :ref:`LaTeX 'sphinxsetup' ` key (refs: #4285) * Easier customizability of LaTeX macros involved in rendering of code-blocks +* Show traceback if conf.py raises an exception (refs: #4369) Bugs fixed ---------- diff --git a/sphinx/config.py b/sphinx/config.py index d3468b0a5..50f7c018c 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -10,6 +10,7 @@ """ import re +import traceback from os import path, getenv from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types @@ -35,6 +36,7 @@ copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])') CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s" if PY3: CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?" +CONFIG_ERROR = "There is a programable error in your configuration file:\n\n%s" CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \ "called sys.exit()" CONFIG_ENUM_WARNING = "The config value `{name}` has to be a one of {candidates}, " \ @@ -152,6 +154,8 @@ class Config(object): raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) + except Exception: + raise ConfigError(CONFIG_ERROR % traceback.format_exc()) self._raw_config = config # these two must be preinitialized because extensions can add their From b04151bca8d43aceb8a0bf018fb736cb215d0729 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 5 Jan 2018 01:41:01 +0100 Subject: [PATCH 0512/1814] improved sidebar search field style --- sphinx/themes/basic/searchbox.html | 6 ++++-- sphinx/themes/basic/static/basic.css_t | 14 +++++++++++++- sphinx/themes/nature/static/nature.css_t | 7 ++----- sphinx/themes/pyramid/static/pyramid.css_t | 7 ++----- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html index a8ea03cc8..506877410 100644 --- a/sphinx/themes/basic/searchbox.html +++ b/sphinx/themes/basic/searchbox.html @@ -10,12 +10,14 @@ {%- if pagename != "search" and builder != "singlehtml" %} {%- endif %} diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 745864e28..efb997d8f 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -82,9 +82,21 @@ div.sphinxsidebar input { } div.sphinxsidebar #searchbox input[type="text"] { - width: 170px; + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; } +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + img { border: 0; max-width: 100%; diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index 5751bf940..ff2b1d5ff 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -125,14 +125,11 @@ div.sphinxsidebar input { font-size: 1em; } -div.sphinxsidebar input[type=text]{ +div.sphinxsidebar .searchformwrapper { margin-left: 20px; + margin-right: 20px; } -div.sphinxsidebar input[type=submit]{ - margin-left: 20px; -} - /* -- body styles ----------------------------------------------------------- */ a { diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t index 93799111e..792f45452 100644 --- a/sphinx/themes/pyramid/static/pyramid.css_t +++ b/sphinx/themes/pyramid/static/pyramid.css_t @@ -148,12 +148,9 @@ div.sphinxsidebar input { font-size: 1em; } -div.sphinxsidebar input[type=text]{ - margin-left: 20px; -} - -div.sphinxsidebar input[type=submit]{ +div.sphinxsidebar .searchformwrapper { margin-left: 20px; + margin-right: 20px; } /* -- sidebars -------------------------------------------------------------- */ From e3efe5884b08e4e4994d58eaf9c645b8f9567547 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 5 Jan 2018 22:25:34 +0900 Subject: [PATCH 0513/1814] Fix #4378: tox: use usedevelop option instead skipsdist --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ae6b2a4b3..2862fd755 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] minversion = 2.0 envlist = docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14} -skipsdist = True [testenv] +usedevelop = True passenv = https_proxy http_proxy no_proxy PERL PERL5LIB description = From bd139453c96864646c0b7b1bf2f30b12587cb235 Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 5 Jan 2018 15:06:10 +0100 Subject: [PATCH 0514/1814] Move SphinxSmartQuotes transform to SphinxStandaloneReader closes #4142 closes #4357 closes #4359 refs: #3967 Adds ``smartquotes``, ``smartquotes_action``, ``smartquotes_excludes`` configuration variables. - if ``smartquotes`` is set to False, then Smart Quotes transform is not applied even if a Docutils configuration file activates it, - the current default of ``smartquotes_excludes`` deactivates Smart Quotes for Japanese language, and also for the ``man`` and ``text`` builders. However, currently ``make text html`` deactivates Smart Quotes for ``html`` too, and ``make html text`` activates them for ``text`` too, because the picked environment is shared and already transformed. - now Smart Quotes get applied also when source documents are in Markdown or other formats. --- doc/config.rst | 65 ++++++++++++++++++++++++++++++---- sphinx/config.py | 5 +++ sphinx/environment/__init__.py | 48 ++++++++++++++++++++----- sphinx/io.py | 12 ++++++- sphinx/parsers.py | 7 ++-- 5 files changed, 117 insertions(+), 20 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index 1f222451d..6b7690c76 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -353,6 +353,63 @@ General configuration .. versionadded:: 1.3 +.. confval:: smartquotes + + If true, the `Docutils Smart Quotes transform`__, originally based on + `SmartyPants`__ (limited to English) and currently applying to many + languages, will be used to convert quotes and dashes to typographically + correct entities. Default: ``True``. + + __ http://docutils.sourceforge.net/docs/user/smartquotes.html + __ https://daringfireball.net/projects/smartypants/ + + .. versionadded:: 1.6.6 + It replaces deprecated :confval:`html_use_smartypants`. + It applies by default to all builders except ``man`` and ``text`` + (see :confval:`smartquotes_excludes`.) + + A `docutils.conf`__ file located in the configuration directory (or a + global :file:`~/.docutils` file) is obeyed unconditionally if it + *deactivates* smart quotes via the corresponding `Docutils option`__. But + if it *activates* them, then :confval:`smartquotes` does prevail. + + __ http://docutils.sourceforge.net/docs/user/config.html + __ http://docutils.sourceforge.net/docs/user/config.html#smart-quotes + +.. confval:: smartquotes_action + + This string, for use with Docutils ``0.14`` or later, customizes the Smart + Quotes transform. See the file :file:`smartquotes.py` at the `Docutils + repository`__ for details. The default ``'qDe'`` educates normal **q**\ + uote characters ``"``, ``'``, em- and en-**D**\ ashes ``---``, ``--``, and + **e**\ llipses ``...``. + + .. versionadded:: 1.6.6 + + __ https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/ + +.. confval:: smartquotes_excludes + + This is a ``dict`` whose default is:: + + {'languages': ['ja'], 'builders': ['man', 'text']} + + Each entry gives a sufficient condition to ignore the + :confval:`smartquotes` setting and deactivate the Smart Quotes transform. + Accepted keys are as above ``'builders'`` or ``'languages'``. + The values are lists. + + .. note:: Currently, in case of invocation of :program:`make` with multiple + targets, the first target name is the only one which is tested against + the ``'builders'`` entry and it decides for all. Also, a ``make text`` + following ``make html`` needs to be issued in the form ``make text + O="-E"`` to force re-parsing of source files, as the cached ones are + already transformed. On the other hand the issue does not arise with + direct usage of :program:`sphinx-build` as it caches + (in its default usage) the parsed source files in per builder locations. + + .. versionadded:: 1.6.6 + .. confval:: tls_verify If true, Sphinx verifies server certifications. Default is ``True``. @@ -784,15 +841,11 @@ that use Sphinx's HTMLWriter class. .. confval:: html_use_smartypants - If true, `SmartyPants `_ - will be used to convert quotes and dashes to typographically correct + If true, quotes and dashes are converted to typographically correct entities. Default: ``True``. .. deprecated:: 1.6 - To disable or customize smart quotes, use the Docutils configuration file - (``docutils.conf``) instead to set there its `smart_quotes option`_. - - .. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes + To disable smart quotes, use rather :confval:`smartquotes`. .. confval:: html_add_permalinks diff --git a/sphinx/config.py b/sphinx/config.py index 50f7c018c..a6632807c 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -134,6 +134,11 @@ class Config(object): tls_verify = (True, 'env'), tls_cacerts = (None, 'env'), + smartquotes = (True, 'env'), + smartquotes_action = ('qDe', 'env'), + smartquotes_excludes = ({'languages': ['ja'], + 'builders': ['man', 'text']}, + 'env'), ) # type: Dict[unicode, Tuple] def __init__(self, dirname, filename, overrides, tags): diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 65a73b019..781382a30 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -20,8 +20,9 @@ import warnings from os import path from copy import copy from collections import defaultdict +from contextlib import contextmanager -from six import BytesIO, itervalues, class_types, next +from six import BytesIO, itervalues, class_types, next, iteritems from six.moves import cPickle as pickle from docutils.io import NullOutput @@ -46,7 +47,7 @@ from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError from sphinx.locale import __ -from sphinx.transforms import SphinxTransformer +from sphinx.transforms import SphinxTransformer, SphinxSmartQuotes from sphinx.versioning import add_uids, merge_doctrees from sphinx.deprecation import RemovedInSphinx17Warning, RemovedInSphinx20Warning from sphinx.environment.adapters.indexentries import IndexEntries @@ -54,7 +55,7 @@ from sphinx.environment.adapters.toctree import TocTree if False: # For type annotation - from typing import Any, Callable, Dict, IO, Iterator, List, Pattern, Set, Tuple, Type, Union # NOQA + from typing import Any, Callable, Dict, IO, Iterator, List, Pattern, Set, Tuple, Type, Union, Generator # NOQA from docutils import nodes # NOQA from sphinx.application import Sphinx # NOQA from sphinx.builders import Builder # NOQA @@ -91,6 +92,22 @@ versioning_conditions = { } # type: Dict[unicode, Union[bool, Callable]] +@contextmanager +def sphinx_smartquotes_action(env): + # type: (BuildEnvironment) -> Generator + if not hasattr(SphinxSmartQuotes, 'smartquotes_action'): + # less than docutils-0.14 + yield + else: + # docutils-0.14 or above + try: + original = SphinxSmartQuotes.smartquotes_action + SphinxSmartQuotes.smartquotes_action = env.config.smartquotes_action + yield + finally: + SphinxSmartQuotes.smartquotes_action = original + + class NoUri(Exception): """Raised by get_relative_uri if there is no URI available.""" pass @@ -600,7 +617,8 @@ class BuildEnvironment(object): # remove all inventory entries for that file app.emit('env-purge-doc', self, docname) self.clear_doc(docname) - self.read_doc(docname, app) + with sphinx_smartquotes_action(self): + self.read_doc(docname, app) def _read_parallel(self, docnames, app, nproc): # type: (List[unicode], Sphinx, int) -> None @@ -612,8 +630,9 @@ class BuildEnvironment(object): def read_process(docs): # type: (List[unicode]) -> unicode self.app = app - for docname in docs: - self.read_doc(docname, app) + with sphinx_smartquotes_action(self): + for docname in docs: + self.read_doc(docname, app) # allow pickling self to send it back return BuildEnvironment.dumps(self) @@ -677,15 +696,26 @@ class BuildEnvironment(object): language = self.config.language or 'en' self.settings['language_code'] = language if 'smart_quotes' not in self.settings: - self.settings['smart_quotes'] = True + self.settings['smart_quotes'] = self.config.smartquotes if self.config.html_use_smartypants is not None: warnings.warn("html_use_smartypants option is deprecated. Smart " "quotes are on by default; if you want to disable " - "or customize them, use the smart_quotes option in " - "docutils.conf.", + "them, use the smartquotes option.", RemovedInSphinx17Warning) self.settings['smart_quotes'] = self.config.html_use_smartypants + # some conditions exclude smart quotes, overriding smart_quotes + for valname, vallist in iteritems(self.config.smartquotes_excludes): + if valname == 'builders': + # this will work only for checking first build target + if self.app.builder.name in vallist: + self.settings['smart_quotes'] = False + break + elif valname == 'languages': + if self.config.language in vallist: + self.settings['smart_quotes'] = False + break + # confirm selected language supports smart_quotes or not for tag in normalize_language_tag(language): if tag in smartchars.quotes: diff --git a/sphinx/io.py b/sphinx/io.py index 8365e22e0..6fcec2cd3 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -18,7 +18,7 @@ from sphinx.transforms import ( ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, - UnreferencedFootnotesDetector + UnreferencedFootnotesDetector, SphinxSmartQuotes ) from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.i18n import ( @@ -98,6 +98,16 @@ class SphinxStandaloneReader(SphinxBaseReader): RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, RefOnlyBulletListTransform, UnreferencedFootnotesDetector] + def __init__(self, app, parsers={}, *args, **kwargs): + SphinxBaseReader.__init__(self, app, parsers, *args, **kwargs) + self.smart_quotes = app.env.settings['smart_quotes'] + + def get_transforms(self): + transforms = SphinxBaseReader.get_transforms(self) + if self.smart_quotes: + transforms.append(SphinxSmartQuotes) + return transforms + class SphinxI18nReader(SphinxBaseReader): """ diff --git a/sphinx/parsers.py b/sphinx/parsers.py index b58eefa23..1aa16a45e 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -13,8 +13,6 @@ import docutils.parsers import docutils.parsers.rst from docutils.transforms.universal import SmartQuotes -from sphinx.transforms import SphinxSmartQuotes - if False: # For type annotation from typing import Any, Dict, List, Type # NOQA @@ -60,10 +58,11 @@ class RSTParser(docutils.parsers.rst.Parser): def get_transforms(self): # type: () -> List[Type[Transform]] - """Sphinx's reST parser replaces a transform class for smart-quotes by own's""" + """Sphinx's reST parser replaces a transform class for smart-quotes by own's + + refs: sphinx.io.SphinxStandaloneReader""" transforms = docutils.parsers.rst.Parser.get_transforms(self) transforms.remove(SmartQuotes) - transforms.append(SphinxSmartQuotes) return transforms From 0d824dfd41302bcea5d8de831bc5f1025c465c1d Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 5 Jan 2018 15:06:38 +0100 Subject: [PATCH 0515/1814] Update CHANGES for PR #4360 --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 181271868..80f8c4faa 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,10 @@ Features added :ref:`LaTeX 'sphinxsetup' ` key (refs: #4285) * Easier customizability of LaTeX macros involved in rendering of code-blocks * Show traceback if conf.py raises an exception (refs: #4369) +* Add :confval:`smartquotes` to disable smart quotes through ``conf.py`` + (refs: #3967) +* Add :confval:`smartquotes_action` and :confval:`smartquotes_excludes` + (refs: #4142, #4357) Bugs fixed ---------- From 3736768a59dd1d13b205b894385eadd9791b1ac4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 6 Jan 2018 13:22:47 +0900 Subject: [PATCH 0516/1814] test: Reduce DeprecationWarning on testing (from docutils) --- setup.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.cfg b/setup.cfg index 0ce6282dc..c19d0d518 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,10 @@ incremental = True check_untyped_defs = True warn_unused_ignores = True +[tool:pytest] +filterwarnings = + ignore::DeprecationWarning:docutils.io + [coverage:run] branch = True source = sphinx From fdf0a33eab4d73a36582acbf3c91530f78bf35ef Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 6 Jan 2018 16:09:53 +0900 Subject: [PATCH 0517/1814] test: Remove PYTHONWARNINGS from travis.yml PYTHONWARNINGS is now controled at tox.ini. So this envvar is no longer referred. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2bd437436..e51523c19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ cache: pip env: global: - PYTHONFAULTHANDLER=x - - PYTHONWARNINGS=all - SKIP_LATEX_BUILD=1 matrix: From 23533e48b22c4187d172ae1d8bf42a21f5c81f2a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 6 Jan 2018 16:34:51 +0900 Subject: [PATCH 0518/1814] Update PYTHONWARNINGS on tox.ini to reduce meaningless warnings --- tests/conftest.py | 9 --------- tox.ini | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6cb239d9f..9fb06edab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -35,14 +35,6 @@ def pytest_report_header(config): sys.version.split()[0]) -def _filter_warnings(): - def ignore(**kwargs): warnings.filterwarnings('ignore', **kwargs) - - ignore(category=DeprecationWarning, module='site') # virtualenv - ignore(category=PendingDeprecationWarning, module=r'_pytest\..*') - ignore(category=ImportWarning, module='pkgutil') - - def _initialize_test_directory(session): testroot = os.path.join(str(session.config.rootdir), 'tests') tempdir = os.path.abspath(os.getenv('SPHINX_TEST_TEMPDIR', @@ -58,5 +50,4 @@ def _initialize_test_directory(session): def pytest_sessionstart(session): - _filter_warnings() _initialize_test_directory(session) diff --git a/tox.ini b/tox.ini index 2862fd755..810b76f0c 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,7 @@ deps = du13: docutils==0.13.1 du14: docutils==0.14 setenv = - PYTHONWARNINGS = all,ignore::ImportWarning:pkgutil + PYTHONWARNINGS = all,ignore::ImportWarning:pkgutil,ignore::ImportWarning:importlib._bootstrap,ignore::ImportWarning:importlib._bootstrap_external,ignore::ImportWarning:pytest_cov.plugin,ignore::DeprecationWarning:site,ignore::DeprecationWarning:_pytest.assertion.rewrite,ignore::DeprecationWarning:_pytest.fixtures SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= pytest -Wall --durations 25 {posargs} From c1b3efe203752407f37770910da4d082b2b32d52 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 6 Jan 2018 21:01:04 +0900 Subject: [PATCH 0519/1814] Fix mypy violation --- sphinx/ext/autodoc/importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index b22af9ff5..cc68436cd 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -151,7 +151,7 @@ def import_module(modname, warningiserror=False): def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warningiserror=False): - # type: (str, List[unicode], str, Callable[[Any, unicode], Any]) -> Any + # type: (str, List[unicode], str, Callable[[Any, unicode], Any], bool) -> Any if objpath: logger.debug('[autodoc] from %s import %s', modname, '.'.join(objpath)) else: From c2a7984e05943f33e0ce367baad1fc7855baf5f3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 6 Jan 2018 22:10:15 +0900 Subject: [PATCH 0520/1814] Fix enum34 members are treated as inherited member --- sphinx/ext/autodoc/importer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index cc68436cd..101cb930f 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -19,7 +19,7 @@ from types import FunctionType, MethodType, ModuleType from six import PY2 from sphinx.util import logging -from sphinx.util.inspect import safe_getattr +from sphinx.util.inspect import isenumclass, safe_getattr if False: # For type annotation @@ -206,6 +206,12 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None): # the members directly defined in the class obj_dict = attrgetter(subject, '__dict__', {}) + # Py34 doesn't have enum members in __dict__. + if sys.version_info[:2] == (3, 4) and isenumclass(subject): + obj_dict = dict(obj_dict) + for name, value in subject.__members__.items(): + obj_dict[name] = value + members = {} for name in dir(subject): try: From e1d8615ce4bd2e3c68f2361447e4e45bbff65d18 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 7 Jan 2018 00:05:48 +0900 Subject: [PATCH 0521/1814] Don't use add_documenter() in sphinx-autogen --- sphinx/ext/autosummary/generate.py | 32 +++++++++++++++++++----------- tests/test_ext_autosummary.py | 2 +- tests/test_templating.py | 4 ++-- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 2873b6082..cfaa4a4ca 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -31,9 +31,9 @@ from jinja2.sandbox import SandboxedEnvironment from sphinx import __display_version__ from sphinx import package_dir -from sphinx.ext.autodoc import add_documenter from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader +from sphinx.registry import SphinxComponentRegistry from sphinx.util.osutil import ensuredir from sphinx.util.inspect import safe_getattr from sphinx.util.rst import escape as rst_escape @@ -47,20 +47,26 @@ if False: from sphinx.environment import BuildEnvironment # NOQA -def setup_documenters(): +class DummyApplication(object): + """Dummy Application class for sphinx-autogen command.""" + + def __init__(self): + self.registry = SphinxComponentRegistry() + + +def setup_documenters(app): from sphinx.ext.autodoc import ( ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, FunctionDocumenter, MethodDocumenter, AttributeDocumenter, InstanceAttributeDocumenter ) - add_documenter(ModuleDocumenter) - add_documenter(ClassDocumenter) - add_documenter(ExceptionDocumenter) - add_documenter(DataDocumenter) - add_documenter(FunctionDocumenter) - add_documenter(MethodDocumenter) - add_documenter(AttributeDocumenter) - add_documenter(InstanceAttributeDocumenter) + documenters = [ + ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, + FunctionDocumenter, MethodDocumenter, AttributeDocumenter, + InstanceAttributeDocumenter + ] + for documenter in documenters: + app.registry.add_documenter(documenter.objtype, documenter) def _simple_info(msg): @@ -395,12 +401,14 @@ The format of the autosummary directive is documented in the def main(argv=sys.argv[1:]): # type: (List[str]) -> None - setup_documenters() + app = DummyApplication() + setup_documenters(app) args = get_parser().parse_args(argv) generate_autosummary_docs(args.source_file, args.output_dir, '.' + args.suffix, template_dir=args.templates, - imported_members=args.imported_members) + imported_members=args.imported_members, + app=app) if __name__ == '__main__': diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 1035d3b3b..000ee3af4 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -60,9 +60,9 @@ def test_mangle_signature(): def test_get_items_summary(make_app, app_params): import sphinx.ext.autosummary import sphinx.ext.autosummary.generate - sphinx.ext.autosummary.generate.setup_documenters() args, kwargs = app_params app = make_app(*args, **kwargs) + sphinx.ext.autosummary.generate.setup_documenters(app) # monkey-patch Autosummary.get_items so we can easily get access to it's # results.. orig_get_items = sphinx.ext.autosummary.Autosummary.get_items diff --git a/tests/test_templating.py b/tests/test_templating.py index 88a196e77..550b3bc7d 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -15,9 +15,9 @@ from sphinx.ext.autosummary.generate import setup_documenters @pytest.mark.sphinx('html', testroot='templating') def test_layout_overloading(make_app, app_params): - setup_documenters() args, kwargs = app_params app = make_app(*args, **kwargs) + setup_documenters(app) app.builder.build_update() result = (app.outdir / 'contents.html').text(encoding='utf-8') @@ -27,9 +27,9 @@ def test_layout_overloading(make_app, app_params): @pytest.mark.sphinx('html', testroot='templating') def test_autosummary_class_template_overloading(make_app, app_params): - setup_documenters() args, kwargs = app_params app = make_app(*args, **kwargs) + setup_documenters(app) app.builder.build_update() result = (app.outdir / 'generated' / 'sphinx.application.TemplateBridge.html').text( From 356765ee769fb26c07f98b887cff16ededf7ca0b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 7 Jan 2018 00:39:41 +0900 Subject: [PATCH 0522/1814] Fix mypy violation --- sphinx/ext/autosummary/generate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index cfaa4a4ca..aeffcb564 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -51,10 +51,12 @@ class DummyApplication(object): """Dummy Application class for sphinx-autogen command.""" def __init__(self): + # type: () -> None self.registry = SphinxComponentRegistry() def setup_documenters(app): + # type: (Any) -> None from sphinx.ext.autodoc import ( ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, FunctionDocumenter, MethodDocumenter, AttributeDocumenter, @@ -91,7 +93,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', warn=_simple_warn, info=_simple_info, base_path=None, builder=None, template_dir=None, imported_members=False, app=None): - # type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool) -> None # NOQA + # type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool, Any) -> None # NOQA showed_sources = list(sorted(sources)) if len(showed_sources) > 20: From 7162fcdff9d76b6923b01c953e32d3949a767548 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 7 Jan 2018 00:51:45 +0900 Subject: [PATCH 0523/1814] Fix typo --- sphinx/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/application.py b/sphinx/application.py index 07b8539a9..1c97fec15 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -649,7 +649,7 @@ class Sphinx(object): def add_autodoc_attrgetter(self, typ, getter): # type: (Type, Callable[[Any, unicode, Any], Any]) -> None logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter)) - self.registy.add_autodoc_attrgetter(typ, getter) + self.registry.add_autodoc_attrgetter(typ, getter) def add_search_language(self, cls): # type: (Any) -> None From bf29ffb284f74b99adbc64d12b58ef4cef123af6 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 4 Jan 2018 20:13:29 +0100 Subject: [PATCH 0524/1814] #4246: Limit width of text body for all themes --- AUTHORS | 1 + CHANGES | 2 ++ doc/theming.rst | 15 ++++++++++++-- sphinx/jinja2glue.py | 20 +++++++++++++++++++ sphinx/themes/agogo/static/agogo.css_t | 2 +- sphinx/themes/basic/static/basic.css_t | 7 ++++++- sphinx/themes/basic/theme.conf | 2 ++ sphinx/themes/classic/static/classic.css_t | 4 ++-- sphinx/themes/haiku/static/haiku.css_t | 4 ++-- sphinx/themes/haiku/theme.conf | 2 ++ sphinx/themes/nature/static/nature.css_t | 2 +- sphinx/themes/pyramid/static/pyramid.css_t | 4 ++-- sphinx/themes/scrolls/static/scrolls.css_t | 3 ++- sphinx/themes/scrolls/theme.conf | 2 ++ .../themes/sphinxdoc/static/sphinxdoc.css_t | 4 ++-- .../traditional/static/traditional.css_t | 6 ++++-- sphinx/themes/traditional/theme.conf | 4 ++++ 17 files changed, 68 insertions(+), 16 deletions(-) diff --git a/AUTHORS b/AUTHORS index f4ce16164..88627e4cb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -34,6 +34,7 @@ Other contributors, listed alphabetically, are: * Horst Gutmann -- internationalization support * Martin Hans -- autodoc improvements * Doug Hellmann -- graphviz improvements +* Tim Hoffmann -- theme improvements * Timotheus Kampik - JS theme & search enhancements * Dave Kuhlman -- original LaTeX writer * Blaise Laflamme -- pyramid theme diff --git a/CHANGES b/CHANGES index bd6a92728..98fb6aa95 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,8 @@ Incompatible changes * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc * #4226: apidoc: Generate new style makefile (make-mode) * #4274: sphinx-build returns 2 as an exit code on argument error +* #4246: Limit width of text body for all themes. Conifigurable via theme + options ``body_min_width`` and ``body_max_width``. Deprecated ---------- diff --git a/doc/theming.rst b/doc/theming.rst index 34bca9607..32aef20fa 100644 --- a/doc/theming.rst +++ b/doc/theming.rst @@ -114,8 +114,19 @@ These themes are: - **nosidebar** (true or false): Don't include the sidebar. Defaults to ``False``. - - **sidebarwidth** (an integer): Width of the sidebar in pixels. (Do not - include ``px`` in the value.) Defaults to 230 pixels. + - **sidebarwidth** (int or str): Width of the sidebar in pixels. + This can be an int, which is interpreted as pixels or a valid CSS + dimension string such as '70em' or '50%'. Defaults to 230 pixels. + + - **body_min_width** (int or str): Minimal width of the document body. + This can be an int, which is interpreted as pixels or a valid CSS + dimension string such as '70em' or '50%'. Use 0 if you don't want + a width limit. Defaults may depend on the theme (often 450px). + + - **body_max_width** (int or str): Maximal width of the document body. + This can be an int, which is interpreted as pixels or a valid CSS + dimension string such as '70em' or '50%'. Use 'none' if you don't + want a width limit. Defaults may depend on the theme (often 800px). * **alabaster** -- `Alabaster theme`_ is a modified "Kr" Sphinx theme from @kennethreitz (especially as used in his Requests project), which was itself originally based on diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 8839e48fa..e6f49d18d 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -45,6 +45,25 @@ def _toint(val): return 0 +def _todim(val): + # type (int or unicode) -> unicode + """ + Make val a css dimension. In particular the following transformations + are performed: + + - None -> 'initial' (default CSS value) + - 0 -> '0' + - ints and string representations of ints are interpreted as pixels. + + Everything else is returned unchanged. + """ + if val is None: + return 'initial' + elif str(val).isdigit(): + return '0' if int(val) == 0 else '%spx' % val + return val + + def _slice_index(values, slices): # type: (List, int) -> Iterator[List] seq = list(values) @@ -164,6 +183,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader): extensions=extensions) self.environment.filters['tobool'] = _tobool self.environment.filters['toint'] = _toint + self.environment.filters['todim'] = _todim self.environment.filters['slice_index'] = _slice_index self.environment.globals['debug'] = contextfunction(pformat) self.environment.globals['accesskey'] = contextfunction(accesskey) diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t index 0b5bbe16b..153a86778 100644 --- a/sphinx/themes/agogo/static/agogo.css_t +++ b/sphinx/themes/agogo/static/agogo.css_t @@ -269,7 +269,7 @@ div.document ol { /* Sidebar */ div.sidebar { - width: {{ theme_sidebarwidth }}; + width: {{ theme_sidebarwidth|todim }}; float: right; font-size: .9em; } diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 745864e28..68724c38d 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -49,7 +49,7 @@ div.sphinxsidebarwrapper { div.sphinxsidebar { float: left; - width: {{ theme_sidebarwidth|toint }}px; + width: {{ theme_sidebarwidth|todim }}; margin-left: -100%; font-size: 90%; word-wrap: break-word; @@ -199,6 +199,11 @@ table.modindextable td { /* -- general body styles --------------------------------------------------- */ +div.body { + min-width: {{ theme_body_min_width|todim }}; + max-width: {{ theme_body_max_width|todim }}; +} + div.body p, div.body dd, div.body li, div.body blockquote { -moz-hyphens: auto; -ms-hyphens: auto; diff --git a/sphinx/themes/basic/theme.conf b/sphinx/themes/basic/theme.conf index 25495e8c6..df02a5aec 100644 --- a/sphinx/themes/basic/theme.conf +++ b/sphinx/themes/basic/theme.conf @@ -7,4 +7,6 @@ sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html [options] nosidebar = false sidebarwidth = 230 +body_min_width = 450 +body_max_width = 800 navigation_with_keys = False diff --git a/sphinx/themes/classic/static/classic.css_t b/sphinx/themes/classic/static/classic.css_t index a84ef8696..9abdae6f4 100644 --- a/sphinx/themes/classic/static/classic.css_t +++ b/sphinx/themes/classic/static/classic.css_t @@ -32,7 +32,7 @@ div.documentwrapper { } div.bodywrapper { - margin: 0 0 0 {{ theme_sidebarwidth|toint }}px; + margin: 0 0 0 {{ theme_sidebarwidth|todim }}; } div.body { @@ -43,7 +43,7 @@ div.body { {%- if theme_rightsidebar|tobool %} div.bodywrapper { - margin: 0 {{ theme_sidebarwidth|toint }}px 0 0; + margin: 0 {{ theme_sidebarwidth|todim }} 0 0; } {%- endif %} diff --git a/sphinx/themes/haiku/static/haiku.css_t b/sphinx/themes/haiku/static/haiku.css_t index 16d49fea4..cc54b79ff 100644 --- a/sphinx/themes/haiku/static/haiku.css_t +++ b/sphinx/themes/haiku/static/haiku.css_t @@ -34,8 +34,8 @@ body { margin: auto; padding: 0px; font-family: "DejaVu Sans", Arial, Helvetica, sans-serif; - min-width: 59em; - max-width: 70em; + min-width: {{ theme_body_min_width|todim }}; + max-width: {{ theme_body_max_width|todim }}; color: {{ theme_textcolor }}; } diff --git a/sphinx/themes/haiku/theme.conf b/sphinx/themes/haiku/theme.conf index 3537da1d3..4caff3c6f 100644 --- a/sphinx/themes/haiku/theme.conf +++ b/sphinx/themes/haiku/theme.conf @@ -5,6 +5,8 @@ pygments_style = autumn [options] full_logo = false +body_min_width = 59em +body_max_width = 70em textcolor = #333333 headingcolor = #0c3762 linkcolor = #dc3c01 diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t index 5751bf940..ff2a722d8 100644 --- a/sphinx/themes/nature/static/nature.css_t +++ b/sphinx/themes/nature/static/nature.css_t @@ -28,7 +28,7 @@ div.documentwrapper { } div.bodywrapper { - margin: 0 0 0 {{ theme_sidebarwidth|toint }}px; + margin: 0 0 0 {{ theme_sidebarwidth|todim }}; } hr { diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t index 93799111e..db600a57f 100644 --- a/sphinx/themes/pyramid/static/pyramid.css_t +++ b/sphinx/themes/pyramid/static/pyramid.css_t @@ -28,7 +28,7 @@ div.documentwrapper { } div.bodywrapper { - margin: 0 0 0 {{ theme_sidebarwidth }}px; + margin: 0 0 0 {{ theme_sidebarwidth|todim }}; } hr { @@ -92,7 +92,7 @@ div.related a { } div.related ul { - padding-left: {{ theme_sidebarwidth|toint + 10 }}px; + padding-left: calc({{ theme_sidebarwidth|todim }} + 10px); } div.sphinxsidebar { diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t index 3edd869af..154fd9a45 100644 --- a/sphinx/themes/scrolls/static/scrolls.css_t +++ b/sphinx/themes/scrolls/static/scrolls.css_t @@ -98,7 +98,8 @@ h1.heading span { } #contentwrapper { - max-width: 680px; + min-width: {{ theme_body_min_width|todim }}; + max-width: {{ theme_body_max_width|todim }}; padding: 0 18px 20px 18px; margin: 0 auto 0 auto; border-right: 1px solid #eee; diff --git a/sphinx/themes/scrolls/theme.conf b/sphinx/themes/scrolls/theme.conf index 4e7800f90..3956063a9 100644 --- a/sphinx/themes/scrolls/theme.conf +++ b/sphinx/themes/scrolls/theme.conf @@ -4,6 +4,8 @@ stylesheet = scrolls.css pygments_style = tango [options] +body_min_width = 0 +body_max_width = 680 headerbordercolor = #1752b4 subheadlinecolor = #0d306b linkcolor = #1752b4 diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t index 2f4275a6c..540fcad3a 100644 --- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t @@ -38,7 +38,7 @@ div.document { } div.bodywrapper { - margin: 0 {{ theme_sidebarwidth|toint + 10 }}px 0 0; + margin: 0 calc({{ theme_sidebarwidth|todim }} + 10px) 0 0; border-right: 1px solid #ccc; } @@ -88,7 +88,7 @@ div.sphinxsidebarwrapper { div.sphinxsidebar { margin: 0; padding: 0.5em 15px 15px 0; - width: {{ theme_sidebarwidth|toint - 20 }}px; + width: calc({{ theme_sidebarwidth|todim }} - 20px); float: right; font-size: 1em; text-align: left; diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t index e5fda3bab..e36d7e073 100644 --- a/sphinx/themes/traditional/static/traditional.css_t +++ b/sphinx/themes/traditional/static/traditional.css_t @@ -23,10 +23,12 @@ div.documentwrapper { } div.bodywrapper { - margin: 0 {{ theme_sidebarwidth }}px 0 0; + margin: 0 {{ theme_sidebarwidth|todim }} 0 0; } div.body { + min-width: {{ theme_body_min_width|todim }}; + max-width: {{ theme_body_max_width|todim }}; background-color: white; padding: 0 20px 30px 20px; } @@ -40,7 +42,7 @@ div.sphinxsidebarwrapper { div.sphinxsidebar { float: right; margin-left: -100%; - width: {{ theme_sidebarwidth }}px; + width: {{ theme_sidebarwidth|todim }}; } div.clearer { diff --git a/sphinx/themes/traditional/theme.conf b/sphinx/themes/traditional/theme.conf index 02b77833e..acc6bc7e6 100644 --- a/sphinx/themes/traditional/theme.conf +++ b/sphinx/themes/traditional/theme.conf @@ -1,3 +1,7 @@ [theme] inherit = basic stylesheet = traditional.css + +[options] +body_min_width = 0 +body_max_width = none From bbfcb2443d511bf790d4fe62ed01079b074fef4b Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 6 Jan 2018 17:49:27 +0100 Subject: [PATCH 0525/1814] cleanup formatting of some sidebar items --- doc/_templates/indexsidebar.html | 10 ++++---- doc/_themes/sphinx13/static/sphinx13.css | 30 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index 6359921a5..b07ef2033 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -20,12 +20,14 @@ Index, or install it with:{%endtrans%}

{%trans%}Questions? Suggestions?{%endtrans%}

{%trans%}Join the sphinx-users mailing list on Google Groups:{%endtrans%}

+
- - + class="subscribeform"> + +
+

{%trans%}or come to the #sphinx-doc channel on FreeNode.{%endtrans%}

{%trans%}You can also open an issue at the tracker.{%endtrans%}

diff --git a/doc/_themes/sphinx13/static/sphinx13.css b/doc/_themes/sphinx13/static/sphinx13.css index 6bdc5a96c..24a33fba7 100644 --- a/doc/_themes/sphinx13/static/sphinx13.css +++ b/doc/_themes/sphinx13/static/sphinx13.css @@ -140,11 +140,37 @@ div.sphinxsidebar .logo img { vertical-align: middle; } +div.subscribeformwrapper { + display: block; + overflow: auto; + margin-bottom: 1.2em; +} + div.sphinxsidebar input { border: 1px solid #aaa; font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; - font-size: 1em; +} + +div.sphinxsidebar .subscribeform { + margin-top: 0; +} + +div.sphinxsidebar .subscribeform input { + border: 1px solid #aaa; + font-size: 0.9em; + float: left; + padding: 0.25em 0.5em; + box-sizing: border-box; +} + +div.sphinxsidebar .subscribeform input[type="text"] { + width: 60%; +} + +div.sphinxsidebar .subscribeform input[type="submit"] { + width: 40%; + border-left: none; } div.sphinxsidebar h3 { @@ -281,7 +307,7 @@ tt { border: 1px solid #ddd; border-radius: 2px; color: #333; - padding: 1px; + padding: 1px 0.2em; } tt.descname, tt.descclassname, tt.xref { From 1498d1359056a80d474266708e3ff372adb40994 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 6 Jan 2018 19:29:48 +0100 Subject: [PATCH 0526/1814] updates to conf.py generated by sphinx-quickstart --- sphinx/templates/quickstart/conf.py_t | 39 ++++++++++++--------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index c42861c28..a1c00f8c7 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -6,14 +6,11 @@ # {{ project }} documentation build configuration file, created by # sphinx-quickstart on {{ now }}. # -# 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,6 +30,18 @@ sys.path.insert(0, u'{{ module_path }}') {% endif -%} {% endif %} +# -- 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 +69,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. # From 2ae7f26fe531c29cedfa01e2f0c3595a4c680972 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 7 Jan 2018 12:09:41 +0900 Subject: [PATCH 0527/1814] test: Adjust testcase for #3962 --- tests/test_ext_apidoc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_ext_apidoc.py b/tests/test_ext_apidoc.py index 83951bf03..2bfc8016e 100644 --- a/tests/test_ext_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -191,7 +191,7 @@ def test_extension_parsed(make_app, apidoc): @pytest.mark.apidoc( - coderoot='test-apidoc-toc', + coderoot='test-apidoc-toc/mypackage', options=["--implicit-namespaces"], ) def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc): @@ -222,7 +222,7 @@ def test_toc_all_references_should_exist_pep420_enabled(make_app, apidoc): @pytest.mark.apidoc( - coderoot='test-apidoc-toc', + coderoot='test-apidoc-toc/mypackage', ) def test_toc_all_references_should_exist_pep420_disabled(make_app, apidoc): """All references in toc should exist. This test doesn't say if From 2484819e96f6616479d4822374f7d4cdf743e31e Mon Sep 17 00:00:00 2001 From: MURAOKA Yusuke Date: Sun, 7 Jan 2018 20:04:53 +0900 Subject: [PATCH 0528/1814] Fix creating build directory for unknown build target --- sphinx/application.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 9195f11af..b4fef818f 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -157,10 +157,6 @@ class Sphinx(object): # status code for command-line application self.statuscode = 0 - if not path.isdir(outdir): - logger.info('making output directory...') - ensuredir(outdir) - # read config self.tags = Tags(tags) self.config = Config(confdir, CONFIG_FILENAME, @@ -197,6 +193,10 @@ class Sphinx(object): # preload builder module (before init config values) self.preload_builder(buildername) + if not path.isdir(outdir): + logger.info('making output directory...') + ensuredir(outdir) + # the config file itself can be an extension if self.config.setup: self._setting_up_extension = ['conf.py'] From cc3abba171ed37dc3377b047788894733944c4d5 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sun, 7 Jan 2018 09:08:29 -0800 Subject: [PATCH 0529/1814] Prefer https & readthedocs.io instead of readthedocs.org for links Read the Docs moved hosting to readthedocs.io instead of readthedocs.org. Fix all links in the project. For additional details, see: https://blog.readthedocs.com/securing-subdomains/ > Starting today, Read the Docs will start hosting projects from subdomains on > the domain readthedocs.io, instead of on readthedocs.org. This change > addresses some security concerns around site cookies while hosting user > generated data on the same domain as our dashboard. --- EXAMPLES | 4 ++-- doc/_templates/index.html | 6 +++--- doc/develop.rst | 2 +- doc/ext/thirdparty.rst | 2 +- doc/faq.rst | 2 +- doc/intro.rst | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/EXAMPLES b/EXAMPLES index 6bf6d0e31..edbf48903 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -93,7 +93,7 @@ Documentation using the classic theme * simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html (customized) * Sprox: http://sprox.org/ (customized) * SymPy: http://docs.sympy.org/ -* TurboGears: https://turbogears.readthedocs.org/ (customized) +* TurboGears: https://turbogears.readthedocs.io/ (customized) * tvtk: http://docs.enthought.com/mayavi/tvtk/ * Varnish: https://www.varnish-cache.org/docs/ (customized, alabaster for index) * Waf: https://waf.io/apidocs/ @@ -259,7 +259,7 @@ Documentation using sphinx_bootstrap_theme * Bootstrap Theme: https://ryan-roemer.github.io/sphinx-bootstrap-theme/ * C/C++ Software Development with Eclipse: http://eclipsebook.in/ * Dataverse: http://guides.dataverse.org/ -* e-cidadania: http://e-cidadania.readthedocs.org/ +* e-cidadania: https://e-cidadania.readthedocs.io/ * Hangfire: http://docs.hangfire.io/ * Hedge: https://documen.tician.de/hedge/ * ObsPy: https://docs.obspy.org/ diff --git a/doc/_templates/index.html b/doc/_templates/index.html index b4bdb5985..5a8a2f025 100644 --- a/doc/_templates/index.html +++ b/doc/_templates/index.html @@ -74,9 +74,9 @@

{%trans%} You can also download PDF/EPUB versions of the Sphinx documentation: - a PDF version generated from + a PDF version generated from the LaTeX Sphinx produces, and - a EPUB version. + a EPUB version. {%endtrans%}

@@ -106,7 +106,7 @@

{%trans%}Hosting{%endtrans%}

{%trans%}Need a place to host your Sphinx docs? - readthedocs.org hosts a lot of Sphinx docs + readthedocs.org hosts a lot of Sphinx docs already, and integrates well with projects' source control. It also features a powerful built-in search that exceeds the possibilities of Sphinx' JavaScript-based offline search.{%endtrans%}

diff --git a/doc/develop.rst b/doc/develop.rst index 4fc7792f7..19ca81ef9 100644 --- a/doc/develop.rst +++ b/doc/develop.rst @@ -138,7 +138,7 @@ own extensions. .. _cmakedomain: https://bitbucket.org/klorenz/sphinxcontrib-cmakedomain .. _GNU Make: http://www.gnu.org/software/make/ .. _makedomain: https://bitbucket.org/klorenz/sphinxcontrib-makedomain -.. _inlinesyntaxhighlight: http://sphinxcontrib-inlinesyntaxhighlight.readthedocs.org +.. _inlinesyntaxhighlight: https://sphinxcontrib-inlinesyntaxhighlight.readthedocs.io/ .. _CMake: https://cmake.org .. _domaintools: https://bitbucket.org/klorenz/sphinxcontrib-domaintools .. _restbuilder: https://pypi.python.org/pypi/sphinxcontrib-restbuilder diff --git a/doc/ext/thirdparty.rst b/doc/ext/thirdparty.rst index 6304e4af3..40c24246a 100644 --- a/doc/ext/thirdparty.rst +++ b/doc/ext/thirdparty.rst @@ -6,7 +6,7 @@ repository. It is open for anyone who wants to maintain an extension publicly; just send a short message asking for write permissions. There are also several extensions hosted elsewhere. The `Sphinx extension -survey `__ contains a +survey `__ contains a comprehensive list. If you write an extension that you think others will find useful or you think diff --git a/doc/faq.rst b/doc/faq.rst index 1ae9a7792..fe3173749 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -58,7 +58,7 @@ Read the Docs Sphinx. They will host sphinx documentation, along with supporting a number of other features including version support, PDF generation, and more. The `Getting Started - `_ + `_ guide is a good place to start. Epydoc diff --git a/doc/intro.rst b/doc/intro.rst index d3328a5ea..d3b191700 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -17,7 +17,7 @@ docs have a look at `Epydoc `_, which also understands reST. For a great "introduction" to writing docs in general -- the whys and hows, see -also `Write the docs `_, written by Eric +also `Write the docs `_, written by Eric Holscher. .. _rinohtype: https://github.com/brechtm/rinohtype From e015ce2a0fdc7dc2640961d962ea4e153c5ad00c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 09:36:35 +0900 Subject: [PATCH 0530/1814] Update CHANGES for PR #4389 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 040f95e1c..252804ef3 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Incompatible changes * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc * #4226: apidoc: Generate new style makefile (make-mode) * #4274: sphinx-build returns 2 as an exit code on argument error +* #4389: output directory will be created after loading extensions Deprecated ---------- @@ -55,6 +56,7 @@ Features added code-blocks * #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 Features removed From db415ba05c974e13ad36d5a385dbc2b552272651 Mon Sep 17 00:00:00 2001 From: Joel Nothman Date: Mon, 8 Jan 2018 13:09:29 +1100 Subject: [PATCH 0531/1814] Avoid duplicate calls to autodoc-process-docstring (#4198) --- sphinx/ext/autosummary/__init__.py | 2 +- tests/test_ext_autosummary.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 3dded11ff..d4fd80467 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -325,7 +325,7 @@ class Autosummary(Directive): # -- Grab the summary documenter.add_content(None) - doc = list(documenter.process_doc([self.result.data])) + doc = self.result.data while doc and not doc[0].strip(): doc.pop(0) diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 0aea99df6..8624153e2 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -73,6 +73,10 @@ def test_get_items_summary(app, status, warning): def handler(app, what, name, obj, options, lines): assert isinstance(lines, list) + + # ensure no docstring is processed twice: + assert 'THIS HAS BEEN HANDLED' not in lines + lines.append('THIS HAS BEEN HANDLED') app.connect('autodoc-process-docstring', handler) sphinx.ext.autosummary.Autosummary.get_items = new_get_items From b5edde474db6440f77b0e24fac0203a863429aee Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Mon, 8 Jan 2018 11:18:36 +0900 Subject: [PATCH 0532/1814] update CHANGES for #4198 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 252804ef3..d841f2371 100644 --- a/CHANGES +++ b/CHANGES @@ -103,6 +103,8 @@ Bugs fixed one of figures and tables * #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter setting +* #4198: autosummary emits multiple 'autodoc-process-docstring' event. Thanks + to Joel Nothman. Testing -------- From 7ba54500fcedce47f7cbe29732d246cc84fd2462 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 11:59:50 +0900 Subject: [PATCH 0533/1814] Fix #4183: doctest: ``:pyversion:`` option also follows PEP-440 specification --- CHANGES | 7 ++++++- doc/ext/doctest.rst | 18 +++++++++++++++--- setup.py | 1 + sphinx/ext/doctest.py | 39 ++++++++++++++++----------------------- tests/test_ext_doctest.py | 39 +++++++++++++++++++++++++-------------- 5 files changed, 63 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index 252804ef3..0133d40de 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ Release 1.7 (in development) ============================ +Dependencies +------------ + +* Add ``packaging`` package + Incompatible changes -------------------- @@ -57,7 +62,7 @@ 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 - +* #4183: doctest: ``:pyversion:`` option also follows PEP-440 specification Features removed ---------------- 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/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/ext/doctest.py b/sphinx/ext/doctest.py index e0ce050f7..948ddfec8 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 @@ -143,16 +139,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] 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(): From 273f834157a90806e0cd2031e8974c43f9787a6f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 12:19:08 +0900 Subject: [PATCH 0534/1814] Fix #4081: Warnings and errors colored the same when building --- CHANGES | 2 +- sphinx/util/logging.py | 2 +- tests/test_util_logging.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index d841f2371..6227328c4 100644 --- a/CHANGES +++ b/CHANGES @@ -58,7 +58,6 @@ Features added * #4332: Let LaTeX obey :confval:`math_numfig` for equation numbering * #4093: sphinx-build creates empty directories for unknown targets/builders - Features removed ---------------- @@ -105,6 +104,7 @@ Bugs fixed setting * #4198: autosummary emits multiple 'autodoc-process-docstring' event. Thanks to Joel Nothman. +* #4081: Warnings and errors colored the same when building Testing -------- diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index ec81f02d7..04bf91830 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -53,7 +53,7 @@ VERBOSITY_MAP.update({ COLOR_MAP = defaultdict(lambda: 'blue') # type: Dict[int, unicode] COLOR_MAP.update({ logging.ERROR: 'darkred', - logging.WARNING: 'darkred', + logging.WARNING: 'red', logging.DEBUG: 'darkgray', }) diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py index e909c2dcf..48eed82b0 100644 --- a/tests/test_util_logging.py +++ b/tests/test_util_logging.py @@ -183,7 +183,7 @@ def test_warning_location(app, status, warning): assert 'index.txt:10: WARNING: message2' in warning.getvalue() logger.warning('message3', location=None) - assert colorize('darkred', 'WARNING: message3') in warning.getvalue() + assert colorize('red', 'WARNING: message3') in warning.getvalue() node = nodes.Node() node.source, node.line = ('index.txt', 10) @@ -200,7 +200,7 @@ def test_warning_location(app, status, warning): node.source, node.line = (None, None) logger.warning('message7', location=node) - assert colorize('darkred', 'WARNING: message7') in warning.getvalue() + assert colorize('red', 'WARNING: message7') in warning.getvalue() def test_pending_warnings(app, status, warning): @@ -236,7 +236,7 @@ def test_colored_logs(app, status, warning): assert colorize('darkgray', 'message1') in status.getvalue() assert 'message2\n' in status.getvalue() # not colored assert 'message3\n' in status.getvalue() # not colored - assert colorize('darkred', 'WARNING: message4') in warning.getvalue() + assert colorize('red', 'WARNING: message4') in warning.getvalue() assert 'WARNING: message5\n' in warning.getvalue() # not colored assert colorize('darkred', 'WARNING: message6') in warning.getvalue() From 9a6ad38e2d23a7285d15d967e9d1eb5dcd2e2cfb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 14:12:44 +0900 Subject: [PATCH 0535/1814] Rename AutoDirective (and make alias) --- sphinx/ext/autodoc/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 68f78eeb2..4de899384 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1477,7 +1477,7 @@ class InstanceAttributeDocumenter(AttributeDocumenter): AttributeDocumenter.add_content(self, more_content, no_docstring=True) -class AutoDirective(object): +class AutodocRegistry(object): """ A registry of Documenters and attrgetters. @@ -1499,6 +1499,9 @@ class AutoDirective(object): _special_attrgetters = {} # type: Dict[Type, Callable] +AutoDirective = AutodocRegistry # for backward compatibility + + def add_documenter(cls): # type: (Type[Documenter]) -> None """Register a new Documenter.""" From 2c920d7d78f2ff63836e3eff445d41bed569d49f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 14:37:03 +0900 Subject: [PATCH 0536/1814] Fix #1922: Upper characters problem in French HTML Search --- sphinx/search/fr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/search/fr.py b/sphinx/search/fr.py index 2cf70357e..615a47383 100644 --- a/sphinx/search/fr.py +++ b/sphinx/search/fr.py @@ -207,4 +207,4 @@ class SearchFrench(SearchLanguage): self.stemmer = snowballstemmer.stemmer('french') def stem(self, word): - return self.stemmer.stemWord(word) + return self.stemmer.stemWord(word.lower()) From f717f2dd64ed427ba68e08728f6757cf34492777 Mon Sep 17 00:00:00 2001 From: Guillaume Gay Date: Mon, 8 Jan 2018 08:49:22 +0100 Subject: [PATCH 0537/1814] Fixes bug when evaluating entry to bool As reported here: https://github.com/rtfd/readthedocs.org/issues/3411 sphinx sometimes fails with the error: ```python File "/home/docs/checkouts/readthedocs.org/user_builds/drf-yasg/envs/latest/lib/python3.5/site-packages/sphinx/ext/viewcode.py", line 74, in has_tag if entry is None or entry[0] != code: TypeError: 'bool' object is not subscriptable ``` This is not critical as whipping the build or even just running it again fixes it, but the error is confusing... I believe switching the two if statement above should prevent this from happening. --- sphinx/ext/viewcode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 2fd4479f8..3df5b86e2 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -71,12 +71,12 @@ def doctree_read(app, doctree): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code - if entry is None or entry[0] != code: + if entry is False: + return + elif entry is None or entry[0] != code: analyzer.find_tags() entry = code, analyzer.tags, {}, refname env._viewcode_modules[modname] = entry # type: ignore - elif entry is False: - return _, tags, used, _ = entry if fullname in tags: used[fullname] = docname From 6448d9b1536ea03f614cb3cb6a83b7f9bda63039 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 18:03:48 +0900 Subject: [PATCH 0538/1814] Refactor autodoc: Use get_documenters() --- sphinx/ext/autodoc/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 070a7bb2e..386245d20 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -296,9 +296,7 @@ class Documenter(object): def documenters(self): # type: () -> Dict[unicode, Type[Documenter]] """Returns registered Documenter classes""" - classes = dict(AutoDirective._registry) # registered directly - classes.update(self.env.app.registry.documenters) # registered by API - return classes + return get_documenters(self.env.app) def add_line(self, line, source, *lineno): # type: (unicode, unicode, int) -> None From 8ca490f3996a6babc10b69fb4c2af5766c6a1a85 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 19:01:54 +0900 Subject: [PATCH 0539/1814] Fix flake8 violation --- sphinx/ext/autodoc/directive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index d36888f7e..5d17481eb 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -12,7 +12,7 @@ from docutils.parsers.rst import Directive from docutils.statemachine import ViewList from docutils.utils import assemble_option_dict -from sphinx.ext.autodoc import AutoDirective, get_documenters +from sphinx.ext.autodoc import get_documenters from sphinx.util import logging from sphinx.util.docutils import switch_source_input from sphinx.util.nodes import nested_parse_with_titles From f366816968e29ba0783fa493d58d4f0a0a03888e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 20:31:57 +0900 Subject: [PATCH 0540/1814] Fix SphinxStandaloneReader.__init__() method has been duplicated --- sphinx/io.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 416dfde10..66ba8334e 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -86,11 +86,8 @@ class SphinxStandaloneReader(SphinxBaseReader): def __init__(self, app, *args, **kwargs): # type: (Sphinx, Any, Any) -> None self.transforms = self.transforms + app.registry.get_transforms() - SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore - - def __init__(self, app, parsers={}, *args, **kwargs): - SphinxBaseReader.__init__(self, app, parsers, *args, **kwargs) self.smart_quotes = app.env.settings['smart_quotes'] + SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore def get_transforms(self): transforms = SphinxBaseReader.get_transforms(self) From b6b71d99c9df23ce77d247c5295df4bbd7712c43 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 20:32:37 +0900 Subject: [PATCH 0541/1814] Initialize settings.smartquotes_locales --- sphinx/environment/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index fc5ac691a..c04073163 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -67,6 +67,7 @@ default_settings = { 'sectsubtitle_xform': False, 'halt_level': 5, 'file_insertion_enabled': True, + 'smartquotes_locales': [], } # This is increased every time an environment attribute is added From 739022730295c4968ecc212bbb80b03981eeced3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 21:38:18 +0900 Subject: [PATCH 0542/1814] Bump to 1.6.6 final --- CHANGES | 4 ++-- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 80f8c4faa..05c1abdba 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.6.6 (in development) -============================== +Release 1.6.6 (released Jan 08, 2018) +===================================== Dependencies ------------ diff --git a/sphinx/__init__.py b/sphinx/__init__.py index b8a62f9e8..332bfe9a2 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.6+' +__version__ = '1.6.6' __released__ = '1.6.6' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 6, 'beta', 0) +version_info = (1, 6, 6, 'final', 0) package_dir = path.abspath(path.dirname(__file__)) From 562683ea32e687c279c019f9837450ba3d6b54df Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 8 Jan 2018 21:42:09 +0900 Subject: [PATCH 0543/1814] Bump version --- CHANGES | 19 ++++++++++++++----- sphinx/__init__.py | 6 +++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 05c1abdba..00fcb59a7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.6.6 (released Jan 08, 2018) -===================================== +Release 1.6.7 (in development) +============================== Dependencies ------------ @@ -13,6 +13,18 @@ Deprecated Features added -------------- +Bugs fixed +---------- + +Testing +-------- + +Release 1.6.6 (released Jan 08, 2018) +===================================== + +Features added +-------------- + * #4181: autodoc: Sort dictionary keys when possible * ``VerbatimHighlightColor`` is a new :ref:`LaTeX 'sphinxsetup' ` key (refs: #4285) @@ -46,9 +58,6 @@ Bugs fixed * Fix links to external option docs with intersphinx (refs: #3769) * #4091: Private members not documented without :undoc-members: -Testing --------- - Release 1.6.5 (released Oct 23, 2017) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 332bfe9a2..69775059c 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -34,13 +34,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.6.6' -__released__ = '1.6.6' # used when Sphinx builds its own docs +__version__ = '1.6.7+' +__released__ = '1.6.7' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 6, 6, 'final', 0) +version_info = (1, 6, 7, 'beta', 0) package_dir = path.abspath(path.dirname(__file__)) From 84b4882b31b0af34fd67fd15ceb57582d6951c32 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 9 Jan 2018 23:01:55 +0900 Subject: [PATCH 0544/1814] Fix smartquotes has been ignored --- sphinx/environment/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index c04073163..251a88589 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -665,7 +665,7 @@ class BuildEnvironment(object): language = self.config.language or 'en' self.settings['language_code'] = language if 'smart_quotes' not in self.settings: - self.settings['smart_quotes'] = True + self.settings['smart_quotes'] = self.config.smartquotes # some conditions exclude smart quotes, overriding smart_quotes for valname, vallist in iteritems(self.config.smartquotes_excludes): From e77267dd943330aea66eaa09f2cd62ea4eb7cc68 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 9 Jan 2018 22:21:49 +0900 Subject: [PATCH 0545/1814] Add tests for smartquotes --- tests/roots/test-smartquotes/conf.py | 7 ++ tests/roots/test-smartquotes/index.rst | 4 ++ tests/test_smartquotes.py | 92 ++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/roots/test-smartquotes/conf.py create mode 100644 tests/roots/test-smartquotes/index.rst create mode 100644 tests/test_smartquotes.py diff --git a/tests/roots/test-smartquotes/conf.py b/tests/roots/test-smartquotes/conf.py new file mode 100644 index 000000000..31e7a6ed4 --- /dev/null +++ b/tests/roots/test-smartquotes/conf.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' + +latex_documents = [ + (master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report') +] diff --git a/tests/roots/test-smartquotes/index.rst b/tests/roots/test-smartquotes/index.rst new file mode 100644 index 000000000..be0d9b89c --- /dev/null +++ b/tests/roots/test-smartquotes/index.rst @@ -0,0 +1,4 @@ +test-smartquotes +================ + +-- "Sphinx" is a tool that makes it easy ... diff --git a/tests/test_smartquotes.py b/tests/test_smartquotes.py new file mode 100644 index 000000000..f9ea9d726 --- /dev/null +++ b/tests/test_smartquotes.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +""" + test_smartquotes + ~~~~~~~~~~~~~~~~ + + Test smart quotes. + + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import pytest +from sphinx.util import docutils + + +@pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True) +def test_basic(app, status, warning): + app.build() + + content = (app.outdir / 'index.html').text() + assert u'

– “Sphinx†is a tool that makes it easy …

' in content + + +@pytest.mark.sphinx(buildername='text', testroot='smartquotes', freshenv=True) +def test_text_builder(app, status, warning): + app.build() + + content = (app.outdir / 'index.txt').text() + assert u'-- "Sphinx" is a tool that makes it easy ...' in content + + +@pytest.mark.sphinx(buildername='man', testroot='smartquotes', freshenv=True) +def test_man_builder(app, status, warning): + app.build() + + content = (app.outdir / 'python.1').text() + assert u'\\-\\- "Sphinx" is a tool that makes it easy ...' in content + + +@pytest.mark.sphinx(buildername='latex', testroot='smartquotes', freshenv=True) +def test_latex_builder(app, status, warning): + app.build() + + content = (app.outdir / 'test.tex').text() + assert u'\\textendash{} “Sphinx†is a tool that makes it easy …' in content + + +@pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True, + confoverrides={'language': 'ja'}) +def test_ja_html_builder(app, status, warning): + app.build() + + content = (app.outdir / 'index.html').text() + assert u'

-- "Sphinx" is a tool that makes it easy ...

' in content + + +@pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True, + confoverrides={'smartquotes': False}) +def test_smartquotes_disabled(app, status, warning): + app.build() + + content = (app.outdir / 'index.html').text() + assert u'

-- "Sphinx" is a tool that makes it easy ...

' in content + + +@pytest.mark.skipif(docutils.__version_info__ < (0, 14), + reason='docutils-0.14 or above is required') +@pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True, + confoverrides={'smartquotes_action': 'q'}) +def test_smartquotes_action(app, status, warning): + app.build() + + content = (app.outdir / 'index.html').text() + assert u'

-- “Sphinx†is a tool that makes it easy ...

' in content + + +@pytest.mark.sphinx(buildername='html', testroot='smartquotes', freshenv=True, + confoverrides={'language': 'ja', 'smartquotes_excludes': {}}) +def test_smartquotes_excludes_language(app, status, warning): + app.build() + + content = (app.outdir / 'index.html').text() + assert u'

– 「Sphinx〠is a tool that makes it easy …

' in content + + +@pytest.mark.sphinx(buildername='man', testroot='smartquotes', freshenv=True, + confoverrides={'smartquotes_excludes': {}}) +def test_smartquotes_excludes_builders(app, status, warning): + app.build() + + content = (app.outdir / 'python.1').text() + assert u'– “Sphinx†is a tool that makes it easy …' in content From 5ad20e6406e656871918698327b41f71d06900ee Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 10 Jan 2018 21:08:51 +0900 Subject: [PATCH 0546/1814] Allow SphinxTransform on read-phase --- sphinx/io.py | 15 ++++++++++++++- sphinx/transforms/i18n.py | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 66ba8334e..471675e0e 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -19,6 +19,7 @@ from docutils.writers import UnfilteredWriter from six import text_type from typing import Any, Union # NOQA +from sphinx.transforms import SphinxTransformer from sphinx.transforms import ( ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, @@ -56,6 +57,11 @@ class SphinxBaseReader(standalone.Reader): This replaces reporter by Sphinx's on generating document. """ + def __init__(self, app, *args, **kwargs): + # type: (Sphinx, Any, Any) -> None + self.env = app.env + standalone.Reader.__init__(self, *args, **kwargs) + def get_transforms(self): # type: () -> List[Transform] return standalone.Reader.get_transforms(self) + self.transforms @@ -66,9 +72,16 @@ class SphinxBaseReader(standalone.Reader): for logging. """ document = standalone.Reader.new_document(self) + + # substitute transformer + document.transformer = SphinxTransformer(document) + document.transformer.set_environment(self.env) + + # substitute reporter reporter = document.reporter document.reporter = LoggingReporter.from_reporter(reporter) document.reporter.set_source(self.source) + return document @@ -87,7 +100,7 @@ class SphinxStandaloneReader(SphinxBaseReader): # type: (Sphinx, Any, Any) -> None self.transforms = self.transforms + app.registry.get_transforms() self.smart_quotes = app.env.settings['smart_quotes'] - SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore + SphinxBaseReader.__init__(self, app, *args, **kwargs) # type: ignore def get_transforms(self): transforms = SphinxBaseReader.get_transforms(self) diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index 5ae33d86a..db67aae97 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -50,7 +50,7 @@ def publish_msgstr(app, source, source_path, source_line, config, settings): :rtype: docutils.nodes.document """ from sphinx.io import SphinxI18nReader - reader = SphinxI18nReader() + reader = SphinxI18nReader(app) reader.set_lineno_for_reporter(source_line) parser = app.registry.create_source_parser(app, '') doc = reader.read( From 776bd09f434958b8d87a4ebe4824668c9368bdcf Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 10 Jan 2018 21:08:51 +0900 Subject: [PATCH 0547/1814] Merge sphinx_smartquotes_action() to SphinxSmartQuotes class --- sphinx/environment/__init__.py | 27 ++++----------------------- sphinx/transforms/__init__.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 251a88589..578068175 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -19,7 +19,6 @@ import warnings from os import path from copy import copy from collections import defaultdict -from contextlib import contextmanager from six import BytesIO, itervalues, class_types, next, iteritems from six.moves import cPickle as pickle @@ -41,7 +40,7 @@ from sphinx.util.matching import compile_matchers from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError -from sphinx.transforms import SphinxTransformer, SphinxSmartQuotes +from sphinx.transforms import SphinxTransformer from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.environment.adapters.toctree import TocTree @@ -84,22 +83,6 @@ versioning_conditions = { } # type: Dict[unicode, Union[bool, Callable]] -@contextmanager -def sphinx_smartquotes_action(env): - # type: (BuildEnvironment) -> Generator - if not hasattr(SphinxSmartQuotes, 'smartquotes_action'): - # less than docutils-0.14 - yield - else: - # docutils-0.14 or above - try: - original = SphinxSmartQuotes.smartquotes_action - SphinxSmartQuotes.smartquotes_action = env.config.smartquotes_action - yield - finally: - SphinxSmartQuotes.smartquotes_action = original - - class NoUri(Exception): """Raised by get_relative_uri if there is no URI available.""" pass @@ -602,8 +585,7 @@ class BuildEnvironment(object): # remove all inventory entries for that file app.emit('env-purge-doc', self, docname) self.clear_doc(docname) - with sphinx_smartquotes_action(self): - self.read_doc(docname, app) + self.read_doc(docname, app) def _read_parallel(self, docnames, app, nproc): # type: (List[unicode], Sphinx, int) -> None @@ -615,9 +597,8 @@ class BuildEnvironment(object): def read_process(docs): # type: (List[unicode]) -> unicode self.app = app - with sphinx_smartquotes_action(self): - for docname in docs: - self.read_doc(docname, app) + for docname in docs: + self.read_doc(docname, app) # allow pickling self to send it back return BuildEnvironment.dumps(self) diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index acfff6a4d..c2d8d4eb5 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -333,12 +333,21 @@ class SphinxContentsFilter(ContentsFilter): raise nodes.SkipNode -class SphinxSmartQuotes(SmartQuotes): +class SphinxSmartQuotes(SmartQuotes, SphinxTransform): """ Customized SmartQuotes to avoid transform for some extra node types. refs: sphinx.parsers.RSTParser """ + @property + def smartquotes_action(self): + # type: () -> unicode + """A smartquotes_action setting for SmartQuotes. + + Users can change this setting through :confval:`smartquotes_action`. + """ + return self.config.smartquotes_action + def get_tokens(self, txtnodes): # A generator that yields ``(texttype, nodetext)`` tuples for a list # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). From 24a6578e09d1806d5888819abc1651bb3428b521 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 10 Jan 2018 21:08:52 +0900 Subject: [PATCH 0548/1814] Make SphinxSmartQuotes more inteligent --- sphinx/environment/__init__.py | 30 +++++----------------------- sphinx/io.py | 9 +-------- sphinx/transforms/__init__.py | 36 +++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 578068175..17f9667a1 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -20,11 +20,10 @@ from os import path from copy import copy from collections import defaultdict -from six import BytesIO, itervalues, class_types, next, iteritems +from six import BytesIO, itervalues, class_types, next from six.moves import cPickle as pickle -from docutils.utils import Reporter, get_source_line, normalize_language_tag -from docutils.utils.smartquotes import smartchars +from docutils.utils import Reporter, get_source_line from docutils.frontend import OptionParser from sphinx import addnodes, versioning @@ -643,29 +642,10 @@ class BuildEnvironment(object): self.config.trim_footnote_reference_space self.settings['gettext_compact'] = self.config.gettext_compact - language = self.config.language or 'en' - self.settings['language_code'] = language - if 'smart_quotes' not in self.settings: - self.settings['smart_quotes'] = self.config.smartquotes + self.settings['language_code'] = self.config.language or 'en' - # some conditions exclude smart quotes, overriding smart_quotes - for valname, vallist in iteritems(self.config.smartquotes_excludes): - if valname == 'builders': - # this will work only for checking first build target - if self.app.builder.name in vallist: - self.settings['smart_quotes'] = False - break - elif valname == 'languages': - if self.config.language in vallist: - self.settings['smart_quotes'] = False - break - - # confirm selected language supports smart_quotes or not - for tag in normalize_language_tag(language): - if tag in smartchars.quotes: - break - else: - self.settings['smart_quotes'] = False + # Allow to disable by 3rd party extension (workaround) + self.settings.setdefault('smart_quotes', True) def read_doc(self, docname, app=None): # type: (unicode, Sphinx) -> None diff --git a/sphinx/io.py b/sphinx/io.py index 471675e0e..61761f697 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -93,21 +93,14 @@ class SphinxStandaloneReader(SphinxBaseReader): Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, - RefOnlyBulletListTransform, UnreferencedFootnotesDetector + RefOnlyBulletListTransform, UnreferencedFootnotesDetector, SphinxSmartQuotes, ] # type: List[Transform] def __init__(self, app, *args, **kwargs): # type: (Sphinx, Any, Any) -> None self.transforms = self.transforms + app.registry.get_transforms() - self.smart_quotes = app.env.settings['smart_quotes'] SphinxBaseReader.__init__(self, app, *args, **kwargs) # type: ignore - def get_transforms(self): - transforms = SphinxBaseReader.get_transforms(self) - if self.smart_quotes: - transforms.append(SphinxSmartQuotes) - return transforms - class SphinxI18nReader(SphinxBaseReader): """ diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index c2d8d4eb5..4e8c6f0bd 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -12,8 +12,9 @@ from docutils import nodes from docutils.transforms import Transform, Transformer from docutils.transforms.parts import ContentsFilter -from docutils.utils import new_document from docutils.transforms.universal import SmartQuotes +from docutils.utils import new_document, normalize_language_tag +from docutils.utils.smartquotes import smartchars from sphinx import addnodes from sphinx.locale import _ @@ -339,6 +340,39 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform): refs: sphinx.parsers.RSTParser """ + def apply(self): + # type: () -> None + if not self.is_available(): + return + + SmartQuotes.apply(self) + + def is_available(self): + # type: () -> bool + builders = self.config.smartquotes_excludes.get('builders', []) + languages = self.config.smartquotes_excludes.get('languages', []) + + if self.document.settings.smart_quotes is False: + # disabled by 3rd party extension (workaround) + return False + elif self.config.smartquotes is False: + # disabled by confval smartquotes + return False + elif self.app.builder.name in builders: + # disabled by confval smartquotes_excludes['builders'] + return False + elif self.config.language in languages: + # disabled by confval smartquotes_excludes['languages'] + return False + + # confirm selected language supports smart_quotes or not + language = self.env.settings['language_code'] + for tag in normalize_language_tag(language): + if tag in smartchars.quotes: + return True + else: + return False + @property def smartquotes_action(self): # type: () -> unicode From 33fd1f446ab0041ae53d42fa7ed5e7b4aa18d74b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 10 Jan 2018 21:35:21 +0900 Subject: [PATCH 0549/1814] latex: Do not display Release label if :confval:`release` is not set --- CHANGES | 1 + sphinx/writers/latex.py | 2 +- tests/test_build_latex.py | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index d9350d21a..b3e6283fd 100644 --- a/CHANGES +++ b/CHANGES @@ -113,6 +113,7 @@ 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 -------- diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index de472b36c..6c86e6174 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'), }) 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): From 90f7c7ef3fd18b5ceff5eef1361f5f71f68209ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Beaupr=C3=A9?= Date: Thu, 11 Jan 2018 13:20:26 -0500 Subject: [PATCH 0550/1814] add link to manpages in HTML builder It is useful to have the HTML documentation builder actually link to real rendered versions of HTML manpages in its output. That way people can click on manpages to get the full documentation. There are a few services offering this online, so we do not explicitly enable one by default, but the Debian manpages repository has a lot of the manpages pre-rendered, so it is used as an example in the documentation. The parsing work is done by a transformer class that parses manpage objects and extract name/section elements. Those then can be used by writers to cross-reference to actual sites. An implementation is done in the two HTML writers, but could also apply to ePUB/PDF writers as well in the future. This is not enabled by default: the `manpages_url` configuration item needs to be enabled to point to the chosen site. The `page`, `section` and `path` parameters are expanded through Python string formatting in the URL on output. Unit tests are fairly limited, but should cover most common use-cases. --- doc/config.rst | 18 ++++++++++++++++++ doc/markup/inline.rst | 3 ++- sphinx/config.py | 1 + sphinx/io.py | 6 +++--- sphinx/transforms/__init__.py | 20 ++++++++++++++++++++ sphinx/writers/html.py | 6 ++++++ sphinx/writers/html5.py | 6 ++++++ tests/roots/test-manpage_url/conf.py | 5 +++++ tests/roots/test-manpage_url/index.rst | 3 +++ tests/test_build_html.py | 13 +++++++++++++ 10 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 tests/roots/test-manpage_url/conf.py create mode 100644 tests/roots/test-manpage_url/index.rst diff --git a/doc/config.rst b/doc/config.rst index 9bdd283a9..587d5785b 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 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/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/io.py b/sphinx/io.py index 66ba8334e..3c32c167c 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -23,7 +23,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 ( @@ -80,7 +80,7 @@ class SphinxStandaloneReader(SphinxBaseReader): Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, - RefOnlyBulletListTransform, UnreferencedFootnotesDetector + RefOnlyBulletListTransform, UnreferencedFootnotesDetector, ManpageLink ] # type: List[Transform] def __init__(self, app, *args, **kwargs): @@ -110,7 +110,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/transforms/__init__.py b/sphinx/transforms/__init__.py index acfff6a4d..ceb8de364 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 @@ -348,3 +350,21 @@ class SphinxSmartQuotes(SmartQuotes): 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/writers/html.py b/sphinx/writers/html.py index b3d27e31a..84e7bfbc9 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 @@ -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..50bf2ea8c 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 @@ -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/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/test_build_html.py b/tests/test_build_html.py index 8265c8471..153ff5165 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -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) From a83e8bab7d03d209f76cc92ffe29a9b89289cf6f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 20:45:02 +0000 Subject: [PATCH 0551/1814] builders: Add 'Builder.epilog' option This allows builders to emit a final epilog message containing information such as where resulting files can be found. This is only emitted if the build was successful. This allows us to remove this content from the 'make_mode' tool and the legacy 'Makefile' and 'make.bat' templates. There's room for more dramatic simplification of the former, but this will come later. Signed-off-by: Stephen Finucane --- doc/extdev/builderapi.rst | 1 + sphinx/application.py | 7 +++ sphinx/builders/__init__.py | 5 +++ sphinx/builders/applehelp.py | 4 ++ sphinx/builders/changes.py | 1 + sphinx/builders/devhelp.py | 4 ++ sphinx/builders/dummy.py | 2 + sphinx/builders/epub3.py | 1 + sphinx/builders/gettext.py | 1 + sphinx/builders/html.py | 12 ++++- sphinx/builders/htmlhelp.py | 2 + sphinx/builders/latex.py | 6 +++ sphinx/builders/linkcheck.py | 2 + sphinx/builders/manpage.py | 2 + sphinx/builders/qthelp.py | 5 +++ sphinx/builders/texinfo.py | 7 +++ sphinx/builders/text.py | 2 + sphinx/builders/xml.py | 4 ++ sphinx/ext/coverage.py | 6 ++- sphinx/ext/doctest.py | 2 + sphinx/make_mode.py | 61 -------------------------- sphinx/templates/quickstart/Makefile_t | 61 -------------------------- sphinx/templates/quickstart/make.bat_t | 50 --------------------- 23 files changed, 73 insertions(+), 175 deletions(-) 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/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..a7ecd0e68 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -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 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/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..b104cfc08 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -278,6 +278,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/make_mode.py b/sphinx/make_mode.py index 0bc1a797d..64268c2ec 100644 --- a/sphinx/make_mode.py +++ b/sphinx/make_mode.py @@ -101,95 +101,60 @@ class Make(object): # 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): @@ -210,19 +175,12 @@ class Make(object): # 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): @@ -237,33 +195,22 @@ 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): @@ -271,26 +218,18 @@ class Make(object): 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..77ce4afe8 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -52,82 +52,46 @@ clean: .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: @@ -160,22 +124,14 @@ xelatexpdf: .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: @@ -187,49 +143,32 @@ 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." diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 230977488..94d28461b 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -78,85 +78,60 @@ if errorlevel 9009 ( 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 ) @@ -183,91 +158,66 @@ if "%1" == "latexpdfja" ( 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 ) From 221dffda3c00f5abf64057e350959d123c50ccac Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 20:45:24 +0000 Subject: [PATCH 0552/1814] make_mode: Remove unnecessary 'make_*' functions These are handled by the default case. Signed-off-by: Stephen Finucane --- sphinx/make_mode.py | 107 -------------------------------------------- 1 file changed, 107 deletions(-) diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py index 64268c2ec..4b325160f 100644 --- a/sphinx/make_mode.py +++ b/sphinx/make_mode.py @@ -97,66 +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 - return 0 - - def build_dirhtml(self): - # type: () -> int - if self.run_generic_build('dirhtml') > 0: - return 1 - return 0 - - def build_singlehtml(self): - # type: () -> int - if self.run_generic_build('singlehtml') > 0: - return 1 - return 0 - - def build_pickle(self): - # type: () -> int - if self.run_generic_build('pickle') > 0: - return 1 - return 0 - - def build_json(self): - # type: () -> int - if self.run_generic_build('json') > 0: - return 1 - return 0 - - def build_htmlhelp(self): - # type: () -> int - if self.run_generic_build('htmlhelp') > 0: - return 1 - return 0 - - def build_qthelp(self): - # type: () -> int - if self.run_generic_build('qthelp') > 0: - return 1 - return 0 - - def build_devhelp(self): - # type: () -> int - if self.run_generic_build('devhelp') > 0: - return 1 - return 0 - - def build_epub(self): - # type: () -> int - if self.run_generic_build('epub') > 0: - return 1 - return 0 - - def build_latex(self): - # type: () -> int - if self.run_generic_build('latex') > 0: - return 1 - return 0 - def build_latexpdf(self): # type: () -> int if self.run_generic_build('latex') > 0: @@ -171,18 +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 - return 0 - - def build_texinfo(self): - # type: () -> int - if self.run_generic_build('texinfo') > 0: - return 1 - return 0 - def build_info(self): # type: () -> int if self.run_generic_build('texinfo') > 0: @@ -197,41 +125,6 @@ class Make(object): return 1 return 0 - def build_changes(self): - # type: () -> int - if self.run_generic_build('changes') > 0: - return 1 - return 0 - - def build_linkcheck(self): - # type: () -> int - res = self.run_generic_build('linkcheck') - return res - - def build_doctest(self): - # type: () -> int - res = self.run_generic_build('doctest') - return res - - def build_coverage(self): - # type: () -> int - if self.run_generic_build('coverage') > 0: - print("Has the coverage extension been enabled?") - return 1 - return 0 - - def build_xml(self): - # type: () -> int - if self.run_generic_build('xml') > 0: - return 1 - return 0 - - def build_pseudoxml(self): - # type: () -> int - if self.run_generic_build('pseudoxml') > 0: - return 1 - return 0 - def run_generic_build(self, builder, doctreedir=None): # type: (unicode, unicode) -> int # compatibility with old Makefile From aa2c5c906566076d3c52c684070b57950b65c7b9 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 20:45:27 +0000 Subject: [PATCH 0553/1814] Makefile: Remove unnecessary targets Most of these are not necessary now that we're not printing different messages for various builders. Signed-off-by: Stephen Finucane --- sphinx/templates/quickstart/Makefile_t | 92 ++------------------------ 1 file changed, 7 insertions(+), 85 deletions(-) diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 77ce4afe8..70925c471 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -10,9 +10,10 @@ 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) {{ rsrcdir }} # the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }} +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) {{ rsrcdir }} .PHONY: help help: @@ -49,50 +50,6 @@ help: clean: rm -rf $(BUILDDIR)/* -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - .PHONY: latexpdf latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @@ -121,18 +78,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 - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @@ -144,31 +89,8 @@ info: gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - -.PHONY: dummy -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy +# Catch-all target: route all unknown targets to Sphinx +.PHONY: Makefile +%: Makefile + $(SPHINXBUILD) -b "$@" $(ALLSPHINXOPTS) "$(BUILDDIR)/$@" From 6f9a262f45a6c7f297bf0c6c4b8a642d0bb8f02a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 20:45:43 +0000 Subject: [PATCH 0554/1814] make.bat: Remove unnecessary targets As with the Makefile previously, these are not necessary now that we're not printing anything different for various builders. Signed-off-by: Stephen Finucane --- sphinx/templates/quickstart/make.bat_t | 123 +------------------------ 1 file changed, 2 insertions(+), 121 deletions(-) diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 94d28461b..4af8fb8c2 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -50,7 +50,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,67 +73,6 @@ if errorlevel 9009 ( :sphinx_ok - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - goto end -) - if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex @@ -155,71 +93,14 @@ if "%1" == "latexpdfja" ( goto end ) -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - goto end -) - if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 goto end ) -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - goto end -) - -if "%1" == "dummy" ( - %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy - if errorlevel 1 exit /b 1 - goto end -) +%SPHINXBUILD% -b %1 %ALLSPHINXOPTS% %BUILDDIR%/%1 +goto end :end popd From f6a045d1714f122d9579f6bd71d0599b8a6d7acb Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 20:45:50 +0000 Subject: [PATCH 0555/1814] Makefile: Make SOURCEDIR configurable It's unlikely that anyone will need to do this but at least give them the opportunity. Signed-off-by: Stephen Finucane --- sphinx/templates/quickstart/Makefile_t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t index 70925c471..bf752404e 100644 --- a/sphinx/templates/quickstart/Makefile_t +++ b/sphinx/templates/quickstart/Makefile_t @@ -5,15 +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 # $(O) is meant as a shortcut for $(SPHINXOPTS) -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) {{ rsrcdir }} +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) $(O) {{ rsrcdir }} +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR) .PHONY: help help: From b16fd2ce0191ada6158b87faf1473bd00315ec3d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Dec 2017 21:00:38 +0000 Subject: [PATCH 0556/1814] make.bat: Make SOURCEDIR configurable It's unlikely that anyone will need to do this but at least give them the opportunity. Signed-off-by: Stephen Finucane --- sphinx/templates/quickstart/make.bat_t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 4af8fb8c2..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% From 32aa664bdf892817f876a9689d7c31da168cf393 Mon Sep 17 00:00:00 2001 From: deoren Date: Thu, 11 Jan 2018 15:19:04 -0600 Subject: [PATCH 0557/1814] Small label/comma fix --- doc/intro.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 `_. From 8f2d4bae86164456a32c68d4dda70b84bd26b303 Mon Sep 17 00:00:00 2001 From: jfbu Date: Fri, 12 Jan 2018 12:53:07 +0100 Subject: [PATCH 0558/1814] Eliminate comma from PDF header when project has no release number --- sphinx/texinputs/sphinx.sty | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 2b41673db..19d0a2e2d 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,29 @@ % \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{\py@release}{\releasename\space\version} +\newcommand{\version}{}% part of \py@release, used by title page and headers +% these two are not used and not documented: \newcommand{\shortversion}{} +\newcommand{\setshortversion}[1]{\renewcommand{\shortversion}{#1}} +% this one is not documented, but used in sphinxmanual.cls and 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}}% not used +% 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 From b1c100ca3b038f930bb55853c96ee29c782d2015 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 24 Oct 2017 13:26:32 +0300 Subject: [PATCH 0559/1814] autodoc: make full reference for classes, aliased with "alias of" We do this here only if class belongs to the different module. Closes sphinx-doc/sphinx#2437 --- CHANGES | 2 ++ sphinx/ext/autodoc.py | 8 +++++++- tests/roots/test-ext-autodoc/autodoc_dummy_bar.py | 5 +++++ tests/roots/test-ext-autodoc/bug2437/__init__.py | 0 .../test-ext-autodoc/bug2437/autodoc_dummy_foo.py | 3 +++ tests/roots/test-ext-autodoc/conf.py | 2 ++ tests/roots/test-ext-autodoc/contents.rst | 6 ++++++ tests/test_ext_autodoc.py | 10 ++++++++++ 8 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/roots/test-ext-autodoc/autodoc_dummy_bar.py create mode 100644 tests/roots/test-ext-autodoc/bug2437/__init__.py create mode 100644 tests/roots/test-ext-autodoc/bug2437/autodoc_dummy_foo.py diff --git a/CHANGES b/CHANGES index 00fcb59a7..829243356 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,8 @@ Features added Bugs fixed ---------- +* #2437: make full reference for classes, aliased with "alias of" + Testing -------- diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index bd686644c..1ccd74647 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -1513,8 +1513,14 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: def add_content(self, more_content, no_docstring=False): # type: (Any, bool) -> None if self.doc_as_attr: - classname = safe_getattr(self.object, '__name__', None) + classname = safe_getattr(self.object, '__qualname__', None) + if not classname: + classname = safe_getattr(self.object, '__name__', None) if classname: + module = safe_getattr(self.object, '__module__', None) + parentmodule = safe_getattr(self.parent, '__module__', None) + if module and module != parentmodule: + classname = str(module) + u'.' + str(classname) content = ViewList( [_('alias of :class:`%s`') % classname], source='') ModuleLevelDocumenter.add_content(self, content, diff --git a/tests/roots/test-ext-autodoc/autodoc_dummy_bar.py b/tests/roots/test-ext-autodoc/autodoc_dummy_bar.py new file mode 100644 index 000000000..d79d1691f --- /dev/null +++ b/tests/roots/test-ext-autodoc/autodoc_dummy_bar.py @@ -0,0 +1,5 @@ +from bug2437.autodoc_dummy_foo import Foo + +class Bar(object): + """Dummy class Bar with alias.""" + my_name = Foo diff --git a/tests/roots/test-ext-autodoc/bug2437/__init__.py b/tests/roots/test-ext-autodoc/bug2437/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-ext-autodoc/bug2437/autodoc_dummy_foo.py b/tests/roots/test-ext-autodoc/bug2437/autodoc_dummy_foo.py new file mode 100644 index 000000000..b578a2255 --- /dev/null +++ b/tests/roots/test-ext-autodoc/bug2437/autodoc_dummy_foo.py @@ -0,0 +1,3 @@ +class Foo(object): + """Dummy class Foo.""" + pass diff --git a/tests/roots/test-ext-autodoc/conf.py b/tests/roots/test-ext-autodoc/conf.py index 01e6dcc75..9f026eb8d 100644 --- a/tests/roots/test-ext-autodoc/conf.py +++ b/tests/roots/test-ext-autodoc/conf.py @@ -10,3 +10,5 @@ source_suffix = '.rst' autodoc_mock_imports = [ 'dummy' ] + +nitpicky = True diff --git a/tests/roots/test-ext-autodoc/contents.rst b/tests/roots/test-ext-autodoc/contents.rst index b808eafda..ce4302204 100644 --- a/tests/roots/test-ext-autodoc/contents.rst +++ b/tests/roots/test-ext-autodoc/contents.rst @@ -1,3 +1,9 @@ .. automodule:: autodoc_dummy_module :members: + +.. automodule:: bug2437.autodoc_dummy_foo + :members: + +.. automodule:: autodoc_dummy_bar + :members: diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index e7057df0f..7a9666792 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -22,3 +22,13 @@ def test_autodoc(app, status, warning): assert isinstance(content[3], addnodes.desc) assert content[3][0].astext() == 'autodoc_dummy_module.test' assert content[3][1].astext() == 'Dummy function using dummy.*' + + # issue sphinx-doc/sphinx#2437 + assert content[11][-1].astext() == """Dummy class Bar with alias. + + + +my_name + +alias of bug2437.autodoc_dummy_foo.Foo""" + assert warning.getvalue() == '' From 12a8d5c0bdd4c5c784846e76b20dc5b596802be5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 11:09:27 +0900 Subject: [PATCH 0560/1814] doc: make looks understandable --- doc/ext/inheritance.rst | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst index 87bfd9eef..0062a8afa 100644 --- a/doc/ext/inheritance.rst +++ b/doc/ext/inheritance.rst @@ -74,9 +74,8 @@ It adds this directive: If you have specified a module in the inheritance diagram like this:: - .. inheritance-diagram:: - dummy.test - :top-classes: dummy.test.B, dummy.test.C + .. 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 @@ -86,11 +85,8 @@ It adds this directive: 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 + .. 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. From 7292386a03bc23f1dc31da3606af5268d949efe1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 11:23:33 +0900 Subject: [PATCH 0561/1814] Fix #3570: autodoc: Do not display typing. module for type hints --- CHANGES | 1 + sphinx/util/inspect.py | 14 +++++++++++--- tests/test_util_inspect.py | 12 ++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index cbecd1df1..9f1684579 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,7 @@ Features added * #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. +* #3570: autodoc: Do not display 'typing.' module for type hints Features removed ---------------- 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/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() From 2324dee1432b757abe106851484356e4703d4005 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 14:29:54 +0900 Subject: [PATCH 0562/1814] Update CHANGES for PR #4235 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 19c56f35c..9a435bfd4 100644 --- a/CHANGES +++ b/CHANGES @@ -73,6 +73,7 @@ Features added * 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 Features removed ---------------- From 9c1bbf19488f6bd9c1261b87fcc0a10002d642a4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 15:44:56 +0900 Subject: [PATCH 0563/1814] Fix jobs_argument() should accept string as an argument --- sphinx/cmdline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 310760d24..c2668065d 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -85,7 +85,7 @@ def handle_exception(app, args, exception, stderr=sys.stderr): def jobs_argument(value): - # type (int, str) -> int + # type: (str) -> int """ Special type to handle 'auto' flags passed to 'sphinx-build' via -j flag. Can be expanded to handle other special scaling requests, such as setting job count @@ -94,7 +94,7 @@ def jobs_argument(value): if value == 'auto': return multiprocessing.cpu_count() else: - return value + return int(value) def get_parser(): From 840b5828e752f4d19d2c569ea4299dcc17c506e3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 15:50:26 +0900 Subject: [PATCH 0564/1814] docs: Add ``-j auto`` option --- doc/man/sphinx-build.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/man/sphinx-build.rst b/doc/man/sphinx-build.rst index 46f213989..fdd0d36c2 100644 --- a/doc/man/sphinx-build.rst +++ b/doc/man/sphinx-build.rst @@ -143,11 +143,15 @@ Options Distribute the build over *N* processes in parallel, to make building on multiprocessor machines more effective. Note that not all parts and not all - builders of Sphinx can be parallelized. + builders of Sphinx can be parallelized. If ``auto`` argument is given, + Sphinx uses the number of CPUs as *N*. .. versionadded:: 1.2 This option should be considered *experimental*. + .. versionchanged:: 1.7 + Support ``auto`` argument. + .. option:: -c path Don't look for the :file:`conf.py` in the source directory, but use the given From f8dec554476c17510208e0fe08956b759cc76d9c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 15:53:15 +0900 Subject: [PATCH 0565/1814] Update docstring --- sphinx/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index c2668065d..365238607 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -89,7 +89,7 @@ def jobs_argument(value): """ Special type to handle 'auto' flags passed to 'sphinx-build' via -j flag. Can be expanded to handle other special scaling requests, such as setting job count - to (cpu_count / 2) + to cpu_count. """ if value == 'auto': return multiprocessing.cpu_count() From f2bc93859aea6e076420e8e7696cba1c42e8af06 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sat, 13 Jan 2018 08:53:16 +0100 Subject: [PATCH 0566/1814] Remove unused and undocumented LaTeX macro ``\shortversion`` --- CHANGES | 2 ++ sphinx/texinputs/sphinx.sty | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index b3e6283fd..a769e7211 100644 --- a/CHANGES +++ b/CHANGES @@ -95,6 +95,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 diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 19d0a2e2d..075ae408b 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1403,12 +1403,9 @@ % \newcommand{\py@release}{\releasename\space\version} \newcommand{\version}{}% part of \py@release, used by title page and headers -% these two are not used and not documented: -\newcommand{\shortversion}{} -\newcommand{\setshortversion}[1]{\renewcommand{\shortversion}{#1}} -% this one is not documented, but used in sphinxmanual.cls and sphinxhowto.cls +% \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls) \newcommand{\releaseinfo}{} -\newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}}% not used +\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 From db361c385156e9ae3b0bd91b6ed3f8524011c22d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 18:42:48 +0900 Subject: [PATCH 0567/1814] Update CHANGES for PR #4354 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c76b3f1d9..fbb607b2a 100644 --- a/CHANGES +++ b/CHANGES @@ -75,6 +75,8 @@ Features added * #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 Features removed ---------------- From f57634a8b8f6f656266b2a967cc3e5626ba70659 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 19:08:23 +0900 Subject: [PATCH 0568/1814] Fix mark up --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index fbb607b2a..2c05a81fa 100644 --- a/CHANGES +++ b/CHANGES @@ -75,8 +75,8 @@ Features added * #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 +* #4354: sphinx-build now emits finish message. Builders can modify it through + ``Builder.epilog`` attribute Features removed ---------------- From 4d040abafb9e0626dcf7a420bbe32cbfa0896df6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 15:18:09 +0900 Subject: [PATCH 0569/1814] Fix #4079: Add notranslate class to let Google Translate know they are not translatable --- CHANGES | 2 ++ sphinx/ext/jsmath.py | 6 +++--- sphinx/ext/mathjax.py | 4 ++-- sphinx/writers/html.py | 6 +++--- sphinx/writers/html5.py | 6 +++--- tests/test_build_html.py | 16 ++++++++-------- tests/test_build_html5.py | 16 ++++++++-------- tests/test_ext_intersphinx.py | 3 ++- tests/test_ext_math.py | 18 +++++++++--------- tests/test_markup.py | 11 ++++++----- 10 files changed, 46 insertions(+), 42 deletions(-) diff --git a/CHANGES b/CHANGES index 2c05a81fa..eb91109a5 100644 --- a/CHANGES +++ b/CHANGES @@ -77,6 +77,8 @@ Features added * #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 +* #4079: html: Add ``notranslate`` class to each code-blocks, literals and maths + to let Google Translate know they are not translatable Features removed ---------------- 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/writers/html.py b/sphinx/writers/html.py index 84e7bfbc9..16fc69bea 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -444,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 @@ -494,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): diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 50bf2ea8c..c2810a898 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -390,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 @@ -440,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): diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 153ff5165..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': [ 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_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"}}', ), From fa51a637a82d3cdd0ae58933013414347c341e93 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 21:00:13 +0900 Subject: [PATCH 0570/1814] shebang line is removed from generated conf.py (refs: #4385) --- CHANGES | 1 + sphinx/templates/quickstart/conf.py_t | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 2c05a81fa..a74447a48 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ 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 Deprecated ---------- diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index a1c00f8c7..2583b9891 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -1,6 +1,3 @@ -{% if PY3 -%} -#!/usr/bin/env python3 -{% endif -%} # -*- coding: utf-8 -*- # # {{ project }} documentation build configuration file, created by From 3663275755ac5e79cce72573d9cea5be88c29ae2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 21:42:18 +0900 Subject: [PATCH 0571/1814] Update CHANGES for PR #4245 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index a74447a48..8096e7d55 100644 --- a/CHANGES +++ b/CHANGES @@ -78,6 +78,7 @@ Features added * #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 Features removed ---------------- From 87b03bf76fa40d2e3f85ce781dd97727cdd0b5ce Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 13 Jan 2018 15:52:50 +0100 Subject: [PATCH 0572/1814] minor conf.py cleanup --- sphinx/templates/quickstart/conf.py_t | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t index 2583b9891..2f3f71b1e 100644 --- a/sphinx/templates/quickstart/conf.py_t +++ b/sphinx/templates/quickstart/conf.py_t @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- # -# {{ project }} documentation build configuration file, created by -# sphinx-quickstart on {{ now }}. +# Configuration file for the Sphinx documentation builder. # # 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 ----------------------------------------------------------- +# -- 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 @@ -27,7 +26,7 @@ sys.path.insert(0, u'{{ module_path }}') {% endif -%} {% endif %} -# -- Project information -------------------------------------------------- +# -- Project information ----------------------------------------------------- project = u'{{ project_str }}' copyright = u'{{ copyright_str }}' @@ -39,7 +38,7 @@ version = u'{{ version_str }}' release = u'{{ release_str }}' -# -- General configuration ------------------------------------------------ +# -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # @@ -82,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. @@ -111,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'). @@ -146,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). @@ -156,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, @@ -169,7 +168,7 @@ texinfo_documents = [ {%- if epub %} -# -- Options for Epub output ---------------------------------------------- +# -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project @@ -192,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 From ac200ecf7cfd1854fe4ce2e937c13f405ec65d19 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 13 Jan 2018 18:27:08 +0900 Subject: [PATCH 0573/1814] Update CHANGES --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 39733a6d8..b91062f68 100644 --- a/CHANGES +++ b/CHANGES @@ -75,6 +75,8 @@ Features added * #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 +* #4271: sphinx-build supports an option called ``-j auto`` to adjust numbers of + processes automatically. Features removed ---------------- From c24dffc5a8e67e87fb6ad79120427f19e5103cf3 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Thu, 11 Jan 2018 20:53:35 +0100 Subject: [PATCH 0574/1814] autodoc: only mock specified modules with their descendants Do not mock the ancestors of the specified modules in autodoc_mock_imports. Only mock the modules themselves and their descendants (as specified in the docs). Fix the test configs accordingly. Signed-off-by: Robin Jarry --- sphinx/ext/autodoc/importer.py | 17 ++++++----------- .../roots/test-root/autodoc_missing_imports.py | 4 ++++ tests/roots/test-root/conf.py | 7 ++++--- 3 files changed, 14 insertions(+), 14 deletions(-) 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/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 From 8b74d93ad9c6b6f7dfe129c2481dd1676562b75e Mon Sep 17 00:00:00 2001 From: jfbu Date: Wed, 3 May 2017 23:52:29 +0200 Subject: [PATCH 0575/1814] Remove unneeded coding from LaTeXTranslator.visit_figure() --- sphinx/writers/latex.py | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 6c86e6174..74b1c52a6 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1853,28 +1853,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 From c399357f38a081cf5f75e98c9627b80928a1c035 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 31 Oct 2017 22:59:01 +0900 Subject: [PATCH 0576/1814] Show a notice if both tabularcolumns and :widths: are given (refs: #4196) --- doc/markup/misc.rst | 5 +++++ sphinx/writers/latex.py | 3 +++ 2 files changed, 8 insertions(+) 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/sphinx/writers/latex.py b/sphinx/writers/latex.py index 6c86e6174..4741de92b 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -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): From 0d61b251c5a6d55eb8a0ce6977e72078664e0a06 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 14 Jan 2018 23:10:04 +0900 Subject: [PATCH 0577/1814] Update CHANGES for PR #4413 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index fe964bb2e..41d512023 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,9 @@ Incompatible changes * 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. Deprecated ---------- From de023f2dc0972fc398975c5614caf89149a2de16 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 14 Jan 2018 23:31:30 +0900 Subject: [PATCH 0578/1814] Fix #3620: html theme: move DOCUMENTATION_OPTIONS to independent JavaScript file (refs: #3620) --- CHANGES | 2 ++ sphinx/themes/basic/documentation_options.js_t | 9 +++++++++ sphinx/themes/basic/layout.html | 12 +----------- 3 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 sphinx/themes/basic/documentation_options.js_t diff --git a/CHANGES b/CHANGES index 41d512023..26849effa 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,8 @@ Incompatible changes * #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 ---------- 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 050de15df..dc05e980d 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -87,17 +87,7 @@ {%- endmacro %} {%- macro script() %} - + {%- for scriptfile in script_files %} {%- endfor %} From eebf9d0a0ecf7fa5bac9da8a6808c38047ca882a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 12 Oct 2017 22:57:20 +0900 Subject: [PATCH 0579/1814] Fix #4137: doctest: Make doctest and testcode blocks highlighted --- CHANGES | 2 ++ sphinx/ext/doctest.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 26849effa..924773f76 100644 --- a/CHANGES +++ b/CHANGES @@ -86,6 +86,8 @@ Features added * #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 Features removed ---------------- diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 1a1c05998..cd35e789a 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -116,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'] = {} From 18dfe37f8c64fe43ff6b7aa0e4f42f0d9d7e9e7c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 00:37:32 +0900 Subject: [PATCH 0580/1814] Enable text_add_secnumbers by default (refs: #4218) --- CHANGES | 4 ++-- doc/config.rst | 2 +- sphinx/builders/text.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 69764b902..e15890e32 100644 --- a/CHANGES +++ b/CHANGES @@ -88,8 +88,8 @@ Features added 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: Add new config values :confval:`text_add_secnumbers` and - :confval:`text_secnumber_suffix` +* #3998: text: Assign section numbers by default. You can control it using + :confval:`text_add_secnumbers` and :confval:`text_secnumber_suffix` Features removed ---------------- diff --git a/doc/config.rst b/doc/config.rst index 56d673d29..830fb69a0 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -2042,7 +2042,7 @@ These options influence text output. .. confval:: text_add_secnumbers A boolean that decides whether section numbers are included in text output. - Default is ``False``. + Default is ``True``. .. versionadded:: 1.7 diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index e894f9936..babb6ccee 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -97,7 +97,7 @@ 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', False, 'env') + app.add_config_value('text_add_secnumbers', True, 'env') app.add_config_value('text_secnumber_suffix', '. ', 'env') return { From dc3d03da1bb826e822f90f502d2b7aca6a41ef6f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 01:01:13 +0900 Subject: [PATCH 0581/1814] test: Fix broken testcases --- tests/test_build_text.py | 53 ++++++++++++++++++------------------ tests/test_intl.py | 58 ++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 56 deletions(-) diff --git a/tests/test_build_text.py b/tests/test_build_text.py index 353925466..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 @@ -114,32 +114,6 @@ def test_list_items_in_admonition(app, status, warning): @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] == "* 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 - - app.config.text_add_secnumbers = True app.builder.build_all() contents = (app.outdir / 'contents.txt').text(encoding='utf8') lines = contents.splitlines() @@ -191,3 +165,28 @@ def test_secnums(app, status, warning): ) 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_intl.py b/tests/test_intl.py index cb13b00f3..0923aa4f8 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -143,8 +143,8 @@ def test_text_warning_node(app): app.build() # test warnings in translation result = (app.outdir / 'warnings.txt').text(encoding='utf-8') - expect = (u"I18N WITH REST WARNINGS" - u"\n***********************\n" + expect = (u"3. I18N WITH REST WARNINGS" + u"\n**************************\n" u"\nLINE OF >>``< Date: Mon, 15 Jan 2018 01:11:58 +0900 Subject: [PATCH 0582/1814] Fix mypy violation --- sphinx/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/io.py b/sphinx/io.py index 61761f697..39d653a19 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -99,7 +99,7 @@ class SphinxStandaloneReader(SphinxBaseReader): def __init__(self, app, *args, **kwargs): # type: (Sphinx, Any, Any) -> None self.transforms = self.transforms + app.registry.get_transforms() - SphinxBaseReader.__init__(self, app, *args, **kwargs) # type: ignore + SphinxBaseReader.__init__(self, app, *args, **kwargs) class SphinxI18nReader(SphinxBaseReader): From 2398bc9f7752bcd429f49340af80196133091547 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 10:12:53 +0900 Subject: [PATCH 0583/1814] Update CHANGES for PR #4396 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 00fcb59a7..184a2b7a9 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,9 @@ Features added Bugs fixed ---------- +* #1922: html search: Upper characters problem in French + + Testing -------- From 4420b43e5a0b5d372c69b2927ec2ceadc1ad1093 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 14 Jan 2018 22:02:53 +0000 Subject: [PATCH 0584/1814] tox: Ignore distutils deprecation warning distutils/__init__.py:4: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses import imp Signed-off-by: Stephen Finucane --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 810b76f0c..45bc438b2 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,7 @@ deps = du13: docutils==0.13.1 du14: docutils==0.14 setenv = - PYTHONWARNINGS = all,ignore::ImportWarning:pkgutil,ignore::ImportWarning:importlib._bootstrap,ignore::ImportWarning:importlib._bootstrap_external,ignore::ImportWarning:pytest_cov.plugin,ignore::DeprecationWarning:site,ignore::DeprecationWarning:_pytest.assertion.rewrite,ignore::DeprecationWarning:_pytest.fixtures + PYTHONWARNINGS = all,ignore::ImportWarning:pkgutil,ignore::ImportWarning:importlib._bootstrap,ignore::ImportWarning:importlib._bootstrap_external,ignore::ImportWarning:pytest_cov.plugin,ignore::DeprecationWarning:site,ignore::DeprecationWarning:_pytest.assertion.rewrite,ignore::DeprecationWarning:_pytest.fixtures,ignore::DeprecationWarning:distutils SPHINX_TEST_TEMPDIR = {envdir}/testbuild commands= pytest -Wall --durations 25 {posargs} From 2c06826ae8bcda97d29201eb9306a5ae397a4703 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 21:02:49 +0900 Subject: [PATCH 0585/1814] Remove duplicated transform entry --- sphinx/io.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sphinx/io.py b/sphinx/io.py index 6943a78d0..0bf03751b 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -92,9 +92,8 @@ class SphinxStandaloneReader(SphinxBaseReader): transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, - RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, - RefOnlyBulletListTransform, UnreferencedFootnotesDetector, SphinxSmartQuotes, - ManpageLink + RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform, + UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink ] # type: List[Transform] def __init__(self, app, *args, **kwargs): From 68e403a67b6d895fe45c3ef1f5f42e2289c15d63 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 21:03:37 +0900 Subject: [PATCH 0586/1814] Process smart_quotes for translated text too --- sphinx/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/io.py b/sphinx/io.py index 0bf03751b..7044ab3c0 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -116,7 +116,7 @@ class SphinxI18nReader(SphinxBaseReader): DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, AutoNumbering, SortIds, RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform, - UnreferencedFootnotesDetector, ManpageLink] + UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink] def set_lineno_for_reporter(self, lineno): # type: (int) -> None From f85ee252af4590d559a1c4963d053f1a679fc3a8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 22:10:01 +0900 Subject: [PATCH 0587/1814] Update message catalog --- sphinx/locale/sphinx.pot | 373 ++++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 177 deletions(-) diff --git a/sphinx/locale/sphinx.pot b/sphinx/locale/sphinx.pot index 51f2e13a5..f52cc7852 100644 --- a/sphinx/locale/sphinx.pot +++ b/sphinx/locale/sphinx.pot @@ -1,23 +1,23 @@ # Translations template for Sphinx. -# Copyright (C) 2017 ORGANIZATION +# Copyright (C) 2018 ORGANIZATION # This file is distributed under the same license as the Sphinx project. -# FIRST AUTHOR , 2017. +# FIRST AUTHOR , 2018. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Sphinx 1.6.2\n" +"Project-Id-Version: Sphinx 1.7\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-05-25 11:17+0900\n" +"POT-Creation-Date: 2018-01-15 21:58+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.4.0\n" +"Generated-By: Babel 2.5.1\n" -#: sphinx/application.py:181 +#: sphinx/application.py:177 #, python-format msgid "" "This project needs at least Sphinx v%s and therefore cannot be built with" @@ -57,103 +57,106 @@ msgstr "" msgid "No builder selected, using default: html" msgstr "" -#: sphinx/application.py:341 +#: sphinx/application.py:334 msgid "succeeded" msgstr "" -#: sphinx/application.py:341 +#: sphinx/application.py:334 msgid "finished with problems" msgstr "" -#: sphinx/application.py:343 +#: sphinx/application.py:336 #, python-format -msgid "build %s, %s warning%s." +msgid "build %s, %s warning." msgstr "" -#: sphinx/application.py:347 +#: sphinx/application.py:340 #, python-format msgid "build %s." msgstr "" -#: sphinx/application.py:506 +#: sphinx/application.py:461 #, python-format msgid "Config value %r already present" msgstr "" -#: sphinx/application.py:518 -#, python-format -msgid "Change of translator for the %s builder." -msgstr "" - -#: sphinx/application.py:526 +#: sphinx/application.py:480 #, python-format msgid "" "while setting up extension %s: node class %r is already registered, its " "visitors will be overridden" msgstr "" -#: sphinx/application.py:535 +#: sphinx/application.py:489 #, python-format msgid "Value for key %r must be a (visit, depart) function tuple" msgstr "" -#: sphinx/application.py:582 +#: sphinx/application.py:529 #, python-format msgid "" "while setting up extension %s: directive %r is already registered, it " "will be overridden" msgstr "" -#: sphinx/application.py:593 sphinx/application.py:605 +#: sphinx/application.py:540 sphinx/application.py:552 #, python-format msgid "" "while setting up extension %s: role %r is already registered, it will be " "overridden" msgstr "" -#: sphinx/config.py:127 +#: sphinx/application.py:699 +#, python-format +msgid "" +"the %s extension does not declare if it is safe for parallel %sing, " +"assuming it isn't - please ask the extension author to check and make it " +"explicit" +msgstr "" + +#: sphinx/config.py:133 #, python-format msgid "Section %s" msgstr "" -#: sphinx/config.py:128 +#: sphinx/config.py:134 #, python-format msgid "Fig. %s" msgstr "" -#: sphinx/config.py:129 +#: sphinx/config.py:135 #, python-format msgid "Table %s" msgstr "" -#: sphinx/config.py:130 +#: sphinx/config.py:136 #, python-format msgid "Listing %s" msgstr "" -#: sphinx/config.py:236 +#: sphinx/config.py:249 #, python-format msgid "" "cannot override dictionary config setting %r, ignoring (use %r to set " "individual elements)" msgstr "" -#: sphinx/config.py:245 +#: sphinx/config.py:258 #, python-format msgid "invalid number %r for config value %r, ignoring" msgstr "" -#: sphinx/config.py:250 +#: sphinx/config.py:263 #, python-format msgid "cannot override config setting %r with unsupported type, ignoring" msgstr "" -#: sphinx/config.py:280 +#: sphinx/config.py:293 #, python-format msgid "unknown config value %r in override, ignoring" msgstr "" -#: sphinx/config.py:299 +#: sphinx/config.py:313 #, python-format msgid "No such config value: %s" msgstr "" @@ -182,85 +185,105 @@ msgid "" "cannot be built with the loaded version (%s)." msgstr "" -#: sphinx/registry.py:56 +#: sphinx/registry.py:73 #, python-format msgid "Builder class %s has no \"name\" attribute" msgstr "" -#: sphinx/registry.py:58 +#: sphinx/registry.py:75 #, python-format msgid "Builder %r already exists (in module %s)" msgstr "" -#: sphinx/registry.py:72 +#: sphinx/registry.py:89 #, python-format msgid "Builder name %s not registered or available through entry point" msgstr "" -#: sphinx/registry.py:80 +#: sphinx/registry.py:97 #, python-format msgid "Builder name %s not registered" msgstr "" -#: sphinx/registry.py:87 +#: sphinx/registry.py:105 #, python-format msgid "domain %s already registered" msgstr "" -#: sphinx/registry.py:102 sphinx/registry.py:112 sphinx/registry.py:119 -#: sphinx/registry.py:125 +#: sphinx/registry.py:130 sphinx/registry.py:142 sphinx/registry.py:150 +#: sphinx/registry.py:158 #, python-format msgid "domain %s not yet registered" msgstr "" -#: sphinx/registry.py:104 +#: sphinx/registry.py:132 #, python-format msgid "new domain not a subclass of registered %s domain" msgstr "" -#: sphinx/registry.py:160 +#: sphinx/registry.py:204 #, python-format msgid "source_parser for %r is already registered" msgstr "" -#: sphinx/registry.py:187 +#: sphinx/registry.py:217 +#, python-format +msgid "Source parser for %s not registered" +msgstr "" + +#: sphinx/registry.py:238 +#, python-format +msgid "source_input for %r is already registered" +msgstr "" + +#: sphinx/registry.py:253 +#, python-format +msgid "source_input for %s not registered" +msgstr "" + +#: sphinx/registry.py:259 +#, python-format +msgid "Change of translator for the %s builder." +msgstr "" + +#: sphinx/registry.py:304 #, python-format msgid "" "the extension %r was already merged with Sphinx since version %s; this " "extension is ignored." msgstr "" -#: sphinx/registry.py:198 +#: sphinx/registry.py:315 msgid "Original exception:\n" msgstr "" -#: sphinx/registry.py:199 +#: sphinx/registry.py:316 #, python-format msgid "Could not import extension %s" msgstr "" -#: sphinx/registry.py:202 +#: sphinx/registry.py:319 #, python-format msgid "" "extension %r has no setup() function; is it really a Sphinx extension " "module?" msgstr "" -#: sphinx/registry.py:211 +#: sphinx/registry.py:328 #, python-format msgid "" "The %s extension used by this project needs at least Sphinx v%s; it " "therefore cannot be built with this version." msgstr "" -#: sphinx/registry.py:221 +#: sphinx/registry.py:338 #, python-format msgid "" "extension %r returned an unsupported object from its setup() function; it" " should return None or a metadata dictionary" msgstr "" -#: sphinx/roles.py:200 +#: sphinx/roles.py:202 #, python-format msgid "Python Enhancement Proposals; PEP %s" msgstr "" @@ -285,64 +308,64 @@ msgstr "" msgid "setting %s.%s occurs in none of the searched theme configs" msgstr "" -#: sphinx/theming.py:237 +#: sphinx/theming.py:238 #, python-format msgid "Theme extension %r does not respond correctly." msgstr "" -#: sphinx/theming.py:264 +#: sphinx/theming.py:265 #, python-format msgid "file %r on theme path is not a valid zipfile or contains no theme" msgstr "" -#: sphinx/theming.py:280 +#: sphinx/theming.py:281 msgid "" "sphinx_rtd_theme is no longer a hard dependency since version 1.4.0. " "Please install it manually.(pip install sphinx_rtd_theme)" msgstr "" -#: sphinx/theming.py:284 +#: sphinx/theming.py:285 #, python-format msgid "no theme named %r found (missing theme.conf?)" msgstr "" -#: sphinx/builders/changes.py:86 +#: sphinx/builders/changes.py:85 msgid "Builtins" msgstr "" -#: sphinx/builders/changes.py:88 +#: sphinx/builders/changes.py:87 msgid "Module level" msgstr "" -#: sphinx/builders/html.py:397 sphinx/transforms/__init__.py:122 -#: sphinx/writers/latex.py:561 sphinx/writers/manpage.py:110 +#: sphinx/builders/html.py:399 sphinx/transforms/__init__.py:126 +#: sphinx/writers/latex.py:583 sphinx/writers/manpage.py:110 #: sphinx/writers/texinfo.py:241 #, python-format msgid "%b %d, %Y" msgstr "" -#: sphinx/builders/html.py:415 sphinx/themes/basic/defindex.html:30 +#: sphinx/builders/html.py:417 sphinx/themes/basic/defindex.html:30 msgid "General Index" msgstr "" -#: sphinx/builders/html.py:415 +#: sphinx/builders/html.py:417 msgid "index" msgstr "" -#: sphinx/builders/html.py:479 +#: sphinx/builders/html.py:481 msgid "next" msgstr "" -#: sphinx/builders/html.py:488 +#: sphinx/builders/html.py:490 msgid "previous" msgstr "" -#: sphinx/builders/html.py:1351 +#: sphinx/builders/html.py:1386 #, python-format msgid "%s %s documentation" msgstr "" -#: sphinx/builders/latex.py:199 sphinx/builders/texinfo.py:217 +#: sphinx/builders/latex.py:205 sphinx/builders/texinfo.py:224 msgid " (in " msgstr "" @@ -402,17 +425,17 @@ msgstr "" msgid "Author: " msgstr "" -#: sphinx/domains/__init__.py:315 +#: sphinx/domains/__init__.py:334 #, python-format msgid "%s %s" msgstr "" -#: sphinx/domains/c.py:65 sphinx/domains/cpp.py:4436 +#: sphinx/domains/c.py:65 sphinx/domains/cpp.py:5441 #: sphinx/domains/python.py:177 msgid "Parameters" msgstr "" -#: sphinx/domains/c.py:68 sphinx/domains/cpp.py:4445 +#: sphinx/domains/c.py:68 sphinx/domains/cpp.py:5450 #: sphinx/domains/javascript.py:210 sphinx/domains/python.py:189 msgid "Returns" msgstr "" @@ -447,12 +470,12 @@ msgstr "" msgid "%s (C variable)" msgstr "" -#: sphinx/domains/c.py:257 sphinx/domains/cpp.py:4820 -#: sphinx/domains/javascript.py:299 sphinx/domains/python.py:696 +#: sphinx/domains/c.py:257 sphinx/domains/cpp.py:5864 +#: sphinx/domains/javascript.py:299 sphinx/domains/python.py:706 msgid "function" msgstr "" -#: sphinx/domains/c.py:258 sphinx/domains/cpp.py:4821 +#: sphinx/domains/c.py:258 sphinx/domains/cpp.py:5865 msgid "member" msgstr "" @@ -460,7 +483,7 @@ msgstr "" msgid "macro" msgstr "" -#: sphinx/domains/c.py:260 sphinx/domains/cpp.py:4822 +#: sphinx/domains/c.py:260 sphinx/domains/cpp.py:5866 msgid "type" msgstr "" @@ -468,72 +491,72 @@ msgstr "" msgid "variable" msgstr "" -#: sphinx/domains/cpp.py:4439 +#: sphinx/domains/cpp.py:5444 msgid "Template Parameters" msgstr "" -#: sphinx/domains/cpp.py:4442 sphinx/domains/javascript.py:207 +#: sphinx/domains/cpp.py:5447 sphinx/domains/javascript.py:207 msgid "Throws" msgstr "" -#: sphinx/domains/cpp.py:4607 +#: sphinx/domains/cpp.py:5629 #, python-format msgid "%s (C++ type)" msgstr "" -#: sphinx/domains/cpp.py:4617 +#: sphinx/domains/cpp.py:5639 #, python-format msgid "%s (C++ concept)" msgstr "" -#: sphinx/domains/cpp.py:4627 +#: sphinx/domains/cpp.py:5649 #, python-format msgid "%s (C++ member)" msgstr "" -#: sphinx/domains/cpp.py:4637 +#: sphinx/domains/cpp.py:5659 #, python-format msgid "%s (C++ function)" msgstr "" -#: sphinx/domains/cpp.py:4647 +#: sphinx/domains/cpp.py:5669 #, python-format msgid "%s (C++ class)" msgstr "" -#: sphinx/domains/cpp.py:4657 +#: sphinx/domains/cpp.py:5679 #, python-format msgid "%s (C++ enum)" msgstr "" -#: sphinx/domains/cpp.py:4677 +#: sphinx/domains/cpp.py:5699 #, python-format msgid "%s (C++ enumerator)" msgstr "" -#: sphinx/domains/cpp.py:4819 sphinx/domains/javascript.py:301 -#: sphinx/domains/python.py:698 +#: sphinx/domains/cpp.py:5863 sphinx/domains/javascript.py:301 +#: sphinx/domains/python.py:708 msgid "class" msgstr "" -#: sphinx/domains/cpp.py:4823 +#: sphinx/domains/cpp.py:5867 msgid "concept" msgstr "" -#: sphinx/domains/cpp.py:4824 +#: sphinx/domains/cpp.py:5868 msgid "enum" msgstr "" -#: sphinx/domains/cpp.py:4825 +#: sphinx/domains/cpp.py:5869 msgid "enumerator" msgstr "" -#: sphinx/domains/javascript.py:131 sphinx/domains/python.py:386 +#: sphinx/domains/javascript.py:131 sphinx/domains/python.py:396 #, python-format msgid "%s() (built-in function)" msgstr "" -#: sphinx/domains/javascript.py:132 sphinx/domains/python.py:451 +#: sphinx/domains/javascript.py:132 sphinx/domains/python.py:461 #, python-format msgid "%s() (%s method)" msgstr "" @@ -548,7 +571,7 @@ msgstr "" msgid "%s (global variable or constant)" msgstr "" -#: sphinx/domains/javascript.py:138 sphinx/domains/python.py:489 +#: sphinx/domains/javascript.py:138 sphinx/domains/python.py:499 #, python-format msgid "%s (%s attribute)" msgstr "" @@ -557,24 +580,24 @@ msgstr "" msgid "Arguments" msgstr "" -#: sphinx/domains/javascript.py:266 sphinx/domains/python.py:566 +#: sphinx/domains/javascript.py:266 sphinx/domains/python.py:576 #, python-format msgid "%s (module)" msgstr "" -#: sphinx/domains/javascript.py:300 sphinx/domains/python.py:700 +#: sphinx/domains/javascript.py:300 sphinx/domains/python.py:710 msgid "method" msgstr "" -#: sphinx/domains/javascript.py:302 sphinx/domains/python.py:697 +#: sphinx/domains/javascript.py:302 sphinx/domains/python.py:707 msgid "data" msgstr "" -#: sphinx/domains/javascript.py:303 sphinx/domains/python.py:703 +#: sphinx/domains/javascript.py:303 sphinx/domains/python.py:713 msgid "attribute" msgstr "" -#: sphinx/domains/javascript.py:304 sphinx/domains/python.py:704 +#: sphinx/domains/javascript.py:304 sphinx/domains/python.py:714 #: sphinx/locale/__init__.py:218 msgid "module" msgstr "" @@ -587,87 +610,87 @@ msgstr "" msgid "Raises" msgstr "" -#: sphinx/domains/python.py:387 sphinx/domains/python.py:445 -#: sphinx/domains/python.py:457 sphinx/domains/python.py:470 +#: sphinx/domains/python.py:397 sphinx/domains/python.py:455 +#: sphinx/domains/python.py:467 sphinx/domains/python.py:480 #, python-format msgid "%s() (in module %s)" msgstr "" -#: sphinx/domains/python.py:390 +#: sphinx/domains/python.py:400 #, python-format msgid "%s (built-in variable)" msgstr "" -#: sphinx/domains/python.py:391 sphinx/domains/python.py:483 +#: sphinx/domains/python.py:401 sphinx/domains/python.py:493 #, python-format msgid "%s (in module %s)" msgstr "" -#: sphinx/domains/python.py:411 +#: sphinx/domains/python.py:421 #, python-format msgid "%s (built-in class)" msgstr "" -#: sphinx/domains/python.py:412 +#: sphinx/domains/python.py:422 #, python-format msgid "%s (class in %s)" msgstr "" -#: sphinx/domains/python.py:449 +#: sphinx/domains/python.py:459 #, python-format msgid "%s() (%s.%s method)" msgstr "" -#: sphinx/domains/python.py:461 +#: sphinx/domains/python.py:471 #, python-format msgid "%s() (%s.%s static method)" msgstr "" -#: sphinx/domains/python.py:464 +#: sphinx/domains/python.py:474 #, python-format msgid "%s() (%s static method)" msgstr "" -#: sphinx/domains/python.py:474 +#: sphinx/domains/python.py:484 #, python-format msgid "%s() (%s.%s class method)" msgstr "" -#: sphinx/domains/python.py:477 +#: sphinx/domains/python.py:487 #, python-format msgid "%s() (%s class method)" msgstr "" -#: sphinx/domains/python.py:487 +#: sphinx/domains/python.py:497 #, python-format msgid "%s (%s.%s attribute)" msgstr "" -#: sphinx/domains/python.py:625 +#: sphinx/domains/python.py:635 msgid "Python Module Index" msgstr "" -#: sphinx/domains/python.py:626 +#: sphinx/domains/python.py:636 msgid "modules" msgstr "" -#: sphinx/domains/python.py:674 +#: sphinx/domains/python.py:684 msgid "Deprecated" msgstr "" -#: sphinx/domains/python.py:699 sphinx/locale/__init__.py:222 +#: sphinx/domains/python.py:709 sphinx/locale/__init__.py:222 msgid "exception" msgstr "" -#: sphinx/domains/python.py:701 +#: sphinx/domains/python.py:711 msgid "class method" msgstr "" -#: sphinx/domains/python.py:702 +#: sphinx/domains/python.py:712 msgid "static method" msgstr "" -#: sphinx/domains/python.py:874 +#: sphinx/domains/python.py:884 msgid " (deprecated)" msgstr "" @@ -728,8 +751,8 @@ msgstr "" #: sphinx/themes/basic/genindex-split.html:11 #: sphinx/themes/basic/genindex-split.html:14 #: sphinx/themes/basic/genindex.html:30 sphinx/themes/basic/genindex.html:33 -#: sphinx/themes/basic/genindex.html:66 sphinx/themes/basic/layout.html:149 -#: sphinx/writers/latex.py:545 sphinx/writers/texinfo.py:517 +#: sphinx/themes/basic/genindex.html:66 sphinx/themes/basic/layout.html:147 +#: sphinx/writers/latex.py:550 sphinx/writers/texinfo.py:517 msgid "Index" msgstr "" @@ -741,14 +764,6 @@ msgstr "" msgid "Search Page" msgstr "" -#: sphinx/environment/__init__.py:569 -#, python-format -msgid "" -"the %s extension does not declare if it is safe for parallel reading, " -"assuming it isn't - please ask the extension author to check and make it " -"explicit" -msgstr "" - #: sphinx/environment/adapters/indexentries.py:85 #, python-format msgid "see %s" @@ -763,16 +778,6 @@ msgstr "" msgid "Symbols" msgstr "" -#: sphinx/ext/autodoc.py:1459 -#, python-format -msgid "Bases: %s" -msgstr "" - -#: sphinx/ext/autodoc.py:1514 -#, python-format -msgid "alias of :class:`%s`" -msgstr "" - #: sphinx/ext/doctest.py:134 #, python-format msgid "missing '+' or '-' in '%s' option." @@ -783,7 +788,7 @@ msgstr "" msgid "'%s' is not a valid option." msgstr "" -#: sphinx/ext/doctest.py:155 +#: sphinx/ext/doctest.py:152 #, python-format msgid "'%s' is not a valid pyversion option" msgstr "" @@ -833,12 +838,12 @@ msgstr "" msgid "graphviz_output_format must be one of 'png', 'svg', but is %r" msgstr "" -#: sphinx/ext/graphviz.py:336 sphinx/ext/graphviz.py:345 +#: sphinx/ext/graphviz.py:338 sphinx/ext/graphviz.py:347 #, python-format msgid "[graph: %s]" msgstr "" -#: sphinx/ext/graphviz.py:338 sphinx/ext/graphviz.py:347 +#: sphinx/ext/graphviz.py:340 sphinx/ext/graphviz.py:349 msgid "[graph]" msgstr "" @@ -857,11 +862,11 @@ msgid "" "%s" msgstr "" -#: sphinx/ext/imgmath.py:274 sphinx/ext/jsmath.py:39 sphinx/ext/mathjax.py:40 +#: sphinx/ext/imgmath.py:339 sphinx/ext/jsmath.py:41 sphinx/ext/mathjax.py:42 msgid "Permalink to this equation" msgstr "" -#: sphinx/ext/intersphinx.py:319 +#: sphinx/ext/intersphinx.py:320 #, python-format msgid "(in %s v%s)" msgstr "" @@ -870,7 +875,7 @@ msgstr "" msgid "[source]" msgstr "" -#: sphinx/ext/mathbase.py:106 +#: sphinx/ext/mathbase.py:123 #, python-format msgid "duplicate label of equation %s, other instance in %s" msgstr "" @@ -879,40 +884,50 @@ msgstr "" msgid "Todo" msgstr "" -#: sphinx/ext/todo.py:149 +#: sphinx/ext/todo.py:154 msgid "<>" msgstr "" -#: sphinx/ext/todo.py:152 +#: sphinx/ext/todo.py:157 #, python-format msgid "(The <> is located in %s, line %d.)" msgstr "" -#: sphinx/ext/todo.py:161 +#: sphinx/ext/todo.py:166 msgid "original entry" msgstr "" -#: sphinx/ext/viewcode.py:179 +#: sphinx/ext/viewcode.py:180 msgid "[docs]" msgstr "" -#: sphinx/ext/viewcode.py:193 +#: sphinx/ext/viewcode.py:194 msgid "Module code" msgstr "" -#: sphinx/ext/viewcode.py:199 +#: sphinx/ext/viewcode.py:200 #, python-format msgid "

Source code for %s

" msgstr "" -#: sphinx/ext/viewcode.py:225 +#: sphinx/ext/viewcode.py:226 msgid "Overview: module code" msgstr "" -#: sphinx/ext/viewcode.py:226 +#: sphinx/ext/viewcode.py:227 msgid "

All modules for which code is available

" msgstr "" +#: sphinx/ext/autodoc/__init__.py:1109 +#, python-format +msgid "Bases: %s" +msgstr "" + +#: sphinx/ext/autodoc/__init__.py:1164 +#, python-format +msgid "alias of :class:`%s`" +msgstr "" + #: sphinx/ext/napoleon/__init__.py:320 msgid "Keyword Arguments" msgstr "" @@ -992,7 +1007,7 @@ msgstr "" msgid "built-in function" msgstr "" -#: sphinx/templates/latex/longtable.tex_t:18 +#: sphinx/templates/latex/longtable.tex_t:18 sphinx/writers/latex.py:711 msgid "continued from previous page" msgstr "" @@ -1005,13 +1020,13 @@ msgstr "" msgid "Table Of Contents" msgstr "" -#: sphinx/themes/agogo/layout.html:51 sphinx/themes/basic/layout.html:152 +#: sphinx/themes/agogo/layout.html:51 sphinx/themes/basic/layout.html:150 #: sphinx/themes/basic/search.html:11 sphinx/themes/basic/search.html:23 #: sphinx/themes/basic/searchresults.html:10 msgid "Search" msgstr "" -#: sphinx/themes/agogo/layout.html:54 sphinx/themes/basic/searchbox.html:15 +#: sphinx/themes/agogo/layout.html:54 sphinx/themes/basic/searchbox.html:16 msgid "Go" msgstr "" @@ -1087,35 +1102,35 @@ msgstr "" msgid "Navigation" msgstr "" -#: sphinx/themes/basic/layout.html:137 +#: sphinx/themes/basic/layout.html:135 #, python-format msgid "Search within %(docstitle)s" msgstr "" -#: sphinx/themes/basic/layout.html:146 +#: sphinx/themes/basic/layout.html:144 msgid "About these documents" msgstr "" -#: sphinx/themes/basic/layout.html:155 +#: sphinx/themes/basic/layout.html:153 msgid "Copyright" msgstr "" -#: sphinx/themes/basic/layout.html:200 +#: sphinx/themes/basic/layout.html:198 #, python-format msgid "©
Copyright %(copyright)s." msgstr "" -#: sphinx/themes/basic/layout.html:202 +#: sphinx/themes/basic/layout.html:200 #, python-format msgid "© Copyright %(copyright)s." msgstr "" -#: sphinx/themes/basic/layout.html:206 +#: sphinx/themes/basic/layout.html:204 #, python-format msgid "Last updated on %(last_updated)s." msgstr "" -#: sphinx/themes/basic/layout.html:209 +#: sphinx/themes/basic/layout.html:207 #, python-format msgid "" "Created using Sphinx " @@ -1162,12 +1177,12 @@ msgid "search" msgstr "" #: sphinx/themes/basic/search.html:43 sphinx/themes/basic/searchresults.html:21 -#: sphinx/themes/basic/static/searchtools.js_t:295 +#: sphinx/themes/basic/static/searchtools.js_t:298 msgid "Search Results" msgstr "" #: sphinx/themes/basic/search.html:45 sphinx/themes/basic/searchresults.html:23 -#: sphinx/themes/basic/static/searchtools.js_t:297 +#: sphinx/themes/basic/static/searchtools.js_t:300 msgid "" "Your search did not match any documents. Please make sure that all words " "are spelled correctly and that you've selected enough categories." @@ -1209,19 +1224,19 @@ msgstr "" msgid "Other changes" msgstr "" -#: sphinx/themes/basic/static/doctools.js_t:169 sphinx/writers/html.py:403 -#: sphinx/writers/html.py:408 sphinx/writers/html5.py:350 -#: sphinx/writers/html5.py:355 +#: sphinx/themes/basic/static/doctools.js_t:193 sphinx/writers/html.py:405 +#: sphinx/writers/html.py:410 sphinx/writers/html5.py:351 +#: sphinx/writers/html5.py:356 msgid "Permalink to this headline" msgstr "" -#: sphinx/themes/basic/static/doctools.js_t:175 sphinx/writers/html.py:124 -#: sphinx/writers/html.py:135 sphinx/writers/html5.py:94 -#: sphinx/writers/html5.py:105 +#: sphinx/themes/basic/static/doctools.js_t:199 sphinx/writers/html.py:126 +#: sphinx/writers/html.py:137 sphinx/writers/html5.py:95 +#: sphinx/writers/html5.py:106 msgid "Permalink to this definition" msgstr "" -#: sphinx/themes/basic/static/doctools.js_t:208 +#: sphinx/themes/basic/static/doctools.js_t:232 msgid "Hide Search Matches" msgstr "" @@ -1233,12 +1248,12 @@ msgstr "" msgid "Preparing search..." msgstr "" -#: sphinx/themes/basic/static/searchtools.js_t:299 +#: sphinx/themes/basic/static/searchtools.js_t:302 #, python-format msgid "Search finished, found %s page(s) matching the search query." msgstr "" -#: sphinx/themes/basic/static/searchtools.js_t:352 +#: sphinx/themes/basic/static/searchtools.js_t:355 msgid ", in " msgstr "" @@ -1255,65 +1270,69 @@ msgstr "" msgid "Contents" msgstr "" -#: sphinx/transforms/post_transforms/__init__.py:138 +#: sphinx/transforms/post_transforms/__init__.py:139 #, python-format msgid "more than one target found for 'any' cross-reference %r: could be %s" msgstr "" -#: sphinx/transforms/post_transforms/__init__.py:168 +#: sphinx/transforms/post_transforms/__init__.py:169 #, python-format msgid "%s:%s reference target not found: %%(target)s" msgstr "" -#: sphinx/transforms/post_transforms/__init__.py:171 +#: sphinx/transforms/post_transforms/__init__.py:172 #, python-format msgid "%r reference target not found: %%(target)s" msgstr "" -#: sphinx/util/docutils.py:171 +#: sphinx/util/docutils.py:217 msgid "when adding directive classes, no additional arguments may be given" msgstr "" -#: sphinx/writers/html.py:412 sphinx/writers/html5.py:359 +#: sphinx/writers/html.py:414 sphinx/writers/html5.py:360 msgid "Permalink to this table" msgstr "" -#: sphinx/writers/html.py:464 sphinx/writers/html5.py:411 +#: sphinx/writers/html.py:466 sphinx/writers/html5.py:412 msgid "Permalink to this code" msgstr "" -#: sphinx/writers/html.py:468 sphinx/writers/html5.py:415 +#: sphinx/writers/html.py:470 sphinx/writers/html5.py:416 msgid "Permalink to this image" msgstr "" -#: sphinx/writers/html.py:470 sphinx/writers/html5.py:417 +#: sphinx/writers/html.py:472 sphinx/writers/html5.py:418 msgid "Permalink to this toctree" msgstr "" -#: sphinx/writers/latex.py:549 +#: sphinx/writers/latex.py:554 msgid "Release" msgstr "" -#: sphinx/writers/latex.py:654 +#: sphinx/writers/latex.py:714 +msgid "continues on next page" +msgstr "" + +#: sphinx/writers/latex.py:718 msgid "page" msgstr "" -#: sphinx/writers/latex.py:704 +#: sphinx/writers/latex.py:768 #, python-format msgid "Unknown configure key: latex_elements[%r] is ignored." msgstr "" -#: sphinx/writers/latex.py:1252 sphinx/writers/manpage.py:275 +#: sphinx/writers/latex.py:1317 sphinx/writers/manpage.py:275 #: sphinx/writers/texinfo.py:670 msgid "Footnotes" msgstr "" -#: sphinx/writers/manpage.py:331 sphinx/writers/text.py:699 +#: sphinx/writers/manpage.py:331 sphinx/writers/text.py:714 #, python-format msgid "[image: %s]" msgstr "" -#: sphinx/writers/manpage.py:332 sphinx/writers/text.py:700 +#: sphinx/writers/manpage.py:332 sphinx/writers/text.py:715 msgid "[image]" msgstr "" From bcb1bd914db1d8013ae7d8a3555f80f90e7b0413 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 22:24:52 +0900 Subject: [PATCH 0588/1814] package: update bump_version.py --- utils/bump_version.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/utils/bump_version.py b/utils/bump_version.py index 9033aee70..3f64f6ecf 100755 --- a/utils/bump_version.py +++ b/utils/bump_version.py @@ -16,11 +16,7 @@ RELEASE_TYPE = {'a': 'alpha', 'b': 'beta'} def stringify_version(version_info, in_develop=True): - if version_info[2] == 0: - version = '.'.join(str(v) for v in version_info[:2]) - else: - version = '.'.join(str(v) for v in version_info[:3]) - + version = '.'.join(str(v) for v in version_info[:3]) if not in_develop and version_info[3] != 'final': version += version_info[3][0] + str(version_info[4]) From bb34f0199a05f41f4f47d2536e82db29a1b78858 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 22:26:11 +0900 Subject: [PATCH 0589/1814] Bump to 1.7.0 beta1 --- CHANGES | 4 ++-- sphinx/__init__.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 955e59802..95ac8d4b0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.7 (in development) -============================ +Release 1.7.0 beta1 (released Jan 15, 2018) +=========================================== Dependencies ------------ diff --git a/sphinx/__init__.py b/sphinx/__init__.py index c84e2672f..3dbabf7f5 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -31,13 +31,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.7+' -__released__ = '1.7' # used when Sphinx builds its own docs +__version__ = '1.7.0b1' +__released__ = '1.7.0b1' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 7, 0, 'beta', 0) +version_info = (1, 7, 0, 'beta', 1) package_dir = path.abspath(path.dirname(__file__)) From a9f949e8580fbd685b8b334a875852f2ad65de8a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 15 Jan 2018 22:29:10 +0900 Subject: [PATCH 0590/1814] Bump version --- CHANGES | 21 +++++++++++++++++++++ sphinx/__init__.py | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 95ac8d4b0..4a02f8692 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Release 1.7.0 beta2 (in development) +==================================== + +Dependencies +------------ + +Incompatible changes +-------------------- + +Deprecated +---------- + +Features added +-------------- + +Bugs fixed +---------- + +Testing +-------- + Release 1.7.0 beta1 (released Jan 15, 2018) =========================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 3dbabf7f5..047f797a7 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -31,13 +31,13 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '1.7.0b1' -__released__ = '1.7.0b1' # used when Sphinx builds its own docs +__version__ = '1.7.0+' +__released__ = '1.7.0' # used when Sphinx builds its own docs # version info for better programmatic use # possible values for 3rd element: 'alpha', 'beta', 'rc', 'final' # 'final' has 0 as the last element -version_info = (1, 7, 0, 'beta', 1) +version_info = (1, 7, 0, 'beta', 2) package_dir = path.abspath(path.dirname(__file__)) From ddcb45dad608c2d93c4a1da9fa17a0d27645e3ab Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 16 Jan 2018 01:03:53 +0900 Subject: [PATCH 0591/1814] Validate -j option is positive --- sphinx/cmdline.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 365238607..4cf5a07ef 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -94,7 +94,11 @@ def jobs_argument(value): if value == 'auto': return multiprocessing.cpu_count() else: - return int(value) + jobs = int(value) + if jobs <= 0: + raise argparse.ArgumentTypeError('job number should be a positive number') + else: + return jobs def get_parser(): From 487c9feebf2f501520fb62c8ecfa7c95a89d24f1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 17 Jan 2018 00:04:12 +0900 Subject: [PATCH 0592/1814] Update CHANGES --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4a02f8692..440ed870d 100644 --- a/CHANGES +++ b/CHANGES @@ -45,7 +45,7 @@ Incompatible changes * 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. + mock them, please specify the name of ancestors explicitly. * #3620: html theme: move DOCUMENTATION_OPTIONS to independent JavaScript file (refs: #4295) * #4246: Limit width of text body for all themes. Conifigurable via theme From c808b4b8db9b51bb0fb4ab7edc9d4fc4304fb7d2 Mon Sep 17 00:00:00 2001 From: deoren Date: Tue, 16 Jan 2018 15:09:45 -0600 Subject: [PATCH 0593/1814] minor typo --- doc/man/sphinx-quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/man/sphinx-quickstart.rst b/doc/man/sphinx-quickstart.rst index c4bbc531b..28a52966f 100644 --- a/doc/man/sphinx-quickstart.rst +++ b/doc/man/sphinx-quickstart.rst @@ -20,7 +20,7 @@ Options .. option:: -q, --quiet - Quiet mode that will skips interactive wizard to specify options. + Quiet mode that will skip interactive wizard to specify options. This option requires `-p`, `-a` and `-v` options. .. option:: -h, --help, --version From e2aaa2860997606104da865dfaff58f5ce2dfd65 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 16 Jan 2018 22:08:06 -0500 Subject: [PATCH 0594/1814] Don't require numfig to use :numref: on sections Tweak logic that rejects a :numref: if numfig is not on to bypass this check if the reference is a section. Section numbers are applied independent of numfig, so the check is not needed, and makes it needlessly difficult to use :numref: if the user only cares about using it on sections. --- sphinx/domains/std.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index bfaa57c4f..686945321 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -715,15 +715,15 @@ class StandardDomain(Domain): if not docname: return None - if env.config.numfig is False: - logger.warning('numfig is disabled. :numref: is ignored.', location=node) - return contnode - target_node = env.get_doctree(docname).ids.get(labelid) figtype = self.get_figtype(target_node) if figtype is None: return None + if figtype != 'section' and env.config.numfig is False: + logger.warning('numfig is disabled. :numref: is ignored.', location=node) + return contnode + try: fignumber = self.get_fignumber(env, builder, figtype, docname, target_node) if fignumber is None: From 9aca29a7816c8989a7d67356f270c255cca3c2bb Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 18 Jan 2018 14:33:17 +0100 Subject: [PATCH 0595/1814] Fix "Undefined control sequence \\hlineSomeText" (#4431; refs: #3435) --- sphinx/writers/latex.py | 2 -- ...ving_threeparagraphs_cell_in_first_col.tex | 20 +++++++++++++++++++ tests/roots/test-latex-table/tabular.rst | 14 +++++++++++++ tests/test_build_latex.py | 11 +++++++--- 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 tests/roots/test-latex-table/expects/table_having_threeparagraphs_cell_in_first_col.tex diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 98fec811c..7791d4aa6 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1477,8 +1477,6 @@ class LaTeXTranslator(nodes.NodeVisitor): context = ('\\par\n\\vskip-\\baselineskip' '\\vbox{\\hbox{\\strut}}\\end{varwidth}%\n') + context self.needs_linetrimming = 1 - if len(node) > 2 and len(node.astext().split('\n')) > 2: - self.needs_linetrimming = 1 if len(node.traverse(nodes.paragraph)) >= 2: self.table.has_oldproblematic = True if isinstance(node.parent.parent, nodes.thead) or (cell.col in self.table.stubs): diff --git a/tests/roots/test-latex-table/expects/table_having_threeparagraphs_cell_in_first_col.tex b/tests/roots/test-latex-table/expects/table_having_threeparagraphs_cell_in_first_col.tex new file mode 100644 index 000000000..7e21181f8 --- /dev/null +++ b/tests/roots/test-latex-table/expects/table_having_threeparagraphs_cell_in_first_col.tex @@ -0,0 +1,20 @@ +\label{\detokenize{tabular:table-with-cell-in-first-column-having-three-paragraphs}} + +\begin{savenotes}\sphinxattablestart +\centering +\begin{tabulary}{\linewidth}[t]{|T|} +\hline +\sphinxstylethead{\sphinxstyletheadfamily +header1 +\unskip}\relax \\ +\hline +cell1-1-par1 + +cell1-1-par2 + +cell1-1-par3 +\\ +\hline +\end{tabulary} +\par +\sphinxattableend\end{savenotes} diff --git a/tests/roots/test-latex-table/tabular.rst b/tests/roots/test-latex-table/tabular.rst index 24091a3e1..b28add3d3 100644 --- a/tests/roots/test-latex-table/tabular.rst +++ b/tests/roots/test-latex-table/tabular.rst @@ -68,6 +68,20 @@ cell2-1 cell2-2 cell3-1 cell3-2 ======= ======= +table with cell in first column having three paragraphs +------------------------------------------------------- + ++--------------+ +| header1 | ++==============+ +| cell1-1-par1 | +| | +| cell1-1-par2 | +| | +| cell1-1-par3 | ++--------------+ + + table having caption -------------------- diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 0c95a0cdb..1ba115092 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -877,7 +877,7 @@ def test_maxlistdepth_at_ten(app, status, warning): @pytest.mark.skipif(docutils.__version_info__ < (0, 13), reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') -@pytest.mark.test_params(shared_result='test_latex_table') +@pytest.mark.test_params(shared_result='latex-table') def test_latex_table_tabulars(app, status, warning): app.builder.build_all() result = (app.outdir / 'test.tex').text(encoding='utf8') @@ -914,6 +914,11 @@ def test_latex_table_tabulars(app, status, warning): expected = get_expected('tabularcolumn') assert actual == expected + # table with cell in first column having three paragraphs + actual = tables['table with cell in first column having three paragraphs'] + expected = get_expected('table_having_threeparagraphs_cell_in_first_col') + assert actual == expected + # table having caption actual = tables['table having caption'] expected = get_expected('table_having_caption') @@ -943,7 +948,7 @@ def test_latex_table_tabulars(app, status, warning): @pytest.mark.skipif(docutils.__version_info__ < (0, 13), reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') -@pytest.mark.test_params(shared_result='test_latex_table') +@pytest.mark.test_params(shared_result='latex-table') def test_latex_table_longtable(app, status, warning): app.builder.build_all() result = (app.outdir / 'test.tex').text(encoding='utf8') @@ -1004,7 +1009,7 @@ def test_latex_table_longtable(app, status, warning): @pytest.mark.skipif(docutils.__version_info__ < (0, 13), reason='docutils-0.13 or above is required') @pytest.mark.sphinx('latex', testroot='latex-table') -@pytest.mark.test_params(shared_result='test_latex_table') +@pytest.mark.test_params(shared_result='latex-table') def test_latex_table_complex_tables(app, status, warning): app.builder.build_all() result = (app.outdir / 'test.tex').text(encoding='utf8') From 357fba4467ce38f39db437856ab87b34e31e1697 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 19 Jan 2018 01:35:14 +0900 Subject: [PATCH 0596/1814] Fix #4412: Updated jQuery version from 3.1.0 to 3.2.1 --- CHANGES | 2 +- .../{jquery-3.1.0.js => jquery-3.2.1.js} | 771 +++++++++++------- sphinx/themes/basic/static/jquery.js | 8 +- tests/test_theming.py | 2 +- 4 files changed, 481 insertions(+), 302 deletions(-) rename sphinx/themes/basic/static/{jquery-3.1.0.js => jquery-3.2.1.js} (94%) diff --git a/CHANGES b/CHANGES index 184a2b7a9..9e473bde1 100644 --- a/CHANGES +++ b/CHANGES @@ -17,7 +17,7 @@ Bugs fixed ---------- * #1922: html search: Upper characters problem in French - +* #4412: Updated jQuery version from 3.1.0 to 3.2.1 Testing -------- diff --git a/sphinx/themes/basic/static/jquery-3.1.0.js b/sphinx/themes/basic/static/jquery-3.2.1.js similarity index 94% rename from sphinx/themes/basic/static/jquery-3.1.0.js rename to sphinx/themes/basic/static/jquery-3.2.1.js index f2fc27478..d2d8ca479 100644 --- a/sphinx/themes/basic/static/jquery-3.1.0.js +++ b/sphinx/themes/basic/static/jquery-3.2.1.js @@ -1,16 +1,15 @@ -/*eslint-disable no-unused-vars*/ /*! - * jQuery JavaScript Library v3.1.0 + * jQuery JavaScript Library v3.2.1 * https://jquery.com/ * * Includes Sizzle.js * https://sizzlejs.com/ * - * Copyright jQuery Foundation and other contributors + * Copyright JS Foundation and other contributors * Released under the MIT license * https://jquery.org/license * - * Date: 2016-07-07T21:44Z + * Date: 2017-03-20T18:59Z */ ( function( global, factory ) { @@ -83,13 +82,13 @@ var support = {}; doc.head.appendChild( script ).parentNode.removeChild( script ); } /* global Symbol */ -// Defining this global in .eslintrc would create a danger of using the global +// Defining this global in .eslintrc.json would create a danger of using the global // unguarded in another place, it seems safer to define global only for this module var - version = "3.1.0", + version = "3.2.1", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -129,13 +128,14 @@ jQuery.fn = jQuery.prototype = { // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { - return num != null ? - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } - // Return all the elements in a clean array - slice.call( this ); + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; }, // Take an array of elements and push it onto the stack @@ -236,11 +236,11 @@ jQuery.extend = jQuery.fn.extend = function() { // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + ( copyIsArray = Array.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; - clone = src && jQuery.isArray( src ) ? src : []; + clone = src && Array.isArray( src ) ? src : []; } else { clone = src && jQuery.isPlainObject( src ) ? src : {}; @@ -279,8 +279,6 @@ jQuery.extend( { return jQuery.type( obj ) === "function"; }, - isArray: Array.isArray, - isWindow: function( obj ) { return obj != null && obj === obj.window; }, @@ -355,10 +353,6 @@ jQuery.extend( { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - each: function( obj, callback ) { var length, i = 0; @@ -543,14 +537,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.0 + * Sizzle CSS Selector Engine v2.3.3 * https://sizzlejs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * - * Date: 2016-01-04 + * Date: 2016-08-08 */ (function( window ) { @@ -696,7 +690,7 @@ var i, // CSS string/identifier serialization // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g, + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, fcssescape = function( ch, asCodePoint ) { if ( asCodePoint ) { @@ -723,7 +717,7 @@ var i, disabledAncestor = addCombinator( function( elem ) { - return elem.disabled === true; + return elem.disabled === true && ("form" in elem || "label" in elem); }, { dir: "parentNode", next: "legend" } ); @@ -1009,26 +1003,54 @@ function createButtonPseudo( type ) { * @param {Boolean} disabled true for :disabled; false for :enabled */ function createDisabledPseudo( disabled ) { - // Known :disabled false positives: - // IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset) - // not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable return function( elem ) { - // Check form elements and option elements for explicit disabling - return "label" in elem && elem.disabled === disabled || - "form" in elem && elem.disabled === disabled || + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { - // Check non-disabled form elements for fieldset[disabled] ancestors - "form" in elem && elem.disabled === false && ( - // Support: IE6-11+ - // Ancestry is covered for us - elem.isDisabled === disabled || + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { - // Otherwise, assume any non-