Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA 2020-12-31 14:33:09 +09:00
commit 62a0ee3fef
10 changed files with 52 additions and 38 deletions

View File

@ -66,6 +66,7 @@ Incompatible changes
Deprecated Deprecated
---------- ----------
* ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()``
* ``sphinx.ext.autodoc.importer.get_module_members()`` * ``sphinx.ext.autodoc.importer.get_module_members()``
Features added Features added
@ -85,6 +86,8 @@ Bugs fixed
* #8594: autodoc: empty __all__ attribute is ignored * #8594: autodoc: empty __all__ attribute is ignored
* #8306: autosummary: mocked modules are documented as empty page when using * #8306: autosummary: mocked modules are documented as empty page when using
:recursive: option :recursive: option
* #8618: html: kbd role produces incorrect HTML when compound-key separators (-,
+ or ^) are used as keystrokes
* #8094: texinfo: image files on the different directory with document are not * #8094: texinfo: image files on the different directory with document are not
copied copied

View File

@ -56,6 +56,11 @@ The following is a list of deprecated interfaces.
- 6.0 - 6.0
- ``docutils.utils.smartyquotes`` - ``docutils.utils.smartyquotes``
* - ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()``
- 3.5
- 5.0
- N/A
* - ``sphinx.ext.autodoc.importer.get_module_members()`` * - ``sphinx.ext.autodoc.importer.get_module_members()``
- 3.5 - 3.5
- 5.0 - 5.0

View File

@ -138,10 +138,7 @@ Coding style
Please follow these guidelines when writing code for Sphinx: Please follow these guidelines when writing code for Sphinx:
* Try to use the same code style as used in the rest of the project. See the * Try to use the same code style as used in the rest of the project.
`Pocoo Styleguide`__ for more information.
__ http://flask.pocoo.org/docs/styleguide/
* For non-trivial changes, please update the :file:`CHANGES` file. If your * For non-trivial changes, please update the :file:`CHANGES` file. If your
changes alter existing behavior, please document this. changes alter existing behavior, please document this.

View File

@ -60,6 +60,7 @@ filterwarnings =
all all
ignore::DeprecationWarning:docutils.io ignore::DeprecationWarning:docutils.io
ignore::DeprecationWarning:pyximport.pyximport ignore::DeprecationWarning:pyximport.pyximport
ignore::ImportWarning:importlib._bootstrap
markers = markers =
apidoc apidoc
setup_command setup_command

View File

@ -37,7 +37,7 @@ class KeyboardTransform(SphinxPostTransform):
""" """
default_priority = 400 default_priority = 400
builders = ('html',) builders = ('html',)
pattern = re.compile(r'(-|\+|\^|\s+)') pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)')
def run(self, **kwargs: Any) -> None: def run(self, **kwargs: Any) -> None:
matcher = NodeMatcher(nodes.literal, classes=["kbd"]) matcher = NodeMatcher(nodes.literal, classes=["kbd"])

View File

