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