Docs(build): linklint is now called sphinx_linklint (#156373)

* Docs(build): linklint is now called sphinx_linklint

* Docs(build): move the lock command to the Makefile

* Update Doc/Makefile

Co-authored-by: Stan Ulbrych <stan@python.org>

* Add a comment clarify cooldown (and excludes) and add to `make help`

---------

Co-authored-by: Stan Ulbrych <stan@python.org>
diff --git a/Doc/Makefile b/Doc/Makefile
index d77ece1..ef6ef8c 100644
--- a/Doc/Makefile
+++ b/Doc/Makefile
@@ -32,6 +32,7 @@
 	@echo "Please use \`make <target>' where <target> is one of"
 	@echo "  clean      to remove build files"
 	@echo "  venv       to create a venv with necessary tools"
+	@echo "  lock       to regenerate the pinned dependencies in $(REQUIREMENTS)"
 	@echo "  html       to make standalone HTML files"
 	@echo "  gettext    to generate POT files"
 	@echo "  htmlview   to open the index page built by the html target in your browser"
@@ -185,6 +186,19 @@
 		echo "The venv has been created in the $(VENVDIR) directory"; \
 	fi
 
+.PHONY: lock
+lock:
+# Dependencies have a 14 day cooldown period to mitigate supply chain attacks,
+# except for sphinx_linklint and python-docs-theme, which are maintained by
+# core team members.
+	uv pip compile requirements.txt \
+		--exclude-newer P14D \
+		--exclude-newer-package sphinx_linklint=PT0S \
+		--exclude-newer-package python-docs-theme=PT0S \
+		--no-cache --output-file $(REQUIREMENTS) \
+		--python-version 3.12 --universal \
+		--custom-compile-command="make lock"
+
 .PHONY: dist-no-html
 dist-no-html: dist-text dist-epub dist-texinfo
 
diff --git a/Doc/conf.py b/Doc/conf.py
index 9b103a5..c768e6f 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -41,7 +41,7 @@
 
 # Skip if downstream redistributors haven't installed them
 _OPTIONAL_EXTENSIONS = (
-    'linklint.ext',
+    'sphinx_linklint.ext',
     'notfound.extension',
     'sphinxext.opengraph',
     'sphinxcontrib.rsvgconverter',
diff --git a/Doc/pylock.toml b/Doc/pylock.toml
index af4627c..94b7d9d 100644
--- a/Doc/pylock.toml
+++ b/Doc/pylock.toml
@@ -1,5 +1,5 @@
 # This file was autogenerated by uv via the following command:
-#    uv pip compile Doc/requirements.txt --exclude-newer P14D --exclude-newer-package linklint=PT0S --exclude-newer-package python-docs-theme=PT0S --exclude-newer-package pygments=PT0S --no-cache --output-file Doc/pylock.toml --python-version 3.12 --universal
+#    make lock
 lock-version = "1.0"
 created-by = "uv"
 requires-python = ">=3.12"
@@ -120,12 +120,6 @@
 wheels = [{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", upload-time = 2025-03-05T20:05:00Z, size = 134899, hashes = { sha256 = "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" } }]
 
 [[packages]]
-name = "linklint"
-version = "1.0.1"
-sdist = { url = "https://files.pythonhosted.org/packages/62/22/c65a97b2192c3c317c472058bf52d7ca88e421998fa8d5c183b2280ab5d4/linklint-1.0.1.tar.gz", upload-time = 2026-06-09T12:30:47Z, size = 22412, hashes = { sha256 = "10201b4366edecfbeb3281883aff857dbe77d40bb56f16f212d372f597342d5f" } }
-wheels = [{ url = "https://files.pythonhosted.org/packages/7b/d8/b2f1708f55f4dd5358b48d28be07ff8e0dadd6d23e41ead2ed1424e90256/linklint-1.0.1-py3-none-any.whl", upload-time = 2026-06-09T12:30:46Z, size = 12828, hashes = { sha256 = "c931f110482f1d17808aa2df78b116adc44d7a14e9e79922c57bf9a7cba40a2d" } }]
-
-[[packages]]
 name = "markupsafe"
 version = "2.1.5"
 sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", upload-time = 2024-02-02T16:31:22Z, size = 19384, hashes = { sha256 = "d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b" } }
@@ -191,6 +185,12 @@
 wheels = [{ url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", upload-time = 2025-03-02T22:31:56Z, size = 3589741, hashes = { sha256 = "4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3" } }]
 
 [[packages]]
+name = "sphinx-linklint"
+version = "2.0.0"
+sdist = { url = "https://files.pythonhosted.org/packages/f6/99/f9947b30fd11e782855a13de1aac7d08634edba1c193a0ee01bf5338531c/sphinx_linklint-2.0.0.tar.gz", upload-time = 2026-08-25T12:47:33Z, size = 23297, hashes = { sha256 = "e7ea4d3b1bd83665e9c2ab9fd92c6c645c805956d2e8ca6b0f528f3a9638910d" } }
+wheels = [{ url = "https://files.pythonhosted.org/packages/d7/3d/6b96af48e139357e1e041a710d943c4bb79ad149c7aab074df784b4395ec/sphinx_linklint-2.0.0-py3-none-any.whl", upload-time = 2026-08-25T12:47:32Z, size = 13390, hashes = { sha256 = "12aa64f3b3faaa6e8a979a7d1f2c38617866652b670e3d19fa0f60a6ce3657ef" } }]
+
+[[packages]]
 name = "sphinx-notfound-page"
 version = "1.0.4"
 sdist = { url = "https://files.pythonhosted.org/packages/73/7d/c545883c714319380325a52c9f80d093c97e718d812fd8090e42b1a08508/sphinx_notfound_page-1.0.4.tar.gz", upload-time = 2024-07-31T12:29:21Z, size = 519228, hashes = { sha256 = "2a52f49cd367b5c4e64072de1591cc367714098500abf4ecb9a3ecb4fec25aae" } }
diff --git a/Doc/requirements.txt b/Doc/requirements.txt
index edaec74..b9072b4 100644
--- a/Doc/requirements.txt
+++ b/Doc/requirements.txt
@@ -13,13 +13,12 @@
 
 blurb
 
-sphinxext-opengraph~=0.13.0
+sphinx-linklint
 sphinx-notfound-page~=1.0.0
+sphinxext-opengraph~=0.13.0
 
 # The theme used by the documentation is stored separately, so we need
 # to install that as well.
 python-docs-theme>=2023.3.1,!=2023.7
 
-linklint
-
 -c constraints.txt