From 3bd40f35b4e808cea6d8a24038dfdb90ebfa52fc Mon Sep 17 00:00:00 2001 From: Tomoko Uchida Date: Sun, 22 Nov 2015 17:54:57 +0900 Subject: [PATCH 01/10] MecabBinder should support both of Python 2 and 3. --- sphinx/search/ja.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index 3c9ee88fd..23de74d37 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -21,7 +21,7 @@ import os import re import sys -from six import iteritems +from six import iteritems, PY3 try: import MeCab @@ -43,13 +43,16 @@ class MecabBinder(object): self.dict_encode = options.get('dic_enc', 'utf-8') def split(self, input): - input2 = input.encode(self.dict_encode) + input2 = input if PY3 else input.encode(self.dict_encode) if native_module: result = self.native.parse(input2) else: result = self.ctypes_libmecab.mecab_sparse_tostr( self.ctypes_mecab, input.encode(self.dict_encode)) - return result.decode(self.dict_encode).split(' ') + if PY3: + return result.split(' ') + else: + return result.decode(self.dict_encode).split(' ') def init_native(self, options): param = '-Owakati' From 47bdbd16556eb0744079ed1c967bc80d5b12de26 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Sun, 29 Nov 2015 12:02:02 +0900 Subject: [PATCH 02/10] Fix #1818: `sphinx.ext.todo` directive generates broken html class attribute as 'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like 'ru' or 'ja'. To fix this, now ``todo`` directive can use ```:class:`` option. --- CHANGES | 3 +++ doc/ext/todo.rst | 4 ++++ sphinx/ext/todo.py | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 2d063d63a..3c0fc312e 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,9 @@ Bugs fixed the page content. * #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks to Suzumizaki. +* #1818: `sphinx.ext.todo` directive generates broken html class attribute as + 'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like + 'ru' or 'ja'. To fix this, now ``todo`` directive can use ```:class:`` option. Release 1.3.1 (released Mar 17, 2015) ===================================== diff --git a/doc/ext/todo.rst b/doc/ext/todo.rst index c0d94ba1d..8ab6eb37a 100644 --- a/doc/ext/todo.rst +++ b/doc/ext/todo.rst @@ -16,6 +16,10 @@ There are two additional directives when using this extension: It will only show up in the output if :confval:`todo_include_todos` is ``True``. + .. versionadded:: 1.3.2 + This directive supports an ``class`` option that determines the class attribute + for HTML output. If not given, the class defaults to ``admonition-todo``. + .. rst:directive:: todolist diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 64359c9b0..faa086fc8 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -13,6 +13,7 @@ """ from docutils import nodes +from docutils.parsers.rst import directives import sphinx from sphinx.locale import _ @@ -38,13 +39,18 @@ class Todo(Directive): required_arguments = 0 optional_arguments = 0 final_argument_whitespace = False - option_spec = {} + option_spec = { + 'class': directives.class_option, + } def run(self): env = self.state.document.settings.env targetid = 'index-%s' % env.new_serialno('index') targetnode = nodes.target('', '', ids=[targetid]) + if not self.options.get('class'): + self.options['class'] = ['admonition-todo'] + ad = make_admonition(todo_node, self.name, [_('Todo')], self.options, self.content, self.lineno, self.content_offset, self.block_text, self.state, self.state_machine) @@ -165,6 +171,7 @@ def merge_info(app, env, docnames, other): def visit_todo_node(self, node): self.visit_admonition(node) + # self.visit_admonition(node, 'todo') def depart_todo_node(self, node): From 12396a71d9c1e7a3bd3a4e5d1447f2033db26794 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 29 Nov 2015 16:57:25 +0900 Subject: [PATCH 03/10] Fix #2140: footnotes in table has broken in LaTeX --- sphinx/writers/latex.py | 17 +++++++++++++++-- tests/root/footnote.txt | 15 +++++++++++++++ tests/test_build_html.py | 8 ++++++-- tests/test_build_latex.py | 18 ++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index d82e7dd76..bebf4b43d 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -137,6 +137,7 @@ class Table(object): self.has_verbatim = False self.caption = None self.longtable = False + self.footnotes = [] class LaTeXTranslator(nodes.NodeVisitor): @@ -495,7 +496,8 @@ class LaTeXTranslator(nodes.NodeVisitor): fnotes = {} for fn in footnotes_under(node): num = fn.children[0].astext().strip() - fnotes[num] = [collected_footnote(*fn.children), False] + newnode = collected_footnote(*fn.children, number=num) + fnotes[num] = [newnode, False] return fnotes def depart_start_of_file(self, node): @@ -743,7 +745,10 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_collected_footnote(self, node): self.in_footnote += 1 - self.body.append('\\footnote{') + if 'in_table' in node: + self.body.append('\\footnotetext[%s]{' % node['number']) + else: + self.body.append('\\footnote[%s]{' % node['number']) def depart_collected_footnote(self, node): self.body.append('}') @@ -839,6 +844,10 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append(endmacro) if not self.table.longtable and self.table.caption is not None: self.body.append('\\end{threeparttable}\n\n') + if self.table.footnotes: + for footnode in self.table.footnotes: + footnode['in_table'] = True + footnode.walkabout(self) self.table = None self.tablebody = None @@ -1532,6 +1541,10 @@ class LaTeXTranslator(nodes.NodeVisitor): # by the next reference if used: self.body.append('\\footnotemark[%s]' % num) + elif self.table: + self.footnotestack[-1][num][1] = True + self.body.append('\\footnotemark[%s]' % num) + self.table.footnotes.append(footnode) else: if self.in_caption: raise UnsupportedError('%s:%s: footnotes in float captions ' diff --git a/tests/root/footnote.txt b/tests/root/footnote.txt index b600697fd..423977a4d 100644 --- a/tests/root/footnote.txt +++ b/tests/root/footnote.txt @@ -24,6 +24,17 @@ citation [bar]_ +footnotes in table +-------------------- + +.. list-table:: Table caption [#]_ + :header-rows: 1 + + * - name [#]_ + - desription + * - VIDIOC_CROPCAP + - Information about VIDIOC_CROPCAP + footenotes -------------------- @@ -39,6 +50,10 @@ footenotes .. [bar] cite +.. [#] footnotes in table + +.. [#] footnotes in table + missing target -------------------- diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 3ee89b72b..e0ed4d44f 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -280,14 +280,18 @@ HTML_XPATH = { (".//dt/a", "double"), ], 'footnote.html': [ - (".//a[@class='footnote-reference'][@href='#id5'][@id='id1']", r"\[1\]"), - (".//a[@class='footnote-reference'][@href='#id6'][@id='id2']", r"\[2\]"), + (".//a[@class='footnote-reference'][@href='#id7'][@id='id1']", r"\[1\]"), + (".//a[@class='footnote-reference'][@href='#id8'][@id='id2']", r"\[2\]"), (".//a[@class='footnote-reference'][@href='#foo'][@id='id3']", r"\[3\]"), (".//a[@class='reference internal'][@href='#bar'][@id='id4']", r"\[bar\]"), + (".//a[@class='footnote-reference'][@href='#id9'][@id='id5']", r"\[4\]"), + (".//a[@class='footnote-reference'][@href='#id10'][@id='id6']", r"\[5\]"), (".//a[@class='fn-backref'][@href='#id1']", r"\[1\]"), (".//a[@class='fn-backref'][@href='#id2']", r"\[2\]"), (".//a[@class='fn-backref'][@href='#id3']", r"\[3\]"), (".//a[@class='fn-backref'][@href='#id4']", r"\[bar\]"), + (".//a[@class='fn-backref'][@href='#id5']", r"\[4\]"), + (".//a[@class='fn-backref'][@href='#id6']", r"\[5\]"), ], 'otherext.html': [ (".//h1", "Generated section"), diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 639204ca1..3d2de232d 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -297,3 +297,21 @@ def test_contentsname_with_language_ja(app, status, warning): print(status.getvalue()) print(warning.getvalue()) assert '\\renewcommand{\\contentsname}{Table of content}' in result + + +@with_app(buildername='latex') +def test_footnote(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\footnote[1]{\nnumbered\n}' in result + assert '\\footnote[2]{\nauto numbered\n}' in result + assert '\\footnote[3]{\nnamed\n}' in result + assert '{\\hyperref[footnote:bar]{\\emph{{[}bar{]}}}}' in result + assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} ' in result + assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite' in result + assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite\n}' in result + assert 'name \\footnotemark[5]' in result + assert '\\end{threeparttable}\n\n\\footnotetext[5]{\nfootnotes in table\n}' in result From f4c5a2e136059f93b0e4a707526a8f0ccee028eb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 29 Nov 2015 20:17:55 +0900 Subject: [PATCH 04/10] Fix #2140: footnotes in caption of table has broken in LaTeX --- sphinx/writers/latex.py | 33 ++++++++++++++++++++++++--------- tests/root/footnote.txt | 2 +- tests/test_build_latex.py | 7 +++++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index bebf4b43d..c88b37395 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -276,6 +276,7 @@ class LaTeXTranslator(nodes.NodeVisitor): # by .. highlight:: directive in the master file self.hlsettingstack = 2 * [[builder.config.highlight_language, sys.maxsize]] + self.bodystack = [] self.footnotestack = [] self.curfilestack = [] self.handled_abbrs = set() @@ -304,6 +305,15 @@ class LaTeXTranslator(nodes.NodeVisitor): self.remember_multirow = {} self.remember_multirowcol = {} + def pushbody(self, newbody): + self.bodystack.append(self.body) + self.body = newbody + + def popbody(self): + body = self.body + self.body = self.bodystack.pop() + return body + def format_docclass(self, docclass): """ prepends prefix to sphinx document classes """ @@ -604,8 +614,8 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append('{') self.context.append('}\n') elif isinstance(parent, nodes.table): - self.table.caption = self.encode(node.astext()) - raise nodes.SkipNode + # Redirect body output until title is finished. + self.pushbody([]) else: self.builder.warn( 'encountered title node not in section, topic, table, ' @@ -617,7 +627,10 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_title(self, node): self.in_title = 0 - self.body.append(self.context.pop()) + if isinstance(node.parent, nodes.table): + self.table.caption = self.popbody() + else: + self.body.append(self.context.pop()) def visit_subtitle(self, node): if isinstance(node.parent, nodes.sidebar): @@ -775,16 +788,18 @@ class LaTeXTranslator(nodes.NodeVisitor): self.tablebody = [] self.tableheaders = [] # Redirect body output until table is finished. - self._body = self.body - self.body = self.tablebody + self.pushbody(self.tablebody) def depart_table(self, node): if self.table.rowcount > 30: self.table.longtable = True - self.body = self._body + self.popbody() if not self.table.longtable and self.table.caption is not None: - self.body.append(u'\n\n\\begin{threeparttable}\n' - u'\\capstart\\caption{%s}\n' % self.table.caption) + self.body.append('\n\n\\begin{threeparttable}\n' + '\\capstart\\caption{') + for caption in self.table.caption: + self.body.append(caption) + self.body.append('}') for id in self.next_table_ids: self.body.append(self.hypertarget(id, anchor=False)) if node['ids']: @@ -1543,7 +1558,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append('\\footnotemark[%s]' % num) elif self.table: self.footnotestack[-1][num][1] = True - self.body.append('\\footnotemark[%s]' % num) + self.body.append('\\protect\\footnotemark[%s]' % num) self.table.footnotes.append(footnode) else: if self.in_caption: diff --git a/tests/root/footnote.txt b/tests/root/footnote.txt index 423977a4d..36ad3fadc 100644 --- a/tests/root/footnote.txt +++ b/tests/root/footnote.txt @@ -50,7 +50,7 @@ footenotes .. [bar] cite -.. [#] footnotes in table +.. [#] footnotes in table caption .. [#] footnotes in table diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 3d2de232d..e2350c6a3 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -313,5 +313,8 @@ def test_footnote(app, status, warning): assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} ' in result assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite' in result assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite\n}' in result - assert 'name \\footnotemark[5]' in result - assert '\\end{threeparttable}\n\n\\footnotetext[5]{\nfootnotes in table\n}' in result + assert '\\capstart\\caption{Table caption \\protect\\footnotemark[4]}' in result + assert 'name \\protect\\footnotemark[5]' in result + assert ('\\end{threeparttable}\n\n' + '\\footnotetext[4]{\nfootnotes in table caption\n}' + '\\footnotetext[5]{\nfootnotes in table\n}' in result) From 042daed015ace1ca3c7b90b550cfbc2d0ad46761 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 29 Nov 2015 22:03:48 +0900 Subject: [PATCH 05/10] Update CHANGES for #2140 --- CHANGES | 1 + sphinx/writers/latex.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3c0fc312e..32de69eb9 100644 --- a/CHANGES +++ b/CHANGES @@ -70,6 +70,7 @@ Bugs fixed * #1818: `sphinx.ext.todo` directive generates broken html class attribute as 'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like 'ru' or 'ja'. To fix this, now ``todo`` directive can use ```:class:`` option. +* #2140: Fix footnotes in table has broken in LaTeX Release 1.3.1 (released Mar 17, 2015) ===================================== diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index c88b37395..5ec86019f 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1555,7 +1555,10 @@ class LaTeXTranslator(nodes.NodeVisitor): # if a footnote has been inserted once, it shouldn't be repeated # by the next reference if used: - self.body.append('\\footnotemark[%s]' % num) + if self.table: + self.body.append('\\protect\\footnotemark[%s]' % num) + else: + self.body.append('\\footnotemark[%s]' % num) elif self.table: self.footnotestack[-1][num][1] = True self.body.append('\\protect\\footnotemark[%s]' % num) From 431d72091d35faa992e9922b219da931e1b62024 Mon Sep 17 00:00:00 2001 From: Tomoko Uchida Date: Sun, 22 Nov 2015 17:54:57 +0900 Subject: [PATCH 06/10] MecabBinder should support both of Python 2 and 3. --- sphinx/search/ja.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index 3c9ee88fd..23de74d37 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -21,7 +21,7 @@ import os import re import sys -from six import iteritems +from six import iteritems, PY3 try: import MeCab @@ -43,13 +43,16 @@ class MecabBinder(object): self.dict_encode = options.get('dic_enc', 'utf-8') def split(self, input): - input2 = input.encode(self.dict_encode) + input2 = input if PY3 else input.encode(self.dict_encode) if native_module: result = self.native.parse(input2) else: result = self.ctypes_libmecab.mecab_sparse_tostr( self.ctypes_mecab, input.encode(self.dict_encode)) - return result.decode(self.dict_encode).split(' ') + if PY3: + return result.split(' ') + else: + return result.decode(self.dict_encode).split(' ') def init_native(self, options): param = '-Owakati' From 2f8af51a2bd2d171d6110c6c1383f6e60e317ff0 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Sun, 29 Nov 2015 22:14:40 +0900 Subject: [PATCH 07/10] update CHANGES for PR #2127 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 32de69eb9..f36f7e0a8 100644 --- a/CHANGES +++ b/CHANGES @@ -71,6 +71,8 @@ Bugs fixed 'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like 'ru' or 'ja'. To fix this, now ``todo`` directive can use ```:class:`` option. * #2140: Fix footnotes in table has broken in LaTeX +* #2127: MecabBinder for html searching feature doesn't work with Python 3. + Thanks to Tomoko Uchida. Release 1.3.1 (released Mar 17, 2015) ===================================== From 4c7db6c67d26151c90aa5f1949f007776edd28f9 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Sun, 29 Nov 2015 22:23:56 +0900 Subject: [PATCH 08/10] fix line length --- tests/test_util_nodes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py index a14e850fe..c90139c88 100644 --- a/tests/test_util_nodes.py +++ b/tests/test_util_nodes.py @@ -136,8 +136,8 @@ def test_extract_messages_without_rawsource(): """ Check node.rawsource is fall-backed by using node.astext() value. - `extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource`` nodes. - So, all nodes which want to translate must have ``rawsource`` value. + `extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource`` + nodes. So, all nodes which want to translate must have ``rawsource`` value. However, sometimes node.rawsource is not set. For example: recommonmark-0.2.0 doesn't set rawsource to `paragraph` node. From 6d0df203e41f31721ead92d31974f05f99382804 Mon Sep 17 00:00:00 2001 From: Takayuki Shimizukawa Date: Sun, 29 Nov 2015 13:28:56 +0000 Subject: [PATCH 09/10] Bump to 1.3.2 final --- CHANGES | 4 ++-- sphinx/__init__.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index f36f7e0a8..2d1177068 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.3.2 (in development) -============================== +Release 1.3.2 (released Nov 29, 2015) +===================================== Features added -------------- diff --git a/sphinx/__init__.py b/sphinx/__init__.py index d46f19779..3b45b23de 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -15,13 +15,13 @@ import sys from os import path -__version__ = '1.3.1+' -__released__ = '1.3.1+' # used when Sphinx builds its own docs +__version__ = '1.3.2' +__released__ = '1.3.2' # 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, 3, 1, 'beta', 1) +version_info = (1, 3, 2, 'final', 0) package_dir = path.abspath(path.dirname(__file__)) From afcea49dc9ade373c9d4dd49f1a5634b378eff40 Mon Sep 17 00:00:00 2001 From: shimizukawa Date: Sun, 29 Nov 2015 23:06:09 +0900 Subject: [PATCH 10/10] Bump version --- CHANGES | 8 ++++++++ sphinx/__init__.py | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 2d1177068..0303adbf4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Release 1.3.3 (in development) +============================== + +Bugs fixed +---------- + + + Release 1.3.2 (released Nov 29, 2015) ===================================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 3b45b23de..7e6c73daf 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -15,13 +15,13 @@ import sys from os import path -__version__ = '1.3.2' -__released__ = '1.3.2' # used when Sphinx builds its own docs +__version__ = '1.3.2+' +__released__ = '1.3.2+' # 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, 3, 2, 'final', 0) +version_info = (1, 3, 3, 'beta', 1) package_dir = path.abspath(path.dirname(__file__))