mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0' into 6375_angle_brackets_in_linktitle
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -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!
|
||||
|
||||
|
||||
3
CHANGES
3
CHANGES
@@ -99,6 +99,8 @@ 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
|
||||
* #6373: autosectionlabel: Allow suppression of warnings
|
||||
* coverage: Support a new ``coverage_ignore_pyobjects`` option
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
@@ -115,6 +117,7 @@ Bugs fixed
|
||||
* #6311: autosummary: autosummary table gets confused by complex type hints
|
||||
* Generated Makefiles lack a final EOL (refs: #6232)
|
||||
* #6375: extlinks: Cannot escape angle brackets in link caption
|
||||
* #6378: linkcheck: Send commonly used User-Agent
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
@@ -296,25 +296,26 @@ General configuration
|
||||
|
||||
Sphinx supports following warning types:
|
||||
|
||||
* app.add_node
|
||||
* app.add_directive
|
||||
* app.add_role
|
||||
* app.add_generic_role
|
||||
* app.add_source_parser
|
||||
* download.not_readable
|
||||
* image.not_readable
|
||||
* ref.term
|
||||
* ref.ref
|
||||
* ref.numref
|
||||
* ref.keyword
|
||||
* ref.option
|
||||
* ref.citation
|
||||
* ref.footnote
|
||||
* ref.doc
|
||||
* ref.python
|
||||
* misc.highlighting_failure
|
||||
* toc.secnum
|
||||
* epub.unknown_project_files
|
||||
* ``app.add_node``
|
||||
* ``app.add_directive``
|
||||
* ``app.add_role``
|
||||
* ``app.add_generic_role``
|
||||
* ``app.add_source_parser``
|
||||
* ``download.not_readable``
|
||||
* ``image.not_readable``
|
||||
* ``ref.term``
|
||||
* ``ref.ref``
|
||||
* ``ref.numref``
|
||||
* ``ref.keyword``
|
||||
* ``ref.option``
|
||||
* ``ref.citation``
|
||||
* ``ref.footnote``
|
||||
* ``ref.doc``
|
||||
* ``ref.python``
|
||||
* ``misc.highlighting_failure``
|
||||
* ``toc.secnum``
|
||||
* ``epub.unknown_project_files``
|
||||
* ``autosectionlabel.*``
|
||||
|
||||
You can choose from these types.
|
||||
|
||||
@@ -334,6 +335,10 @@ General configuration
|
||||
|
||||
Added ``ref.footnote``
|
||||
|
||||
.. versionchanged:: 2.1
|
||||
|
||||
Added ``autosectionlabel.*``
|
||||
|
||||
.. confval:: needs_sphinx
|
||||
|
||||
If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will
|
||||
|
||||
@@ -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
|
||||
@@ -348,9 +348,16 @@ class Sphinx:
|
||||
status = (self.statuscode == 0 and
|
||||
__('succeeded') or __('finished with problems'))
|
||||
if self._warncount:
|
||||
logger.info(bold(__('build %s, %s warning.',
|
||||
'build %s, %s warnings.', self._warncount) %
|
||||
(status, self._warncount)))
|
||||
if self.warningiserror:
|
||||
msg = __('build %s, %s warning (with warnings treated as errors).',
|
||||
'build %s, %s warnings (with warnings treated as errors).',
|
||||
self._warncount)
|
||||
else:
|
||||
msg = __('build %s, %s warning.',
|
||||
'build %s, %s warnings.',
|
||||
self._warncount)
|
||||
|
||||
logger.info(bold(msg % (status, self._warncount)))
|
||||
else:
|
||||
logger.info(bold(__('build %s.') % status))
|
||||
|
||||
|
||||
@@ -108,7 +108,8 @@ class CheckExternalLinksBuilder(Builder):
|
||||
kwargs = {
|
||||
'allow_redirects': True,
|
||||
'headers': {
|
||||
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8'
|
||||
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
|
||||
'User-Agent': requests.useragent_header[0][1],
|
||||
},
|
||||
}
|
||||
if self.app.config.linkcheck_timeout:
|
||||
|
||||
@@ -55,7 +55,7 @@ def register_sections_as_label(app, document):
|
||||
if name in labels:
|
||||
logger.warning(__('duplicate label %s, other instance in %s'),
|
||||
name, app.env.doc2path(labels[name][0]),
|
||||
location=node)
|
||||
location=node, type='autosectionlabel', subtype=docname)
|
||||
|
||||
anonlabels[name] = docname, labelid
|
||||
labels[name] = docname, labelid, sectname
|
||||
|
||||
@@ -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)
|
||||
|
||||
12
tests/roots/test-ext-coverage/conf.py
Normal file
12
tests/roots/test-ext-coverage/conf.py
Normal 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$',
|
||||
]
|
||||
22
tests/roots/test-ext-coverage/coverage_ignored.py
Normal file
22
tests/roots/test-ext-coverage/coverage_ignored.py
Normal 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
|
||||
22
tests/roots/test-ext-coverage/coverage_not_ignored.py
Normal file
22
tests/roots/test-ext-coverage/coverage_not_ignored.py
Normal 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
|
||||
6
tests/roots/test-ext-coverage/index.rst
Normal file
6
tests/roots/test-ext-coverage/index.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
.. automodule:: coverage_ignored
|
||||
:members:
|
||||
|
||||
|
||||
.. automodule:: coverage_not_ignored
|
||||
:members:
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user