Support coverage_ignore_pyobjects in the coverage builder

This commit is contained in:
Adrián Chaves 2019-05-14 14:48:52 +02:00
parent c81ae00430
commit e84ba7f78a
9 changed files with 109 additions and 3 deletions

View File

@ -82,6 +82,7 @@ Other contributors, listed alphabetically, are:
* Stephen Finucane -- setup command improvements and documentation
* Daniel Pizetta -- inheritance diagram improvements
* KINEBUCHI Tomohiko -- typing Sphinx as well as docutils
* Adrián Chaves (Gallaecio) -- coverage builder improvements
Many thanks for all contributions!

View File

@ -99,6 +99,7 @@ Features added
* #6306: html: Add a label to search form for accessability purposes
* #6358: The ``rawsource`` property of ``production`` nodes now contains the
full production rule
* Support a new ``coverage_ignore_pyobjects`` option in the coverage builder
Bugs fixed
----------

View File

@ -22,6 +22,16 @@ should check:
.. confval:: coverage_ignore_classes
.. confval:: coverage_ignore_pyobjects
List of `Python regular expressions`_.
If any of these regular expressions matches any part of the full import path
of a Python object, that Python object is excluded from the documentation
coverage report.
.. versionadded:: 2.1
.. confval:: coverage_c_path
.. confval:: coverage_c_regexes
@ -40,3 +50,5 @@ should check:
``False`` by default.
.. versionadded:: 1.1
.. _Python regular expressions: https://docs.python.org/library/re

View File

@ -79,6 +79,8 @@ class CoverageBuilder(Builder):
self.config.coverage_ignore_classes)
self.fun_ignorexps = compile_regex_list('coverage_ignore_functions',
self.config.coverage_ignore_functions)
self.py_ignorexps = compile_regex_list('coverage_ignore_pyobjects',
self.config.coverage_ignore_pyobjects)
def get_outdated_docs(self):
# type: () -> str
@ -130,6 +132,12 @@ class CoverageBuilder(Builder):
op.write(' * %-50s [%9s]\n' % (name, typ))
op.write('\n')
def ignore_pyobj(self, full_name):
for exp in self.py_ignorexps:
if exp.search(full_name):
return True
return False
def build_py_coverage(self):
# type: () -> None
objects = self.env.domaindata['py']['objects']
@ -143,7 +151,7 @@ class CoverageBuilder(Builder):
if exp.match(mod_name):
ignore = True
break
if ignore:
if ignore or self.ignore_pyobj(mod_name):
continue
try:
@ -169,6 +177,8 @@ class CoverageBuilder(Builder):
continue
full_name = '%s.%s' % (mod_name, name)
if self.ignore_pyobj(full_name):
continue
if inspect.isfunction(obj):
if full_name not in objects:
@ -209,11 +219,11 @@ class CoverageBuilder(Builder):
if skip_undoc and not attr.__doc__:
# skip methods without docstring if wished
continue
full_attr_name = '%s.%s' % (full_name, attr_name)
if self.ignore_pyobj(full_attr_name):
continue
if full_attr_name not in objects:
attrs.append(attr_name)
if attrs:
# some attributes are undocumented
classes[name] = attrs
@ -270,6 +280,7 @@ def setup(app):
app.add_config_value('coverage_ignore_modules', [], False)
app.add_config_value('coverage_ignore_functions', [], False)
app.add_config_value('coverage_ignore_classes', [], False)
app.add_config_value('coverage_ignore_pyobjects', [], False)
app.add_config_value('coverage_c_path', [], False)
app.add_config_value('coverage_c_regexes', {}, False)
app.add_config_value('coverage_ignore_c_items', {}, False)

View File

@ -0,0 +1,12 @@
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage']
coverage_ignore_pyobjects = [
r'^coverage_ignored(\..*)?$',
r'\.Ignored$',
r'\.Documented\.ignored\d$',
]

View File

@ -0,0 +1,22 @@
class Documented:
"""Documented"""
def ignored1(self):
pass
def ignored2(self):
pass
def not_ignored1(self):
pass
def not_ignored2(self):
pass
class Ignored:
pass
class NotIgnored:
pass

View File

@ -0,0 +1,22 @@
class Documented:
"""Documented"""
def ignored1(self):
pass
def ignored2(self):
pass
def not_ignored1(self):
pass
def not_ignored2(self):
pass
class Ignored:
pass
class NotIgnored:
pass

View File

@ -0,0 +1,6 @@
.. automodule:: coverage_ignored
:members:
.. automodule:: coverage_not_ignored
:members:

View File

@ -45,3 +45,22 @@ def test_build(app, status, warning):
assert 'classes' in undoc_py['autodoc_target']
assert 'Class' in undoc_py['autodoc_target']['classes']
assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class']
@pytest.mark.sphinx('coverage', testroot='ext-coverage')
def test_coverage_ignore_pyobjects(app, status, warning):
app.builder.build_all()
actual = (app.outdir / 'python.txt').text()
expected = '''Undocumented Python objects
===========================
coverage_not_ignored
--------------------
Classes:
* Documented -- missing methods:
- not_ignored1
- not_ignored2
* NotIgnored
'''
assert actual == expected