Skip to content

chore: add link-checking command #551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

jameslamb
Copy link

Reading through the packaging guide, as part of working on pyOpenSci/pyosPackage#56, I noticed that there are a lot of links to external resources in the packaging guide.

Enough that I think it'd be worth adding some automation to check the validity of those links.

@agriyakhetarpal recently taught me (in jameslamb/pydistcheck#293 (comment)) about 2 forms of this that are really useful and do complementary things:

This PR proposes introducing a nox session that can be used to run the Sphinx link checks. As of this PR, running this from the root of the repo:

nox -e docs-linkcheck

Generates a summary like this:

...
(  tests/code-cov: line   31) redirect  https://codecov.io/ - permanently to https://about.codecov.io/
(tutorials/add-readme: line  180) ok        https://coderefinery.github.io/github-without-command-line/doi/
(package-structure-code/publish-python-package-pypi-conda: line   99) ok        https://conda-forge.org/
...
46 remaining broken or redirecting URLs (click me)
$ cat ./_build/linkcheck_output/output.txt
package-structure-code/pyproject-toml-python-package-metadata.md:34: [broken] ../tutorials/3-pyproject-toml.html: 
package-structure-code/pyproject-toml-python-package-metadata.md:48: [broken] ../tutorials/extras/6-setuppy-to-pyproject-toml.html: 
package-structure-code/publish-python-package-pypi-conda.md:175: [broken] ../tutorials/publish-conda-forge.html: 
package-structure-code/publish-python-package-pypi-conda.md:43: [broken] ../tutorials/publish-pypi.html: 
package-structure-code/python-package-structure.md:166: [broken] /tutorials/create-python-package.html#step-1-set-up-the-package-directory-structure: 
package-structure-code/intro.md:14: [broken] /tutorials/intro: 
documentation/repository-files/license-files.md:10: [broken] <https://www.pyopensci.org/about-peer-review/>: 
package-structure-code/pyproject-toml-python-package-metadata.md:18: [redirected with unknown code] https://PyPI.org/classifiers/ to https://pypi.org/classifiers/
tests/code-cov.md:31: [redirected permanently] https://codecov.io/ to https://about.codecov.io/
package-structure-code/python-package-distribution-files-sdist-wheel.md:150: [redirected permanently] https://conda.io/projects/conda-build/en/latest/user-guide/tutorials/index.html to https://docs.conda.io/projects/conda-build/en/latest/user-guide/tutorials/index.html
TRANSLATING.md:350: [redirected permanently] https://discord.gg/NQtTTqtv to https://discord.com/invite/NQtTTqtv
documentation/hosting-tools/publish-documentation-online.md:25: [redirected permanently] https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages to https://docs.github.com/en/pages/getting-started-with-github-pages/what-is-github-pages
documentation/repository-files/readme-file-best-practices.md:63: [redirected with Found] https://docs.readthedocs.io/en/stable/badges.html to https://docs.readthedocs.com/platform/stable/badges.html
package-structure-code/declare-dependencies.md:371: [redirected with Found] https://docs.readthedocs.io/en/stable/build-customization.html#install-dependencies-with-poetry to https://docs.readthedocs.com/platform/stable/build-customization.html
package-structure-code/declare-dependencies.md:370: [redirected with Found] https://docs.readthedocs.io/en/stable/config-file/index.html to https://docs.readthedocs.com/platform/stable/config-file/index.html
tutorials/create-python-package.md:548: [broken] https://epydoc.sourceforge.net/epytext.html: 403 Client Error: Forbidden for url: https://epydoc.sourceforge.net/epytext.html
documentation/repository-files/readme-file-best-practices.md:78: [redirected permanently] https://github.com/pandera-dev/pandera/workflows/CI%20Tests/badge.svg?branch=main to https://github.com/unionai-oss/pandera/workflows/CI%20Tests/badge.svg?branch=main
package-structure-code/code-style-linting-format.md:284: [broken] https://github.com/pre-commit/pre-commit-hooks#hooks-available: Anchor 'hooks-available' not found
index.md:266: [broken] https://github.com/pyOpenSci/python-package-guide#contributors-: Anchor 'contributors-' not found
documentation/repository-files/readme-file-best-practices.md:78: [redirected permanently] https://github.com/pandera-dev/pandera/actions?query=workflow%3A%22CI+Tests%22+branch%3Amain to https://github.com/unionai-oss/pandera/actions?query=workflow%3A%22CI+Tests%22+branch%3Amain
tutorials/get-to-know-hatch.md:45: [redirected with Found] https://github.com/pypa/hatch/releases/latest/download/hatch-universal.pkg to https://release-assets.githubusercontent.com/github-production-release-asset/92997800/a6167801-6ca9-4ac5-ac7c-21a4c6c8c75c?sp=r&sv=2018-11-09&sr=b&spr=https&se=2025-07-12T23%3A46%3A52Z&rscd=attachment%3B+filename%3Dhatch-universal.pkg&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2025-07-12T22%3A46%3A36Z&ske=2025-07-12T23%3A46%3A52Z&sks=b&skv=2018-11-09&sig=CRIzlQ2Es1UyKfwGQRCX%2BWqt8h1efHVr3oQ6kF%2FbV0U%3D&jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc1MjM2MTYwNiwibmJmIjoxNzUyMzYxMzA2LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.Uduc-iOkI9ctuAAeBX1dZgeXDcCh6Fc9dhb1_cNsW2E&response-content-disposition=attachment%3B%20filename%3Dhatch-universal.pkg&response-content-type=application%2Foctet-stream
tutorials/get-to-know-hatch.md:53: [redirected with Found] https://github.com/pypa/hatch/releases/latest/download/hatch-x64.msi to https://release-assets.githubusercontent.com/github-production-release-asset/92997800/753aa9e4-be17-4329-81bd-920cce26e870?sp=r&sv=2018-11-09&sr=b&spr=https&se=2025-07-12T23%3A40%3A52Z&rscd=attachment%3B+filename%3Dhatch-x64.msi&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2025-07-12T22%3A40%3A34Z&ske=2025-07-12T23%3A40%3A52Z&sks=b&skv=2018-11-09&sig=WJ4UnXcYCNRKC8lkK7XqlcyDhx4ewJ%2BdCfddbjkC6Gk%3D&jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc1MjM2MTYwNiwibmJmIjoxNzUyMzYxMzA2LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.Uduc-iOkI9ctuAAeBX1dZgeXDcCh6Fc9dhb1_cNsW2E&response-content-disposition=attachment%3B%20filename%3Dhatch-x64.msi&response-content-type=application%2Foctet-stream
documentation/hosting-tools/website-hosting-optimizing-your-docs.md:40: [redirected permanently] https://github.com/wpilibsuite/sphinxext-opengraph to https://github.com/sphinx-doc/sphinxext-opengraph
documentation/hosting-tools/sphinx-python-package-documentation-tools.md:49: [redirected with Found] https://myst-parser.readthedocs.io/ to https://myst-parser.readthedocs.io/en/latest/
tests/run-tests.md:120: [redirected with Found] https://nox.thea.codes/ to https://nox.thea.codes/en/stable/
documentation/repository-files/license-files.md:46: [redirected permanently] https://opensource.org/licenses/ to https://opensource.org/license
package-structure-code/pyproject-toml-python-package-metadata.md:77: [redirected with Found] https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ to https://packaging.python.org/en/latest/specifications/pyproject-toml/
package-structure-code/declare-dependencies.md:215: [redirected with Found] https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#dependencies-optional-dependencies to https://packaging.python.org/en/latest/specifications/pyproject-toml/
package-structure-code/python-package-build-tools.md:30: [redirected permanently] https://pdm.fming.dev/latest/ to https://pdm-project.org/latest/
package-structure-code/python-package-build-tools.md:251: [redirected permanently] https://pdm.fming.dev/latest/usage/dependency/#about-update-strategy to https://pdm-project.org/latest/usage/dependency/
documentation/hosting-tools/sphinx-python-package-documentation-tools.md:57: [redirected with Found] https://pydata-sphinx-theme.readthedocs.io/ to https://pydata-sphinx-theme.readthedocs.io/en/stable/
package-structure-code/python-package-build-tools.md:27: [redirected with Found] https://pypa-build.readthedocs.io/en/stable/ to https://build.pypa.io/en/stable/
documentation/repository-files/readme-file-best-practices.md:85: [redirected permanently] https://pyopensci.org/badges/peer-reviewed.svg to https://www.pyopensci.org/badges/peer-reviewed.svg
documentation/hosting-tools/publish-documentation-online.md:8: [redirected with Found] https://readthedocs.org/ to https://about.readthedocs.com/?ref=app.readthedocs.org
package-structure-code/declare-dependencies.md:350: [redirected with Found] https://readthedocs.org to https://about.readthedocs.com/?ref=app.readthedocs.org
documentation/hosting-tools/sphinx-python-package-documentation-tools.md:58: [redirected with Found] https://sphinx-book-theme.readthedocs.io/ to https://sphinx-book-theme.readthedocs.io/en/stable/
tutorials/publish-pypi.md:313: [redirected permanently] https://test.pypi.org/project/pyosPackage/ to https://test.pypi.org/project/pyospackage/
tutorials/intro.md:259: [redirected permanently] https://the-turing-way.netlify.app/reproducible-research/compendia.html to https://book.the-turing-way.org/reproducible-research/compendia.html
tutorials/get-to-know-hatch.md:189: [redirected permanently] https://www.choosealicense.com to https://choosealicense.com/
CONTRIBUTING.md:44: [redirected permanently] https://www.github.com/pyopensci/python-package-guide to https://github.com/pyopensci/python-package-guide
documentation/hosting-tools/sphinx-python-package-documentation-tools.md:17: [redirected with Found] https://www.sphinx-doc.org/ to https://www.sphinx-doc.org/en/master/
package-structure-code/python-package-versions.md:14: [redirected with Found] https://www.python.org/dev/peps/pep-0440/#semantic-versioning to https://peps.python.org/pep-0440/
documentation/repository-files/readme-file-best-practices.md:82: [redirected with Found] https://zenodo.org/badge/556814582.svg to https://zenodo.org/badge/DOI/10.5281/zenodo.13154979.svg
tests/write-tests.md:77: [redirected permanently] https://zenodo.org/record/8185113 to https://zenodo.org/records/8185113
documentation/repository-files/readme-file-best-practices.md:82: [redirected with Found] https://zenodo.org/badge/latestdoi/556814582 to https://zenodo.org/records/13154979
package-structure-code/pyproject-toml-python-package-metadata.md:102: [redirected with Found] https://github.com/Ouranosinc/xclim/blob/master/pyproject.toml to https://github.com/Ouranosinc/xclim/blob/main/pyproject.toml

It also fixes a few link issues that were caught by this:

These were all successfully redirecting today, but using the direct targets will make page loads a little faster and reduce the risk of those links being broken if those redirections are eventually removed in the future.

Notes for Reviewers

Thanks for your time and consideration. If this is annoying please close it and sorry for the noise.

Why not fix all the links?

I just didn't want this to be too large, especially since I'm new to this project.

If maintainers are receptive to it, I'd be happy to create an issue documenting the remaining broken links, so folks can contribute fixes for them.

Why not also add lychee?

Again just trying to keep this small and focused. If maintainers are receptive, I'd be happy to put up a follow-up PR proposing adding that. Here's what it can look like: jameslamb/pydistcheck#312

Should this run in CI?

It would be helpful, but you might find that link checks break so often that they're disruptive to have in CI that runs on every commit to every PR. In my experience, for every 1 "this was permanently deleted" type of error, you'll experience like 25 of the form "temporary network disruption", "server down for maintenance", etc.

A once-a-week scheduled job and a README badge making the status visible is probably enough. Up to yall though, that's definitely bigger than this PR and depends on your interest. I'd be happy to create an issue or follow-up PR if you'd like.

How I tested this

pre-commit run --all-files
nox -e docs-test

@jameslamb jameslamb changed the title WIP: chore: add link-checking command chore: add link-checking command Jul 12, 2025
@jameslamb jameslamb marked this pull request as ready for review July 12, 2025 23:37
@tkoyama010 tkoyama010 requested a review from Copilot July 13, 2025 09:04
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds an automated link-checking step for the Sphinx documentation and updates a number of broken or redirected URLs throughout the guide.

  • Introduces a new docs-linkcheck nox session with linkcheck parameters and output directory
  • Configures Sphinx’s linkcheck in conf.py and documents the session in CONTRIBUTING.md
  • Fixes several external links (Hatch, setuptools-scm, peer-reviewed badge) and updates translations accordingly

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tutorials/add-readme.md Update peer-reviewed badge link to software-submission
tests/run-tests.md Update Hatch repository URL to pypa/hatch
package-structure-code/python-package-versions.md Update setuptools-scm repo URL
noxfile.py Add docs-linkcheck session and linkcheck constants
conf.py Configure Sphinx linkcheck ignore rules
CONTRIBUTING.md Document the new docs-linkcheck nox session
documentation/repository-files/readme-file-best-practices.md Update peer-reviewed badge link in best practices guide
locales/ja/LC_MESSAGES/tests.po Update Hatch URL in Japanese translation
locales/ja/LC_MESSAGES/package-structure-code.po Update setuptools-scm URL in Japanese translation
locales/ja/LC_MESSAGES/documentation.po Update peer-reviewed badge URL in Japanese translation
locales/es/LC_MESSAGES/tests.po Update Hatch URL in Spanish translation
locales/es/LC_MESSAGES/package-structure-code.po Update setuptools-scm URL in Spanish translation
locales/es/LC_MESSAGES/documentation.po Update peer-reviewed badge URL in Spanish translation
Comments suppressed due to low confidence (3)

package-structure-code/python-package-versions.md:226

  • [nitpick] The link text uses an underscore but the project name has a hyphen. Consider updating Setuptools_scm to setuptools-scm for consistency with the repository name.
[`Setuptools_scm`](https://github.com/pypa/setuptools-scm/) is an

noxfile.py:78

  • This new docs-linkcheck session isn't covered by any automated tests. Consider adding a test or CI job to ensure the linkcheck session runs as expected.
@nox.session(name="docs-linkcheck")

CONTRIBUTING.md:193

  • [nitpick] You might also want to mention this new session in the project README or main documentation index so contributors know about the docs-linkcheck command.
    nox -e docs-linkcheck

"""
Check that links are well-formed and point to something that exists.
"""
session.install("-e", ".")
Copy link
Preview

Copilot AI Jul 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider creating the LINKCHECK_OUTPUT_DIR before running Sphinx to avoid errors if the directory does not exist (e.g., LINKCHECK_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)).

Suggested change
session.install("-e", ".")
session.install("-e", ".")
# Ensure LINKCHECK_OUTPUT_DIR exists
LINKCHECK_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant