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

linkcheck: Update configuration defaults for Sphinx 8.0 #12630

Merged
Merged
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
----------
Expand Down
36 changes: 15 additions & 21 deletions doc/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
46 changes: 2 additions & 44 deletions sphinx/builders/linkcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import re
import socket
import time
import warnings
from html.parser import HTMLParser
from os import path
from queue import PriorityQueue, Queue
Expand All @@ -20,7 +19,6 @@
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
Expand Down Expand Up @@ -66,25 +64,6 @@ def init(self) -> None:
# 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('')
Expand Down Expand Up @@ -510,27 +489,6 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> tuple[str, str, int]:

# 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

Expand Down Expand Up @@ -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')

Expand Down
10 changes: 2 additions & 8 deletions tests/test_builders/test_build_linkcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
RateLimit,
compile_linkcheck_allowed_redirects,
)
from sphinx.deprecation import RemovedInSphinx80Warning
from sphinx.util import requests
from sphinx.util.console import strip_colors

Expand Down Expand Up @@ -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})
Expand All @@ -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)
Expand Down