From 05eb2ca06f8725acf824dcee2b61754bdffa52c4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 29 Apr 2021 20:20:01 +0900 Subject: [PATCH 1/9] Close #6525: linkcheck: Add linkcheck_warn_redirects Add a new confval; `linkcheck_warn_redirects` to emit a warning when the hyperlink is redirected. It's useful to detect unexpected redirects under the warn-is-error mode. --- CHANGES | 2 ++ doc/usage/configuration.rst | 8 ++++++++ sphinx/builders/linkcheck.py | 9 +++++++-- tests/test_build_linkcheck.py | 16 ++++++++++++++-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index da8580fe67..2a3ebbf5cb 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,8 @@ Features added text * #9176: i18n: Emit a debug message if message catalog file not found under :confval:`locale_dirs` +* #6525: linkcheck: Add :confval:`linkcheck_warn_redirects` to emit a warning + when the hyperlink is redirected * #9097: Optimize the paralell build * #9131: Add :confval:`nitpick_ignore_regex` to ignore nitpicky warnings using regular expressions diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 0b2bd4e3ea..c5397e6c87 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2642,6 +2642,14 @@ Options for the linkcheck builder .. versionadded:: 3.4 +.. confval:: linkcheck_warn_redirects + + If true, emit a warning when redirection detected on checking hyperlinks. + It's useful to detect unexpected redirects under :option:`the warn-is-error + mode `. Default is ``False``. + + .. versionadded:: 4.1 + Options for the XML builder --------------------------- diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index a46b80c081..568687a108 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -272,8 +272,12 @@ def process_result(self, result: CheckResult) -> None: except KeyError: text, color = ('with unknown code', purple) linkstat['text'] = text - logger.info(color('redirect ') + result.uri + - color(' - ' + text + ' to ' + result.message)) + if self.config.linkcheck_warn_redirects: + logger.warning('redirect ' + result.uri + ' - ' + text + ' to ' + + result.message, location=(filename, result.lineno)) + else: + logger.info(color('redirect ') + result.uri + + color(' - ' + text + ' to ' + result.message)) self.write_entry('redirected ' + text, result.docname, filename, result.lineno, result.uri + ' to ' + result.message) else: @@ -657,6 +661,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: # commonly used for dynamic pages app.add_config_value('linkcheck_anchors_ignore', ["^!"], None) app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None) + app.add_config_value('linkcheck_warn_redirects', False, None) return { 'version': 'builtin', diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index fd7a5482ab..2314006e5b 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -23,6 +23,7 @@ import requests from sphinx.builders.linkcheck import HyperlinkAvailabilityCheckWorker, RateLimit +from sphinx.testing.util import strip_escseq from sphinx.util.console import strip_colors from .utils import CERT_FILE, http_server, https_server @@ -250,7 +251,7 @@ def log_date_time_string(self): @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) -def test_follows_redirects_on_HEAD(app, capsys): +def test_follows_redirects_on_HEAD(app, capsys, warning): with http_server(make_redirect_handler(support_head=True)): app.build() stdout, stderr = capsys.readouterr() @@ -265,10 +266,11 @@ def test_follows_redirects_on_HEAD(app, capsys): 127.0.0.1 - - [] "HEAD /?redirected=1 HTTP/1.1" 204 - """ ) + assert warning.getvalue() == '' @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) -def test_follows_redirects_on_GET(app, capsys): +def test_follows_redirects_on_GET(app, capsys, warning): with http_server(make_redirect_handler(support_head=False)): app.build() stdout, stderr = capsys.readouterr() @@ -284,6 +286,16 @@ def test_follows_redirects_on_GET(app, capsys): 127.0.0.1 - - [] "GET /?redirected=1 HTTP/1.1" 204 - """ ) + assert warning.getvalue() == '' + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={'linkcheck_warn_redirects': True}) +def test_linkcheck_warn_redirects(app, warning): + with http_server(make_redirect_handler(support_head=False)): + app.build() + assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/ - with Found to " + "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) class OKHandler(http.server.BaseHTTPRequestHandler): From 707319aab2ce89d7b0c20a774521559110697df6 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 29 Apr 2021 23:37:38 +0900 Subject: [PATCH 2/9] Close #6525: linkcheck: Add linkcheck_ignore_redirects Add a new confval; linkcheck_ignore_redirects to ignore hyperlinks that are redirected as expected. --- CHANGES | 2 ++ doc/usage/configuration.rst | 19 +++++++++++++++++++ sphinx/builders/linkcheck.py | 30 ++++++++++++++++++++++++++++-- tests/test_build_linkcheck.py | 20 ++++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 2a3ebbf5cb..a193f3749e 100644 --- a/CHANGES +++ b/CHANGES @@ -38,6 +38,8 @@ Features added :confval:`locale_dirs` * #6525: linkcheck: Add :confval:`linkcheck_warn_redirects` to emit a warning when the hyperlink is redirected +* #6525: linkcheck: Add :confval:`linkcheck_ignore_redirects` to ignore + hyperlinks that are redirected to expected URLs * #9097: Optimize the paralell build * #9131: Add :confval:`nitpick_ignore_regex` to ignore nitpicky warnings using regular expressions diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index c5397e6c87..463199170a 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2522,6 +2522,25 @@ Options for the linkcheck builder .. versionadded:: 1.1 +.. confval:: linkcheck_ignore_redirects + + A dictionary that maps a pattern of the source URI to a pattern of the canonical + URI. If set, linkcheck builder treated as "ignored" if a hyperlink in the source + document that matches to the pattern of the source URI, and it redirects to the + URL that matches to the pattern of the canonical URI. Example: + + .. code-block:: python + + linkcheck_ignore_redirects = { + # All HTTP redirections from the source URI to the canonical URI will be ignored. + 'http://sphinx-doc.org/.*': 'https://sphinx-doc.org/en/master/.*' + } + + It's helpful to enable :confval:`linkcheck_warn_redirects` not to warn the URIs + that causes HTTP redirection as expected. + + .. versionadded:: 4.1 + .. confval:: linkcheck_request_headers A dictionary that maps baseurls to HTTP request headers. diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 568687a108..e96b45d253 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -498,13 +498,23 @@ def check_uri() -> Tuple[str, str, int]: new_url = response.url if anchor: new_url += '#' + anchor - # history contains any redirects, get last - if response.history: + + if ignored_redirect(req_url, new_url): + return 'working', '', 0 + elif response.history: + # history contains any redirects, get last code = response.history[-1].status_code return 'redirected', new_url, code else: return 'redirected', new_url, 0 + def ignored_redirect(url: str, new_url: str) -> bool: + for from_url, to_url in self.config.linkcheck_ignore_redirects.items(): + if from_url.match(url) and to_url.match(new_url): + return True + + return False + def check(docname: str) -> Tuple[str, str, int]: # check for various conditions without bothering the network if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'tel:')): @@ -646,11 +656,25 @@ def run(self, **kwargs: Any) -> None: hyperlinks[uri] = uri_info +def compile_linkcheck_ignore_redirects(app: Sphinx, config: Config) -> None: + """Compile patterns in linkcheck_ignore_redirects to the regexp objects.""" + for url, pattern in list(app.config.linkcheck_ignore_redirects.items()): + try: + app.config.linkcheck_ignore_redirects[re.compile(url)] = re.compile(pattern) + except re.error as exc: + logger.warning(__('Failed to compile regex in linkcheck_ignore_redirects: %r %s'), + exc.pattern, exc.msg) + finally: + # Remove the original regexp-string + app.config.linkcheck_ignore_redirects.pop(url) + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(CheckExternalLinksBuilder) app.add_post_transform(HyperlinkCollector) app.add_config_value('linkcheck_ignore', [], None) + app.add_config_value('linkcheck_ignore_redirects', {}, None) app.add_config_value('linkcheck_auth', [], None) app.add_config_value('linkcheck_request_headers', {}, None) app.add_config_value('linkcheck_retries', 1, None) @@ -663,6 +687,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None) app.add_config_value('linkcheck_warn_redirects', False, None) + app.connect('config-inited', compile_linkcheck_ignore_redirects, priority=800) + return { 'version': 'builtin', 'parallel_read_safe': True, diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 2314006e5b..604856308d 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -298,6 +298,26 @@ def test_linkcheck_warn_redirects(app, warning): "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True, + confoverrides={ + 'linkcheck_ignore_redirects': {'http://localhost:.*/': '.*'} + }) +def test_linkcheck_ignore_redirects(app): + with http_server(make_redirect_handler(support_head=False)): + app.build() + + with open(app.outdir / 'output.json') as fp: + content = json.load(fp) + assert content == { + "code": 0, + "status": "working", + "filename": "index.rst", + "lineno": 1, + "uri": "http://localhost:7777/", + "info": "", + } + + class OKHandler(http.server.BaseHTTPRequestHandler): def do_HEAD(self): self.send_response(200, "OK") From ce9e2e6c74959f8e84c91693718d9d8a9e433a99 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 20 May 2021 23:25:25 +0900 Subject: [PATCH 3/9] Rename linkcheck_ignore_redirects to linkcheck_allowed_redirects --- CHANGES | 4 ++-- doc/usage/configuration.rst | 8 ++++---- sphinx/builders/linkcheck.py | 22 +++++++++++----------- tests/test_build_linkcheck.py | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index a193f3749e..e5963cfcc0 100644 --- a/CHANGES +++ b/CHANGES @@ -38,8 +38,8 @@ Features added :confval:`locale_dirs` * #6525: linkcheck: Add :confval:`linkcheck_warn_redirects` to emit a warning when the hyperlink is redirected -* #6525: linkcheck: Add :confval:`linkcheck_ignore_redirects` to ignore - hyperlinks that are redirected to expected URLs +* #6525: linkcheck: Add :confval:`linkcheck_allowed_redirects` to mark + hyperlinks that are redirected to expected URLs as "working" * #9097: Optimize the paralell build * #9131: Add :confval:`nitpick_ignore_regex` to ignore nitpicky warnings using regular expressions diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 463199170a..9f110f6569 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2522,17 +2522,17 @@ Options for the linkcheck builder .. versionadded:: 1.1 -.. confval:: linkcheck_ignore_redirects +.. confval:: linkcheck_allowed_redirects A dictionary that maps a pattern of the source URI to a pattern of the canonical - URI. If set, linkcheck builder treated as "ignored" if a hyperlink in the source + URI. If set, linkcheck builder treated as "working" if a hyperlink in the source document that matches to the pattern of the source URI, and it redirects to the URL that matches to the pattern of the canonical URI. Example: .. code-block:: python - linkcheck_ignore_redirects = { - # All HTTP redirections from the source URI to the canonical URI will be ignored. + linkcheck_working_redirects = { + # All HTTP redirections from the source URI to the canonical URI will be treated as "working". 'http://sphinx-doc.org/.*': 'https://sphinx-doc.org/en/master/.*' } diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index e96b45d253..2da438cbf2 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -499,7 +499,7 @@ def check_uri() -> Tuple[str, str, int]: if anchor: new_url += '#' + anchor - if ignored_redirect(req_url, new_url): + if allowed_redirect(req_url, new_url): return 'working', '', 0 elif response.history: # history contains any redirects, get last @@ -508,8 +508,8 @@ def check_uri() -> Tuple[str, str, int]: else: return 'redirected', new_url, 0 - def ignored_redirect(url: str, new_url: str) -> bool: - for from_url, to_url in self.config.linkcheck_ignore_redirects.items(): + def allowed_redirect(url: str, new_url: str) -> bool: + for from_url, to_url in self.config.linkcheck_allowed_redirects.items(): if from_url.match(url) and to_url.match(new_url): return True @@ -656,17 +656,17 @@ def run(self, **kwargs: Any) -> None: hyperlinks[uri] = uri_info -def compile_linkcheck_ignore_redirects(app: Sphinx, config: Config) -> None: - """Compile patterns in linkcheck_ignore_redirects to the regexp objects.""" - for url, pattern in list(app.config.linkcheck_ignore_redirects.items()): +def compile_linkcheck_allowed_redirects(app: Sphinx, config: Config) -> None: + """Compile patterns in linkcheck_allowed_redirects to the regexp objects.""" + for url, pattern in list(app.config.linkcheck_allowed_redirects.items()): try: - app.config.linkcheck_ignore_redirects[re.compile(url)] = re.compile(pattern) + app.config.linkcheck_allowed_redirects[re.compile(url)] = re.compile(pattern) except re.error as exc: - logger.warning(__('Failed to compile regex in linkcheck_ignore_redirects: %r %s'), + logger.warning(__('Failed to compile regex in linkcheck_allowed_redirects: %r %s'), exc.pattern, exc.msg) finally: # Remove the original regexp-string - app.config.linkcheck_ignore_redirects.pop(url) + app.config.linkcheck_allowed_redirects.pop(url) def setup(app: Sphinx) -> Dict[str, Any]: @@ -674,7 +674,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(HyperlinkCollector) app.add_config_value('linkcheck_ignore', [], None) - app.add_config_value('linkcheck_ignore_redirects', {}, None) + app.add_config_value('linkcheck_allowed_redirects', {}, None) app.add_config_value('linkcheck_auth', [], None) app.add_config_value('linkcheck_request_headers', {}, None) app.add_config_value('linkcheck_retries', 1, None) @@ -687,7 +687,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None) app.add_config_value('linkcheck_warn_redirects', False, None) - app.connect('config-inited', compile_linkcheck_ignore_redirects, priority=800) + app.connect('config-inited', compile_linkcheck_allowed_redirects, priority=800) return { 'version': 'builtin', diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 604856308d..7d03d1df42 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -300,9 +300,9 @@ def test_linkcheck_warn_redirects(app, warning): @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True, confoverrides={ - 'linkcheck_ignore_redirects': {'http://localhost:.*/': '.*'} + 'linkcheck_allowed_redirects': {'http://localhost:.*/': '.*'} }) -def test_linkcheck_ignore_redirects(app): +def test_linkcheck_allowed_redirects(app): with http_server(make_redirect_handler(support_head=False)): app.build() From c97e9b14c42455119fae8b0fa670e0c5bfa4b930 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 20 May 2021 23:43:34 +0900 Subject: [PATCH 4/9] Update docs --- doc/usage/configuration.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 9f110f6569..2ac06a4d5d 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2525,19 +2525,22 @@ Options for the linkcheck builder .. confval:: linkcheck_allowed_redirects A dictionary that maps a pattern of the source URI to a pattern of the canonical - URI. If set, linkcheck builder treated as "working" if a hyperlink in the source - document that matches to the pattern of the source URI, and it redirects to the - URL that matches to the pattern of the canonical URI. Example: + URI. The linkcheck builder treats the redirected link as "working" when: + + - the link in the document matches the source URI pattern, and + - the redirect location matches the canonical URI pattern. + + Example: .. code-block:: python linkcheck_working_redirects = { # All HTTP redirections from the source URI to the canonical URI will be treated as "working". - 'http://sphinx-doc.org/.*': 'https://sphinx-doc.org/en/master/.*' + r'https://sphinx-doc\.org/.*': r'https://sphinx-doc\.org/en/master/.*' } - It's helpful to enable :confval:`linkcheck_warn_redirects` not to warn the URIs - that causes HTTP redirection as expected. + It's helpful to enable :confval:`linkcheck_warn_redirects` to warn for URIs + causing unexpected HTTP redirection. .. versionadded:: 4.1 @@ -2663,7 +2666,7 @@ Options for the linkcheck builder .. confval:: linkcheck_warn_redirects - If true, emit a warning when redirection detected on checking hyperlinks. + If true, emits a warning when the response for a hyperlink is a redirect. It's useful to detect unexpected redirects under :option:`the warn-is-error mode `. Default is ``False``. From 4201a84b35c0bb483db2b863b33cb8639c62da63 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 21 May 2021 02:04:01 +0900 Subject: [PATCH 5/9] Add testcase for combination of allow_redirects and warn_redirects --- .../conf.py | 1 + .../index.rst | 2 + tests/test_build_linkcheck.py | 54 +++++++++++++------ 3 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 tests/roots/test-linkcheck-localserver-warn-redirects/conf.py create mode 100644 tests/roots/test-linkcheck-localserver-warn-redirects/index.rst diff --git a/tests/roots/test-linkcheck-localserver-warn-redirects/conf.py b/tests/roots/test-linkcheck-localserver-warn-redirects/conf.py new file mode 100644 index 0000000000..a45d22e282 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-warn-redirects/conf.py @@ -0,0 +1 @@ +exclude_patterns = ['_build'] diff --git a/tests/roots/test-linkcheck-localserver-warn-redirects/index.rst b/tests/roots/test-linkcheck-localserver-warn-redirects/index.rst new file mode 100644 index 0000000000..7c57d56712 --- /dev/null +++ b/tests/roots/test-linkcheck-localserver-warn-redirects/index.rst @@ -0,0 +1,2 @@ +`local server1 `_ +`local server2 `_ diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 7d03d1df42..461305ad71 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -289,33 +289,55 @@ def test_follows_redirects_on_GET(app, capsys, warning): assert warning.getvalue() == '' -@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True, - confoverrides={'linkcheck_warn_redirects': True}) +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', + freshenv=True, confoverrides={'linkcheck_warn_redirects': True}) def test_linkcheck_warn_redirects(app, warning): with http_server(make_redirect_handler(support_head=False)): app.build() - assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/ - with Found to " + assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path1 - with Found to " "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) + assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path2 - with Found to " + "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) + assert len(warning.getvalue().splitlines()) == 2 -@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True, - confoverrides={ - 'linkcheck_allowed_redirects': {'http://localhost:.*/': '.*'} +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', + freshenv=True, confoverrides={ + 'linkcheck_allowed_redirects': {'http://localhost:7777/.*1': '.*'} }) -def test_linkcheck_allowed_redirects(app): +def test_linkcheck_allowed_redirects(app, warning): with http_server(make_redirect_handler(support_head=False)): app.build() with open(app.outdir / 'output.json') as fp: - content = json.load(fp) - assert content == { - "code": 0, - "status": "working", - "filename": "index.rst", - "lineno": 1, - "uri": "http://localhost:7777/", - "info": "", - } + records = [json.loads(l) for l in fp.readlines()] + + assert len(records) == 2 + result = {r["uri"]: r["status"] for r in records} + assert result["http://localhost:7777/path1"] == "working" + assert result["http://localhost:7777/path2"] == "redirected" + assert warning.getvalue() == '' + + +@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', + freshenv=True, confoverrides={ + 'linkcheck_allowed_redirects': {'http://localhost:7777/.*1': '.*'}, + 'linkcheck_warn_redirects': True, + }) +def test_linkcheck_allowed_redirects_and_linkcheck_warn_redirects(app, warning): + with http_server(make_redirect_handler(support_head=False)): + app.build() + + with open(app.outdir / 'output.json') as fp: + records = [json.loads(l) for l in fp.readlines()] + + assert len(records) == 2 + result = {r["uri"]: r["status"] for r in records} + assert result["http://localhost:7777/path1"] == "working" + assert result["http://localhost:7777/path2"] == "redirected" + assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path2 - with Found to " + "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) + assert len(warning.getvalue().splitlines()) == 1 class OKHandler(http.server.BaseHTTPRequestHandler): From fe89a07a9241bbdcf924e92b85237943169a3590 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 May 2021 02:54:17 +0900 Subject: [PATCH 6/9] Fix typo in doc/usage/configuration.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Freitag --- doc/usage/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 2ac06a4d5d..e8dc706c8d 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2534,7 +2534,7 @@ Options for the linkcheck builder .. code-block:: python - linkcheck_working_redirects = { + linkcheck_allowed_redirects = { # All HTTP redirections from the source URI to the canonical URI will be treated as "working". r'https://sphinx-doc\.org/.*': r'https://sphinx-doc\.org/en/master/.*' } From 48c80b17b48662c3081b042a3b6972e29f445d77 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 May 2021 02:58:29 +0900 Subject: [PATCH 7/9] doc: Fix indentation --- doc/usage/configuration.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 58921c96a3..f78b430b5a 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2532,8 +2532,8 @@ Options for the linkcheck builder A dictionary that maps a pattern of the source URI to a pattern of the canonical URI. The linkcheck builder treats the redirected link as "working" when: - - the link in the document matches the source URI pattern, and - - the redirect location matches the canonical URI pattern. + - the link in the document matches the source URI pattern, and + - the redirect location matches the canonical URI pattern. Example: From 2887dd07df1792ec8e504c75590b8a3d3e8753a8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 May 2021 02:59:35 +0900 Subject: [PATCH 8/9] doc: Fix indentation --- doc/usage/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index f78b430b5a..9494bd5bdb 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2675,7 +2675,7 @@ Options for the linkcheck builder It's useful to detect unexpected redirects under :option:`the warn-is-error mode `. Default is ``False``. - .. versionadded:: 4.1 + .. versionadded:: 4.1 Options for the XML builder From 988a79de65737e403cd27721ce091760cf62b97f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 31 May 2021 21:48:58 +0900 Subject: [PATCH 9/9] linkcheck: Emit a warning for disallowed redirects Now linkcheck builder integrates `linkcheck_warn_redirects` into `linkcheck_allowed_redirects`. As a result, linkcheck builder will emit a warning when "disallowed" redirection detected via `linkcheck_allowed_redirects`. --- CHANGES | 2 -- doc/usage/configuration.rst | 13 +++---------- sphinx/builders/linkcheck.py | 3 +-- tests/test_build_linkcheck.py | 30 ------------------------------ 4 files changed, 4 insertions(+), 44 deletions(-) diff --git a/CHANGES b/CHANGES index 0a82da183e..074eb3cea9 100644 --- a/CHANGES +++ b/CHANGES @@ -43,8 +43,6 @@ Features added text * #9176: i18n: Emit a debug message if message catalog file not found under :confval:`locale_dirs` -* #6525: linkcheck: Add :confval:`linkcheck_warn_redirects` to emit a warning - when the hyperlink is redirected * #6525: linkcheck: Add :confval:`linkcheck_allowed_redirects` to mark hyperlinks that are redirected to expected URLs as "working" * #1874: py domain: Support union types using ``|`` in info-field-list diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 9494bd5bdb..73ca1b6001 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2544,8 +2544,9 @@ Options for the linkcheck builder r'https://sphinx-doc\.org/.*': r'https://sphinx-doc\.org/en/master/.*' } - It's helpful to enable :confval:`linkcheck_warn_redirects` to warn for URIs - causing unexpected HTTP redirection. + If set, linkcheck builder will emit a warning when disallowed redirection + found. It's useful to detect unexpected redirects under :option:`the + warn-is-error mode `. .. versionadded:: 4.1 @@ -2669,14 +2670,6 @@ Options for the linkcheck builder .. versionadded:: 3.4 -.. confval:: linkcheck_warn_redirects - - If true, emits a warning when the response for a hyperlink is a redirect. - It's useful to detect unexpected redirects under :option:`the warn-is-error - mode `. Default is ``False``. - - .. versionadded:: 4.1 - Options for the XML builder --------------------------- diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 2da438cbf2..ca7bd56173 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -272,7 +272,7 @@ def process_result(self, result: CheckResult) -> None: except KeyError: text, color = ('with unknown code', purple) linkstat['text'] = text - if self.config.linkcheck_warn_redirects: + if self.config.linkcheck_allowed_redirects: logger.warning('redirect ' + result.uri + ' - ' + text + ' to ' + result.message, location=(filename, result.lineno)) else: @@ -685,7 +685,6 @@ def setup(app: Sphinx) -> Dict[str, Any]: # commonly used for dynamic pages app.add_config_value('linkcheck_anchors_ignore', ["^!"], None) app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None) - app.add_config_value('linkcheck_warn_redirects', False, None) app.connect('config-inited', compile_linkcheck_allowed_redirects, priority=800) diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 461305ad71..bc85e402ff 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -289,18 +289,6 @@ def test_follows_redirects_on_GET(app, capsys, warning): assert warning.getvalue() == '' -@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', - freshenv=True, confoverrides={'linkcheck_warn_redirects': True}) -def test_linkcheck_warn_redirects(app, warning): - with http_server(make_redirect_handler(support_head=False)): - app.build() - assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path1 - with Found to " - "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) - assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path2 - with Found to " - "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) - assert len(warning.getvalue().splitlines()) == 2 - - @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', freshenv=True, confoverrides={ 'linkcheck_allowed_redirects': {'http://localhost:7777/.*1': '.*'} @@ -316,25 +304,7 @@ def test_linkcheck_allowed_redirects(app, warning): result = {r["uri"]: r["status"] for r in records} assert result["http://localhost:7777/path1"] == "working" assert result["http://localhost:7777/path2"] == "redirected" - assert warning.getvalue() == '' - -@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-warn-redirects', - freshenv=True, confoverrides={ - 'linkcheck_allowed_redirects': {'http://localhost:7777/.*1': '.*'}, - 'linkcheck_warn_redirects': True, - }) -def test_linkcheck_allowed_redirects_and_linkcheck_warn_redirects(app, warning): - with http_server(make_redirect_handler(support_head=False)): - app.build() - - with open(app.outdir / 'output.json') as fp: - records = [json.loads(l) for l in fp.readlines()] - - assert len(records) == 2 - result = {r["uri"]: r["status"] for r in records} - assert result["http://localhost:7777/path1"] == "working" - assert result["http://localhost:7777/path2"] == "redirected" assert ("index.rst.rst:1: WARNING: redirect http://localhost:7777/path2 - with Found to " "http://localhost:7777/?redirected=1\n" in strip_escseq(warning.getvalue())) assert len(warning.getvalue().splitlines()) == 1