Skip to content

Commit

Permalink
Close #5208: linkcheck: Support checks for local links
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Jul 19, 2020
1 parent f30284e commit f95ba21
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -27,6 +27,7 @@ Features added
* #7902: html theme: Add a new option :confval:`globaltoc_maxdepth` to control
the behavior of globaltoc in sidebar
* #7840: i18n: Optimize the dependencies check on bootstrap
* #5208: linkcheck: Support checks for local links
* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains.
Update the documentation to better reflect the relationship between this option
and the ``:noindex:`` option.
Expand Down
17 changes: 15 additions & 2 deletions sphinx/builders/linkcheck.py
Expand Up @@ -35,6 +35,8 @@

logger = logging.getLogger(__name__)

uri_re = re.compile('[a-z]+://')

This comment has been minimized.

Copy link
@westurner

westurner Jul 20, 2020

Contributor

Protocol-relative URLs can start with //

href="//example.org/index.html"

https://twitter.com/westurner/status/1284937606145495040?s=19

This comment has been minimized.

Copy link
@tk0miya

tk0miya Jul 23, 2020

Author Member

Absolutely!

This comment has been minimized.

Copy link
@tk0miya

tk0miya Jul 23, 2020

Author Member

I just posted #8000 to fix this.



DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
Expand Down Expand Up @@ -210,10 +212,21 @@ def check_uri() -> Tuple[str, str, int]:

def check() -> Tuple[str, str, int]:
# check for various conditions without bothering the network
if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'ftp:')):
if len(uri) == 0 or uri.startswith(('#', 'mailto:')):
return 'unchecked', '', 0
elif not uri.startswith(('http:', 'https:')):
return 'local', '', 0
if uri_re.match(uri):
# non supported URI schemes (ex. ftp)
return 'unchecked', '', 0
else:
if path.exists(path.join(self.srcdir, uri)):
return 'working', '', 0
else:
for rex in self.to_ignore:
if rex.match(uri):
return 'ignored', '', 0
else:
return 'broken', '', 0
elif uri in self.good:
return 'working', 'old', 0
elif uri in self.broken:
Expand Down
2 changes: 2 additions & 0 deletions tests/roots/test-linkcheck/links.txt
Expand Up @@ -11,6 +11,8 @@ Some additional anchors to exercise ignore code
* `Example Bar invalid <https://www.google.com/#top>`_
* `Example anchor invalid <http://www.sphinx-doc.org/en/1.7/intro.html#does-not-exist>`_
* `Complete nonsense <https://localhost:7777/doesnotexist>`_
* `Example valid local file <conf.py>`_
* `Example invalid local file <path/to/notfound>`_

.. image:: https://www.google.com/image.png
.. figure:: https://www.google.com/image2.png
13 changes: 8 additions & 5 deletions tests/test_build_linkcheck.py
Expand Up @@ -30,7 +30,9 @@ def test_defaults(app, status, warning):
# images should fail
assert "Not Found for url: https://www.google.com/image.png" in content
assert "Not Found for url: https://www.google.com/image2.png" in content
assert len(content.splitlines()) == 5
# looking for local file should fail
assert "[broken] path/to/notfound" in content
assert len(content.splitlines()) == 6


@pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True)
Expand All @@ -47,8 +49,8 @@ def test_defaults_json(app, status, warning):
"info"]:
assert attr in row

assert len(content.splitlines()) == 8
assert len(rows) == 8
assert len(content.splitlines()) == 10
assert len(rows) == 10
# the output order of the rows is not stable
# due to possible variance in network latency
rowsby = {row["uri"]:row for row in rows}
Expand All @@ -69,7 +71,7 @@ def test_defaults_json(app, status, warning):
assert dnerow['uri'] == 'https://localhost:7777/doesnotexist'
assert rowsby['https://www.google.com/image2.png'] == {
'filename': 'links.txt',
'lineno': 16,
'lineno': 18,
'status': 'broken',
'code': 0,
'uri': 'https://www.google.com/image2.png',
Expand All @@ -92,7 +94,8 @@ def test_defaults_json(app, status, warning):
'https://localhost:7777/doesnotexist',
'http://www.sphinx-doc.org/en/1.7/intro.html#',
'https://www.google.com/image.png',
'https://www.google.com/image2.png']
'https://www.google.com/image2.png',
'path/to/notfound']
})
def test_anchors_ignored(app, status, warning):
app.builder.build_all()
Expand Down

0 comments on commit f95ba21

Please sign in to comment.