diff --git a/.gitignore b/.gitignore index 298a9c370..be28908ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pyc *.egg *.so +*.swp .dir-locals.el .ropeproject/ diff --git a/CHANGES b/CHANGES index 169bf5b50..cacd91f52 100644 --- a/CHANGES +++ b/CHANGES @@ -69,14 +69,39 @@ Bugs fixed * #2168: Fix raw directive does not work for text writer * #2171: Fix cannot linkcheck url with unicode * #2182: LaTeX: support image file names with more than 1 dots -* #2189: Fix previous sibling link for first file in subdirectory uses last file, not intended previous from root toctree +* #2189: Fix previous sibling link for first file in subdirectory uses last file, not + intended previous from root toctree * #2003: Fix decode error under python2 (only) when ``make linkcheck`` is run * #2186: Fix LaTeX output of \mathbb in math * #1480, #2188: LaTeX: Support math in section titles * #2071: Fix same footnote in more than two section titles => LaTeX/PDF Bug * #2040: Fix UnicodeDecodeError in sphinx-apidoc when author contains non-ascii characters * #2193: Fix shutil.SameFileError if source directory and destination directory are same - +* #2178: Fix unparseable C++ cross-reference when referencing a function with :cpp:any: +* #2206: Fix Sphinx latex doc build failed due to a footnotes +* #2201: Fix wrong table caption for tables with over 30 rows +* #2213: Set
in the classic theme to fit with

+* #1815: Fix linkcheck does not raise an exception if warniserror set to true and link is + broken +* #2197: Fix slightly cryptic error message for missing index.rst file +* #1894: Unlisted phony targets in quickstart Makefile +* #2125: Fix unifies behavior of collapsed fields (``GroupedField`` and ``TypedField``) +* #1408: Check latex_logo validity before copying +* #771: Fix latex output doesn't set tocdepth +* #1820: On Windows, console coloring is broken with colorama version 0.3.3. + Now sphinx use colorama>=0.3.5 to avoid this problem. +* #2072: Fix footnotes in chapter-titles do not appear in PDF output +* #1580: Fix paragraphs in longtable don't work in Latex output +* #1366: Fix centered image not centered in latex +* #1860: Fix man page using ``:samp:`` with braces - font doesn't reset +* #1610: Sphinx crashes in japanese indexing in some systems +* Fix Sphinx crashes if mecab initialization failed +* #2160: Fix broken TOC of PDFs if section includes an image +* #2172: Fix dysfunctional admonition \py@lightbox in sphinx.sty. Thanks to jfbu. +* #2198,#2205: ``make gettext`` generate broken msgid for definition lists. +* #2062: Escape characters in doctests are treated incorrectly with Python 2. +* #2225: Fix if the option does not begin with dash, linking is not performed +* #2226: Fix math is not HTML-encoded when :nowrap: is given (jsmath, mathjax) Release 1.3.3 (released Dec 2, 2015) ==================================== diff --git a/doc/_templates/index.html b/doc/_templates/index.html index ccef89a78..4c23114db 100644 --- a/doc/_templates/index.html +++ b/doc/_templates/index.html @@ -62,11 +62,11 @@

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

{%trans%}Examples{%endtrans%}

diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index 56094809f..b6f12f031 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -14,15 +14,7 @@

{%trans%}Current version: {{ version }}{%endtrans%}

{%trans%}Get Sphinx from the Python Package Index, or install it with:{%endtrans%}

-{% if version.split('b')|length > 1 %} -
pip install Sphinx=={{ version }}
-

{%trans%}Stable version docs -are also available.{%endtrans%}

-{% else %}
pip install -U Sphinx
-

{%trans%}Latest development version docs -are also available.{%endtrans%}

-{% endif %} {% endif %}

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

