mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '1.8' into 5433_latex_ImportError
This commit is contained in:
commit
2c0359f3a1
5
CHANGES
5
CHANGES
@ -19,6 +19,10 @@ Bugs fixed
|
|||||||
* #5418: Incorrect default path for sphinx-build -d/doctrees files
|
* #5418: Incorrect default path for sphinx-build -d/doctrees files
|
||||||
* #5421: autodoc emits deprecation warning for :confval:`autodoc_default_flags`
|
* #5421: autodoc emits deprecation warning for :confval:`autodoc_default_flags`
|
||||||
* #5422: lambda object causes PicklingError on storing environment
|
* #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'
|
* #5433: latex: ImportError: cannot import name 'DEFAULT_SETTINGS'
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
@ -36,6 +40,7 @@ Dependencies
|
|||||||
``xelatex/lualatex``), instructs ``make latexpdf`` to use :program:`xindy`
|
``xelatex/lualatex``), instructs ``make latexpdf`` to use :program:`xindy`
|
||||||
for general index. Make sure your LaTeX distribution includes it.
|
for general index. Make sure your LaTeX distribution includes it.
|
||||||
(refs: #5134)
|
(refs: #5134)
|
||||||
|
* LaTeX: ``latexmk`` is required for ``make latexpdf`` on Windows
|
||||||
|
|
||||||
Incompatible changes
|
Incompatible changes
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/sphinx.svg
|
.. image:: https://img.shields.io/pypi/v/sphinx.svg
|
||||||
:target: https://pypi.org/project/Sphinx/
|
:target: https://pypi.org/project/Sphinx/
|
||||||
:alt: Package on PyPi
|
:alt: Package on PyPI
|
||||||
|
|
||||||
.. image:: https://readthedocs.org/projects/sphinx/badge/?version=master
|
.. image:: https://readthedocs.org/projects/sphinx/badge/?version=master
|
||||||
:target: http://www.sphinx-doc.org/
|
:target: http://www.sphinx-doc.org/
|
||||||
|
@ -16,7 +16,7 @@ import warnings
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from types import FunctionType, MethodType, ModuleType
|
from types import FunctionType, MethodType, ModuleType
|
||||||
|
|
||||||
from six import PY2
|
from six import PY2, iteritems
|
||||||
|
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.inspect import isenumclass, safe_getattr
|
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:
|
if name not in members:
|
||||||
members[name] = Attribute(name, True, value)
|
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
|
# other members
|
||||||
for name in dir(subject):
|
for name in dir(subject):
|
||||||
try:
|
try:
|
||||||
|
@ -153,7 +153,7 @@ class TestDirective(SphinxDirective):
|
|||||||
if self.name == 'doctest' and 'pyversion' in self.options:
|
if self.name == 'doctest' and 'pyversion' in self.options:
|
||||||
try:
|
try:
|
||||||
spec = self.options['pyversion']
|
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):
|
if not is_allowed_version(spec, python_version):
|
||||||
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
|
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
|
||||||
node['options'][flag] = True # Skip the test
|
node['options'][flag] = True # Skip the test
|
||||||
|
@ -427,6 +427,6 @@ def inspect_main(argv):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import logging # type: ignore
|
import logging # type: ignore
|
||||||
logging.basicConfig()
|
logging.basicConfig() # type: ignore
|
||||||
|
|
||||||
inspect_main(argv=sys.argv[1:]) # type: ignore
|
inspect_main(argv=sys.argv[1:]) # type: ignore
|
||||||
|
@ -32,7 +32,7 @@ class ModuleAnalyzer(object):
|
|||||||
def for_string(cls, string, modname, srcname='<string>'):
|
def for_string(cls, string, modname, srcname='<string>'):
|
||||||
# type: (unicode, unicode, unicode) -> ModuleAnalyzer
|
# type: (unicode, unicode, unicode) -> ModuleAnalyzer
|
||||||
if isinstance(string, bytes):
|
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
|
return cls(StringIO(string), modname, srcname, decoded=True) # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -31,6 +31,7 @@ if "%1" == "help" (
|
|||||||
echo. devhelp to make HTML files and a Devhelp project
|
echo. devhelp to make HTML files and a Devhelp project
|
||||||
echo. epub to make an epub
|
echo. epub to make an epub
|
||||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
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. text to make text files
|
||||||
echo. man to make manual pages
|
echo. man to make manual pages
|
||||||
echo. texinfo to make Texinfo files
|
echo. texinfo to make Texinfo files
|
||||||
|
@ -30,7 +30,7 @@ class path(text_type):
|
|||||||
# type: (unicode, unicode, unicode) -> path
|
# type: (unicode, unicode, unicode) -> path
|
||||||
if isinstance(s, str):
|
if isinstance(s, str):
|
||||||
s = s.decode(encoding, errors)
|
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
|
return text_type.__new__(cls, s) # type: ignore
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -314,8 +314,9 @@ def get_module_source(modname):
|
|||||||
filename += 'w'
|
filename += 'w'
|
||||||
elif not (lfilename.endswith('.py') or lfilename.endswith('.pyw')):
|
elif not (lfilename.endswith('.py') or lfilename.endswith('.pyw')):
|
||||||
raise PycodeError('source is not a .py file: %r' % filename)
|
raise PycodeError('source is not a .py file: %r' % filename)
|
||||||
elif '.egg' in filename:
|
elif ('.egg' + os.path.sep) in filename:
|
||||||
eggpath, _ = re.split('(?<=\\.egg)/', filename)
|
pat = '(?<=\\.egg)' + re.escape(os.path.sep)
|
||||||
|
eggpath, _ = re.split(pat, filename, 1)
|
||||||
if path.isfile(eggpath):
|
if path.isfile(eggpath):
|
||||||
return 'file', filename
|
return 'file', filename
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ def get_image_size(filename):
|
|||||||
|
|
||||||
def guess_mimetype_for_stream(stream, default=None):
|
def guess_mimetype_for_stream(stream, default=None):
|
||||||
# type: (IO, unicode) -> unicode
|
# type: (IO, unicode) -> unicode
|
||||||
imgtype = imghdr.what(stream)
|
imgtype = imghdr.what(stream) # type: ignore
|
||||||
if imgtype:
|
if imgtype:
|
||||||
return 'image/' + imgtype
|
return 'image/' + imgtype
|
||||||
else:
|
else:
|
||||||
@ -141,4 +141,4 @@ def test_svg(h, f):
|
|||||||
|
|
||||||
# install test_svg() to imghdr
|
# install test_svg() to imghdr
|
||||||
# refs: https://docs.python.org/3.6/library/imghdr.html#imghdr.tests
|
# refs: https://docs.python.org/3.6/library/imghdr.html#imghdr.tests
|
||||||
imghdr.tests.append(test_svg)
|
imghdr.tests.append(test_svg) # type: ignore
|
||||||
|
@ -235,7 +235,7 @@ def abspath(pathdir):
|
|||||||
try:
|
try:
|
||||||
pathdir = pathdir.decode(fs_encoding)
|
pathdir = pathdir.decode(fs_encoding)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
raise UnicodeDecodeError('multibyte filename not supported on '
|
raise UnicodeDecodeError('multibyte filename not supported on ' # type: ignore
|
||||||
'this filesystem encoding '
|
'this filesystem encoding '
|
||||||
'(%r)' % fs_encoding)
|
'(%r)' % fs_encoding)
|
||||||
return pathdir
|
return pathdir
|
||||||
|
@ -34,7 +34,7 @@ except ImportError:
|
|||||||
from urllib3.exceptions import InsecureRequestWarning # type: ignore
|
from urllib3.exceptions import InsecureRequestWarning # type: ignore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# for requests < 2.4.0
|
# for requests < 2.4.0
|
||||||
InsecureRequestWarning = None
|
InsecureRequestWarning = None # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
|
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
|
||||||
@ -44,7 +44,7 @@ except ImportError:
|
|||||||
from urllib3.exceptions import InsecurePlatformWarning # type: ignore
|
from urllib3.exceptions import InsecurePlatformWarning # type: ignore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# for requests < 2.4.0
|
# for requests < 2.4.0
|
||||||
InsecurePlatformWarning = None
|
InsecurePlatformWarning = None # type: ignore
|
||||||
|
|
||||||
# try to load requests[security] (but only if SSL is available)
|
# try to load requests[security] (but only if SSL is available)
|
||||||
try:
|
try:
|
||||||
|
@ -223,19 +223,6 @@ class InstAttCls(object):
|
|||||||
"""Docstring for instance attribute InstAttCls.ia2."""
|
"""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):
|
class CustomIter(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Create a new `CustomIter`."""
|
"""Create a new `CustomIter`."""
|
||||||
|
19
tests/roots/test-ext-autodoc/target/enum.py
Normal file
19
tests/roots/test-ext-autodoc/target/enum.py
Normal 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
|
@ -829,7 +829,6 @@ def test_autodoc_ignore_module_all(app):
|
|||||||
'.. py:class:: CustomDataDescriptor2(doc)',
|
'.. py:class:: CustomDataDescriptor2(doc)',
|
||||||
'.. py:class:: CustomDataDescriptorMeta',
|
'.. py:class:: CustomDataDescriptorMeta',
|
||||||
'.. py:class:: CustomDict',
|
'.. py:class:: CustomDict',
|
||||||
'.. py:class:: EnumCls',
|
|
||||||
'.. py:class:: InstAttCls()',
|
'.. py:class:: InstAttCls()',
|
||||||
'.. py:class:: Outer',
|
'.. py:class:: Outer',
|
||||||
' .. py:class:: Outer.Inner',
|
' .. py:class:: Outer.Inner',
|
||||||
@ -1263,48 +1262,54 @@ def test_instance_attributes(app):
|
|||||||
def test_enum_class(app):
|
def test_enum_class(app):
|
||||||
options = {"members": None,
|
options = {"members": None,
|
||||||
"undoc-members": True}
|
"undoc-members": True}
|
||||||
actual = do_autodoc(app, 'class', 'target.EnumCls', options)
|
actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options)
|
||||||
assert list(actual) == [
|
assert list(actual) == [
|
||||||
'',
|
'',
|
||||||
'.. py:class:: EnumCls',
|
'.. py:class:: EnumCls',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
'',
|
'',
|
||||||
' this is enum class',
|
' this is enum class',
|
||||||
' ',
|
' ',
|
||||||
' ',
|
' ',
|
||||||
|
' .. py:method:: EnumCls.say_hello()',
|
||||||
|
' :module: target.enum',
|
||||||
|
' ',
|
||||||
|
' a method says hello to you.',
|
||||||
|
' ',
|
||||||
|
' ',
|
||||||
' .. py:attribute:: EnumCls.val1',
|
' .. py:attribute:: EnumCls.val1',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
' :annotation: = 12',
|
' :annotation: = 12',
|
||||||
' ',
|
' ',
|
||||||
' doc for val1',
|
' doc for val1',
|
||||||
' ',
|
' ',
|
||||||
' ',
|
' ',
|
||||||
' .. py:attribute:: EnumCls.val2',
|
' .. py:attribute:: EnumCls.val2',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
' :annotation: = 23',
|
' :annotation: = 23',
|
||||||
' ',
|
' ',
|
||||||
' doc for val2',
|
' doc for val2',
|
||||||
' ',
|
' ',
|
||||||
' ',
|
' ',
|
||||||
' .. py:attribute:: EnumCls.val3',
|
' .. py:attribute:: EnumCls.val3',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
' :annotation: = 34',
|
' :annotation: = 34',
|
||||||
' ',
|
' ',
|
||||||
' doc for val3',
|
' doc for val3',
|
||||||
' ',
|
' ',
|
||||||
' ',
|
' ',
|
||||||
' .. py:attribute:: EnumCls.val4',
|
' .. py:attribute:: EnumCls.val4',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
' :annotation: = 34',
|
' :annotation: = 34',
|
||||||
' '
|
' '
|
||||||
]
|
]
|
||||||
|
|
||||||
# checks for an attribute of EnumClass
|
# 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) == [
|
assert list(actual) == [
|
||||||
'',
|
'',
|
||||||
'.. py:attribute:: EnumCls.val1',
|
'.. py:attribute:: EnumCls.val1',
|
||||||
' :module: target',
|
' :module: target.enum',
|
||||||
' :annotation: = 12',
|
' :annotation: = 12',
|
||||||
'',
|
'',
|
||||||
' doc for val1',
|
' doc for val1',
|
||||||
@ -1473,7 +1478,7 @@ def test_merge_autodoc_default_flags2(app):
|
|||||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
def test_autodoc_default_options(app):
|
def test_autodoc_default_options(app):
|
||||||
# no settings
|
# 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.val1' not in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
||||||
actual = do_autodoc(app, 'class', 'target.CustomIter')
|
actual = do_autodoc(app, 'class', 'target.CustomIter')
|
||||||
@ -1481,7 +1486,7 @@ def test_autodoc_default_options(app):
|
|||||||
|
|
||||||
# with :members:
|
# with :members:
|
||||||
app.config.autodoc_default_options = {'members': None}
|
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.val1' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
||||||
|
|
||||||
@ -1490,7 +1495,7 @@ def test_autodoc_default_options(app):
|
|||||||
'members': None,
|
'members': None,
|
||||||
'undoc-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.val1' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val4' in actual
|
assert ' .. py:attribute:: EnumCls.val4' in actual
|
||||||
|
|
||||||
@ -1516,7 +1521,7 @@ def test_autodoc_default_options(app):
|
|||||||
'members': None,
|
'members': None,
|
||||||
'exclude-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.val1' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
assert ' .. py:attribute:: EnumCls.val4' not in actual
|
||||||
app.config.autodoc_default_options = {
|
app.config.autodoc_default_options = {
|
||||||
@ -1540,7 +1545,7 @@ def test_autodoc_default_options(app):
|
|||||||
def test_autodoc_default_options_with_values(app):
|
def test_autodoc_default_options_with_values(app):
|
||||||
# with :members:
|
# with :members:
|
||||||
app.config.autodoc_default_options = {'members': 'val1,val2'}
|
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.val1' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val2' in actual
|
assert ' .. py:attribute:: EnumCls.val2' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val3' not in actual
|
assert ' .. py:attribute:: EnumCls.val3' not in actual
|
||||||
@ -1564,7 +1569,7 @@ def test_autodoc_default_options_with_values(app):
|
|||||||
'members': None,
|
'members': None,
|
||||||
'exclude-members': 'val1'
|
'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.val1' not in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val2' in actual
|
assert ' .. py:attribute:: EnumCls.val2' in actual
|
||||||
assert ' .. py:attribute:: EnumCls.val3' in actual
|
assert ' .. py:attribute:: EnumCls.val3' in actual
|
||||||
|
Loading…
Reference in New Issue
Block a user