diff --git a/CHANGES b/CHANGES index a1c77c790..069a89ec8 100644 --- a/CHANGES +++ b/CHANGES @@ -86,7 +86,7 @@ Features removed * ``sphinx.ext.pngmath`` extension -Release 1.7.3 (in development) +Release 1.7.4 (in development) ============================== Dependencies @@ -104,6 +104,15 @@ Features added Bugs fixed ---------- +Testing +-------- + +Release 1.7.3 (released Apr 23, 2018) +===================================== + +Bugs fixed +---------- + * #4769: autodoc loses the first staticmethod parameter * #4790: autosummary: too wide two column tables in PDF builds * #4795: Latex customization via ``_templates/longtable.tex_t`` is broken @@ -120,9 +129,8 @@ 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 - -Testing --------- +* #4459: duplicated labels detector does not work well in parallel build +* #4878: Crashed with extension which returns invalid metadata Release 1.7.2 (released Mar 21, 2018) ===================================== diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 50e9b2e5e..3784be11b 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 _ 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 0ea6114d6..fdc1cd613 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 _ 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 312b509a0..72e794944 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -579,9 +579,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') @@ -776,12 +784,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 fcb461484..3e1a45044 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 _ 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 97433b12e..3168d1929 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -559,7 +559,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 @@ -568,6 +567,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, []) @@ -576,6 +580,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 4789b117e..68ae40f8a 100644 --- a/sphinx/ext/mathbase.py +++ b/sphinx/ext/mathbase.py @@ -76,6 +76,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): diff --git a/sphinx/registry.py b/sphinx/registry.py index dc42219ae..e11f0654d 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -471,6 +471,7 @@ class SphinxComponentRegistry(object): logger.warning(__('extension %r returned an unsupported object from ' 'its setup() function; it should return None or a ' 'metadata dictionary'), extname) + metadata = {} app.extensions[extname] = Extension(extname, mod, **metadata) app._setting_up_extension.pop()