diff --git a/doc/extdev/envapi.rst b/doc/extdev/envapi.rst index 84ad3e0d9..729725fc5 100644 --- a/doc/extdev/envapi.rst +++ b/doc/extdev/envapi.rst @@ -17,7 +17,11 @@ Build environment API .. attribute:: srcdir - Source directory (the directory containing ``conf.py``). + Source directory. + + .. attribute:: confdir + + Directory containing ``conf.py``. .. attribute:: doctreedir diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index 10db17d79..0e825b66a 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -242,9 +242,8 @@ objects: .. rst:role:: option - A command-line option to an executable program. The leading hyphen(s) must - be included. This generates a link to a :rst:dir:`option` directive, if it - exists. + A command-line option to an executable program. This generates a link to + a :rst:dir:`option` directive, if it exists. The following role creates a cross-reference to a term in a diff --git a/setup.py b/setup.py index cc977f50f..f04b36a5f 100644 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ requires = [ extras_require = { # Environment Marker works for wheel 0.24 or later ':sys_platform=="win32"': [ - 'colorama', + 'colorama>=0.3.5', ], 'websupport': [ 'sqlalchemy>=0.9', @@ -73,7 +73,7 @@ extras_require = { # for sdist installation with pip-1.5.6 if sys.platform == 'win32': - requires.append('colorama') + requires.append('colorama>=0.3.5') # Provide a "compile_catalog" command that also creates the translated # JavaScript files if Babel is available. diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py index 1eef58d66..18041eae3 100644 --- a/sphinx/builders/latex.py +++ b/sphinx/builders/latex.py @@ -20,6 +20,7 @@ from docutils.frontend import OptionParser from sphinx import package_dir, addnodes from sphinx.util import texescape +from sphinx.errors import SphinxError from sphinx.locale import _ from sphinx.builders import Builder from sphinx.environment import NoUri @@ -94,9 +95,18 @@ class LaTeXBuilder(Builder): destination_path=path.join(self.outdir, targetname), encoding='utf-8') self.info("processing " + targetname + "... ", nonl=1) + toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree) + if toctrees: + if toctrees[0].get('maxdepth'): + tocdepth = int(toctrees[0].get('maxdepth')) + else: + tocdepth = None + else: + tocdepth = None doctree = self.assemble_doctree( docname, toctree_only, appendices=((docclass != 'howto') and self.config.latex_appendices or [])) + doctree['tocdepth'] = tocdepth self.post_process_images(doctree) self.info("writing... ", nonl=1) doctree.settings = docsettings @@ -191,6 +201,9 @@ class LaTeXBuilder(Builder): # the logo is handled differently if self.config.latex_logo: logobase = path.basename(self.config.latex_logo) - copyfile(path.join(self.confdir, self.config.latex_logo), - path.join(self.outdir, logobase)) + logotarget = path.join(self.outdir, logobase) + if not path.isfile(path.join(self.confdir, self.config.latex_logo)): + raise SphinxError('logo file %r does not exist' % self.config.latex_logo) + elif not path.isfile(logotarget): + copyfile(path.join(self.confdir, self.config.latex_logo), logotarget) self.info('done') diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 5dac89e2f..72010113a 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -243,11 +243,12 @@ class CheckExternalLinksBuilder(Builder): elif status == 'working': self.info(darkgreen('ok ') + uri + info) elif status == 'broken': - self.info(red('broken ') + uri + red(' - ' + info)) self.write_entry('broken', docname, lineno, uri + ': ' + info) - if self.app.quiet: + if self.app.quiet or self.app.warningiserror: self.warn('broken link: %s' % uri, '%s:%s' % (self.env.doc2path(docname), lineno)) + else: + self.info(red('broken ') + uri + red(' - ' + info)) elif status == 'redirected': text, color = { 301: ('permanently', darkred), diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 148766ad9..081055b95 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3924,6 +3924,9 @@ class CPPXRefRole(XRefRole): parent = env.ref_context.get('cpp:parentSymbol', None) if parent: refnode['cpp:parentKey'] = parent.get_lookup_key() + if refnode['reftype'] == 'any': + # Remove parentheses from the target (not from title) + title, target = self._fix_parens(env, True, title, target) # TODO: should this really be here? if not has_explicit_title: target = target.lstrip('~') # only has a meaning for the title @@ -4048,6 +4051,14 @@ class CPPDomain(Domain): name = text_type(fullNestedName).lstrip(':') docname = s.docname assert docname + if declaration.objectType == 'function': + title = name + if title.endswith('()'): + title = title[:-2] # remove parentheses + if env.config.add_function_parentheses: + title += '()' + contnode.pop(0) + contnode.insert(0, nodes.Text(title)) return make_refnode(builder, fromdocname, docname, declaration.get_newest_id(), contnode, name ), declaration.objectType diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index efd406082..9939b093b 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -210,10 +210,6 @@ class Program(Directive): class OptionXRefRole(XRefRole): def process_link(self, env, refnode, has_explicit_title, title, target): - # validate content - if not re.match(r'(.+ )?[-/+\w]', target): - env.warn_node('Malformed :option: %r, does not contain option ' - 'marker - or -- or / or +' % target, refnode) refnode['std:program'] = env.ref_context.get('std:program') return title, target @@ -666,22 +662,23 @@ class StandardDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) elif typ == 'option': + progname = node.get('std:program') target = target.strip() - # most obvious thing: we are a flag option without program - if target.startswith(('-', '/', '+')): - progname = node.get('std:program') - elif re.search(r'[-/+]', target): - try: - progname, target = re.split(r' (?=-|--|/|\+)', target, 1) - except ValueError: - return None - progname = ws_re.sub('-', progname.strip()) - else: - progname = None - docname, labelid = self.data['progoptions'].get((progname, target), - ('', '')) + docname, labelid = self.data['progoptions'].get((progname, target), ('', '')) if not docname: - return None + commands = [] + while ws_re.search(target): + subcommand, target = ws_re.split(target, 1) + commands.append(subcommand) + progname = "-".join(commands) + + docname, labelid = self.data['progoptions'].get((progname, target), + ('', '')) + if docname: + break + else: + return None + return make_refnode(builder, fromdocname, docname, labelid, contnode) else: diff --git a/sphinx/environment.py b/sphinx/environment.py index 399e51e5e..88075a5d9 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -618,8 +618,8 @@ class BuildEnvironment: self._read_serial(docnames, app) if config.master_doc not in self.all_docs: - self.warn(None, 'master file %s not found' % - self.doc2path(config.master_doc)) + raise SphinxError('master file %s not found' % + self.doc2path(config.master_doc)) self.app = None diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index e22024d42..72ee9f85d 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -45,14 +45,6 @@ else: return text -class _SpoofOutSphinx(doctest._SpoofOut): - # override: convert console encoding to unicode - if PY2: - def getvalue(self): - result = doctest._SpoofOut.getvalue(self) - return result.decode('string_escape') - - # set up the necessary directives class TestDirective(Directive): @@ -184,11 +176,6 @@ class TestCode(object): class SphinxDocTestRunner(doctest.DocTestRunner): - def __init__(self, *args, **kw): - doctest.DocTestRunner.__init__(self, *args, **kw) - # Override a fake output target for capturing doctest output. - self._fakeout = _SpoofOutSphinx() - def summarize(self, out, verbose=None): string_io = StringIO() old_stdout = sys.stdout @@ -262,9 +249,10 @@ Results of doctest builder run on %s self.outfile.write(text) def _warn_out(self, text): - self.info(text, nonl=True) - if self.app.quiet: + if self.app.quiet or self.app.warningiserror: self.warn(text) + else: + self.info(text, nonl=True) if isinstance(text, binary_type): text = force_decode(text, None) self.outfile.write(text) diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index 2cc661430..f5e4ce0d7 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -26,7 +26,7 @@ def html_visit_math(self, node): def html_visit_displaymath(self, node): if node['nowrap']: self.body.append(self.starttag(node, 'div', CLASS='math')) - self.body.append(node['latex']) + self.body.append(self.encode(node['latex'])) self.body.append('') raise nodes.SkipNode for i, part in enumerate(node['latex'].split('\n\n')): diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index d512db465..61e8c05b5 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -30,7 +30,7 @@ def html_visit_displaymath(self, node): self.body.append(self.starttag(node, 'div', CLASS='math')) if node['nowrap']: self.body.append(self.builder.config.mathjax_display[0] + - node['latex'] + + self.encode(node['latex']) + self.builder.config.mathjax_display[1]) self.body.append('') raise nodes.SkipNode diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 4e12300fb..dec86ae24 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -296,8 +296,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, '%(project_fn)s.tex', u'%(project_doc_texescaped_str)s', - u'%(author_texescaped_str)s', 'manual'), + (master_doc, '%(project_fn)s.tex', u'%(project_doc_texescaped_str)s', + u'%(author_texescaped_str)s', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -340,9 +340,9 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, '%(project_fn)s', u'%(project_doc_str)s', - author, '%(project_fn)s', 'One line description of project.', - 'Miscellaneous'), + (master_doc, '%(project_fn)s', u'%(project_doc_str)s', + author, '%(project_fn)s', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. @@ -371,10 +371,10 @@ epub_copyright = copyright # The basename for the epub file. It defaults to the project name. #epub_basename = project -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. #epub_theme = 'epub' # The language of the text. It defaults to the language option @@ -489,9 +489,7 @@ $(SPHINXOPTS) %(rsrcdir)s # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) %(rsrcdir)s -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp \ -epub latex latexpdf text man changes linkcheck doctest coverage gettext - +.PHONY: help help: \t@echo "Please use \\`make ' where is one of" \t@echo " html to make standalone HTML files" @@ -520,40 +518,48 @@ help: (if enabled)" \t@echo " coverage to run coverage check of the documentation (if enabled)" +.PHONY: clean clean: \trm -rf $(BUILDDIR)/* +.PHONY: html html: \t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html \t@echo \t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html." +.PHONY: dirhtml dirhtml: \t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml \t@echo \t@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." +.PHONY: singlehtml singlehtml: \t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml \t@echo \t@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." +.PHONY: pickle pickle: \t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle \t@echo \t@echo "Build finished; now you can process the pickle files." +.PHONY: json json: \t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json \t@echo \t@echo "Build finished; now you can process the JSON files." +.PHONY: htmlhelp htmlhelp: \t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp \t@echo \t@echo "Build finished; now you can run HTML Help Workshop with the" \\ \t ".hhp project file in $(BUILDDIR)/htmlhelp." +.PHONY: qthelp qthelp: \t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp \t@echo @@ -563,6 +569,7 @@ qthelp: \t@echo "To view the help file:" \t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc" +.PHONY: applehelp applehelp: \t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp \t@echo @@ -571,6 +578,7 @@ applehelp: \t "~/Library/Documentation/Help or install it in your application" \\ \t "bundle." +.PHONY: devhelp devhelp: \t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp \t@echo @@ -581,11 +589,13 @@ devhelp: $$HOME/.local/share/devhelp/%(project_fn)s" \t@echo "# devhelp" +.PHONY: epub epub: \t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub \t@echo \t@echo "Build finished. The epub file is in $(BUILDDIR)/epub." +.PHONY: latex latex: \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t@echo @@ -593,28 +603,33 @@ latex: \t@echo "Run \\`make' in that directory to run these through (pdf)latex" \\ \t "(use \\`make latexpdf' here to do that automatically)." +.PHONY: latexpdf latexpdf: \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t@echo "Running LaTeX files through pdflatex..." \t$(MAKE) -C $(BUILDDIR)/latex all-pdf \t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." +.PHONY: latexpdfja latexpdfja: \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t@echo "Running LaTeX files through platex and dvipdfmx..." \t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja \t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." +.PHONY: text text: \t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text \t@echo \t@echo "Build finished. The text files are in $(BUILDDIR)/text." +.PHONY: man man: \t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man \t@echo \t@echo "Build finished. The manual pages are in $(BUILDDIR)/man." +.PHONY: texinfo texinfo: \t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo \t@echo @@ -622,43 +637,51 @@ texinfo: \t@echo "Run \\`make' in that directory to run these through makeinfo" \\ \t "(use \\`make info' here to do that automatically)." +.PHONY: info info: \t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo \t@echo "Running Texinfo files through makeinfo..." \tmake -C $(BUILDDIR)/texinfo info \t@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." +.PHONY: gettext gettext: \t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale \t@echo \t@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." +.PHONY: changes changes: \t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes \t@echo \t@echo "The overview file is in $(BUILDDIR)/changes." +.PHONY: linkcheck linkcheck: \t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck \t@echo \t@echo "Link check complete; look for any errors in the above output " \\ \t "or in $(BUILDDIR)/linkcheck/output.txt." +.PHONY: doctest doctest: \t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest \t@echo "Testing of doctests in the sources finished, look at the " \\ \t "results in $(BUILDDIR)/doctest/output.txt." +.PHONY: coverage coverage: \t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage \t@echo "Testing of coverage in the sources finished, look at the " \\ \t "results in $(BUILDDIR)/coverage/python.txt." +.PHONY: xml xml: \t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml \t@echo \t@echo "Build finished. The XML files are in $(BUILDDIR)/xml." +.PHONY: pseudoxml pseudoxml: \t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml \t@echo diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index 23de74d37..3acbb649a 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -29,6 +29,7 @@ try: except ImportError: native_module = False +from sphinx.errors import SphinxError from sphinx.search import SearchLanguage @@ -86,9 +87,16 @@ class MecabBinder(object): if dict: param += ' -d %s' % dict + fs_enc = sys.getfilesystemencoding() or sys.getdefaultencoding() + self.ctypes_libmecab = ctypes.CDLL(libpath) + self.ctypes_libmecab.mecab_new2.argtypes = (ctypes.c_char_p,) + self.ctypes_libmecab.mecab_new2.restype = ctypes.c_void_p + self.ctypes_libmecab.mecab_sparse_tostr.argtypes = (ctypes.c_void_p, ctypes.c_char_p) self.ctypes_libmecab.mecab_sparse_tostr.restype = ctypes.c_char_p - self.ctypes_mecab = self.ctypes_libmecab.mecab_new2(param) + self.ctypes_mecab = self.ctypes_libmecab.mecab_new2(param.encode(fs_enc)) + if self.ctypes_mecab is None: + raise SphinxError('mecab initialization failed') def __del__(self): if self.ctypes_libmecab: diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 25eef2a74..138e84f54 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -270,16 +270,15 @@ \fbox{\TheSbox} } -\newcommand{\py@lightbox}{{% - \setlength\parskip{0pt}\par - \noindent\rule[0ex]{\linewidth}{0.5pt}% - \par\noindent\vspace{-0.5ex}% - }} -\newcommand{\py@endlightbox}{{% - \setlength{\parskip}{0pt}% - \par\noindent\rule[0.5ex]{\linewidth}{0.5pt}% - \par\vspace{-0.5ex}% - }} +\newcommand{\py@lightbox}{% + \par\allowbreak + \noindent\rule{\linewidth}{0.5pt}\par\nobreak + {\parskip\z@skip\noindent}% + } +\newcommand{\py@endlightbox}{% + \par\nobreak + {\parskip\z@skip\noindent\rule[.4\baselineskip]{\linewidth}{0.5pt}}\par + } % Some are quite plain: \newcommand{\py@noticestart@note}{\py@lightbox} diff --git a/sphinx/themes/classic/static/classic.css_t b/sphinx/themes/classic/static/classic.css_t index 15d072954..3f3274ec3 100644 --- a/sphinx/themes/classic/static/classic.css_t +++ b/sphinx/themes/classic/static/classic.css_t @@ -223,7 +223,7 @@ a.headerlink:hover { color: white; } -div.body p, div.body dd, div.body li { +div.body p, div.body dd, div.body li, div.body blockquote { text-align: justify; line-height: 130%; } diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index d503ac58b..f556f302f 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -106,8 +106,6 @@ class GroupedField(Field): def make_field(self, types, domain, items): fieldname = nodes.field_name('', self.label) listnode = self.list_type() - if len(items) == 1 and self.can_collapse: - return Field.make_field(self, types, domain, items[0]) for fieldarg, content in items: par = nodes.paragraph() par += self.make_xref(self.rolename, domain, fieldarg, @@ -115,6 +113,9 @@ class GroupedField(Field): par += nodes.Text(' -- ') par += content listnode += nodes.list_item('', par) + if len(items) == 1 and self.can_collapse: + fieldbody = nodes.field_body('', listnode[0][0]) + return nodes.field('', fieldname, fieldbody) fieldbody = nodes.field_body('', listnode) return nodes.field('', fieldname, fieldbody) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 2b0fff81d..d35f45265 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -47,8 +47,10 @@ def apply_source_workaround(node): node.line = definition_list_item.line - 1 node.rawsource = node.astext() # set 'classifier1' (or 'classifier2') if isinstance(node, nodes.term): - # overwrite: ``term : classifier1 : classifier2`` -> ``term text`` - node.rawsource = node.astext() + # strip classifier from rawsource of term + for classifier in reversed(node.parent.traverse(nodes.classifier)): + node.rawsource = re.sub( + '\s*:\s*%s' % classifier.astext(), '', node.rawsource) # workaround: recommonmark-0.2.0 doesn't set rawsource attribute if not node.rawsource: diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index a54175a2c..c475e0bc5 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -25,6 +25,7 @@ from sphinx import highlighting from sphinx.errors import SphinxError from sphinx.locale import admonitionlabels, _ from sphinx.util import split_into +from sphinx.util.nodes import clean_astext from sphinx.util.osutil import ustrftime from sphinx.util.texescape import tex_escape_map, tex_replace_map from sphinx.util.smartypants import educate_quotes_latex @@ -53,6 +54,7 @@ HEADER = r'''%% Generated by Sphinx. \author{%(author)s} \newcommand{\sphinxlogo}{%(logo)s} \renewcommand{\releasename}{%(releasename)s} +%(tocdepth)s %(makeindex)s ''' @@ -234,7 +236,6 @@ class Table(object): self.has_verbatim = False self.caption = None self.longtable = False - self.footnotes = [] class LaTeXTranslator(nodes.NodeVisitor): @@ -276,6 +277,7 @@ class LaTeXTranslator(nodes.NodeVisitor): 'printindex': '\\printindex', 'transition': '\n\n\\bigskip\\hrule{}\\bigskip\n\n', 'figure_align': 'htbp', + 'tocdepth': '', } # sphinx specific document classes @@ -360,6 +362,13 @@ class LaTeXTranslator(nodes.NodeVisitor): if self.elements['extraclassoptions']: self.elements['classoptions'] += ',' + \ self.elements['extraclassoptions'] + if document.get('tocdepth'): + if document.settings.docclass == 'howto': + self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' % + document['tocdepth']) + else: + self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' % + (document['tocdepth'] - 1)) self.highlighter = highlighting.PygmentsBridge( 'latex', @@ -377,7 +386,8 @@ class LaTeXTranslator(nodes.NodeVisitor): sys.maxsize]] self.bodystack = [] self.footnotestack = [] - self.termfootnotestack = [] + self.footnote_restricted = False + self.pending_footnotes = [] self.curfilestack = [] self.handled_abbrs = set() if document.settings.docclass == 'howto': @@ -416,6 +426,19 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body = self.bodystack.pop() return body + def restrict_footnote(self, node): + if self.footnote_restricted is False: + self.footnote_restricted = node + self.pending_footnotes = [] + + def unrestrict_footnote(self, node): + if self.footnote_restricted == node: + self.footnote_restricted = False + for footnode in self.pending_footnotes: + footnode['footnotetext'] = True + footnode.walkabout(self) + self.pending_footnotes = [] + def format_docclass(self, docclass): """ prepends prefix to sphinx document classes """ @@ -697,13 +720,18 @@ class LaTeXTranslator(nodes.NodeVisitor): self.this_is_the_title = 0 raise nodes.SkipNode elif isinstance(parent, nodes.section): + short = '' + if node.traverse(nodes.image): + short = '[%s]' % ' '.join(clean_astext(node).split()).translate(tex_escape_map) + try: - self.body.append(r'\%s{' % self.sectionnames[self.sectionlevel]) + self.body.append(r'\%s%s{' % (self.sectionnames[self.sectionlevel], short)) except IndexError: # just use "subparagraph", it's not numbered anyway - self.body.append(r'\%s{' % self.sectionnames[-1]) + self.body.append(r'\%s%s{' % (self.sectionnames[-1], short)) self.context.append('}\n') + self.restrict_footnote(node) if self.next_section_ids: for id in self.next_section_ids: self.context[-1] += self.hypertarget(id, anchor=False) @@ -733,6 +761,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.table.caption = self.popbody() else: self.body.append(self.context.pop()) + self.unrestrict_footnote(node) def visit_subtitle(self, node): if isinstance(node.parent, nodes.sidebar): @@ -893,6 +922,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.tableheaders = [] # Redirect body output until table is finished. self.pushbody(self.tablebody) + self.restrict_footnote(node) def depart_table(self, node): if self.table.rowcount > 30: @@ -936,7 +966,10 @@ class LaTeXTranslator(nodes.NodeVisitor): else: self.body.append('{|' + ('L|' * self.table.colcount) + '}\n') if self.table.longtable and self.table.caption is not None: - self.body.append(u'\\caption{%s}' % self.table.caption) + self.body.append(u'\\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)) self.next_table_ids.clear() @@ -963,10 +996,7 @@ 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['footnotetext'] = True - footnode.walkabout(self) + self.unrestrict_footnote(node) self.table = None self.tablebody = None @@ -1078,6 +1108,8 @@ class LaTeXTranslator(nodes.NodeVisitor): context += str(extracols + 1) context += '}{l|}{}' self.table.col += extracols + if len(node.traverse(nodes.paragraph)) >= 2: + self.table.has_problematic = True self.context.append(context) def depart_entry(self, node): @@ -1140,16 +1172,12 @@ class LaTeXTranslator(nodes.NodeVisitor): if node.get('ids'): ctx += self.hypertarget(node['ids'][0]) self.body.append('\\item[{') - self.termfootnotestack.append([]) + self.restrict_footnote(node) self.context.append(ctx) def depart_term(self, node): self.body.append(self.context.pop()) - footnotes = self.termfootnotestack.pop() - for footnode in footnotes: - footnode['footnotetext'] = True - footnode.walkabout(self) - + self.unrestrict_footnote(node) self.in_term -= 1 def visit_termsep(self, node): @@ -1264,12 +1292,12 @@ class LaTeXTranslator(nodes.NodeVisitor): (1, 'top'): ('', ''), (1, 'middle'): ('\\raisebox{-0.5\\height}{', '}'), (1, 'bottom'): ('\\raisebox{-\\height}{', '}'), - (0, 'center'): ('{\\hfill', '\\hfill}'), + (0, 'center'): ('{\\hspace*{\\fill}', '\\hspace*{\\fill}}'), # These 2 don't exactly do the right thing. The image should # be floated alongside the paragraph. See # http://www.w3.org/TR/html4/struct/objects.html#adef-align-IMG - (0, 'left'): ('{', '\\hfill}'), - (0, 'right'): ('{\\hfill', '}'), + (0, 'left'): ('{', '\\hspace*{\\fill}}'), + (0, 'right'): ('{\\hspace*{\\fill}', '}'), } try: pre.append(align_prepost[is_inline, attrs['align']][0]) @@ -1306,6 +1334,7 @@ class LaTeXTranslator(nodes.NodeVisitor): for id in self.next_figure_ids: ids += self.hypertarget(id, anchor=False) self.next_figure_ids.clear() + self.restrict_footnote(node) if (len(node.children) and isinstance(node.children[0], nodes.image) and node.children[0]['ids']): @@ -1333,6 +1362,7 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_figure(self, node): self.body.append(self.context.pop()) + self.unrestrict_footnote(node) def visit_caption(self, node): self.in_caption += 1 @@ -1668,18 +1698,11 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append('\\protect\\footnotemark[%s]' % num) else: self.body.append('\\footnotemark[%s]' % num) - elif self.table: + elif self.footnote_restricted: self.footnotestack[-1][num][1] = True self.body.append('\\protect\\footnotemark[%s]' % num) - self.table.footnotes.append(footnode) - elif self.in_term: - self.body.append('\\footnotemark[%s]' % num) - self.termfootnotestack[-1].append(footnode) + self.pending_footnotes.append(footnode) else: - if self.in_caption: - raise UnsupportedError('%s:%s: footnotes in float captions ' - 'are not supported by LaTeX' % - (self.curfilestack[-1], node.line)) self.footnotestack[-1][num][1] = True footnode.walkabout(self) raise nodes.SkipChildren diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 4343f6a33..30e77165f 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -30,12 +30,42 @@ class ManualPageWriter(Writer): self.builder.translator_class or ManualPageTranslator) def translate(self): + transform = NestedInlineTransform(self.document) + transform.apply() visitor = self.translator_class(self.builder, self.document) self.visitor = visitor self.document.walkabout(visitor) self.output = visitor.astext() +class NestedInlineTransform(object): + """ + Flatten nested inline nodes: + + Before: + foo=1&bar=2 + After: + foo=var&bar=2 + """ + def __init__(self, document): + self.document = document + + def apply(self): + def is_inline(node): + return isinstance(node, (nodes.literal, nodes.emphasis, nodes.strong)) + + for node in self.document.traverse(is_inline): + if any(is_inline(subnode) for subnode in node): + pos = node.parent.index(node) + for subnode in reversed(node[1:]): + node.remove(subnode) + if is_inline(subnode): + node.parent.insert(pos + 1, subnode) + else: + newnode = node.__class__('', subnode, **node.attributes) + node.parent.insert(pos + 1, newnode) + + class ManualPageTranslator(BaseTranslator): """ Custom translator. diff --git a/tests/root/math.txt b/tests/root/math.txt index aeba85f24..5a209bed4 100644 --- a/tests/root/math.txt +++ b/tests/root/math.txt @@ -7,7 +7,7 @@ This is inline math: :math:`a^2 + b^2 = c^2`. .. math:: - a^2 + b^2 = c^2 + a + 1 < b .. math:: :label: foo @@ -23,4 +23,9 @@ This is inline math: :math:`a^2 + b^2 = c^2`. n \in \mathbb N +.. math:: + :nowrap: + + a + 1 < b + Referencing equation :eq:`foo`. diff --git a/tests/root/objects.txt b/tests/root/objects.txt index 8bdfc3015..cd711070f 100644 --- a/tests/root/objects.txt +++ b/tests/root/objects.txt @@ -174,7 +174,17 @@ Others .. option:: arg -Link to :option:`perl +p` and :option:`arg`. +Link to :option:`perl +p` and :option:`arg` + +.. program:: hg + +.. option:: commit + +.. program:: git commit + +.. option:: -p + +Link to :option:`hg commit` and :option:`git commit -p`. User markup diff --git a/tests/roots/test-autosummary/conf.py b/tests/roots/test-autosummary/conf.py index d9a447480..5cb589cda 100644 --- a/tests/roots/test-autosummary/conf.py +++ b/tests/roots/test-autosummary/conf.py @@ -7,3 +7,5 @@ extensions = ['sphinx.ext.autosummary'] # The suffix of source filenames. source_suffix = '.rst' autosummary_generate = True + +exclude_patterns = ['_build'] diff --git a/tests/roots/test-build-text/conf.py b/tests/roots/test-build-text/conf.py index 1ba342a65..23d0ae840 100644 --- a/tests/roots/test-build-text/conf.py +++ b/tests/roots/test-build-text/conf.py @@ -1,2 +1,3 @@ master_doc = 'contents' source_suffix = '.txt' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-circular/conf.py b/tests/roots/test-circular/conf.py index e69de29bb..027d21cda 100644 --- a/tests/roots/test-circular/conf.py +++ b/tests/roots/test-circular/conf.py @@ -0,0 +1 @@ +exclude_patterns = ['_build'] diff --git a/tests/roots/test-contentsname/conf.py b/tests/roots/test-contentsname/conf.py index cf05c9b5c..c46e40773 100644 --- a/tests/roots/test-contentsname/conf.py +++ b/tests/roots/test-contentsname/conf.py @@ -2,3 +2,4 @@ master_doc = 'index' html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-directive-code/conf.py b/tests/roots/test-directive-code/conf.py index f81c30bc4..e10f5e5fb 100644 --- a/tests/roots/test-directive-code/conf.py +++ b/tests/roots/test-directive-code/conf.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- master_doc = 'index' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-directive-only/conf.py b/tests/roots/test-directive-only/conf.py index eb3a3d0d2..b9209f08b 100644 --- a/tests/roots/test-directive-only/conf.py +++ b/tests/roots/test-directive-only/conf.py @@ -1,2 +1,3 @@ project = 'test-directive-only' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-doctest/conf.py b/tests/roots/test-doctest/conf.py index f6a12edb9..fcf6a6cda 100644 --- a/tests/roots/test-doctest/conf.py +++ b/tests/roots/test-doctest/conf.py @@ -1,5 +1,6 @@ extensions = ['sphinx.ext.doctest'] project = 'test project for doctest' -master_doc = 'doctest.txt' +master_doc = 'doctest' source_suffix = '.txt' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-doctest/doctest.txt b/tests/roots/test-doctest/doctest.txt index ac5da0d15..053601f3c 100644 --- a/tests/roots/test-doctest/doctest.txt +++ b/tests/roots/test-doctest/doctest.txt @@ -136,3 +136,14 @@ umlauts: äöü. >>> print('Japanese: 日本語') Japanese: 日本語 +keep control char in raw string +------------------------------- + +.. doctest:: + + >>> print('one\ntwo') + one + two + >>> print(r'one\ntwo') + one\ntwo + diff --git a/tests/roots/test-docutilsconf/conf.py b/tests/roots/test-docutilsconf/conf.py index 67074ec64..0a88a65fd 100644 --- a/tests/roots/test-docutilsconf/conf.py +++ b/tests/roots/test-docutilsconf/conf.py @@ -3,3 +3,4 @@ project = 'Sphinx docutils conf ' source_suffix = '.txt' keep_warnings = True +exclude_patterns = ['_build'] diff --git a/tests/roots/test-domain-cpp/any-role.rst b/tests/roots/test-domain-cpp/any-role.rst new file mode 100644 index 000000000..dacd2f600 --- /dev/null +++ b/tests/roots/test-domain-cpp/any-role.rst @@ -0,0 +1,10 @@ +any role +-------- + +* :cpp:any:`Sphinx` +* ref function without parens :cpp:any:`hello`. +* ref function with parens :cpp:any:`hello()`. +* :cpp:any:`Sphinx::version` +* :cpp:any:`version` +* :cpp:any:`List` +* :cpp:any:`MyEnum` diff --git a/tests/roots/test-domain-cpp/conf.py b/tests/roots/test-domain-cpp/conf.py new file mode 100644 index 000000000..c46e40773 --- /dev/null +++ b/tests/roots/test-domain-cpp/conf.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' +html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-domain-cpp/index.rst b/tests/roots/test-domain-cpp/index.rst new file mode 100644 index 000000000..9be739f1e --- /dev/null +++ b/tests/roots/test-domain-cpp/index.rst @@ -0,0 +1,37 @@ +test-domain-cpp +=============== + +directives +---------- + +.. cpp:class:: public Sphinx + + The description of Sphinx class. + +.. cpp:function:: int hello(char *name) + + The description of hello function. + +.. cpp:member:: float Sphinx::version + + The description of Sphinx::version. + +.. cpp:var:: int version + + The description of version. + +.. cpp:type:: std::vector List + + The description of List type. + +.. cpp:enum:: MyEnum + + An unscoped enum. + +.. cpp:enum-class:: MyScopedEnum + + A scoped enum. + +.. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type + + A scoped enum with non-default visibility, and with a specified underlying type. diff --git a/tests/roots/test-domain-cpp/roles.rst b/tests/roots/test-domain-cpp/roles.rst new file mode 100644 index 000000000..8baf29b4c --- /dev/null +++ b/tests/roots/test-domain-cpp/roles.rst @@ -0,0 +1,10 @@ +roles +----- + +* :cpp:class:`Sphinx` +* ref function without parens :cpp:func:`hello`. +* ref function with parens :cpp:func:`hello()`. +* :cpp:member:`Sphinx::version` +* :cpp:var:`version` +* :cpp:type:`List` +* :cpp:enum:`MyEnum` diff --git a/tests/roots/test-double-inheriting-theme/conf.py b/tests/roots/test-double-inheriting-theme/conf.py index dfdccc49b..c2f8db3b0 100644 --- a/tests/roots/test-double-inheriting-theme/conf.py +++ b/tests/roots/test-double-inheriting-theme/conf.py @@ -5,3 +5,4 @@ import sys, os templates_path = ['_templates'] master_doc = 'index' html_theme = 'base_theme2' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-ext-graphviz/conf.py b/tests/roots/test-ext-graphviz/conf.py index cecd53668..6dce9d0c6 100644 --- a/tests/roots/test-ext-graphviz/conf.py +++ b/tests/roots/test-ext-graphviz/conf.py @@ -2,3 +2,4 @@ extensions = ['sphinx.ext.graphviz'] master_doc = 'index' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-ext-ifconfig/conf.py b/tests/roots/test-ext-ifconfig/conf.py index 327bd126d..d205fe9f5 100644 --- a/tests/roots/test-ext-ifconfig/conf.py +++ b/tests/roots/test-ext-ifconfig/conf.py @@ -2,6 +2,7 @@ extensions = ['sphinx.ext.ifconfig'] master_doc = 'index' +exclude_patterns = ['_build'] confval1 = True diff --git a/tests/roots/test-ext-viewcode/conf.py b/tests/roots/test-ext-viewcode/conf.py index a99a72bbc..c2b358fb5 100644 --- a/tests/roots/test-ext-viewcode/conf.py +++ b/tests/roots/test-ext-viewcode/conf.py @@ -6,6 +6,7 @@ import os sys.path.insert(0, os.path.abspath('.')) extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] master_doc = 'index' +exclude_patterns = ['_build'] if 'test_linkcode' in tags: diff --git a/tests/roots/test-footnotes/conf.py b/tests/roots/test-footnotes/conf.py index cf05c9b5c..c46e40773 100644 --- a/tests/roots/test-footnotes/conf.py +++ b/tests/roots/test-footnotes/conf.py @@ -2,3 +2,4 @@ master_doc = 'index' html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-footnotes/index.rst b/tests/roots/test-footnotes/index.rst index e8137da71..a20052037 100644 --- a/tests/roots/test-footnotes/index.rst +++ b/tests/roots/test-footnotes/index.rst @@ -33,9 +33,11 @@ The section with a reference to [AuthorYear]_ .. [1] Second .. [#] Third -The section with a reference to [1]_ +The section with a reference to [#]_ ===================================== +.. [#] Footnote in section + `URL in term `_ Description Description Description ... @@ -46,3 +48,95 @@ Footnote in term [#]_ Description2 .. [#] Footnote in term + +.. figure:: rimg.png + + This is the figure caption with a footnote to [#]_. + +.. [#] Footnote in caption + +.. list-table:: footnote [#]_ in caption of normal table + :widths: 1 1 + :header-rows: 1 + + * - name + - desc + * - a + - b + * - a + - b + +.. [#] Foot note in table + +.. list-table:: footnote [#]_ in caption of longtable + :widths: 1 1 + :header-rows: 1 + + * - name + - desc + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + * - a + - b + +.. [#] Foot note in longtable diff --git a/tests/roots/test-image-in-section/conf.py b/tests/roots/test-image-in-section/conf.py new file mode 100644 index 000000000..7da44fdae --- /dev/null +++ b/tests/roots/test-image-in-section/conf.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' +exclude_patterns = ['_build'] + +rst_epilog = ''' +.. |picture| image:: pic.png + :width: 15pt + :height: 15pt + :alt: alternative_text +''' + diff --git a/tests/roots/test-image-in-section/index.rst b/tests/roots/test-image-in-section/index.rst new file mode 100644 index 000000000..a69db0a77 --- /dev/null +++ b/tests/roots/test-image-in-section/index.rst @@ -0,0 +1,18 @@ +test-image-in-section +===================== +this is dummy content + + +|picture| Test section +---------------------- +blah blah blah + + +Another section +--------------- +another blah + + +Other [blah] |picture| section +------------------------------ +other blah diff --git a/tests/roots/test-image-in-section/pic.png b/tests/roots/test-image-in-section/pic.png new file mode 100644 index 000000000..1081dc143 Binary files /dev/null and b/tests/roots/test-image-in-section/pic.png differ diff --git a/tests/roots/test-intl/conf.py b/tests/roots/test-intl/conf.py index 74446a143..aafd9ba79 100644 --- a/tests/roots/test-intl/conf.py +++ b/tests/roots/test-intl/conf.py @@ -7,3 +7,4 @@ templates_path = ['_templates'] html_additional_pages = {'index': 'index.html'} release = version = '2013.120' gettext_additional_targets = ['index'] +exclude_patterns = ['_build'] diff --git a/tests/roots/test-intl/definition_terms.po b/tests/roots/test-intl/definition_terms.po index 6de1d1c42..8a8199378 100644 --- a/tests/roots/test-intl/definition_terms.po +++ b/tests/roots/test-intl/definition_terms.po @@ -25,14 +25,14 @@ msgstr "SOME TERM" msgid "The corresponding definition" msgstr "THE CORRESPONDING DEFINITION" -msgid "Some other term" -msgstr "SOME OTHER TERM" +msgid "Some *term* `with link `__" +msgstr "SOME *TERM* `WITH LINK `__" msgid "The corresponding definition #2" msgstr "THE CORRESPONDING DEFINITION #2" -msgid "Some term with" -msgstr "SOME TERM WITH" +msgid "Some **term** with" +msgstr "SOME **TERM** WITH" msgid "classifier1" msgstr "CLASSIFIER1" diff --git a/tests/roots/test-intl/definition_terms.txt b/tests/roots/test-intl/definition_terms.txt index 66230f98f..e85953024 100644 --- a/tests/roots/test-intl/definition_terms.txt +++ b/tests/roots/test-intl/definition_terms.txt @@ -6,9 +6,9 @@ i18n with definition terms Some term The corresponding definition -Some other term +Some *term* `with link `__ The corresponding definition #2 -Some term with : classifier1 : classifier2 +Some **term** with : classifier1 : classifier2 The corresponding definition diff --git a/tests/roots/test-numbered-circular/conf.py b/tests/roots/test-numbered-circular/conf.py index e69de29bb..027d21cda 100644 --- a/tests/roots/test-numbered-circular/conf.py +++ b/tests/roots/test-numbered-circular/conf.py @@ -0,0 +1 @@ +exclude_patterns = ['_build'] diff --git a/tests/roots/test-numfig/conf.py b/tests/roots/test-numfig/conf.py index cf05c9b5c..c46e40773 100644 --- a/tests/roots/test-numfig/conf.py +++ b/tests/roots/test-numfig/conf.py @@ -2,3 +2,4 @@ master_doc = 'index' html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-setup/doc/conf.py b/tests/roots/test-setup/doc/conf.py index a55679a4b..b1c9acf46 100644 --- a/tests/roots/test-setup/doc/conf.py +++ b/tests/roots/test-setup/doc/conf.py @@ -3,3 +3,4 @@ project = 'Sphinx smallest project' source_suffix = '.txt' keep_warnings = True +exclude_patterns = ['_build'] diff --git a/tests/roots/test-templating/conf.py b/tests/roots/test-templating/conf.py index 225da82e7..ff8207454 100644 --- a/tests/roots/test-templating/conf.py +++ b/tests/roots/test-templating/conf.py @@ -5,6 +5,7 @@ source_suffix = '.txt' keep_warnings = True templates_path = ['_templates'] release = version = '2013.120' +exclude_patterns = ['_build'] extensions = ['sphinx.ext.autosummary'] autosummary_generate = ['autosummary_templating'] diff --git a/tests/roots/test-theming/conf.py b/tests/roots/test-theming/conf.py index 2717087d1..608afcfcd 100644 --- a/tests/roots/test-theming/conf.py +++ b/tests/roots/test-theming/conf.py @@ -2,4 +2,5 @@ html_theme = 'test-theme' master_doc = 'index' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-tocdepth/conf.py b/tests/roots/test-tocdepth/conf.py index cf05c9b5c..c46e40773 100644 --- a/tests/roots/test-tocdepth/conf.py +++ b/tests/roots/test-tocdepth/conf.py @@ -2,3 +2,4 @@ master_doc = 'index' html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-toctree-glob/conf.py b/tests/roots/test-toctree-glob/conf.py index cf05c9b5c..c46e40773 100644 --- a/tests/roots/test-toctree-glob/conf.py +++ b/tests/roots/test-toctree-glob/conf.py @@ -2,3 +2,4 @@ master_doc = 'index' html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-toctree-maxdepth/bar.rst b/tests/roots/test-toctree-maxdepth/bar.rst new file mode 100644 index 000000000..d70dec90d --- /dev/null +++ b/tests/roots/test-toctree-maxdepth/bar.rst @@ -0,0 +1,27 @@ +:tocdepth: 2 + +=== +Bar +=== + +should be 2 + +Bar A +===== + +should be 2.1 + +.. toctree:: + + baz + +Bar B +===== + +should be 2.2 + +Bar B1 +------ + +should be 2.2.1 + diff --git a/tests/roots/test-toctree-maxdepth/baz.rst b/tests/roots/test-toctree-maxdepth/baz.rst new file mode 100644 index 000000000..b07fa0507 --- /dev/null +++ b/tests/roots/test-toctree-maxdepth/baz.rst @@ -0,0 +1,5 @@ +Baz A +----- + +should be 2.1.1 + diff --git a/tests/roots/test-toctree-maxdepth/conf.py b/tests/roots/test-toctree-maxdepth/conf.py new file mode 100644 index 000000000..c46e40773 --- /dev/null +++ b/tests/roots/test-toctree-maxdepth/conf.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' +html_theme = 'classic' +exclude_patterns = ['_build'] diff --git a/tests/roots/test-toctree-maxdepth/foo.rst b/tests/roots/test-toctree-maxdepth/foo.rst new file mode 100644 index 000000000..61fd539ff --- /dev/null +++ b/tests/roots/test-toctree-maxdepth/foo.rst @@ -0,0 +1,26 @@ +=== +Foo +=== + +should be 1 + +Foo A +===== + +should be 1.1 + +Foo A1 +------ + +should be 1.1.1 + +Foo B +===== + +should be 1.2 + +Foo B1 +------ + +should be 1.2.1 + diff --git a/tests/roots/test-toctree-maxdepth/index.rst b/tests/roots/test-toctree-maxdepth/index.rst new file mode 100644 index 000000000..30dc61c8b --- /dev/null +++ b/tests/roots/test-toctree-maxdepth/index.rst @@ -0,0 +1,9 @@ +test-toctree-max-depth +====================== + +.. toctree:: + :numbered: + :maxdepth: 2 + + foo + bar diff --git a/tests/roots/test-versioning/conf.py b/tests/roots/test-versioning/conf.py index edcf92951..fb54e7972 100644 --- a/tests/roots/test-versioning/conf.py +++ b/tests/roots/test-versioning/conf.py @@ -1,3 +1,4 @@ project = 'versioning test root' master_doc = 'index' source_suffix = '.txt' +exclude_patterns = ['_build'] diff --git a/tests/test_build.py b/tests/test_build.py index 5b9d7a756..97ef651a6 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -12,6 +12,7 @@ from six import BytesIO from textwrap import dedent +from sphinx.errors import SphinxError from util import with_app, rootdir, tempdir, SkipTest, TestApp @@ -73,6 +74,18 @@ def test_build_all(): yield verify_build, buildername, srcdir +@with_app(buildername='text') +def test_master_doc_not_found(app, status, warning): + (app.srcdir / 'contents.txt').move(app.srcdir / 'contents.txt.bak') + try: + app.builder.build_all() + assert False # SphinxError not raised + except Exception as exc: + assert isinstance(exc, SphinxError) + finally: + (app.srcdir / 'contents.txt.bak').move(app.srcdir / 'contents.txt') + + @with_app(buildername='text', testroot='circular') def test_circular_toctree(app, status, warning): app.builder.build_all() diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 91bc8e382..6dc56acb1 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -16,7 +16,7 @@ from six import PY3, iteritems from six.moves import html_entities from sphinx import __display_version__ -from util import remove_unicode_literals, gen_with_app +from util import remove_unicode_literals, gen_with_app, with_app from etree13 import ElementTree as ET @@ -31,9 +31,7 @@ http://www.python.org/logo.png reading included file u'.*?wrongenc.inc' seems to be wrong, try giving an \ :encoding: option\\n? %(root)s/includes.txt:4: WARNING: download file not readable: .*?nonexisting.png -(%(root)s/markup.txt:\\d+: WARNING: Malformed :option: u'&option', does \ -not contain option marker - or -- or / or \\+ -%(root)s/undecodable.txt:3: WARNING: undecodable source characters, replacing \ +(%(root)s/undecodable.txt:3: WARNING: undecodable source characters, replacing \ with "\\?": b?'here: >>>(\\\\|/)xbb<<<' )?""" @@ -234,6 +232,23 @@ HTML_XPATH = { (".//td[@class='field-body']/ul/li/strong", '^hour$'), (".//td[@class='field-body']/ul/li/em", '^DuplicateType$'), (".//td[@class='field-body']/ul/li/em", tail_check(r'.* Some parameter')), + # others + (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span", + 'perl'), + (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span", + '\+p'), + (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span", + 'arg'), + (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span", + 'hg'), + (".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span", + 'commit'), + (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span", + 'git'), + (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span", + 'commit'), + (".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span", + '-p'), ], 'contents.html': [ (".//meta[@name='hc'][@content='hcval']", ''), @@ -914,3 +929,18 @@ def test_numfig_with_secnum_depth(app, status, warning): for xpath, check, be_found in paths: yield check_xpath, etree, fname, xpath, check, be_found + + +@with_app(buildername='html') +def test_jsmath(app, status, warning): + app.builder.build_all() + content = (app.outdir / 'math.html').text() + + assert '
\na^2 + b^2 = c^2
' in content + assert '
\n\\begin{split}a + 1 < b\\end{split}
' in content + assert ('(1)
\n' + 'e^{i\\pi} = 1
' in content) + assert ('(2)
\n' + 'e^{ix} = \\cos x + i\\sin x
' in content) + assert '
\nn \\in \\mathbb N
' in content + assert '
\na + 1 < b
' in content diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 774ed4273..ad4192bbb 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -16,6 +16,7 @@ from subprocess import Popen, PIPE from six import PY3 +from sphinx.errors import SphinxError from sphinx.writers.latex import LaTeXTranslator from util import SkipTest, remove_unicode_literals, with_app @@ -334,7 +335,17 @@ def test_reference_in_caption(app, status, warning): assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result assert '\\caption{The table title with a reference to {[}AuthorYear{]}}' in result assert '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result - assert '\\chapter{The section with a reference to \\protect\\footnotemark[1]}' in result + assert ('\\chapter{The section with a reference to \\protect\\footnotemark[4]}\n' + '\\label{index:the-section-with-a-reference-to}' + '\\footnotetext[4]{\nFootnote in section\n}' in result) + assert ('\\caption{This is the figure caption with a footnote to ' + '\\protect\\footnotemark[6].}\end{figure}\n' + '\\footnotetext[6]{\nFootnote in caption\n}')in result + assert ('\\caption{footnote \\protect\\footnotemark[7] ' + 'in caption of normal table}') in result + assert '\\end{threeparttable}\n\n\\footnotetext[7]{\nFoot note in table\n}' in result + assert '\\caption{footnote \\protect\\footnotemark[8] in caption of longtable}' in result + assert '\end{longtable}\n\n\\footnotetext[8]{\nFoot note in longtable\n}' in result @with_app(buildername='latex', testroot='footnotes', @@ -353,8 +364,8 @@ def test_latex_show_urls_is_inline(app, status, warning): '(http://sphinx-doc.org/\\textasciitilde{}test/)' in result) assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term} (http://sphinx-doc.org/)}] ' '\\leavevmode\nDescription' in result) - assert ('\\item[{Footnote in term \\footnotemark[4]}] ' - '\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result) + assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] ' + '\\leavevmode\\footnotetext[5]{\nFootnote in term\n}\nDescription' in result) assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist} ' '(http://sphinx-doc.org/)}] \\leavevmode\nDescription' in result) assert ('\\href{https://github.com/sphinx-doc/sphinx}' @@ -378,12 +389,12 @@ def test_latex_show_urls_is_footnote(app, status, warning): assert 'Third footnote: \\footnote[5]{\nThird\n}' in result assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde}' '\\footnote[4]{\nhttp://sphinx-doc.org/\\textasciitilde{}test/\n}' in result) - assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\footnotemark[6]}] ' - '\\leavevmode\\footnotetext[6]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) - assert ('\\item[{Footnote in term \\footnotemark[8]}] ' - '\\leavevmode\\footnotetext[8]{\nFootnote in term\n}\nDescription' in result) - assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\footnotemark[7]}] ' + assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\protect\\footnotemark[7]}] ' '\\leavevmode\\footnotetext[7]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) + assert ('\\item[{Footnote in term \\protect\\footnotemark[9]}] ' + '\\leavevmode\\footnotetext[9]{\nFootnote in term\n}\nDescription' in result) + assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\protect\\footnotemark[8]}] ' + '\\leavevmode\\footnotetext[8]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) assert ('\\href{https://github.com/sphinx-doc/sphinx}' '{https://github.com/sphinx-doc/sphinx}\n' in result) assert ('\\href{mailto:sphinx-dev@googlegroups.com}' @@ -405,11 +416,61 @@ def test_latex_show_urls_is_no(app, status, warning): assert '\\href{http://sphinx-doc.org/~test/}{URL including tilde}' in result assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}}] ' '\\leavevmode\nDescription' in result) - assert ('\\item[{Footnote in term \\footnotemark[4]}] ' - '\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result) + assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] ' + '\\leavevmode\\footnotetext[5]{\nFootnote in term\n}\nDescription' in result) assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}}] ' '\\leavevmode\nDescription' in result) assert ('\\href{https://github.com/sphinx-doc/sphinx}' '{https://github.com/sphinx-doc/sphinx}\n' in result) assert ('\\href{mailto:sphinx-dev@googlegroups.com}' '{sphinx-dev@googlegroups.com}\n' in result) + + +@with_app(buildername='latex', testroot='image-in-section') +def test_image_in_section(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'Python.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert ('\chapter[Test section]{\includegraphics[width=15pt,height=15pt]{{pic}.png} Test section}' + in result) + assert ('\chapter[Other {[}blah{]} section]{Other {[}blah{]} \includegraphics[width=15pt,height=15pt]{{pic}.png} section}' in result) + assert ('\chapter{Another section}' in result) + + +@with_app(buildername='latex', confoverrides={'latex_logo': 'notfound.jpg'}) +def test_latex_logo_if_not_found(app, status, warning): + try: + app.builder.build_all() + assert False # SphinxError not raised + except Exception as exc: + assert isinstance(exc, SphinxError) + + +@with_app(buildername='latex', testroot='toctree-maxdepth', + confoverrides={'latex_documents': [ + ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'manual'), + ]}) +def test_toctree_maxdepth_manual(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\setcounter{tocdepth}{1}' in result + + +@with_app(buildername='latex', testroot='toctree-maxdepth', + confoverrides={'latex_documents': [ + ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation', + 'Georg Brandl', 'howto'), + ]}) +def test_toctree_maxdepth_howto(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\setcounter{tocdepth}{2}' in result diff --git a/tests/test_build_manpage.py b/tests/test_build_manpage.py new file mode 100644 index 000000000..85ae5be44 --- /dev/null +++ b/tests/test_build_manpage.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +""" + test_build_manpage + ~~~~~~~~~~~~~~~~~~ + + Test the build process with manpage builder with the test root. + + :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from __future__ import print_function + +from util import with_app + + +@with_app(buildername='man') +def test_all(app, status, warning): + app.builder.build_all() + assert (app.outdir / 'SphinxTests.1').exists() + + content = (app.outdir / 'SphinxTests.1').text() + assert r'\fBprint \fP\fIi\fP\fB\en\fP' in content diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index ba96945fd..fbf211711 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -9,9 +9,11 @@ :license: BSD, see LICENSE for details. """ +import re + from six import text_type -from util import raises +from util import raises, with_app from sphinx import addnodes from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError @@ -393,3 +395,49 @@ def test_templates(): # for a in ids: # print(a) # raise DefinitionError("") + + +@with_app(testroot='domain-cpp') +def test_build_domain_cpp(app, status, warning): + app.builder.build_all() + + roles = (app.outdir / 'roles.html').text() + assert re.search('
  • Sphinx
  • ', roles) + assert re.search(('
  • ref function without parens ' + 'hello\(\)\.
  • '), roles) + assert re.search(('
  • ref function with parens ' + 'hello\(\)\.
  • '), roles) + assert re.search('
  • Sphinx::version
  • ', + roles) + assert re.search('
  • version
  • ', roles) + assert re.search('
  • List
  • ', roles) + assert re.search('
  • MyEnum
  • ', roles) + + any_role = (app.outdir / 'any-role.html').text() + assert re.search('
  • Sphinx
  • ', any_role) + assert re.search(('
  • ref function without parens ' + 'hello\(\)\.
  • '), any_role) + assert re.search(('
  • ref function with parens ' + 'hello\(\)\.
  • '), any_role) + assert re.search('
  • Sphinx::version
  • ', + any_role) + assert re.search('
  • version
  • ', any_role) + assert re.search('
  • List
  • ', any_role) + assert re.search('
  • MyEnum
  • ', any_role) + + +@with_app(testroot='domain-cpp', confoverrides={'add_function_parentheses': False}) +def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning): + app.builder.build_all() + + roles = (app.outdir / 'roles.html').text() + assert re.search(('
  • ref function without parens ' + 'hello\.
  • '), roles) + assert re.search(('
  • ref function with parens ' + 'hello\.
  • '), roles) + + any_role = (app.outdir / 'any-role.html').text() + assert re.search(('
  • ref function without parens ' + 'hello\.
  • '), any_role) + assert re.search(('
  • ref function with parens ' + 'hello\.
  • '), any_role) diff --git a/tests/test_intl.py b/tests/test_intl.py index dabb2a3f5..691b68061 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -16,6 +16,7 @@ import re from subprocess import Popen, PIPE from xml.etree import ElementTree +from babel.messages import pofile from nose.tools import assert_equal from six import string_types @@ -40,6 +41,11 @@ def gen_with_intl_app(builder, confoverrides={}, *args, **kw): return gen_with_app(builder, *args, **default_kw) +def read_po(pathname): + with pathname.open() as f: + return pofile.read_po(f) + + def setup_module(): if not root.exists(): (rootdir / 'roots' / 'test-intl').copytree(root) @@ -175,16 +181,16 @@ def test_text_builder(app, status, warning): u'WARNING: Literal block expected; none found.' yield assert_re_search, expected_warning_expr, warnings - # --- definition terms: regression test for #975 + # --- definition terms: regression test for #975, #2198, #2205 result = (app.outdir / 'definition_terms.txt').text(encoding='utf-8') expect = (u"\nI18N WITH DEFINITION TERMS" u"\n**************************\n" u"\nSOME TERM" u"\n THE CORRESPONDING DEFINITION\n" - u"\nSOME OTHER TERM" + u"\nSOME *TERM* WITH LINK" u"\n THE CORRESPONDING DEFINITION #2\n" - u"\nSOME TERM WITH : CLASSIFIER1 : CLASSIFIER2" + u"\nSOME **TERM** WITH : CLASSIFIER1 : CLASSIFIER2" u"\n THE CORRESPONDING DEFINITION\n" ) yield assert_equal, result, expect @@ -280,8 +286,8 @@ def test_text_builder(app, status, warning): u"\n * **foo** -- DESCRIPTION OF PARAMETER foo\n" u"\n * **bar** -- DESCRIPTION OF PARAMETER bar\n" u"\nclass Cls3(values)\n" - u"\n Raises ValueError:" - u"\n IF THE VALUES ARE OUT OF RANGE\n" + u"\n Raises:" + u"\n **ValueError** -- IF THE VALUES ARE OUT OF RANGE\n" u"\nclass Cls4(values)\n" u"\n Raises:" u"\n * **TypeError** -- IF THE VALUES ARE NOT VALID\n" @@ -304,6 +310,31 @@ def test_text_builder(app, status, warning): yield assert_in, d.upper() + " BODY", result +@gen_with_intl_app('gettext', freshenv=True) +def test_gettext_builder(app, status, warning): + app.builder.build_all() + + # --- definition terms: regression test for #2198, #2205 + expect = read_po(app.srcdir / 'definition_terms.po') + actual = read_po(app.outdir / 'definition_terms.pot') + for expect_msg in [m for m in expect if m.id]: + yield assert_in, expect_msg.id, [m.id for m in actual if m.id] + + # --- glossary terms: regression test for #1090 + expect = read_po(app.srcdir / 'glossary_terms.po') + actual = read_po(app.outdir / 'glossary_terms.pot') + for expect_msg in [m for m in expect if m.id]: + yield assert_in, expect_msg.id, [m.id for m in actual if m.id] + warnings = warning.getvalue().replace(os.sep, '/') + yield assert_not_in, 'term not in glossary', warnings + + # --- glossary term inconsistencies: regression test for #1090 + expect = read_po(app.srcdir / 'glossary_terms_inconsistency.po') + actual = read_po(app.outdir / 'glossary_terms_inconsistency.pot') + for expect_msg in [m for m in expect if m.id]: + yield assert_in, expect_msg.id, [m.id for m in actual if m.id] + + @gen_with_intl_app('html', freshenv=True) def test_html_builder(app, status, warning): app.builder.build_all() diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py index 47ef8ecce..03ca13266 100644 --- a/tests/test_util_i18n.py +++ b/tests/test_util_i18n.py @@ -55,7 +55,8 @@ def test_catalog_write_mo(dir): cat = i18n.CatalogInfo(dir, 'test', 'utf-8') cat.write_mo('en') assert path.exists(cat.mo_path) - assert read_mo(open(cat.mo_path, 'rb')) is not None + with open(cat.mo_path, 'rb') as f: + assert read_mo(f) is not None @with_tempdir