Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close #8022: autodoc: Allow to hide the value of the variables via metadata #8596

Merged
merged 2 commits into from Dec 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES
Expand Up @@ -13,6 +13,10 @@ Deprecated
Features added
--------------

* #8022: autodoc: autodata and autoattribute directives does not show right-hand
value of the variable if docstring contains ``:meta hide-value:`` in
info-field-list

Bugs fixed
----------

Expand Down
10 changes: 10 additions & 0 deletions doc/usage/extensions/autodoc.rst
Expand Up @@ -182,6 +182,16 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,

.. versionadded:: 3.1

* autodoc considers a variable member does not have any default value if its
docstring contains ``:meta hide-value:`` in its :ref:`info-field-lists`.
Example:

.. code-block:: rst

var1 = None #: :meta hide-value:

.. versionadded:: 3.5

* Python "special" members (that is, those named like ``__special__``) will
be included if the ``special-members`` flag option is given::

Expand Down
46 changes: 46 additions & 0 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1883,6 +1883,17 @@ def import_object(self, raiseerror: bool = False) -> bool:

return ret

def should_suppress_value_header(self) -> bool:
if super().should_suppress_value_header():
return True
else:
doc = self.get_doc()
metadata = extract_metadata('\n'.join(sum(doc, [])))
if 'hide-value' in metadata:
return True

return False

def add_directive_header(self, sig: str) -> None:
super().add_directive_header(sig)
sourcename = self.get_sourcename()
Expand Down Expand Up @@ -1914,8 +1925,32 @@ def get_real_modname(self) -> str:
return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname

def get_module_comment(self, attrname: str) -> Optional[List[str]]:
try:
analyzer = ModuleAnalyzer.for_module(self.modname)
analyzer.analyze()
key = ('', attrname)
if key in analyzer.attr_docs:
return list(analyzer.attr_docs[key])
except PycodeError:
pass

return None

def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:
# Check the variable has a docstring-comment
comment = self.get_module_comment(self.objpath[-1])
if comment:
return [comment]
else:
return super().get_doc(encoding, ignore)

def add_content(self, more_content: Optional[StringList], no_docstring: bool = False
) -> None:
# Disable analyzing variable comment on Documenter.add_content() to control it on
# DataDocumenter.add_content()
self.analyzer = None

if not more_content:
more_content = StringList()

Expand Down Expand Up @@ -2352,6 +2387,17 @@ def get_real_modname(self) -> str:
return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname

def should_suppress_value_header(self) -> bool:
if super().should_suppress_value_header():
return True
else:
doc = self.get_doc()
metadata = extract_metadata('\n'.join(sum(doc, [])))
if 'hide-value' in metadata:
return True

return False

def add_directive_header(self, sig: str) -> None:
super().add_directive_header(sig)
sourcename = self.get_sourcename()
Expand Down
19 changes: 19 additions & 0 deletions tests/roots/test-ext-autodoc/target/hide_value.py
@@ -0,0 +1,19 @@
#: docstring
#:
#: :meta hide-value:
SENTINEL1 = object()

#: :meta hide-value:
SENTINEL2 = object()


class Foo:
"""docstring"""

#: docstring
#:
#: :meta hide-value:
SENTINEL1 = object()

#: :meta hide-value:
SENTINEL2 = object()
46 changes: 46 additions & 0 deletions tests/test_ext_autodoc.py
Expand Up @@ -2235,3 +2235,49 @@ def test_name_mangling(app):
' name of Foo',
'',
]


@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_hide_value(app):
options = {'members': True}
actual = do_autodoc(app, 'module', 'target.hide_value', options)
assert list(actual) == [
'',
'.. py:module:: target.hide_value',
'',
'',
'.. py:class:: Foo()',
' :module: target.hide_value',
'',
' docstring',
'',
'',
' .. py:attribute:: Foo.SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
'',
' .. py:attribute:: Foo.SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
tk0miya marked this conversation as resolved.
Show resolved Hide resolved
'',
'',
'.. py:data:: SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
'',
'.. py:data:: SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]
26 changes: 26 additions & 0 deletions tests/test_ext_autodoc_autoattribute.py
Expand Up @@ -189,3 +189,29 @@ def test_autoattribute_TypeVar(app):
" alias of TypeVar('T1')",
'',
]


@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_hide_value(app):
actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL1')
assert list(actual) == [
'',
'.. py:attribute:: Foo.SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
]

actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL2')
assert list(actual) == [
'',
'.. py:attribute:: Foo.SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]
26 changes: 26 additions & 0 deletions tests/test_ext_autodoc_autodata.py
Expand Up @@ -129,3 +129,29 @@ def test_autodata_TypeVar(app):
" alias of TypeVar('T1')",
'',
]


@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodata_hide_value(app):
actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL1')
assert list(actual) == [
'',
'.. py:data:: SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
]

actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL2')
assert list(actual) == [
'',
'.. py:data:: SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]