linkcheck: Update configuration defaults for Sphinx 8.0 (#12630)

- Links that respond with HTTP 401 (unauthorized) responses are now considered ``broken`` by default.
- Timeouts that occur when checking a link are now reported with a distinct `timeout` status code, instead of the previous ``broken``.
- The previous behaviours are still available and can be configured on an opt-in basis per-project using ``conf.py``.

Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
James Addison
2024-07-20 20:41:22 +01:00
committed by GitHub
parent 2034f7d3b2
commit cc08854bc2
4 changed files with 25 additions and 73 deletions

View File

@@ -51,6 +51,12 @@ Incompatible changes
Patch by Adam Turner.
* Removed the tuple interface to :py:class:`!sphinx.ext.autodoc.ObjectMember`.
Patch by Adam Turner.
* #12630: Sphinx 8 makes two changes to the ``linkcheck`` configuration defaults:
* :confval:`linkcheck_allow_unauthorized` is now ``False`` by default.
* :confval:`linkcheck_report_timeouts_as_broken` is now ``False`` by default.
Patch by James Addison.
Deprecated
----------

View File

@@ -3714,20 +3714,17 @@ and the number of workers to use.
.. confval:: linkcheck_allow_unauthorized
:type: :code-py:`bool`
:default: :code-py:`True`
:default: :code-py:`False`
When a webserver responds with an HTTP 401 (unauthorised) response,
the current default behaviour of the *linkcheck* builder is
to treat the link as "working".
To change that behaviour, set this option to :code-py:`False`.
to treat the link as "broken".
To change that behaviour, set this option to :code-py:`True`.
.. attention::
The default value for this option will be changed in Sphinx 8.0;
from that version onwards,
HTTP 401 responses to checked hyperlinks will be treated
as "broken" by default.
.. xref RemovedInSphinx80Warning
.. versionchanged:: 8.0
The default value for this option changed to :code-py:`False`,
meaning HTTP 401 responses to checked hyperlinks
are treated as "broken" by default.
.. versionadded:: 7.3
@@ -3755,21 +3752,18 @@ and the number of workers to use.
.. confval:: linkcheck_report_timeouts_as_broken
:type: :code-py:`bool`
:default: :code-py:`True`
:default: :code-py:`False`
When an HTTP response is not received from a webserver before the configured
:confval:`linkcheck_timeout` expires,
the current default behaviour of the *linkcheck* builder is
to treat the link as 'broken'.
To report timeouts using a distinct report code of ``timeout``,
set :confval:`linkcheck_report_timeouts_as_broken` to :code-py:`False`.
If :confval:`linkcheck_timeout` expires while waiting for a response from
a hyperlink, the *linkcheck* builder will report the link as a ``timeout``
by default. To report timeouts as ``broken`` instead, you can
set :confval:`linkcheck_report_timeouts_as_broken` to :code-py:`True`.
.. attention::
From Sphinx 8.0 onwards, timeouts that occur while checking hyperlinks
.. versionchanged:: 8.0
The default value for this option changed to :code-py:`False`,
meaning timeouts that occur while checking hyperlinks
will be reported using the new 'timeout' status code.
.. xref RemovedInSphinx80Warning
.. versionadded:: 7.3
.. confval:: linkcheck_request_headers

View File

@@ -7,7 +7,6 @@ import json
import re
import socket
import time
import warnings
from html.parser import HTMLParser
from os import path
from queue import PriorityQueue, Queue
@@ -20,7 +19,6 @@ from requests.exceptions import ConnectionError, HTTPError, SSLError, TooManyRed
from requests.exceptions import Timeout as RequestTimeout
from sphinx.builders.dummy import DummyBuilder
from sphinx.deprecation import RemovedInSphinx80Warning
from sphinx.locale import __
from sphinx.transforms.post_transforms import SphinxPostTransform
from sphinx.util import encode_uri, logging, requests
@@ -66,25 +64,6 @@ class CheckExternalLinksBuilder(DummyBuilder):
# set a timeout for non-responding servers
socket.setdefaulttimeout(5.0)
if not self.config.linkcheck_allow_unauthorized:
deprecation_msg = (
"The default value for 'linkcheck_allow_unauthorized' will change "
"from `True` in Sphinx 7.3+ to `False`, meaning that HTTP 401 "
"unauthorized responses will be reported as broken by default. "
"See https://github.com/sphinx-doc/sphinx/issues/11433 for details."
)
warnings.warn(deprecation_msg, RemovedInSphinx80Warning, stacklevel=1)
if self.config.linkcheck_report_timeouts_as_broken:
deprecation_msg = (
"The default value for 'linkcheck_report_timeouts_as_broken' will change "
'to False in Sphinx 8, meaning that request timeouts '
"will be reported with a new 'timeout' status, instead of as 'broken'. "
'This is intended to provide more detail as to the failure mode. '
'See https://github.com/sphinx-doc/sphinx/issues/11868 for details.'
)
warnings.warn(deprecation_msg, RemovedInSphinx80Warning, stacklevel=1)
def finish(self) -> None:
checker = HyperlinkAvailabilityChecker(self.config)
logger.info('')
@@ -510,27 +489,6 @@ class HyperlinkAvailabilityCheckWorker(Thread):
# Unauthorized: the client did not provide required credentials
if status_code == 401:
if self._allow_unauthorized:
deprecation_msg = (
"\n---\n"
"The linkcheck builder encountered an HTTP 401 "
"(unauthorized) response, and will report it as "
"'working' in this version of Sphinx to maintain "
"backwards-compatibility."
"\n"
"This logic will change in Sphinx 8.0 which will "
"report the hyperlink as 'broken'."
"\n"
"To explicitly continue treating unauthorized "
"hyperlink responses as 'working', set the "
"'linkcheck_allow_unauthorized' config option to "
"``True``."
"\n"
"See https://github.com/sphinx-doc/sphinx/issues/11433 "
"for details."
"\n---"
)
warnings.warn(deprecation_msg, RemovedInSphinx80Warning, stacklevel=1)
status = 'working' if self._allow_unauthorized else 'broken'
return status, 'unauthorized', 0
@@ -717,8 +675,8 @@ def setup(app: Sphinx) -> ExtensionMetadata:
app.add_config_value('linkcheck_anchors_ignore', ['^!'], '')
app.add_config_value('linkcheck_anchors_ignore_for_url', (), '', (tuple, list))
app.add_config_value('linkcheck_rate_limit_timeout', 300.0, '', (int, float))
app.add_config_value('linkcheck_allow_unauthorized', True, '')
app.add_config_value('linkcheck_report_timeouts_as_broken', True, '', bool)
app.add_config_value('linkcheck_allow_unauthorized', False, '')
app.add_config_value('linkcheck_report_timeouts_as_broken', False, '', bool)
app.add_event('linkcheck-process-uri')

View File

@@ -27,7 +27,6 @@ from sphinx.builders.linkcheck import (
RateLimit,
compile_linkcheck_allowed_redirects,
)
from sphinx.deprecation import RemovedInSphinx80Warning
from sphinx.util import requests
from sphinx.util.console import strip_colors
@@ -503,7 +502,6 @@ def test_auth_header_uses_first_match(app: Sphinx) -> None:
assert content["status"] == "working"
@pytest.mark.filterwarnings('ignore::sphinx.deprecation.RemovedInSphinx80Warning')
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck-localserver', freshenv=True,
confoverrides={'linkcheck_allow_unauthorized': False})
@@ -522,18 +520,14 @@ def test_unauthorized_broken(app: Sphinx) -> None:
'linkcheck', testroot='linkcheck-localserver', freshenv=True,
confoverrides={'linkcheck_auth': [(r'^$', ('user1', 'password'))]})
def test_auth_header_no_match(app: Sphinx) -> None:
with (
serve_application(app, custom_handler(valid_credentials=("user1", "password"))),
pytest.warns(RemovedInSphinx80Warning, match='linkcheck builder encountered an HTTP 401'),
):
with serve_application(app, custom_handler(valid_credentials=("user1", "password"))):
app.build()
with open(app.outdir / "output.json", encoding="utf-8") as fp:
content = json.load(fp)
# This link is considered working based on the default linkcheck_allow_unauthorized=true
assert content["info"] == "unauthorized"
assert content["status"] == "working"
assert content["status"] == "broken"
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)