Merge branch '1.7-release'

This commit is contained in:
Takeshi KOMIYA 2018-01-20 02:22:48 +09:00
commit 3b28aadba9
10 changed files with 551 additions and 317 deletions

View File

@ -16,6 +16,9 @@ Features added
Bugs fixed
----------
* #4415: autodoc classifies inherited classmethods as regular methods
* #4415: autodoc classifies inherited staticmethods as regular methods
Testing
--------
@ -45,7 +48,7 @@ Incompatible changes
* shebang line is removed from generated conf.py
* #2557: autodoc: :confval:`autodoc_mock_imports` only mocks specified modules
with their descendants. It does not mock their ancestors. If you want to
mock them, please specify the name of ancestors implicitly.
mock them, please specify the name of ancestors explicitly.
* #3620: html theme: move DOCUMENTATION_OPTIONS to independent JavaScript file
(refs: #4295)
* #4246: Limit width of text body for all themes. Conifigurable via theme
@ -190,7 +193,8 @@ Bugs fixed
----------
* #1922: html search: Upper characters problem in French
* #4412: Updated jQuery version from 3.1.0 to 3.2.1
* #4438: math: math with labels with whitespace cause html error
Testing
--------

View File

@ -32,7 +32,7 @@ from sphinx.application import ExtensionError
from sphinx.util import logging
from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \
safe_getattr, object_description, is_builtin_class_method, \
isenumattribute, getdoc
isenumattribute, isclassmethod, isstaticmethod, getdoc
from sphinx.util.docstrings import prepare_docstring
if False:
@ -1261,12 +1261,14 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
# to distinguish classmethod/staticmethod
obj = self.parent.__dict__.get(self.object_name)
if obj is None:
obj = self.object
if isinstance(obj, classmethod):
if isclassmethod(obj):
self.directivetype = 'classmethod'
# document class and static members before ordinary ones
self.member_order = self.member_order - 1
elif isinstance(obj, staticmethod):
elif isstaticmethod(obj, cls=self.parent, name=self.object_name):
self.directivetype = 'staticmethod'
# document class and static members before ordinary ones
self.member_order = self.member_order - 1

View File

@ -10,6 +10,7 @@
"""
from docutils import nodes, utils
from docutils.nodes import make_id
from docutils.parsers.rst import Directive, directives
from sphinx.config import string_classes
@ -55,7 +56,8 @@ class MathDomain(Domain):
label = 'mathematics'
initial_data = {
'objects': {}, # labelid -> (docname, eqno)
'nameids': {}, # label -> equation ID
'objects': {}, # equation ID -> (docname, eqno)
} # type: Dict[unicode, Dict[unicode, Tuple[unicode, int]]]
dangling_warnings = {
'eq': 'equation not found: %(target)s',
@ -63,9 +65,9 @@ class MathDomain(Domain):
def clear_doc(self, docname):
# type: (unicode) -> None
for labelid, (doc, eqno) in list(self.data['objects'].items()):
for equation_id, (doc, eqno) in list(self.data['objects'].items()):
if doc == docname:
del self.data['objects'][labelid]
del self.data['objects'][equation_id]
def merge_domaindata(self, docnames, otherdata):
# type: (Iterable[unicode], Dict) -> None
@ -84,10 +86,10 @@ class MathDomain(Domain):
newnode['target'] = target
return newnode
else:
node_id = make_id('equation-%s' % target)
if env.config.math_numfig and env.config.numfig:
if docname in env.toc_fignumbers:
id = 'equation-' + target
number = env.toc_fignumbers[docname]['displaymath'].get(id, ())
number = env.toc_fignumbers[docname]['displaymath'].get(node_id, ())
number = '.'.join(map(str, number))
else:
number = ''
@ -98,8 +100,8 @@ class MathDomain(Domain):
logger.warning('Invalid math_eqref_format: %r', exc,
location=node)
title = nodes.Text("(%d)" % number)
return make_refnode(builder, fromdocname, docname,
"equation-" + target, title)
title = nodes.Text("(%d)" % number)
return make_refnode(builder, fromdocname, docname, node_id, title)
else:
return None
@ -260,7 +262,8 @@ class MathDirective(Directive):
node['number'] = eqno
# add target node
target = nodes.target('', '', ids=['equation-' + node['label']])
node_id = make_id('equation-%s' % node['label'])
target = nodes.target('', '', ids=[node_id])
self.state.document.note_explicit_target(target)
ret.insert(0, target)
except UserWarning as exc:

File diff suppressed because one or more lines are too long

View File

@ -154,6 +154,40 @@ def isenumattribute(x):
return isinstance(x, enum.Enum)
def isclassmethod(obj):
# type: (Any) -> bool
"""Check if the object is classmethod."""
if isinstance(obj, classmethod):
return True
elif inspect.ismethod(obj):
if getattr(obj, 'im_self', None): # py2
return True
elif getattr(obj, '__self__', None): # py3
return True
return False
def isstaticmethod(obj, cls=None, name=None):
# type: (Any, Any, unicode) -> bool
"""Check if the object is staticmethod."""
if isinstance(obj, staticmethod):
return True
elif cls and name:
# trace __mro__ if the method is defined in parent class
#
# .. note:: This only works with new style classes.
for basecls in getattr(cls, '__mro__', []):
meth = basecls.__dict__.get(name)
if meth:
if isinstance(meth, staticmethod):
return True
else:
return False
return False
def isdescriptor(x):
# type: (Any) -> bool
"""Check if the object is some kind of descriptor."""

View File

@ -64,6 +64,14 @@ class Base(object):
def inheritedmeth(self):
"""Inherited function."""
@classmethod
def inheritedclassmeth(cls):
"""Inherited class method."""
@staticmethod
def inheritedstaticmeth(cls):
"""Inherited static method."""
class Derived(Base):
def inheritedmeth(self):

View File

@ -715,6 +715,8 @@ def test_generate():
assert_processes(should, 'class', 'Class')
options.inherited_members = True
should.append(('method', 'target.Class.inheritedmeth'))
should.append(('method', 'target.Class.inheritedclassmeth'))
should.append(('method', 'target.Class.inheritedstaticmeth'))
assert_processes(should, 'class', 'Class')
# test special members
@ -798,7 +800,9 @@ def test_generate():
' .. py:attribute:: Class.inst_attr_comment',
' .. py:attribute:: Class.inst_attr_string',
' .. py:attribute:: Class._private_inst_attr',
' .. py:classmethod:: Class.inheritedclassmeth()',
' .. py:method:: Class.inheritedmeth()',
' .. py:staticmethod:: Class.inheritedstaticmeth()',
],
'class', 'Class', member_order='bysource', all_members=True)
del directive.env.ref_context['py:module']

View File

@ -40,9 +40,9 @@ def test_jsmath(app, status, warning):
assert (u'<span class="eqno">(1)<a class="headerlink" href="#equation-foo" '
u'title="Permalink to this equation">\xb6</a></span>'
u'<div class="math notranslate" id="equation-foo">\ne^{i\\pi} = 1</div>' in content)
assert (u'<span class="eqno">(2)<a class="headerlink" href="#equation-math:0" '
assert (u'<span class="eqno">(2)<a class="headerlink" href="#equation-math-0" '
u'title="Permalink to this equation">\xb6</a></span>'
u'<div class="math notranslate" id="equation-math:0">\n'
u'<div class="math notranslate" id="equation-math-0">\n'
u'e^{ix} = \\cos x + i\\sin x</div>' in content)
assert '<div class="math notranslate">\nn \\in \\mathbb N</div>' in content
assert '<div class="math notranslate">\na + 1 &lt; b</div>' in content
@ -102,7 +102,7 @@ def test_math_number_all_mathjax(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
html = (r'<div class="math notranslate" id="equation-index:0">\s*'
html = (r'<div class="math notranslate" id="equation-index-0">\s*'
r'<span class="eqno">\(1\)<a .*>\xb6</a></span>\\\[a\^2\+b\^2=c\^2\\\]</div>')
assert re.search(html, content, re.S)

View File

@ -71,7 +71,7 @@ def test_js_source(app, status, warning):
app.builder.build(['contents'])
v = '3.1.0'
v = '3.2.1'
msg = 'jquery.js version does not match to {v}'.format(v=v)
jquery_min = (app.outdir / '_static' / 'jquery.js').text()
assert 'jQuery v{v}'.format(v=v) in jquery_min, msg