Merge branch '1.8'

This commit is contained in:
Takeshi KOMIYA 2018-09-20 20:01:14 +09:00
commit 522105b79b
18 changed files with 106 additions and 49 deletions

View File

@ -57,6 +57,12 @@ Bugs fixed
* #5418: Incorrect default path for sphinx-build -d/doctrees files
* #5421: autodoc emits deprecation warning for :confval:`autodoc_default_flags`
* #5422: lambda object causes PicklingError on storing environment
* #5417: Sphinx fails to build with syntax error in Python 2.7.5
* #4911: add latexpdf to make.bat for non make-mode
* #5436: Autodoc does not work with enum subclasses with properties/methods
* #5437: autodoc: crashed on modules importing eggs
* #5433: latex: ImportError: cannot import name 'DEFAULT_SETTINGS'
* #5431: autodoc: ``autofunction`` emits a warning for callable objects
Testing
--------
@ -73,6 +79,7 @@ Dependencies
``xelatex/lualatex``), instructs ``make latexpdf`` to use :program:`xindy`
for general index. Make sure your LaTeX distribution includes it.
(refs: #5134)
* LaTeX: ``latexmk`` is required for ``make latexpdf`` on Windows
Incompatible changes
--------------------

View File

@ -35,3 +35,12 @@ class math_reference(nodes.Inline, nodes.Referential, nodes.TextElement):
class thebibliography(nodes.container):
"""A node for wrapping bibliographies."""
pass
HYPERLINK_SUPPORT_NODES = (
nodes.figure,
nodes.literal_block,
nodes.table,
nodes.section,
captioned_literal_block,
)

View File

@ -1008,7 +1008,13 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
# cannot introspect arguments of a C function or method
return None
try:
args = Signature(self.object).format_args()
if (not isfunction(self.object) and
not isbuiltin(self.object) and
not inspect.isclass(self.object) and
hasattr(self.object, '__call__')):
args = Signature(self.object.__call__).format_args()
else:
args = Signature(self.object).format_args()
except TypeError:
if (is_builtin_class_method(self.object, '__new__') and
is_builtin_class_method(self.object, '__init__')):

View File

@ -16,7 +16,7 @@ import warnings
from collections import namedtuple
from types import FunctionType, MethodType, ModuleType
from six import PY2
from six import PY2, iteritems
from sphinx.util import logging
from sphinx.util.inspect import isenumclass, safe_getattr
@ -248,6 +248,11 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
if name not in members:
members[name] = Attribute(name, True, value)
superclass = subject.__mro__[1]
for name, value in iteritems(obj_dict):
if name not in superclass.__dict__:
members[name] = Attribute(name, True, value)
# other members
for name in dir(subject):
try:

View File

@ -153,7 +153,7 @@ class TestDirective(SphinxDirective):
if self.name == 'doctest' and 'pyversion' in self.options:
try:
spec = self.options['pyversion']
python_version = '.'.join(str(v) for v in sys.version_info[:3])
python_version = '.'.join([str(v) for v in sys.version_info[:3]])
if not is_allowed_version(spec, python_version):
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
node['options'][flag] = True # Skip the test

View File

@ -416,6 +416,6 @@ def inspect_main(argv):
if __name__ == '__main__':
import logging # type: ignore
logging.basicConfig()
logging.basicConfig() # type: ignore
inspect_main(argv=sys.argv[1:]) # type: ignore

View File

@ -32,7 +32,7 @@ class ModuleAnalyzer(object):
def for_string(cls, string, modname, srcname='<string>'):
# type: (unicode, unicode, unicode) -> ModuleAnalyzer
if isinstance(string, bytes):
return cls(BytesIO(string), modname, srcname)
return cls(BytesIO(string), modname, srcname) # type: ignore
return cls(StringIO(string), modname, srcname, decoded=True) # type: ignore
@classmethod

View File

@ -31,6 +31,7 @@ if "%1" == "help" (
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. latexpdf to make LaTeX files and run them through platex/dvipdfmx
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files

View File

@ -30,7 +30,7 @@ class path(text_type):
# type: (unicode, unicode, unicode) -> path
if isinstance(s, str):
s = s.decode(encoding, errors)
return text_type.__new__(cls, s)
return text_type.__new__(cls, s) # type: ignore
return text_type.__new__(cls, s) # type: ignore
@property

View File

@ -314,8 +314,9 @@ def get_module_source(modname):
filename += 'w'
elif not (lfilename.endswith('.py') or lfilename.endswith('.pyw')):
raise PycodeError('source is not a .py file: %r' % filename)
elif '.egg' in filename:
eggpath, _ = re.split('(?<=\\.egg)/', filename)
elif ('.egg' + os.path.sep) in filename:
pat = '(?<=\\.egg)' + re.escape(os.path.sep)
eggpath, _ = re.split(pat, filename, 1)
if path.isfile(eggpath):
return 'file', filename

View File

@ -73,7 +73,7 @@ def get_image_size(filename):
def guess_mimetype_for_stream(stream, default=None):
# type: (IO, unicode) -> unicode
imgtype = imghdr.what(stream)
imgtype = imghdr.what(stream) # type: ignore
if imgtype:
return 'image/' + imgtype
else:
@ -141,4 +141,4 @@ def test_svg(h, f):
# install test_svg() to imghdr
# refs: https://docs.python.org/3.6/library/imghdr.html#imghdr.tests
imghdr.tests.append(test_svg)
imghdr.tests.append(test_svg) # type: ignore

View File

@ -235,7 +235,7 @@ def abspath(pathdir):
try:
pathdir = pathdir.decode(fs_encoding)
except UnicodeDecodeError:
raise UnicodeDecodeError('multibyte filename not supported on '
raise UnicodeDecodeError('multibyte filename not supported on ' # type: ignore
'this filesystem encoding '
'(%r)' % fs_encoding)
return pathdir

View File

@ -34,7 +34,7 @@ except ImportError:
from urllib3.exceptions import InsecureRequestWarning # type: ignore
except ImportError:
# for requests < 2.4.0
InsecureRequestWarning = None
InsecureRequestWarning = None # type: ignore
try:
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
@ -44,7 +44,7 @@ except ImportError:
from urllib3.exceptions import InsecurePlatformWarning # type: ignore
except ImportError:
# for requests < 2.4.0
InsecurePlatformWarning = None
InsecurePlatformWarning = None # type: ignore
# try to load requests[security] (but only if SSL is available)
try:

View File

@ -24,7 +24,6 @@ from six import itervalues, text_type
from sphinx import addnodes
from sphinx import highlighting
from sphinx.builders.latex.nodes import captioned_literal_block, footnotetext
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _, __
@ -57,13 +56,6 @@ SHORTHANDOFF = r'''
MAX_CITATION_LABEL_LENGTH = 8
LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
HYPERLINK_SUPPORT_NODES = (
nodes.figure,
nodes.literal_block,
nodes.table,
nodes.section,
captioned_literal_block,
)
ENUMERATE_LIST_STYLE = defaultdict(lambda: r'\arabic',
{
'arabic': r'\arabic',
@ -2615,3 +2607,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
#
# refs: https://github.com/sphinx-doc/sphinx/issues/4889
from sphinx.builders.latex.transforms import URI_SCHEMES, ShowUrlsTransform # NOQA
# FIXME: Workaround to avoid circular import
# refs: https://github.com/sphinx-doc/sphinx/issues/5433
from sphinx.builders.latex.nodes import HYPERLINK_SUPPORT_NODES, captioned_literal_block, footnotetext # NOQA

View File

@ -223,19 +223,6 @@ class InstAttCls(object):
"""Docstring for instance attribute InstAttCls.ia2."""
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""
val4 = 34
class CustomIter(object):
def __init__(self):
"""Create a new `CustomIter`."""

View File

@ -0,0 +1,8 @@
class Callable():
"""A callable object that behaves like a function."""
def __call__(self, arg1, arg2, **kwargs):
pass
function = Callable()

View File

@ -0,0 +1,19 @@
from __future__ import absolute_import
import enum
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""
val4 = 34
def say_hello(self):
"""a method says hello to you."""
pass

View File

@ -829,7 +829,6 @@ def test_autodoc_ignore_module_all(app):
'.. py:class:: CustomDataDescriptor2(doc)',
'.. py:class:: CustomDataDescriptorMeta',
'.. py:class:: CustomDict',
'.. py:class:: EnumCls',
'.. py:class:: InstAttCls()',
'.. py:class:: Outer',
' .. py:class:: Outer.Inner',
@ -1263,48 +1262,54 @@ def test_instance_attributes(app):
def test_enum_class(app):
options = {"members": None,
"undoc-members": True}
actual = do_autodoc(app, 'class', 'target.EnumCls', options)
actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options)
assert list(actual) == [
'',
'.. py:class:: EnumCls',
' :module: target',
' :module: target.enum',
'',
' this is enum class',
' ',
' ',
' .. py:method:: EnumCls.say_hello()',
' :module: target.enum',
' ',
' a method says hello to you.',
' ',
' ',
' .. py:attribute:: EnumCls.val1',
' :module: target',
' :module: target.enum',
' :annotation: = 12',
' ',
' doc for val1',
' ',
' ',
' .. py:attribute:: EnumCls.val2',
' :module: target',
' :module: target.enum',
' :annotation: = 23',
' ',
' doc for val2',
' ',
' ',
' .. py:attribute:: EnumCls.val3',
' :module: target',
' :module: target.enum',
' :annotation: = 34',
' ',
' doc for val3',
' ',
' ',
' .. py:attribute:: EnumCls.val4',
' :module: target',
' :module: target.enum',
' :annotation: = 34',
' '
]
# checks for an attribute of EnumClass
actual = do_autodoc(app, 'attribute', 'target.EnumCls.val1')
actual = do_autodoc(app, 'attribute', 'target.enum.EnumCls.val1')
assert list(actual) == [
'',
'.. py:attribute:: EnumCls.val1',
' :module: target',
' :module: target.enum',
' :annotation: = 12',
'',
' doc for val1',
@ -1341,6 +1346,19 @@ def test_descriptor_class(app):
]
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autofunction_for_callable(app):
actual = do_autodoc(app, 'function', 'target.callable.function')
assert list(actual) == [
'',
'.. py:function:: function(arg1, arg2, **kwargs)',
' :module: target.callable',
'',
' A callable object that behaves like a function.',
' '
]
@pytest.mark.sphinx('html', testroot='root')
def test_mocked_module_imports(app):
options = {"members": 'TestAutodoc,decoratedFunction'}
@ -1473,7 +1491,7 @@ def test_merge_autodoc_default_flags2(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_default_options(app):
# no settings
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' not in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual
actual = do_autodoc(app, 'class', 'target.CustomIter')
@ -1481,7 +1499,7 @@ def test_autodoc_default_options(app):
# with :members:
app.config.autodoc_default_options = {'members': None}
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual
@ -1490,7 +1508,7 @@ def test_autodoc_default_options(app):
'members': None,
'undoc-members': None,
}
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' in actual
@ -1516,7 +1534,7 @@ def test_autodoc_default_options(app):
'members': None,
'exclude-members': None,
}
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual
app.config.autodoc_default_options = {
@ -1540,7 +1558,7 @@ def test_autodoc_default_options(app):
def test_autodoc_default_options_with_values(app):
# with :members:
app.config.autodoc_default_options = {'members': 'val1,val2'}
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val2' in actual
assert ' .. py:attribute:: EnumCls.val3' not in actual
@ -1564,7 +1582,7 @@ def test_autodoc_default_options_with_values(app):
'members': None,
'exclude-members': 'val1'
}
actual = do_autodoc(app, 'class', 'target.EnumCls')
actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' not in actual
assert ' .. py:attribute:: EnumCls.val2' in actual
assert ' .. py:attribute:: EnumCls.val3' in actual