From ed11c52495ac62bef7a038140b448bf40f1cece9 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 31 Jul 2023 23:14:05 +0100 Subject: [PATCH 1/8] Add illustrative test coverage --- tests/test_build_linkcheck.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 42e4e03521b..21ba93c026d 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -152,6 +152,7 @@ def test_defaults(app): } # looking for '#top' and '#does-not-exist' not found should fail assert rowsby["http://localhost:7777/#top"]["info"] == "Anchor 'top' not found" + assert rowsby["http://localhost:7777/#top"]["status"] == "broken" assert rowsby["http://localhost:7777#does-not-exist"]["info"] == "Anchor 'does-not-exist' not found" # images should fail assert "Not Found for url: http://localhost:7777/image.png" in rowsby["http://localhost:7777/image.png"]["info"] @@ -166,6 +167,21 @@ def test_defaults(app): } +@pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True, confoverrides={'linkcheck_anchors': False}) +def test_check_link_response_only(app): + with http_server(DefaultsHandler): + app.build() + + # JSON output + assert (app.outdir / 'output.json').exists() + content = (app.outdir / 'output.json').read_text(encoding='utf8') + + rows = [json.loads(x) for x in content.splitlines()] + row = rows[0] + rowsby = {row["uri"]: row for row in rows} + assert rowsby["http://localhost:7777/#top"]["status"] == "working" + + @pytest.mark.sphinx('linkcheck', testroot='linkcheck-too-many-retries', freshenv=True) def test_too_many_retries(app): with http_server(DefaultsHandler): From 028ac4efe6b4af40208f5487321bf93087647b0a Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 31 Jul 2023 23:14:48 +0100 Subject: [PATCH 2/8] Fixup: skip anchor checks within successful HTTP response content when anchor checking is not enabled --- sphinx/builders/linkcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 1b7b56eeea3..dc707d7d4f5 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -406,7 +406,7 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> tuple[str, str, int]: _user_agent=self.user_agent, _tls_info=(self.tls_verify, self.tls_cacerts), ) as response: - if response.ok and anchor and not contains_anchor(response, anchor): + if response.ok and self.check_anchors and anchor and not contains_anchor(response, anchor): raise Exception(__(f'Anchor {anchor!r} not found')) # Copy data we need from the (closed) response From 6fc369e12192aea9a2e38f3f1b5968db1f3b4737 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 31 Jul 2023 23:25:16 +0100 Subject: [PATCH 3/8] Fix lint warnings: unused variable, and line length limit exceeded in linkcheck builder tests --- tests/test_build_linkcheck.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py index 21ba93c026d..04b09314044 100644 --- a/tests/test_build_linkcheck.py +++ b/tests/test_build_linkcheck.py @@ -167,7 +167,9 @@ def test_defaults(app): } -@pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True, confoverrides={'linkcheck_anchors': False}) +@pytest.mark.sphinx( + 'linkcheck', testroot='linkcheck', freshenv=True, + confoverrides={'linkcheck_anchors': False}) def test_check_link_response_only(app): with http_server(DefaultsHandler): app.build() @@ -177,7 +179,6 @@ def test_check_link_response_only(app): content = (app.outdir / 'output.json').read_text(encoding='utf8') rows = [json.loads(x) for x in content.splitlines()] - row = rows[0] rowsby = {row["uri"]: row for row in rows} assert rowsby["http://localhost:7777/#top"]["status"] == "working" From 7d90b4326a6137db7994be05e96aafa21fa7279e Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 31 Jul 2023 23:27:25 +0100 Subject: [PATCH 4/8] Fix lint warning: line length limit exceeded in linkcheck builder --- sphinx/builders/linkcheck.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index dc707d7d4f5..fad4f11d247 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -406,8 +406,9 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> tuple[str, str, int]: _user_agent=self.user_agent, _tls_info=(self.tls_verify, self.tls_cacerts), ) as response: - if response.ok and self.check_anchors and anchor and not contains_anchor(response, anchor): - raise Exception(__(f'Anchor {anchor!r} not found')) + if response.ok and self.check_anchors: + if anchor and not contains_anchor(response, anchor): + raise Exception(__(f'Anchor {anchor!r} not found')) # Copy data we need from the (closed) response status_code = response.status_code From 3fa8e3b863e606cde227b165841350a04391c92c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:54:22 +0100 Subject: [PATCH 5/8] Move check_anchors test first; combine two if-statements --- sphinx/builders/linkcheck.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index fad4f11d247..fab4ba04047 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -406,8 +406,8 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> tuple[str, str, int]: _user_agent=self.user_agent, _tls_info=(self.tls_verify, self.tls_cacerts), ) as response: - if response.ok and self.check_anchors: - if anchor and not contains_anchor(response, anchor): + if (self.check_anchors and response.ok and anchor + and not contains_anchor(response, anchor)): raise Exception(__(f'Anchor {anchor!r} not found')) # Copy data we need from the (closed) response From 90caa67a78a0b2916c0d18bc850d6d15b78148e3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:59:01 +0100 Subject: [PATCH 6/8] Fix indentation --- sphinx/builders/linkcheck.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index fab4ba04047..81b1e145f8e 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -407,8 +407,8 @@ def _check_uri(self, uri: str, hyperlink: Hyperlink) -> tuple[str, str, int]: _tls_info=(self.tls_verify, self.tls_cacerts), ) as response: if (self.check_anchors and response.ok and anchor - and not contains_anchor(response, anchor)): - raise Exception(__(f'Anchor {anchor!r} not found')) + and not contains_anchor(response, anchor)): + raise Exception(__(f'Anchor {anchor!r} not found')) # Copy data we need from the (closed) response status_code = response.status_code From 3a7307378ec7f38f14278cb0b7ecb5e3a1622d1b Mon Sep 17 00:00:00 2001 From: James Addison Date: Tue, 1 Aug 2023 17:34:40 +0100 Subject: [PATCH 7/8] Update CHANGES for PR #11544 --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 443ef7d6865..eefba25ab5d 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,10 @@ Features added Bugs fixed ---------- +* #11542: linkcheck builder: regression: URL anchors were reported as missing + when the 'linkcheck_anchors' configuration setting was set to 'False'. + Patch by James Addison. + Testing ------- From b7e54edb8e70e28ae187ad3c645dbe5647ee3e99 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 2 Aug 2023 02:01:48 +0100 Subject: [PATCH 8/8] Wording --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index eefba25ab5d..a62c6e00f49 100644 --- a/CHANGES +++ b/CHANGES @@ -16,8 +16,8 @@ Features added Bugs fixed ---------- -* #11542: linkcheck builder: regression: URL anchors were reported as missing - when the 'linkcheck_anchors' configuration setting was set to 'False'. +* #11542: linkcheck: Properly respect :confval:`linkcheck_anchors` + and do not spuriously report failures to validate anchors. Patch by James Addison. Testing