From 77c391a1b178a35b0157e00689acb3904b77694d Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 3 May 2025 09:58:59 +0100 Subject: gh-131524: Update platform CLI to use argparse (#131542) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | 42 ++++++++++++-- Lib/test/test_platform.py | 65 +++++++++++++++++++++- .../2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst | 2 + 3 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst diff --git a/Lib/platform.py b/Lib/platform.py index a621925..507552f 100644 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -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() diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 6ba630a..b90edc0 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -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 index 0000000..28926d0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-21-17-34-27.gh-issue-131524.Vj1pO_.rst @@ -0,0 +1,2 @@ +Add help message to :mod:`platform` command-line interface. Contributed by +Harry Lees. -- cgit v0.12