Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 5 additions & 39 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,49 +1,15 @@
Release 9.1.0 (released Dec 31, 2025)
=====================================
Release 9.2.0 (in development)
==============================

Dependencies
------------

* #14153: Drop Python 3.11 support.
* #12555: Drop Docutils 0.20 support.
Patch by Adam Turner

Features added
--------------

* Add :meth:`~sphinx.application.Sphinx.add_static_dir` for copying static
assets from extensions to the build output.
Patch by Jared Dillard
* Add :confval:`linkcheck_ignore_status_codes` to ignore configurable status
codes for certain URLs.
Patch by Leo Singer

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

* #14189: autodoc: Fix duplicate ``:no-index-entry:`` for modules.
Patch by Adam Turner
* #13713: Fix compatibility with MyST-Parser.
Patch by Adam Turner
* Fix tests for Python 3.15.
Patch by Adam Turner
* #14089: autodoc: Fix default option parsing.
Patch by Adam Turner
* Remove incorrect static typing assertions.
Patch by Adam Turner
* #14050: LaTeXTranslator fails to build documents using the "acronym"
standard role.
Patch by Günter Milde
* LaTeX: Fix rendering for grid filled merged vertical cell.
Patch by Tim Nordell
* #14228: LaTeX: Fix overrun footer for cases of merged vertical table cells.
Patch by Tim Nordell
* #14207: Fix creating ``HTMLThemeFactory`` objects in third-party extensions.
Patch by Adam Turner
* #3099: LaTeX: PDF build crashes if a code-block contains more than
circa 1350 codelines (about 27 a4-sized pages at default pointsize).
Patch by Jean-François B.
* #14064: LaTeX: TABs ending up in sphinxVerbatim fail to obey tab stops.
Patch by Jean-François B.
* #14089: autodoc: Improve support for non-weakreferencable objects.
Patch by Adam Turner
* LaTeX: Fix accidental removal at ``3.5.0`` (#8854) of the documentation of
``literalblockcappos`` key of :ref:`'sphinxsetup' <latexsphinxsetup>`.
Patch by Jean-François B.
54 changes: 54 additions & 0 deletions doc/changes/9.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
==========
Sphinx 9.1
==========


Release 9.1.0 (released Dec 31, 2025)
=====================================

Dependencies
------------

* #14153: Drop Python 3.11 support.
* #12555: Drop Docutils 0.20 support.
Patch by Adam Turner

Features added
--------------

* Add :meth:`~sphinx.application.Sphinx.add_static_dir` for copying static
assets from extensions to the build output.
Patch by Jared Dillard

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

* #14189: autodoc: Fix duplicate ``:no-index-entry:`` for modules.
Patch by Adam Turner
* #13713: Fix compatibility with MyST-Parser.
Patch by Adam Turner
* Fix tests for Python 3.15.
Patch by Adam Turner
* #14089: autodoc: Fix default option parsing.
Patch by Adam Turner
* Remove incorrect static typing assertions.
Patch by Adam Turner
* #14050: LaTeXTranslator fails to build documents using the "acronym"
standard role.
Patch by Günter Milde
* LaTeX: Fix rendering for grid filled merged vertical cell.
Patch by Tim Nordell
* #14228: LaTeX: Fix overrun footer for cases of merged vertical table cells.
Patch by Tim Nordell
* #14207: Fix creating ``HTMLThemeFactory`` objects in third-party extensions.
Patch by Adam Turner
* #3099: LaTeX: PDF build crashes if a code-block contains more than
circa 1350 codelines (about 27 a4-sized pages at default pointsize).
Patch by Jean-François B.
* #14064: LaTeX: TABs ending up in sphinxVerbatim fail to obey tab stops.
Patch by Jean-François B.
* #14089: autodoc: Improve support for non-weakreferencable objects.
Patch by Adam Turner
* LaTeX: Fix accidental removal at ``3.5.0`` (#8854) of the documentation of
``literalblockcappos`` key of :ref:`'sphinxsetup' <latexsphinxsetup>`.
Patch by Jean-François B.
17 changes: 17 additions & 0 deletions doc/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3952,6 +3952,23 @@ and the number of workers to use.

.. versionadded:: 1.1

.. confval:: linkcheck_ignore_status_codes
:type: :code-py:`dict`
:default: :code-py:`{}`

A dictionary that maps regular expressions for URLs to status codes that
should be ignored.

Example:

.. code-block:: python

linkcheck_ignore_status_codes = {
r"^https://doi.org/": [403]
}

.. versionadded:: 9.2


Domain options
==============
Expand Down
18 changes: 18 additions & 0 deletions sphinx/builders/linkcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ def __init__(
(re.compile(pattern), auth_info)
for pattern, auth_info in config.linkcheck_auth
]
self.ignore_status_codes = [
(re.compile(pattern), frozenset(codes))
for pattern, codes in config.linkcheck_ignore_status_codes.items()
]

self.timeout: int | float | None = config.linkcheck_timeout
self.request_headers: dict[str, dict[str, str]] = (
Expand Down Expand Up @@ -596,6 +600,16 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> _URIProperties:
)

except HTTPError as err:
if any(
pattern.match(req_url) and status_code in codes
for pattern, codes in self.ignore_status_codes
):
return (
_Status.IGNORED,
f'ignored status: {status_code}',
status_code,
)

error_message = str(err)

# Unauthorized: the client did not provide required credentials
Expand Down Expand Up @@ -844,8 +858,12 @@ def setup(app: Sphinx) -> ExtensionMetadata:
'',
types=frozenset({frozenset, list, set, tuple}),
)
app.add_config_value(
'linkcheck_ignore_status_codes', {}, '', types=frozenset({dict})
)

app.add_event('linkcheck-process-uri')
app.add_event('linkcheck-process-result')

# priority 900 to happen after ``check_confval_types()``
app.connect('config-inited', compile_linkcheck_allowed_redirects, priority=900)
Expand Down
3 changes: 3 additions & 0 deletions tests/roots/test-linkcheck-ignore-status-codes/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exclude_patterns = ['_build']
linkcheck_timeout = 0.25
linkcheck_ignore_status_codes = {r'^http://localhost:\d+/.*': [418]}
1 change: 1 addition & 0 deletions tests/roots/test-linkcheck-ignore-status-codes/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* `Example Foo <http://localhost:7777/>`_
18 changes: 18 additions & 0 deletions tests/test_builders/test_build_linkcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1522,3 +1522,21 @@ def test_linkcheck_case_sensitivity(
assert rowsby[f'http://{address}/path1']['status'] == expected_path1
assert rowsby[f'http://{address}/path2']['status'] == expected_path2
assert rowsby[f'http://{address}/PATH3']['status'] == expected_path3


@pytest.mark.sphinx(
'linkcheck',
testroot='linkcheck-ignore-status-codes',
freshenv=True,
)
def test_ignore_status_codes(app: SphinxTestApp) -> None:
class TeapotServerErrorHandler(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'

def do_GET(self) -> None:
self.send_error(418, "I'm a teapot")

with serve_application(app, TeapotServerErrorHandler) as address:
app.build()
content = (app.outdir / 'output.txt').read_text(encoding='utf8')
assert not content
Loading