Close #6558: glossary: emit a warning for duplicated glossary entry

This commit is contained in:
Takeshi KOMIYA 2019-07-08 01:20:04 +09:00
parent 1fc4e8c251
commit c358e04b09
4 changed files with 42 additions and 8 deletions

View File

@ -20,6 +20,8 @@ Incompatible changes
Deprecated Deprecated
---------- ----------
* ``sphinx.domains.std.StandardDomain.add_object()``
Features added Features added
-------------- --------------
@ -27,6 +29,8 @@ Features added
old stub file old stub file
* #5923: autodoc: ``:inherited-members:`` option takes a name of anchestor class * #5923: autodoc: ``:inherited-members:`` option takes a name of anchestor class
not to document inherited members of the class and uppers not to document inherited members of the class and uppers
* #6558: glossary: emit a warning for duplicated glossary entry
* #6558: std domain: emit a warning for duplicated generic objects
Bugs fixed Bugs fixed
---------- ----------

View File

@ -26,6 +26,11 @@ The following is a list of deprecated interfaces.
- (will be) Removed - (will be) Removed
- Alternatives - Alternatives
* - ``sphinx.domains.std.StandardDomain.add_object()``
- 3.0
- 5.0
- ``sphinx.domains.std.StandardDomain.note_object()``
* - ``sphinx.environment.BuildEnvironment.indexentries`` * - ``sphinx.environment.BuildEnvironment.indexentries``
- 2.4 - 2.4
- 4.0 - 4.0

View File

@ -22,7 +22,7 @@ from docutils.statemachine import StringList
from sphinx import addnodes from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref from sphinx.addnodes import desc_signature, pending_xref
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
from sphinx.directives import ObjectDescription from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType from sphinx.domains import Domain, ObjType
from sphinx.locale import _, __ from sphinx.locale import _, __
@ -81,7 +81,8 @@ class GenericObject(ObjectDescription):
targetname, '', None)) targetname, '', None))
std = cast(StandardDomain, self.env.get_domain('std')) std = cast(StandardDomain, self.env.get_domain('std'))
std.add_object(self.objtype, name, self.env.docname, targetname) std.note_object(self.objtype, name, targetname,
location=(self.env.docname, self.lineno))
class EnvVar(GenericObject): class EnvVar(GenericObject):
@ -143,7 +144,7 @@ class Target(SphinxDirective):
_, name = self.name.split(':', 1) _, name = self.name.split(':', 1)
std = cast(StandardDomain, self.env.get_domain('std')) std = cast(StandardDomain, self.env.get_domain('std'))
std.add_object(name, fullname, self.env.docname, targetname) std.note_object(name, fullname, targetname, location=(self.env.docname, self.lineno))
return ret return ret
@ -261,7 +262,7 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
gloss_entries.add(new_id) gloss_entries.add(new_id)
std = cast(StandardDomain, env.get_domain('std')) std = cast(StandardDomain, env.get_domain('std'))
std.add_object('term', termtext.lower(), env.docname, new_id) std.note_object('term', termtext.lower(), new_id, location=(env.docname, lineno))
# add an index entry too # add an index entry too
indexnode = addnodes.index() indexnode = addnodes.index()
@ -443,7 +444,8 @@ class ProductionList(SphinxDirective):
if idname not in self.state.document.ids: if idname not in self.state.document.ids:
subnode['ids'].append(idname) subnode['ids'].append(idname)
self.state.document.note_implicit_target(subnode, subnode) self.state.document.note_implicit_target(subnode, subnode)
domain.add_object('token', subnode['tokenname'], self.env.docname, idname) domain.note_object('token', subnode['tokenname'], idname,
location=(self.env.docname, self.lineno))
subnode.extend(token_xrefs(tokens)) subnode.extend(token_xrefs(tokens))
node.append(subnode) node.append(subnode)
return [node] return [node]
@ -539,6 +541,23 @@ class StandardDomain(Domain):
def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]: def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid
def note_object(self, objtype: str, name: str, labelid: str, location: Any = None
) -> None:
"""Note a generic object for cross reference.
.. versionadded:: 3.0
"""
if (objtype, name) in self.objects:
docname = self.objects[objtype, name][0]
logger.warning(__('duplicate %s description of %s, other instance in %s'),
objtype, name, docname, location=location)
self.objects[objtype, name] = (self.env.docname, labelid)
def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None:
warnings.warn('StandardDomain.add_object() is deprecated.',
RemovedInSphinx50Warning)
self.objects[objtype, name] = (docname, labelid)
@property @property
def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]: def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid
@ -620,9 +639,6 @@ class StandardDomain(Domain):
continue continue
self.labels[name] = docname, labelid, sectname self.labels[name] = docname, labelid, sectname
def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None:
self.objects[objtype, name] = (docname, labelid)
def add_program_option(self, program: str, name: str, docname: str, labelid: str) -> None: def add_program_option(self, program: str, name: str, docname: str, labelid: str) -> None:
self.progoptions[program, name] = (docname, labelid) self.progoptions[program, name] = (docname, labelid)

View File

@ -172,6 +172,15 @@ def test_glossary_warning(app, status, warning):
assert ("case3.rst:4: WARNING: glossary term must be preceded by empty line" assert ("case3.rst:4: WARNING: glossary term must be preceded by empty line"
in warning.getvalue()) in warning.getvalue())
# duplicated terms
text = (".. glossary::\n"
"\n"
" term-case4\n"
" term-case4\n")
restructuredtext.parse(app, text, "case4")
assert ("case4.txt:3: WARNING: duplicate term description of term-case4, "
"other instance in case4" in warning.getvalue())
def test_glossary_comment(app): def test_glossary_comment(app):
text = (".. glossary::\n" text = (".. glossary::\n"