@ -24,8 +24,8 @@ from sphinx.application import Sphinx
from sphinx.config import ENUM, Config from sphinx.config import ENUM, Config
from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning
from sphinx.environment import BuildEnvironment from sphinx.environment import BuildEnvironment
from sphinx.ext.autodoc.importer import (ClassAttribute, get_class_members, get_object_members, from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module,
import_module, import_object) import_object)
from sphinx.ext.autodoc.mock import ismock, mock from sphinx.ext.autodoc.mock import ismock, mock
from sphinx.locale import _, __ from sphinx.locale import _, __
from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.pycode import ModuleAnalyzer, PycodeError
@ -1602,10 +1602,6 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename) self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename)
def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]: def get_object_members(self, want_all: bool) -> Tuple[bool, ObjectMembers]:
def convert(m: ClassAttribute) -> ObjectMember:
"""Convert ClassAttribute object to ObjectMember."""
return ObjectMember(m.name, m.value, class_=m.class_, docstring=m.docstring)
members = get_class_members(self.object, self.objpath, self.get_attr) members = get_class_members(self.object, self.objpath, self.get_attr)
if not want_all: if not want_all:
if not self.options.members: if not self.options.members:
@ -1614,15 +1610,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
selected = [] selected = []
for name in self.options.members: # type: str for name in self.options.members: # type: str
if name in members: if name in members:
selected.append(convert(members[name])) selected.append(members[name])
else: else:
logger.warning(__('missing attribute %s in object %s') % logger.warning(__('missing attribute %s in object %s') %
(name, self.fullname), type='autodoc') (name, self.fullname), type='autodoc')
return False, selected return False, selected
elif self.options.inherited_members: elif self.options.inherited_members:
return False, [convert(m) for m in members.values()] return False, list(members.values())
else: else:
return False, [convert(m) for m in members.values() if m.class_ == self.object] return False, [m for m in members.values() if m.class_ == self.object]
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]: def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
if self.doc_as_attr: if self.doc_as_attr:
@ -2341,6 +2337,8 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
def isinstanceattribute(self) -> bool: def isinstanceattribute(self) -> bool:
"""Check the subject is an instance attribute.""" """Check the subject is an instance attribute."""
warnings.warn('AttributeDocumenter.isinstanceattribute() is deprecated.',
RemovedInSphinx50Warning)
# uninitialized instance variable (PEP-526) # uninitialized instance variable (PEP-526)
with mock(self.config.autodoc_mock_imports): with mock(self.config.autodoc_mock_imports):
try: try:

View File

@ -23,6 +23,8 @@ if False:
# For type annotation # For type annotation
from typing import Type # NOQA from typing import Type # NOQA
from sphinx.ext.autodoc import ObjectMember
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -233,37 +235,27 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
return members return members
class ClassAttribute:
"""The attribute of the class."""
def __init__(self, cls: Any, name: str, value: Any, docstring: Optional[str] = None):
self.class_ = cls
self.name = name
self.value = value
self.docstring = docstring
def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
) -> Dict[str, ClassAttribute]: ) -> Dict[str, "ObjectMember"]:
"""Get members and attributes of target class.""" """Get members and attributes of target class."""
from sphinx.ext.autodoc import INSTANCEATTR from sphinx.ext.autodoc import INSTANCEATTR, ObjectMember
# the members directly defined in the class # the members directly defined in the class
obj_dict = attrgetter(subject, '__dict__', {}) obj_dict = attrgetter(subject, '__dict__', {})
members = {} # type: Dict[str, ClassAttribute] members = {} # type: Dict[str, ObjectMember]
# enum members # enum members
if isenumclass(subject): if isenumclass(subject):
for name, value in subject.__members__.items(): for name, value in subject.__members__.items():
if name not in members: if name not in members:
members[name] = ClassAttribute(subject, name, value) members[name] = ObjectMember(name, value, class_=subject)
superclass = subject.__mro__[1] superclass = subject.__mro__[1]
for name in obj_dict: for name in obj_dict:
if name not in superclass.__dict__: if name not in superclass.__dict__:
value = safe_getattr(subject, name) value = safe_getattr(subject, name)
members[name] = ClassAttribute(subject, name, value) members[name] = ObjectMember(name, value, class_=subject)
# members in __slots__ # members in __slots__
try: try:
@ -272,7 +264,8 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
from sphinx.ext.autodoc import SLOTSATTR from sphinx.ext.autodoc import SLOTSATTR
for name, docstring in __slots__.items(): for name, docstring in __slots__.items():
members[name] = ClassAttribute(subject, name, SLOTSATTR, docstring) members[name] = ObjectMember(name, SLOTSATTR, class_=subject,
docstring=docstring)
except (AttributeError, TypeError, ValueError): except (AttributeError, TypeError, ValueError):
pass pass
@ -283,9 +276,9 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
unmangled = unmangle(subject, name) unmangled = unmangle(subject, name)
if unmangled and unmangled not in members: if unmangled and unmangled not in members:
if name in obj_dict: if name in obj_dict:
members[unmangled] = ClassAttribute(subject, unmangled, value) members[unmangled] = ObjectMember(unmangled, value, class_=subject)
else: else:
members[unmangled] = ClassAttribute(None, unmangled, value) members[unmangled] = ObjectMember(unmangled, value)
except AttributeError: except AttributeError:
continue continue
@ -296,7 +289,7 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
for name in getannotations(cls): for name in getannotations(cls):
name = unmangle(cls, name) name = unmangle(cls, name)
if name and name not in members: if name and name not in members:
members[name] = ClassAttribute(cls, name, INSTANCEATTR) members[name] = ObjectMember(name, INSTANCEATTR, class_=cls)
except AttributeError: except AttributeError:
pass pass
@ -308,8 +301,8 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
analyzer.analyze() analyzer.analyze()
for (ns, name), docstring in analyzer.attr_docs.items(): for (ns, name), docstring in analyzer.attr_docs.items():
if ns == qualname and name not in members: if ns == qualname and name not in members:
members[name] = ClassAttribute(cls, name, INSTANCEATTR, members[name] = ObjectMember(name, INSTANCEATTR, class_=cls,
'\n'.join(docstring)) docstring='\n'.join(docstring))
except (AttributeError, PycodeError): except (AttributeError, PycodeError):
pass pass
except AttributeError: except AttributeError:

