From ea5fd7284c4402e9668b321c1c78cdeb52992491 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 20 Feb 2016 23:25:00 +0900 Subject: [PATCH 1/3] Refactor: all of warnfuncs bypasses kwargs to Sphinx.warn() --- sphinx/builders/__init__.py | 21 ++++++++++++--------- sphinx/environment.py | 14 +++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 38e009a8f..8863050ba 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -260,12 +260,12 @@ class Builder(object): # while reading, collect all warnings from docutils warnings = [] - self.env.set_warnfunc(lambda *args: warnings.append(args)) + self.env.set_warnfunc(lambda *args, **kwargs: warnings.append((args, kwargs))) updated_docnames = set(self.env.update(self.config, self.srcdir, self.doctreedir, self.app)) self.env.set_warnfunc(self.warn) - for warning in warnings: - self.warn(*warning) + for warning, kwargs in warnings: + self.warn(*warning, **kwargs) doccount = len(updated_docnames) self.info(bold('looking for now-outdated files... '), nonl=1) @@ -350,7 +350,7 @@ class Builder(object): self.info('done') warnings = [] - self.env.set_warnfunc(lambda *args: warnings.append(args)) + self.env.set_warnfunc(lambda *args, **kwargs: warnings.append((args, kwargs))) if self.parallel_ok: # number of subprocesses is parallel-1 because the main process # is busy loading doctrees and doing write_doc_serialized() @@ -366,13 +366,16 @@ class Builder(object): doctree = self.env.get_and_resolve_doctree(docname, self) self.write_doc_serialized(docname, doctree) self.write_doc(docname, doctree) - for warning in warnings: - self.warn(*warning) + for warning, kwargs in warnings: + self.warn(*warning, **kwargs) def _write_parallel(self, docnames, warnings, nproc): def write_process(docs): local_warnings = [] - self.env.set_warnfunc(lambda *args: local_warnings.append(args)) + + def warnfunc(*args, **kwargs): + local_warnings.append((args, kwargs)) + self.env.set_warnfunc(warnfunc) for docname, doctree in docs: self.write_doc(docname, doctree) return local_warnings @@ -402,8 +405,8 @@ class Builder(object): self.info(bold('waiting for workers...')) tasks.join() - for warning in warnings: - self.warn(*warning) + for warning, kwargs in warnings: + self.warn(*warning, **kwargs) def prepare_writing(self, docnames): """A place where you can add logic before :meth:`write_doc` is run""" diff --git a/sphinx/environment.py b/sphinx/environment.py index b8b40b8e6..cdb6f92a5 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -242,7 +242,7 @@ class BuildEnvironment: self.versioning_condition = condition self.versioning_compare = compare - def warn(self, docname, msg, lineno=None): + def warn(self, docname, msg, lineno=None, **kwargs): """Emit a warning. This differs from using ``app.warn()`` in that the warning may not @@ -250,11 +250,11 @@ class BuildEnvironment: the update of the environment. """ # strange argument order is due to backwards compatibility - self._warnfunc(msg, (docname, lineno)) + self._warnfunc(msg, (docname, lineno), **kwargs) - def warn_node(self, msg, node): + def warn_node(self, msg, node, **kwargs): """Like :meth:`warn`, but with source information taken from *node*.""" - self._warnfunc(msg, '%s:%s' % get_source_line(node)) + self._warnfunc(msg, '%s:%s' % get_source_line(node), **kwargs) def clear_doc(self, docname): """Remove all traces of a source file in the inventory.""" @@ -576,7 +576,7 @@ class BuildEnvironment: def read_process(docs): self.app = app self.warnings = [] - self.set_warnfunc(lambda *args: self.warnings.append(args)) + self.set_warnfunc(lambda *args, **kwargs: self.warnings.append((args, kwargs))) for docname in docs: self.read_doc(docname, app) # allow pickling self to send it back @@ -603,8 +603,8 @@ class BuildEnvironment: app.info(bold('waiting for workers...')) tasks.join() - for warning in warnings: - self._warnfunc(*warning) + for warning, kwargs in warnings: + self._warnfunc(*warning, **kwargs) def check_dependents(self, already): to_rewrite = self.assign_section_numbers() + self.assign_figure_numbers() From ae9d786390e62d2e265eddba5cea68485928e442 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 21 Feb 2016 00:12:31 +0900 Subject: [PATCH 2/3] Add :confval:`suppress_warnings` to supress arbitrary warning message --- CHANGES | 1 + doc/config.rst | 19 +++++++++++++++++++ sphinx/application.py | 8 +++++++- sphinx/config.py | 1 + sphinx/environment.py | 2 +- sphinx/util/logging.py | 29 +++++++++++++++++++++++++++++ tests/test_util_logging.py | 26 ++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 sphinx/util/logging.py create mode 100644 tests/test_util_logging.py diff --git a/CHANGES b/CHANGES index 921508d24..e94fb7f30 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,7 @@ Features added * #1921: Support figure substitutions by :confval:`language` and :confval:`figure_language_filename` * #2245: Add ``latex_elements["passoptionstopackages"]`` option to call PassOptionsToPackages in early stage of preambles. +* Add :confval:`suppress_warnings` to suppress arbitrary warning message (experimental) Bugs fixed ---------- diff --git a/doc/config.rst b/doc/config.rst index 40ee674cd..84da0cea3 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -212,6 +212,25 @@ General configuration .. versionadded:: 0.5 +.. confval:: suppress_warnings + + A list of warning types to suppress arbitrary warning messages. + + Sphinx supports following warning types: + + * ref.term + * ref.ref + * ref.numref + * ref.keyword + * ref.citation + * ref.doc + + You can choose from these types. + + Now, this option should be considered *experimental*. + + .. versionadded:: 1.4 + .. confval:: needs_sphinx If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will diff --git a/sphinx/application.py b/sphinx/application.py index 57f29aced..9ff99b691 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -41,6 +41,7 @@ from sphinx.util import pycompat # noqa: imported for side-effects from sphinx.util import import_object from sphinx.util.tags import Tags from sphinx.util.osutil import ENOENT +from sphinx.util.logging import is_suppressed_warning from sphinx.util.console import bold, lightgray, darkgray, darkgreen, \ term_width_line @@ -318,7 +319,7 @@ class Sphinx(object): wfile.flush() self.messagelog.append(message) - def warn(self, message, location=None, prefix='WARNING: '): + def warn(self, message, location=None, prefix='WARNING: ', type=None, subtype=None): """Emit a warning. If *location* is given, it should either be a tuple of (docname, lineno) @@ -326,12 +327,17 @@ class Sphinx(object): *prefix* usually should not be changed. + *type* and *subtype* are used to suppress warnings with :confval:`suppress_warnings`. + .. note:: For warnings emitted during parsing, you should use :meth:`.BuildEnvironment.warn` since that will collect all warnings during parsing for later output. """ + if is_suppressed_warning(type, subtype, self.config.suppress_warnings): + return + if isinstance(location, tuple): docname, lineno = location if docname: diff --git a/sphinx/config.py b/sphinx/config.py index ba3dc11b4..9434a77c7 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -71,6 +71,7 @@ class Config(object): templates_path = ([], 'html'), template_bridge = (None, 'html', [str]), keep_warnings = (False, 'env'), + suppress_warnings = ([], 'env'), modindex_common_prefix = ([], 'html'), rst_epilog = (None, 'env', [str]), rst_prolog = (None, 'env', [str]), diff --git a/sphinx/environment.py b/sphinx/environment.py index cdb6f92a5..cdfba95f1 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -1540,7 +1540,7 @@ class BuildEnvironment: (node['refdomain'], typ) else: msg = '%r reference target not found: %%(target)s' % typ - self.warn_node(msg % {'target': target}, node) + self.warn_node(msg % {'target': target}, node, type='ref', subtype=typ) def _resolve_doc_reference(self, builder, node, contnode): # directly reference to document by source name; diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py new file mode 100644 index 000000000..ef91b728b --- /dev/null +++ b/sphinx/util/logging.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + sphinx.util.logging + ~~~~~~~~~~~~~~~~~~~ + + Logging utility functions for Sphinx. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + + +def is_suppressed_warning(type, subtype, suppress_warnings): + """Check the warning is suppressed or not.""" + if type is None: + return False + + for warning_type in suppress_warnings: + if '.' in warning_type: + target, subtarget = warning_type.split('.', 1) + else: + target, subtarget = warning_type, None + + if target == type: + if (subtype is None or subtarget is None or + subtarget == subtype or subtarget == '*'): + return True + + return False diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py new file mode 100644 index 000000000..d88d3cc6d --- /dev/null +++ b/tests/test_util_logging.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +""" + test_util_logging + ~~~~~~~~~~~~~~~~~ + + Test logging util. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from __future__ import print_function + +from sphinx.util.logging import is_suppressed_warning + + +def test_is_suppressed_warning(): + suppress_warnings = ["ref", "files.*", "rest.duplicated_labels"] + + assert is_suppressed_warning(None, None, suppress_warnings) is False + assert is_suppressed_warning("ref", None, suppress_warnings) is True + assert is_suppressed_warning("ref", "numref", suppress_warnings) is True + assert is_suppressed_warning("ref", "option", suppress_warnings) is True + assert is_suppressed_warning("files", "image", suppress_warnings) is True + assert is_suppressed_warning("files", "stylesheet", suppress_warnings) is True + assert is_suppressed_warning("rest", "syntax", suppress_warnings) is False + assert is_suppressed_warning("rest", "duplicated_labels", suppress_warnings) is True From 2441c647d214e166649f54b2ef58efe545785388 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 21 Feb 2016 00:46:50 +0900 Subject: [PATCH 3/3] Fix #2229: no warning is given for unknown options --- CHANGES | 1 + doc/config.rst | 1 + sphinx/domains/std.py | 3 ++- tests/test_build_html.py | 1 + tests/test_build_latex.py | 1 + tests/test_build_texinfo.py | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index e94fb7f30..904ff098c 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Features added * #2245: Add ``latex_elements["passoptionstopackages"]`` option to call PassOptionsToPackages in early stage of preambles. * Add :confval:`suppress_warnings` to suppress arbitrary warning message (experimental) +* #2229: Fix no warning is given for unknown options Bugs fixed ---------- diff --git a/doc/config.rst b/doc/config.rst index 84da0cea3..41ec68ec8 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -222,6 +222,7 @@ General configuration * ref.ref * ref.numref * ref.keyword + * ref.option * ref.citation * ref.doc diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index dc1a283bb..e5f9ab557 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -447,7 +447,7 @@ class StandardDomain(Domain): 'productionlist': ProductionList, } roles = { - 'option': OptionXRefRole(), + 'option': OptionXRefRole(warn_dangling=True), 'envvar': EnvVarXRefRole(), # links to tokens in grammar productions 'token': XRefRole(), @@ -485,6 +485,7 @@ class StandardDomain(Domain): 'the label must precede a section header)', 'numref': 'undefined label: %(target)s', 'keyword': 'unknown keyword: %(target)s', + 'option': 'unknown option: %(target)s', } enumerable_nodes = { # node_class -> (figtype, title_getter) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index ab23ed084..b1181fbeb 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -40,6 +40,7 @@ HTML_WARNINGS = ENV_WARNINGS + """\ %(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.\\*' %(root)s/markup.txt:271: WARNING: Could not lex literal_block as "c". Highlighting skipped. %(root)s/footnote.txt:60: WARNING: citation not found: missing +%(root)s/markup.txt:160: WARNING: unknown option: &option """ if PY3: diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index b71751266..73fa17275 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -24,6 +24,7 @@ from test_build_html import ENV_WARNINGS LATEX_WARNINGS = ENV_WARNINGS + """\ +%(root)s/markup.txt:160: WARNING: unknown option: &option %(root)s/footnote.txt:60: WARNING: citation not found: missing %(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.\\*' %(root)s/markup.txt:271: WARNING: Could not lex literal_block as "c". Highlighting skipped. diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py index 00f2b2232..1cf2232c4 100644 --- a/tests/test_build_texinfo.py +++ b/tests/test_build_texinfo.py @@ -23,6 +23,7 @@ from test_build_html import ENV_WARNINGS TEXINFO_WARNINGS = ENV_WARNINGS + """\ +%(root)s/markup.txt:160: WARNING: unknown option: &option %(root)s/footnote.txt:60: WARNING: citation not found: missing %(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.\\*' %(root)s/images.txt:29: WARNING: no matching candidate for image URI u'svgimg.\\*'