Merge pull request #5227 from tk0miya/changeset_domain

refactor: Move repository of changesets to domain from env
This commit is contained in:
Takeshi KOMIYA
2018-08-04 18:43:47 +09:00
committed by GitHub
7 changed files with 217 additions and 99 deletions

View File

@@ -84,9 +84,11 @@ Deprecated
* ``env._read_parallel()`` is deprecated
* ``env.write_doctree()`` is deprecated
* ``env._nitpick_ignore`` is deprecated
* ``env.versionchanges`` is deprecated
* ``env.dump()`` is deprecated
* ``env.dumps()`` is deprecated
* ``env.topickle()`` is deprecated
* ``env.note_versionchange()`` is deprecated
* ``sphinx.writers.latex.Table.caption_footnotetexts`` is deprecated
* ``sphinx.writers.latex.Table.header_footnotetexts`` is deprecated
* ``sphinx.writers.latex.LaTeXTranslator.footnotestack`` is deprecated
@@ -116,6 +118,7 @@ Deprecated
* ``sphinx.ext.mathbase.is_in_section_title()`` is deprecated
* ``sphinx.ext.mathbase.MathDomain`` is deprecated
* ``sphinx.ext.mathbase.setup_math()`` is deprecated
* ``sphinx.directives.other.VersionChanges`` is deprecated
* ``sphinx.highlighting.PygmentsBridge.unhighlight()`` is deprecated
* ``sphinx.ext.mathbase.get_node_equation_number()`` is deprecated
* ``sphinx.ext.mathbase.wrap_displaymath()`` is deprecated

View File

@@ -131,6 +131,11 @@ The following is a list of deprecated interface.
- 4.0
- :meth:`~sphinx.application.Sphinx.add_js_file()`
* - ``sphinx.directives.other.VersionChanges``
- 1.8
- 3.0
- ``sphinx.domains.changeset.VersionChanges``
* - ``sphinx.highlighting.PygmentsBridge.unhighlight()``
- 1.8
- 3.0
@@ -385,6 +390,11 @@ The following is a list of deprecated interface.
- 3.0
- :confval:`nitpick_ignore`
* - ``BuildEnvironment.versionchanges``
- 1.8
- 3.0
- N/A
* - ``BuildEnvironment.update()``
- 1.8
- 3.0
@@ -410,6 +420,11 @@ The following is a list of deprecated interface.
- 3.0
- ``Builder.write_doctree()``
* - ``BuildEnvironment.note_versionchange()``
- 1.8
- 3.0
- ``ChangesDomain.note_changeset()``
* - ``warn()`` (template helper function)
- 1.8
- 3.0

View File

