https://github.com/python/cpython/commit/16dcb576f7623e19f22be631bbc0e565335da969
commit: 16dcb576f7623e19f22be631bbc0e565335da969
branch: main
author: Ɓukasz Langa <luk...@langa.pl>
committer: ambv <luk...@langa.pl>
date: 2025-04-09T01:01:36+02:00
summary:

gh-131507: Add a way to recreate the `Misc/mypy` symlinks if missing (#132274)

They will be removed in source tarballs so they don't appear
in the SBOM.

Co-authored-by: Stan Ulbrych <89152624+stanfromirel...@users.noreply.github.com>

files:
A Misc/mypy/make_symlinks.py
A Misc/mypy/typed-stdlib.txt
M .github/workflows/mypy.yml
M Misc/mypy/README.md

diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml
index 6d1c6b5b5e6347..212f3e8d70c836 100644
--- a/.github/workflows/mypy.yml
+++ b/.github/workflows/mypy.yml
@@ -59,4 +59,5 @@ jobs:
           cache: pip
           cache-dependency-path: Tools/requirements-dev.txt
       - run: pip install -r Tools/requirements-dev.txt
+      - run: python3 Misc/mypy/make_symlinks.py --symlink
       - run: mypy --config-file ${{ matrix.target }}/mypy.ini
diff --git a/Misc/mypy/README.md b/Misc/mypy/README.md
index 05eda6c0b82f0a..03eb8bce8d5113 100644
--- a/Misc/mypy/README.md
+++ b/Misc/mypy/README.md
@@ -4,6 +4,7 @@ This directory stores symlinks to standard library modules and 
packages
 that are fully type-annotated and ready to be used in type checking of
 the rest of the stdlib or Tools/ and so on.
 
+## Why this is necessary
 Due to most of the standard library being untyped, we prefer not to
 point mypy directly at `Lib/` for type checking.  Additionally, mypy
 as a tool does not support shadowing typing-related standard libraries
@@ -11,6 +12,13 @@ like `types`, `typing`, and `collections.abc`.
 
 So instead, we set `mypy_path` to include this directory,
 which only links modules and packages we know are safe to be
-type-checked themselves and used as dependencies.
+type-checked themselves and used as dependencies.  See
+`Lib/_pyrepl/mypy.ini` for a usage example.
 
-See `Lib/_pyrepl/mypy.ini` for an example.
\ No newline at end of file
+## I want to add a new type-checked module
+Add it to `typed-stdlib.txt` and run `make_symlinks.py --symlink`.
+
+## I don't see any symlinks in this directory
+The symlinks in this directory are skipped in source tarballs
+in Python releases. This ensures they don't end up in the SBOM. To
+recreate them, run the `make_symlinks.py --symlink` script.
diff --git a/Misc/mypy/make_symlinks.py b/Misc/mypy/make_symlinks.py
new file mode 100755
index 00000000000000..9150604ed7939a
--- /dev/null
+++ b/Misc/mypy/make_symlinks.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import os
+from pathlib import Path
+
+CURRENT_DIR = Path(__file__).parent
+MISC_DIR = CURRENT_DIR.parent
+REPO_ROOT = MISC_DIR.parent
+LIB_DIR = REPO_ROOT / "Lib"
+FILE_LIST = CURRENT_DIR / "typed-stdlib.txt"
+
+parser = argparse.ArgumentParser(prog="make_symlinks.py")
+parser.add_argument(
+    "--symlink",
+    action="store_true",
+    help="Create symlinks",
+)
+parser.add_argument(
+    "--clean",
+    action="store_true",
+    help="Delete any pre-existing symlinks",
+)
+
+args = parser.parse_args()
+
+if args.clean:
+    for entry in CURRENT_DIR.glob("*"):
+        if entry.is_symlink():
+            entry_at_root = entry.relative_to(REPO_ROOT)
+            print(f"removing pre-existing {entry_at_root}")
+            entry.unlink()
+
+for link in FILE_LIST.read_text().splitlines():
+    link = link.strip()
+    if not link or link.startswith('#'):
+        continue
+
+    src = LIB_DIR / link
+    dst = CURRENT_DIR / link
+    src_at_root = src.relative_to(REPO_ROOT)
+    dst_at_root = dst.relative_to(REPO_ROOT)
+    if (
+        dst.is_symlink()
+        and src.resolve(strict=True) == dst.resolve(strict=True)
+    ):
+        continue
+
+    if not args.symlink and args.clean:
+        # when the user called --clean without --symlink, don't report missing
+        # symlinks that we just deleted ourselves
+        continue
+
+    # we specifically want to create relative-path links with ..
+    src_rel = os.path.relpath(src, CURRENT_DIR)
+    action = "symlinking" if args.symlink else "missing symlink to"
+    print(f"{action} {src_at_root} at {dst_at_root}")
+    if args.symlink:
+        os.symlink(src_rel, dst)
diff --git a/Misc/mypy/typed-stdlib.txt b/Misc/mypy/typed-stdlib.txt
new file mode 100644
index 00000000000000..8cd6858b4e591e
--- /dev/null
+++ b/Misc/mypy/typed-stdlib.txt
@@ -0,0 +1,4 @@
+# These libraries in the stdlib can be type-checked.
+
+_colorize.py
+_pyrepl

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to