From f4f693eff7b081785cc5704a6ff22cf0371355f3 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 10 Feb 2018 14:25:52 +0900 Subject: [PATCH] #4459: duplicated labels detector does not work well in parallel build --- CHANGES | 1 + sphinx/domains/c.py | 9 ++++++++- sphinx/domains/javascript.py | 20 +++++++++++++++++++- sphinx/domains/python.py | 25 +++++++++++++++++++++---- sphinx/domains/rst.py | 8 +++++++- sphinx/domains/std.py | 10 +++++++++- sphinx/ext/mathbase.py | 4 ++++ 7 files changed, 69 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index ad3fa708e..a3dca85e9 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Bugs fixed * toctree directive tries to glob for URL having query_string * #4871: html search: Upper characters problem in German * #4717: latex: Compilation for German docs failed with LuaLaTeX and XeLaTeX +* #4459: duplicated labels detector does not work well in parallel build Testing -------- diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index f0c81db7b..df07c7731 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -19,6 +19,7 @@ from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.locale import l_, _ from sphinx.roles import XRefRole +from sphinx.util import logging from sphinx.util.docfields import Field, TypedField from sphinx.util.nodes import make_refnode @@ -29,6 +30,8 @@ if False: from sphinx.builders import Builder # NOQA from sphinx.environment import BuildEnvironment # NOQA +logger = logging.getLogger(__name__) + # RE to split at word boundaries wsplit_re = re.compile(r'(\W+)') @@ -287,9 +290,13 @@ class CDomain(Domain): def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None - # XXX check duplicates for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: + if fullname in self.data['objects']: + other, _ = self.data['objects'][fullname] + logger.warning('duplicate C object description of %s, ' + 'other instance in %s' % + (fullname, self.env.doc2path(other))) self.data['objects'][fullname] = (fn, objtype) def resolve_xref(self, env, fromdocname, builder, diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 734969fc1..e64177cdc 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -18,6 +18,7 @@ from sphinx.domains import Domain, ObjType from sphinx.domains.python import _pseudo_parse_arglist from sphinx.locale import l_, _ from sphinx.roles import XRefRole +from sphinx.util import logging from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.nodes import make_refnode @@ -29,6 +30,8 @@ if False: from sphinx.builders import Builder # NOQA from sphinx.environment import BuildEnvironment # NOQA +logger = logging.getLogger(__name__) + class JSObject(ObjectDescription): """ @@ -255,6 +258,12 @@ class JSModule(Directive): noindex = 'noindex' in self.options ret = [] if not noindex: + modules = env.domaindata['js']['modules'] + if mod_name in modules: + self.state_machine.reporter.warning( + 'duplicate module description of %s, ' % mod_name + + 'other instance in ' + self.env.doc2path(modules[mod_name]), + line=self.lineno) env.domaindata['js']['modules'][mod_name] = env.docname # Make a duplicate entry in 'objects' to facilitate searching for # the module in JavaScriptDomain.find_obj() @@ -335,12 +344,21 @@ class JavaScriptDomain(Domain): def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None - # XXX check duplicates for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: + if fullname in self.data['objects']: + otherdoc, _ = self.data['objects'][fullname] + logger.warning('duplicate object description of %s, ' + 'other instance in %s' % + (fullname, self.env.doc2path(otherdoc))) self.data['objects'][fullname] = (fn, objtype) for mod_name, pkg_docname in otherdata['modules'].items(): if pkg_docname in docnames: + if mod_name in self.data['modules']: + otherdoc = self.data['modules'][mod_name] + logger.warning('duplicate module description of %s, ' + 'other instance in %s' % + (mod_name, self.env.doc2path(otherdoc))) self.data['modules'][mod_name] = pkg_docname def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0): diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index b0900b385..47ab5cd12 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -560,9 +560,17 @@ class PyModule(Directive): env.ref_context['py:module'] = modname ret = [] if not noindex: - env.domaindata['py']['modules'][modname] = \ - (env.docname, self.options.get('synopsis', ''), - self.options.get('platform', ''), 'deprecated' in self.options) + modules = env.domaindata['py']['modules'] + if modname in modules: + self.state_machine.reporter.warning( + 'duplicate module description of %s, ' + 'other instance in %s, use :noindex: for one of them' % + (modname, self.env.doc2path(modules[modname])), + line=self.lineno) + modules[modname] = (env.docname, + self.options.get('synopsis', ''), + self.options.get('platform', ''), + 'deprecated' in self.options) # make a duplicate entry in 'objects' to facilitate searching for # the module in PythonDomain.find_obj() env.domaindata['py']['objects'][modname] = (env.docname, 'module') @@ -757,12 +765,21 @@ class PythonDomain(Domain): def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None - # XXX check duplicates? for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: + if fullname in self.data['objects']: + otherdoc, _ = self.data['objects'][fullname] + logger.warning('duplicate object description of %s, ' + 'other instance in %s, use :noindex: for one of them' % + (fullname, self.env.doc2path(otherdoc))) self.data['objects'][fullname] = (fn, objtype) for modname, data in otherdata['modules'].items(): if data[0] in docnames: + if modname in self.data['modules']: + otherdoc, _, _, _ = self.data['modules'][modname] + logger.warning('duplicate module description of %s, ' + 'other instance in %s, use :noindex: for one of them' % + (modname, self.env.doc2path(otherdoc))) self.data['modules'][modname] = data def find_obj(self, env, modname, classname, name, type, searchmode=0): diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index c14eb180f..609fa501f 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -18,6 +18,7 @@ from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.locale import l_, _ from sphinx.roles import XRefRole +from sphinx.util import logging from sphinx.util.nodes import make_refnode if False: @@ -29,6 +30,7 @@ if False: from sphinx.environment import BuildEnvironment # NOQA +logger = logging.getLogger(__name__) dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$') @@ -139,9 +141,13 @@ class ReSTDomain(Domain): def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None - # XXX check duplicates for (typ, name), doc in otherdata['objects'].items(): if doc in docnames: + if (typ, name) in self.data['objects']: + otherdoc = self.data['objects'][typ, name] + logger.warning('duplicate description of %s %s, ' + 'other instance in %s' % + (typ, name, self.env.doc2path(otherdoc))) self.data['objects'][typ, name] = doc def resolve_xref(self, env, fromdocname, builder, typ, target, node, diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 937760c45..2b726d3e7 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -547,7 +547,6 @@ class StandardDomain(Domain): def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None - # XXX duplicates? for key, data in otherdata['progoptions'].items(): if data[0] in docnames: self.data['progoptions'][key] = data @@ -556,6 +555,11 @@ class StandardDomain(Domain): self.data['objects'][key] = data for key, data in otherdata['citations'].items(): if data[0] in docnames: + if key in self.data['citations']: + otherdoc, _, _ = self.data['catations'] + logger.warning('duplicate citation %s, other instance in %s' % + (key, self.env.doc2path(otherdoc)), + type='ref', subtype='citation') self.data['citations'][key] = data for key, data in otherdata['citation_refs'].items(): citation_refs = self.data['citation_refs'].setdefault(key, []) @@ -564,6 +568,10 @@ class StandardDomain(Domain): citation_refs.append(docname) for key, data in otherdata['labels'].items(): if data[0] in docnames: + if key in self.data['labels']: + otherdoc, _, _ = self.data['labels'] + logger.warning('duplicate label %s, other instance in %s' % + (key, self.env.doc2path(otherdoc))) self.data['labels'][key] = data for key, data in otherdata['anonlabels'].items(): if data[0] in docnames: diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py index 3cc734537..b217d5d56 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -72,6 +72,10 @@ class MathDomain(Domain): # type: (Iterable[unicode], Dict) -> None for labelid, (doc, eqno) in otherdata['objects'].items(): if doc in docnames: + if labelid in self.data['objects']: + otherdoc, _ = self.data['objects'] + logger.warning('duplicate label of equation %s, other instance in %s' % + (labelid, self.env.doc2path(otherdoc))) self.data['objects'][labelid] = (doc, eqno) def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):