@@ -80,6 +80,7 @@ builtin_extensions = (
'sphinx.builders.xml',
'sphinx.config',
'sphinx.domains.c',
'sphinx.domains.changeset',
'sphinx.domains.cpp',
'sphinx.domains.javascript',
'sphinx.domains.math',

View File

@@ -11,11 +11,13 @@
import codecs
from os import path
from typing import cast
from six import iteritems
from sphinx import package_dir
from sphinx.builders import Builder
from sphinx.domains.changeset import ChangeSetDomain
from sphinx.locale import _, __
from sphinx.theming import HTMLThemeFactory
from sphinx.util import logging
@@ -60,6 +62,7 @@ class ChangesBuilder(Builder):
def write(self, *ignored):
# type: (Any) -> None
version = self.config.version
domain = cast(ChangeSetDomain, self.env.get_domain('changeset'))
libchanges = {} # type: Dict[unicode, List[Tuple[unicode, unicode, int]]]
apichanges = [] # type: List[Tuple[unicode, unicode, int]]
otherchanges = {} # type: Dict[Tuple[unicode, unicode], List[Tuple[unicode, unicode, int]]] # NOQA
@@ -67,21 +70,22 @@ class ChangesBuilder(Builder):
logger.info(bold(__('no changes in version %s.') % version))
return
logger.info(bold('writing summary file...'))
for type, docname, lineno, module, descname, content in \
self.env.versionchanges[version]:
if isinstance(descname, tuple):
descname = descname[0]
ttext = self.typemap[type]
context = content.replace('\n', ' ')
if descname and docname.startswith('c-api'):
for changeset in domain.get_changesets_for(version):
if isinstance(changeset.descname, tuple):
descname = changeset.descname[0]
else:
descname = changeset.descname
ttext = self.typemap[changeset.type]
context = changeset.content.replace('\n', ' ')
if descname and changeset.docname.startswith('c-api'):
if context:
entry = '<b>%s</b>: <i>%s:</i> %s' % (descname, ttext,
context)
else:
entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
apichanges.append((entry, docname, lineno))
elif descname or module:
if not module:
apichanges.append((entry, changeset.docname, changeset.lineno))
elif descname or changeset.module:
if not changeset.module:
module = _('Builtins')
if not descname:
descname = _('Module level')
@@ -90,15 +94,15 @@ class ChangesBuilder(Builder):
context)
else:
entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
libchanges.setdefault(module, []).append((entry, docname,
lineno))
libchanges.setdefault(module, []).append((entry, changeset.docname,
changeset.lineno))
else:
if not context:
continue
entry = '<i>%s:</i> %s' % (ttext.capitalize(), context)
title = self.env.titles[docname].astext()
otherchanges.setdefault((docname, title), []).append(
(entry, docname, lineno))
title = self.env.titles[changeset.docname].astext()
otherchanges.setdefault((changeset.docname, title), []).append(
(entry, changeset.docname, changeset.lineno))
ctx = {
'project': self.config.project,

View File

@@ -17,8 +17,8 @@ from docutils.parsers.rst.directives.misc import Class
from docutils.parsers.rst.directives.misc import Include as BaseInclude
from six.moves import range
from sphinx import addnodes, locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning
from sphinx import addnodes
from sphinx.domains.changeset import VersionChange # NOQA # for compatibility
from sphinx.locale import _
from sphinx.util import url_re, docname_join
from sphinx.util.docutils import SphinxDirective
@@ -32,19 +32,6 @@ if False:
from sphinx.application import Sphinx # NOQA
versionlabels = {
'versionadded': _('New in version %s'),
'versionchanged': _('Changed in version %s'),
'deprecated': _('Deprecated since version %s'),
} # type: Dict[unicode, unicode]
locale.versionlabels = DeprecatedDict(
versionlabels,
'sphinx.locale.versionlabels is deprecated. '
'Please use sphinx.directives.other.versionlabels instead.',
RemovedInSphinx30Warning
)
glob_re = re.compile(r'.*[*?\[].*')
@@ -218,54 +205,6 @@ class Index(SphinxDirective):
return [indexnode, targetnode]
class VersionChange(SphinxDirective):
"""
Directive to describe a change/addition/deprecation in a specific version.
"""
has_content = True
required_arguments = 1
optional_arguments = 1
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
node = addnodes.versionmodified()
node.document = self.state.document
set_source_info(self, node)
node['type'] = self.name
node['version'] = self.arguments[0]
text = versionlabels[self.name] % self.arguments[0]
if len(self.arguments) == 2:
inodes, messages = self.state.inline_text(self.arguments[1],
self.lineno + 1)
para = nodes.paragraph(self.arguments[1], '', *inodes, translatable=False)
set_source_info(self, para)
node.append(para)
else:
messages = []
if self.content:
self.state.nested_parse(self.content, self.content_offset, node)
if len(node):
if isinstance(node[0], nodes.paragraph) and node[0].rawsource:
content = nodes.inline(node[0].rawsource, translatable=True)
content.source = node[0].source
content.line = node[0].line
content += node[0].children
node[0].replace_self(nodes.paragraph('', '', content, translatable=False))
node[0].insert(0, nodes.inline('', '%s: ' % text,
classes=['versionmodified']))
else:
para = nodes.paragraph('', '',
nodes.inline('', '%s.' % text,
classes=['versionmodified']),
translatable=False)
node.append(para)
# XXX should record node.source as well
self.env.note_versionchange(node['type'], node['version'], node, node.line)
return [node] + messages
class SeeAlso(BaseAdmonition):
"""
An admonition mentioning things to look at as reference.
@@ -475,9 +414,6 @@ def setup(app):
directives.register_directive('moduleauthor', Author)
directives.register_directive('codeauthor', Author)
directives.register_directive('index', Index)
directives.register_directive('deprecated', VersionChange)
directives.register_directive('versionadded', VersionChange)
directives.register_directive('versionchanged', VersionChange)
directives.register_directive('seealso', SeeAlso)
directives.register_directive('tabularcolumns', TabularColumns)
directives.register_directive('centered', Centered)

159
sphinx/domains/changeset.py Normal file
View File

@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
"""
sphinx.domains.changeset
~~~~~~~~~~~~~~~~~~~~~~~~
The changeset domain.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from typing import NamedTuple
from docutils import nodes
from six import iteritems
from sphinx import addnodes
from sphinx import locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning
from sphinx.domains import Domain
from sphinx.locale import _
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info
if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA
versionlabels = {
'versionadded': _('New in version %s'),
'versionchanged': _('Changed in version %s'),
'deprecated': _('Deprecated since version %s'),
} # type: Dict[unicode, unicode]
locale.versionlabels = DeprecatedDict(
versionlabels,
'sphinx.locale.versionlabels is deprecated. '
'Please use sphinx.domains.changeset.versionlabels instead.',
RemovedInSphinx30Warning
)
ChangeSet = NamedTuple('ChangeSet', [('type', str),
('docname', str),
('lineno', int),
('module', str),
('descname', str),
('content', str)])
class VersionChange(SphinxDirective):
"""
Directive to describe a change/addition/deprecation in a specific version.
"""
has_content = True
required_arguments = 1
optional_arguments = 1
final_argument_whitespace = True
option_spec = {} # type: Dict
def run(self):
# type: () -> List[nodes.Node]
node = addnodes.versionmodified()
node.document = self.state.document
set_source_info(self, node)
node['type'] = self.name
node['version'] = self.arguments[0]
text = versionlabels[self.name] % self.arguments[0]
if len(self.arguments) == 2:
inodes, messages = self.state.inline_text(self.arguments[1],
self.lineno + 1)
para = nodes.paragraph(self.arguments[1], '', *inodes, translatable=False)
set_source_info(self, para)
node.append(para)
else:
messages = []
if self.content:
self.state.nested_parse(self.content, self.content_offset, node)
if len(node):
if isinstance(node[0], nodes.paragraph) and node[0].rawsource:
content = nodes.inline(node[0].rawsource, translatable=True)
content.source = node[0].source
content.line = node[0].line
content += node[0].children
node[0].replace_self(nodes.paragraph('', '', content, translatable=False))
node[0].insert(0, nodes.inline('', '%s: ' % text,
classes=['versionmodified']))
else:
para = nodes.paragraph('', '',
nodes.inline('', '%s.' % text,
classes=['versionmodified']),
translatable=False)
node.append(para)
self.env.get_domain('changeset').note_changeset(node) # type: ignore
return [node] + messages
class ChangeSetDomain(Domain):
"""Domain for changesets."""
name = 'changeset'
label = 'changeset'
initial_data = {
'changes': {}, # version -> list of ChangeSet
} # type: Dict
def clear_doc(self, docname):
# type: (unicode) -> None
for version, changes in iteritems(self.data['changes']):
for changeset in changes[:]:
if changeset.docname == docname:
changes.remove(changeset)
def merge_domaindata(self, docnames, otherdata):
# type: (List[unicode], Dict) -> None
# XXX duplicates?
for version, otherchanges in iteritems(otherdata['changes']):
changes = self.data['changes'].setdefault(version, [])
for changeset in otherchanges:
if changeset.docname in docnames:
changes.append(changeset)
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, unicode, nodes.Node) -> None
pass # nothing to do here. All changesets are registered on calling directive.
def note_changeset(self, node):
# type: (nodes.Node) -> None
version = node['version']
module = self.env.ref_context.get('py:module')
objname = self.env.temp_data.get('object')
changeset = ChangeSet(node['type'], self.env.docname, node.line, # type: ignore
module, objname, node.astext())
self.data['changes'].setdefault(version, []).append(changeset)
def get_changesets_for(self, version):
# type: (unicode) -> List[ChangeSet]
return self.data['changes'].get(version, [])
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.add_domain(ChangeSetDomain)
app.add_directive('deprecated', VersionChange)
app.add_directive('versionadded', VersionChange)
app.add_directive('versionchanged', VersionChange)
return {
'version': 'builtin',
'env_version': 1,
'parallel_read_safe': True,
'parallel_write_safe': True,
}

