]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-131524: Update platform CLI to use argparse (#131542)
authorHarry <harry.lees@gmail.com>
Sat, 3 May 2025 08:58:59 +0000 (09:58 +0100)
committerGitHub <noreply@github.com>
Sat, 3 May 2025 08:58:59 +0000 (08:58 +0000)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Lib/platform.py
Lib/test/test_platform.py
Misc/NEWS.d/next/Library/2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst [new file with mode: 0644]

index a62192589af8ff9d842138f93c0335180d17c3e8..507552f360ba595e9365246322483ea55e5ee3cd 100644 (file)
@@ -1464,9 +1464,41 @@ def invalidate_caches():
 
 ### Command line interface
 
-if __name__ == '__main__':
-    # Default is to print the aliased verbose platform string
-    terse = ('terse' in sys.argv or '--terse' in sys.argv)
-    aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
+def _parse_args(args: list[str] | None):
+    import argparse
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument("args", nargs="*", choices=["nonaliased", "terse"])
+    parser.add_argument(
+        "--terse",
+        action="store_true",
+        help=(
+            "return only the absolute minimum information needed "
+            "to identify the platform"
+        ),
+    )
+    parser.add_argument(
+        "--nonaliased",
+        dest="aliased",
+        action="store_false",
+        help=(
+            "disable system/OS name aliasing. If aliasing is enabled, "
+            "some platforms report system names different from "
+            "their common names, e.g. SunOS is reported as Solaris"
+        ),
+    )
+
+    return parser.parse_args(args)
+
+
+def _main(args: list[str] | None = None):
+    args = _parse_args(args)
+
+    terse = args.terse or ("terse" in args.args)
+    aliased = args.aliased and ('nonaliased' not in args.args)
+
     print(platform(aliased, terse))
-    sys.exit(0)
+
+
+if __name__ == "__main__":
+    _main()
index 6ba630ad527f919c0b5aa8a8f2a3644bc45adf8d..b90edc05e0454e41bf26c6974a66cdf62c210197 100644 (file)
@@ -1,5 +1,8 @@
-import os
+import contextlib
 import copy
+import io
+import itertools
+import os
 import pickle
 import platform
 import subprocess
@@ -741,5 +744,65 @@ class PlatformTest(unittest.TestCase):
         self.assertEqual(len(info["SPECIALS"]), 5)
 
 
+class CommandLineTest(unittest.TestCase):
+    def setUp(self):
+        platform.invalidate_caches()
+        self.addCleanup(platform.invalidate_caches)
+
+    def invoke_platform(self, *flags):
+        output = io.StringIO()
+        with contextlib.redirect_stdout(output):
+            platform._main(args=flags)
+        return output.getvalue()
+
+    def test_unknown_flag(self):
+        with self.assertRaises(SystemExit):
+            output = io.StringIO()
+            # suppress argparse error message
+            with contextlib.redirect_stderr(output):
+                _ = self.invoke_platform('--unknown')
+            self.assertStartsWith(output, "usage: ")
+
+    def test_invocation(self):
+        flags = (
+            "--terse", "--nonaliased", "terse", "nonaliased"
+        )
+
+        for r in range(len(flags) + 1):
+            for combination in itertools.combinations(flags, r):
+                self.invoke_platform(*combination)
+
+    def test_arg_parsing(self):
+        # For backwards compatibility, the `aliased` and `terse` parameters are
+        # computed based on a combination of positional arguments and flags.
+        #
+        # Test that the arguments are correctly passed to the underlying
+        # `platform.platform()` call.
+        options = (
+            (["--nonaliased"], False, False),
+            (["nonaliased"], False, False),
+            (["--terse"], True, True),
+            (["terse"], True, True),
+            (["nonaliased", "terse"], False, True),
+            (["--nonaliased", "terse"], False, True),
+            (["--terse", "nonaliased"], False, True),
+        )
+
+        for flags, aliased, terse in options:
+            with self.subTest(flags=flags, aliased=aliased, terse=terse):
+                with mock.patch.object(platform, 'platform') as obj:
+                    self.invoke_platform(*flags)
+                    obj.assert_called_once_with(aliased, terse)
+
+    def test_help(self):
+        output = io.StringIO()
+
+        with self.assertRaises(SystemExit):
+            with contextlib.redirect_stdout(output):
+                platform._main(args=["--help"])
+
+        self.assertStartsWith(output.getvalue(), "usage:")
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst b/Misc/NEWS.d/next/Library/2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst
new file mode 100644 (file)
index 0000000..28926d0
--- /dev/null
@@ -0,0 +1,2 @@
+Add help message to :mod:`platform` command-line interface. Contributed by
+Harry Lees.