View File

@ -86,12 +86,11 @@ def setup_documenters(app: Any) -> None:
DecoratorDocumenter, ExceptionDocumenter, DecoratorDocumenter, ExceptionDocumenter,
FunctionDocumenter, MethodDocumenter, ModuleDocumenter, FunctionDocumenter, MethodDocumenter, ModuleDocumenter,
NewTypeAttributeDocumenter, NewTypeDataDocumenter, NewTypeAttributeDocumenter, NewTypeDataDocumenter,
PropertyDocumenter, SingledispatchFunctionDocumenter) PropertyDocumenter)
documenters = [ documenters = [
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter, FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,
NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
SingledispatchFunctionDocumenter,
] # type: List[Type[Documenter]] ] # type: List[Type[Documenter]]
for documenter in documenters: for documenter in documenters:
app.registry.add_documenter(documenter.objtype, documenter) app.registry.add_documenter(documenter.objtype, documenter)

View File

@ -251,6 +251,17 @@ def get_verifier(verify, verify_re):
'</kbd></p>'), '</kbd></p>'),
'\\sphinxkeyboard{\\sphinxupquote{Control+X}}', '\\sphinxkeyboard{\\sphinxupquote{Control+X}}',
), ),
(
# kbd role
'verify',
':kbd:`Alt+^`',
('<p><kbd class="kbd docutils literal notranslate">'
'<kbd class="kbd docutils literal notranslate">Alt</kbd>'
'+'
'<kbd class="kbd docutils literal notranslate">^</kbd>'
'</kbd></p>'),
'\\sphinxkeyboard{\\sphinxupquote{Alt+\\textasciicircum{}}}',
),
( (
# kbd role # kbd role
'verify', 'verify',
@ -266,6 +277,13 @@ def get_verifier(verify, verify_re):
'</kbd></p>'), '</kbd></p>'),
'\\sphinxkeyboard{\\sphinxupquote{M\\sphinxhyphen{}x M\\sphinxhyphen{}s}}', '\\sphinxkeyboard{\\sphinxupquote{M\\sphinxhyphen{}x M\\sphinxhyphen{}s}}',
), ),
(
# kbd role
'verify',
':kbd:`-`',
'<p><kbd class="kbd docutils literal notranslate">-</kbd></p>',
'\\sphinxkeyboard{\\sphinxupquote{\\sphinxhyphen{}}}',
),
( (
# non-interpolation of dashes in option role # non-interpolation of dashes in option role
'verify_re', 'verify_re',

View File

@ -23,7 +23,7 @@ deps =
extras = extras =
test test
setenv = setenv =
PYTHONWARNINGS = all,ignore::ImportWarning:importlib._bootstrap_external,ignore::DeprecationWarning:site,ignore::DeprecationWarning:distutils PYTHONWARNINGS = all,ignore::ImportWarning:importlib._bootstrap_external,ignore::DeprecationWarning:site,ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:pip._vendor.packaging.version
PYTEST_ADDOPTS = {env:PYTEST_ADDOPTS:} --color yes PYTEST_ADDOPTS = {env:PYTEST_ADDOPTS:} --color yes
commands= commands=
python -X dev -m pytest --durations 25 {posargs} python -X dev -m pytest --durations 25 {posargs}