View File

@@ -186,9 +186,6 @@ class BuildEnvironment(object):
self.indexentries = {} # type: Dict[unicode, List[Tuple[unicode, unicode, unicode, unicode, unicode]]] # NOQA
# docname -> list of
# (type, unicode, target, aliasname)
self.versionchanges = {} # type: Dict[unicode, List[Tuple[unicode, unicode, int, unicode, unicode, unicode]]] # NOQA
# version -> list of (type, docname,
# lineno, module, descname, content)
# these map absolute path -> (docnames, unique filename)
self.images = FilenameUniqDict() # type: FilenameUniqDict
@@ -321,10 +318,6 @@ class BuildEnvironment(object):
self.reread_always.discard(docname)
self.included.discard(docname)
for version, changes in self.versionchanges.items():
new = [change for change in changes if change[1] != docname]
changes[:] = new
for domain in self.domains.values():
domain.clear_doc(docname)
@@ -343,10 +336,6 @@ class BuildEnvironment(object):
if docname in other.included:
self.included.add(docname)
for version, changes in other.versionchanges.items():
self.versionchanges.setdefault(version, []).extend(
change for change in changes if change[1] in docnames)
for domainname, domain in self.domains.items():
domain.merge_domaindata(docnames, other.domaindata[domainname])
app.emit('env-merge-info', self, docnames, other)
@@ -571,13 +560,6 @@ class BuildEnvironment(object):
"""
self.reread_always.add(self.docname)
def note_versionchange(self, type, version, node, lineno):
# type: (unicode, unicode, nodes.Node, int) -> None
self.versionchanges.setdefault(version, []).append(
(type, self.temp_data['docname'], lineno,
self.ref_context.get('py:module'),
self.temp_data.get('object'), node.astext()))
def note_toctree(self, docname, toctreenode):
# type: (unicode, addnodes.toctree) -> None
"""Note a TOC tree directive in a document and gather information about
@@ -857,3 +839,21 @@ class BuildEnvironment(object):
RemovedInSphinx30Warning)
with open(filename, 'wb') as f:
self.dump(self, f)
@property
def versionchanges(self):
# type: () -> Dict[unicode, List[Tuple[unicode, unicode, int, unicode, unicode, unicode]]] # NOQA
warnings.warn('env.versionchanges() is deprecated. '
'Please use ChangeSetDomain instead.',
RemovedInSphinx30Warning)
return self.domaindata['changeset']['changes']
def note_versionchange(self, type, version, node, lineno):
# type: (unicode, unicode, nodes.Node, int) -> None
warnings.warn('env.note_versionchange() is deprecated. '
'Please use ChangeSetDomain.note_changeset() instead.',
RemovedInSphinx30Warning)
node['type'] = type
node['version'] = version
node.line = lineno
self.get_domain('changeset').note_changeset(node) # type: ignore