bpo-43795: Don't list private names in the limited API (GH-26740)


* Remove struct _node from the stable ABI list

This struct was removed along with the old parser in Python 3.9 (PEP 617)

* Stable ABI list: Use the public name "PyFrameObject" rather than "_frame"

* Ensure limited API doesn't contain private names

Names prefixed by an underscore are private by definition.

* Add a blurb
(cherry picked from commit 7cad9cb51bdae2144cbab330f13a607ba3471742)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
diff --git a/Tools/scripts/stable_abi.py b/Tools/scripts/stable_abi.py
index 2ba5b66..b7fd2c8 100755
--- a/Tools/scripts/stable_abi.py
+++ b/Tools/scripts/stable_abi.py
@@ -492,6 +492,16 @@ def gcc_get_limited_api_definitions(headers):
     )
     return stable_data | stable_exported_data | stable_functions
 
+def check_private_names(manifest):
+    """Ensure limited API doesn't contain private names
+
+    Names prefixed by an underscore are private by definition.
+    """
+    for name, item in manifest.contents.items():
+        if name.startswith('_') and not item.abi_only:
+            raise ValueError(
+                f'`{name}` is private (underscore-prefixed) and should be '
+                + 'removed from the stable ABI list or or marked `abi_only`')
 
 def main():
     parser = argparse.ArgumentParser(
@@ -557,6 +567,8 @@ def main():
     with args.file.open() as file:
         manifest = parse_manifest(file)
 
+    check_private_names(manifest)
+
     # Remember results of all actions (as booleans).
     # At the end we'll check that at least one action was run,
     # and also fail if any are false.