Skip to content

Commit 7c6a3c3

Browse files
authored
Merge pull request #1950 from FFY00/linkcheck-local-remote
Restore linkcheck for specs
2 parents 4dd0764 + 5a56b2e commit 7c6a3c3

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
source/guides/github-actions-ci-cd-sample/* @webknjaz
22
source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @webknjaz
33

4+
# Sphinx extension
5+
pug_sphinx_extensions/ @FFY00
6+
47
# build-details.json
58
source/specifications/build-details/ @FFY00
69
source/specifications/specs/build-details-*.json @FFY00

pug_sphinx_extensions/__init__.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import os
2+
import pathlib
3+
import urllib
4+
5+
import sphinx.application
6+
import sphinx.util.logging
7+
8+
9+
DOMAIN = "packaging.python.org"
10+
11+
12+
logger = sphinx.util.logging.getLogger(__name__)
13+
14+
15+
def resolve_local_html_link(app: sphinx.application.Sphinx, url_path: str) -> str:
16+
"""Takes path of a link pointing an HTML render of the current project,
17+
and returns local path of the referenced document.
18+
19+
Support links to renders from both the `html` and `dirhtml` builders.
20+
21+
Example:
22+
23+
.. code-block:: python
24+
25+
>>> resolve_local_html_link('https://packaging.python.org/en/latest/flow/')
26+
'{srcdir}/flow.rst'
27+
>>> resolve_local_html_link('https://packaging.python.org/en/latest/flow.html')
28+
'{srcdir}/flow.rst'
29+
>>> resolve_local_html_link('https://packaging.python.org/en/latest/specifications/schemas/')
30+
'{srcdir}/specifications/schemas/index.rst'
31+
>>> resolve_local_html_link('https://packaging.python.org/en/latest/specifications/schemas/build-details-v1.0.schema.json')
32+
'{html_extra_path0}/specifications/schemas/build-details-v1.0.schema.json'
33+
34+
"""
35+
# Search for document in html_extra_path
36+
for entry in app.config.html_extra_path:
37+
candidate = (app.confdir / entry / url_path).resolve()
38+
if candidate.is_dir():
39+
candidate = candidate / "index.html"
40+
if candidate.exists():
41+
return os.fspath(candidate)
42+
# Convert html path to source path
43+
url_path = url_path.removesuffix("/") # Normalize
44+
if url_path.endswith(".html"):
45+
document = url_path.removesuffix(".html")
46+
elif (candidate := f"{url_path}/index") in app.project.docnames:
47+
document = candidate
48+
else:
49+
document = url_path
50+
return app.env.doc2path(document)
51+
52+
53+
def rewrite_local_uri(app: sphinx.application.Sphinx, uri: str) -> str:
54+
"""Replace remote URIs targeting https://packaging.python.org/en/latest/...
55+
with local ones, so that local changes are taken into account by linkcheck.
56+
57+
Additionally, resolve local relative links to html_extra_path.
58+
"""
59+
local_uri = uri
60+
parsed = urllib.parse.urlparse(uri)
61+
# Links to https://packaging.python.org/en/latest/...
62+
if parsed.hostname == DOMAIN and parsed.path.startswith("/en/latest/"):
63+
document = parsed.path.removeprefix("/en/latest/")
64+
local_uri = resolve_local_html_link(app, document)
65+
logger.verbose(
66+
f"{uri!s} is a remote URL that points to local sources, "
67+
"replacing it with a local URL in linkcheck to take new changes "
68+
"into account (pass -vv for more info)"
69+
)
70+
logger.debug(f"Replacing linkcheck URL {uri!r} with {local_uri!r}")
71+
# Local relative links
72+
if not parsed.scheme and not parsed.netloc and parsed.path:
73+
full_path = pathlib.Path(app.env.docname).parent / parsed.path
74+
local_uri = resolve_local_html_link(app, os.fspath(full_path))
75+
if local_uri != uri:
76+
logger.verbose(f"Local linkcheck URL {uri!r} resolved as {local_uri!r}")
77+
return local_uri
78+
79+
80+
def setup(app: sphinx.application.Sphinx) -> dict[str, bool]:
81+
app.connect("linkcheck-process-uri", rewrite_local_uri)
82+
83+
return {
84+
"parallel_read_safe": True,
85+
"parallel_write_safe": True,
86+
}

source/conf.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
33

44
import os
5+
import pathlib
6+
import sys
7+
8+
_ROOT = pathlib.Path(__file__).resolve().parent.parent
9+
sys.path.append(os.fspath(_ROOT))
510

611
# Some options are only enabled for the main packaging.python.org deployment builds
712
RTD_BUILD = bool(os.getenv("READTHEDOCS"))
@@ -22,6 +27,7 @@
2227
root_doc = "index"
2328

2429
extensions = [
30+
"pug_sphinx_extensions",
2531
"sphinx.ext.extlinks",
2632
"sphinx.ext.intersphinx",
2733
"sphinx.ext.todo",
@@ -133,7 +139,6 @@
133139

134140
linkcheck_ignore = [
135141
r"http://localhost:\d+",
136-
r"https://packaging\.python\.org/en/latest/specifications/schemas/.*",
137142
r"https://test\.pypi\.org/project/example-package-YOUR-USERNAME-HERE",
138143
r"https://pypi\.org/manage/.*",
139144
r"https://test\.pypi\.org/manage/.*",
@@ -162,9 +167,6 @@
162167
# https://github.com/pypa/packaging.python.org/issues/1744
163168
r"https://pypi\.org/",
164169
]
165-
linkcheck_exclude_documents = [
166-
"specifications/schemas/index",
167-
]
168170

169171
# -- Options for extlinks ----------------------------------------------------------
170172
# https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html#configuration

0 commit comments

Comments
 (0)