mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
refactored code and tests, prepared for numpy feature
This commit is contained in:
parent
a60e1c10b7
commit
ec30f77712
@ -300,7 +300,7 @@ class ExamplePEP526Class:
|
||||
|
||||
If the class has public attributes, they may be documented here
|
||||
in an ``Attributes`` section and follow the same formatting as a
|
||||
function's ``Args`` section. If ``napoleon_google_attr_annotations``
|
||||
function's ``Args`` section. If ``napoleon_attr_annotations``
|
||||
is True, types can be specified in the class body using ``PEP 526``
|
||||
annotations.
|
||||
|
||||
|
@ -302,7 +302,7 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
|
||||
napoleon_use_param = True
|
||||
napoleon_use_rtype = True
|
||||
napoleon_type_aliases = None
|
||||
napoleon_google_attr_annotations = False
|
||||
napoleon_attr_annotations = True
|
||||
|
||||
.. _Google style:
|
||||
https://google.github.io/styleguide/pyguide.html
|
||||
@ -540,8 +540,10 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
.. confval:: napoleon_google_attr_annotations
|
||||
.. confval:: napoleon_attr_annotations
|
||||
|
||||
True to allow using `PEP 526`_ attributes annotations in classes.
|
||||
If an attribute is documented in the docstring without a type and
|
||||
has an annotation in the class body, that type is used.
|
||||
True to allow using `PEP 526`_ attributes annotations in classes.
|
||||
If an attribute is documented in the docstring without a type and
|
||||
has an annotation in the class body, that type is used.
|
||||
|
||||
.. versionadded:: 3.4
|
@ -44,7 +44,7 @@ class Config:
|
||||
napoleon_preprocess_types = False
|
||||
napoleon_type_aliases = None
|
||||
napoleon_custom_sections = None
|
||||
napoleon_google_attr_annotations = False
|
||||
napoleon_attr_annotations = False
|
||||
|
||||
.. _Google style:
|
||||
https://google.github.io/styleguide/pyguide.html
|
||||
@ -258,7 +258,7 @@ class Config:
|
||||
section. If the entry is a tuple/list/indexed container, the first entry
|
||||
is the name of the section, the second is the section key to emulate.
|
||||
|
||||
napoleon_google_attr_annotations : :obj:`bool` (Defaults to False)
|
||||
napoleon_attr_annotations : :obj:`bool` (Defaults to True)
|
||||
Use the type annotations of class attributes that are documented in the docstring
|
||||
but do not have a type in the docstring.
|
||||
|
||||
@ -279,7 +279,7 @@ class Config:
|
||||
'napoleon_preprocess_types': (False, 'env'),
|
||||
'napoleon_type_aliases': (None, 'env'),
|
||||
'napoleon_custom_sections': (None, 'env'),
|
||||
'napoleon_google_attr_annotations': (False, 'env'),
|
||||
'napoleon_attr_annotations': (True, 'env'),
|
||||
}
|
||||
|
||||
def __init__(self, **settings: Any) -> None:
|
||||
|
@ -14,14 +14,15 @@ import collections
|
||||
import inspect
|
||||
import re
|
||||
from functools import partial
|
||||
from typing import Any, Callable, Dict, List, Tuple, Union, get_type_hints
|
||||
from typing import Any, Callable, Dict, List, Tuple, Union
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.config import Config as SphinxConfig
|
||||
from sphinx.ext.napoleon.iterators import modify_iter
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import safe_getattr, stringify_annotation
|
||||
from sphinx.util.inspect import stringify_annotation
|
||||
from sphinx.util.typing import get_type_hints
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -601,25 +602,15 @@ class GoogleDocstring:
|
||||
def _parse_attributes_section(self, section: str) -> List[str]:
|
||||
lines = []
|
||||
for _name, _type, _desc in self._consume_fields():
|
||||
# code adapted from autodoc.AttributeDocumenter:add_directive_header
|
||||
if not _type and self._what in ('class', 'exception') and self._obj:
|
||||
if self._config.napoleon_google_attr_annotations:
|
||||
if self._config.napoleon_attr_annotations:
|
||||
# cache the class annotations
|
||||
if not hasattr(self, "_annotations"):
|
||||
try:
|
||||
self._annotations = get_type_hints(self._obj)
|
||||
except NameError:
|
||||
# Failed to evaluate ForwardRef (maybe TYPE_CHECKING)
|
||||
self._annotations = safe_getattr(self._obj, '__annotations__', {})
|
||||
except TypeError:
|
||||
self._annotations = {}
|
||||
except KeyError:
|
||||
# a broken class found
|
||||
# (refs: https://github.com/sphinx-doc/sphinx/issues/8084)
|
||||
self._annotations = {}
|
||||
except AttributeError:
|
||||
# AttributeError is raised on 3.5.2 (fixed by 3.5.3)
|
||||
self._annotations = {}
|
||||
localns = getattr(self._config, "autodoc_type_aliases", {}) or {}
|
||||
localns.update(getattr(
|
||||
self._config, "napoleon_type_aliases", {}
|
||||
) or {})
|
||||
self._annotations = get_type_hints(self._obj, None, localns)
|
||||
if _name in self._annotations:
|
||||
_type = stringify_annotation(self._annotations[_name])
|
||||
if self._config.napoleon_use_ivar:
|
||||
|
@ -66,7 +66,7 @@ def get_type_hints(obj: Any, globalns: Dict = None, localns: Dict = None) -> Dic
|
||||
from sphinx.util.inspect import safe_getattr # lazy loading
|
||||
|
||||
try:
|
||||
return typing.get_type_hints(obj, None, localns)
|
||||
return typing.get_type_hints(obj, globalns, localns)
|
||||
except NameError:
|
||||
# Failed to evaluate ForwardRef (maybe TYPE_CHECKING)
|
||||
return safe_getattr(obj, '__annotations__', {})
|
||||
|
@ -1,10 +0,0 @@
|
||||
class PEP526Class:
|
||||
"""Sample class with PEP 526 annotations
|
||||
|
||||
Attributes:
|
||||
attr1: Attr1 description.
|
||||
attr2: Attr2 description.
|
||||
"""
|
||||
|
||||
attr1: int
|
||||
attr2: str
|
18
tests/ext_napoleon_pep526_data_google.py
Normal file
18
tests/ext_napoleon_pep526_data_google.py
Normal file
@ -0,0 +1,18 @@
|
||||
"""
|
||||
Test module for napoleon PEP 526 compatiblity with google style
|
||||
"""
|
||||
|
||||
module_level_var: int = 99
|
||||
"""This is an example module level variable"""
|
||||
|
||||
|
||||
class PEP526GoogleClass:
|
||||
"""Sample class with PEP 526 annotations and google docstring
|
||||
|
||||
Attributes:
|
||||
attr1: Attr1 description.
|
||||
attr2: Attr2 description.
|
||||
"""
|
||||
|
||||
attr1: int
|
||||
attr2: str
|
22
tests/ext_napoleon_pep526_data_numpy.py
Normal file
22
tests/ext_napoleon_pep526_data_numpy.py
Normal file
@ -0,0 +1,22 @@
|
||||
"""
|
||||
Test module for napoleon PEP 526 compatiblity with numpy style
|
||||
"""
|
||||
|
||||
module_level_var: int = 99
|
||||
"""This is an example module level variable"""
|
||||
|
||||
|
||||
class PEP526NumpyClass:
|
||||
"""
|
||||
Sample class with PEP 526 annotations and numpy docstring
|
||||
|
||||
Attributes
|
||||
----------
|
||||
attr 1:
|
||||
Attr1 description
|
||||
|
||||
attr 2:
|
||||
Attr2 description
|
||||
"""
|
||||
attr1: int
|
||||
attr2: str
|
@ -25,7 +25,11 @@ from sphinx.ext.napoleon.docstring import (GoogleDocstring, NumpyDocstring,
|
||||
_token_type, _tokenize_type_spec)
|
||||
|
||||
if sys.version_info >= (3, 6):
|
||||
from ext_napoleon_docstring_data import PEP526Class
|
||||
# TODO: enable imports when used
|
||||
# import ext_napoleon_pep526_data_google
|
||||
# import ext_napoleon_pep526_data_numpy
|
||||
from ext_napoleon_pep526_data_google import PEP526GoogleClass
|
||||
from ext_napoleon_pep526_data_numpy import PEP526NumpyClass
|
||||
|
||||
|
||||
class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))):
|
||||
@ -1095,16 +1099,17 @@ Do as you please
|
||||
:kwtype gotham_is_yours: None
|
||||
"""
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
def test_pep_526_annotations(self):
|
||||
if sys.version_info >= (3, 6):
|
||||
# Test class attributes annotations
|
||||
config = Config(
|
||||
napoleon_google_attr_annotations=True
|
||||
napoleon_attr_annotations=True
|
||||
)
|
||||
actual = str(GoogleDocstring(cleandoc(PEP526Class.__doc__), config, app=None, what="class",
|
||||
obj=PEP526Class))
|
||||
actual = str(GoogleDocstring(cleandoc(PEP526GoogleClass.__doc__), config, app=None, what="class",
|
||||
obj=PEP526GoogleClass))
|
||||
expected = """\
|
||||
Sample class with PEP 526 annotations
|
||||
Sample class with PEP 526 annotations and google docstring
|
||||
|
||||
.. attribute:: attr1
|
||||
|
||||
@ -1120,6 +1125,9 @@ Sample class with PEP 526 annotations
|
||||
"""
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
# test module-level variables documentation
|
||||
# TODO: use the ext_napoleon_pep526_data_google.module_level_var for that
|
||||
|
||||
|
||||
class NumpyDocstringTest(BaseDocstringTest):
|
||||
docstrings = [(
|
||||
@ -2430,3 +2438,29 @@ class TestNumpyDocstring:
|
||||
actual = numpy_docstring._escape_args_and_kwargs(name)
|
||||
|
||||
assert actual == expected
|
||||
|
||||
def test_pep_526_annotations(self):
|
||||
if sys.version_info >= (3, 6):
|
||||
# test class attributes annotations
|
||||
# TODO: change this test after implementation in Numpy doc style
|
||||
config = Config(
|
||||
napoleon_attr_annotations=True
|
||||
)
|
||||
actual = str(NumpyDocstring(cleandoc(PEP526NumpyClass.__doc__), config, app=None, what="class",
|
||||
obj=PEP526NumpyClass))
|
||||
expected = """\
|
||||
Sample class with PEP 526 annotations and numpy docstring
|
||||
|
||||
.. attribute:: attr 1
|
||||
|
||||
Attr1 description
|
||||
|
||||
.. attribute:: attr 2
|
||||
|
||||
Attr2 description
|
||||
"""
|
||||
print(actual)
|
||||
assert expected == actual
|
||||
|
||||
# test module-level variables documentation
|
||||
# TODO: use the ext_napoleon_pep526_data_google.module_level_var for that
|
||||
|
Loading…
Reference in New Issue
Block a user