From 5ee6049db755cf6077c61a2e1cb71f95318bce24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Thu, 5 Nov 2026 19:19:54 -0300 Subject: [PATCH 1/4] gh-161452: Fix python -m random with a non-positive integer input When given a single integer input, main() called randint() inside the same try block that converts the input with int(). The ValueError that randint() raises for an empty range was then taken to mean that the input is not an integer, so "python -m random 0" printed 0.0 and a negative N printed a random negative float, instead of failing like "--integer N" does. Only convert the input inside the try block. Co-Authored-By: Claude Opus 5.5 --- Lib/random.py | 3 ++- Lib/test/test_random.py | 8 ++++++++ .../2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst diff --git a/Lib/random.py b/Lib/random.py index 7db761034509d3..da36aeceb46dc4 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -1067,7 +1067,6 @@ def main(arg_list: list[str] | None = None) -> int | str: try: # Is it an integer? val = int(val) - return randint(1, val) except ValueError: try: # Is it a float? @@ -1076,6 +1075,8 @@ def main(arg_list: list[str] | None = None) -> int | str: except ValueError: # Split in case of space-separated string: "a b c" return choice(val.split()) + else: + return randint(1, val) if len(args.input) >= 2: return choice(args.input) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 8d093ab1b7014a..0f1f2f8166b317 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -1482,6 +1482,14 @@ def test_main(self): random.seed(0) self.assertEqual(random.main(shlex.split(command)), expected) + def test_main_empty_integer_range(self): + # An integer input is the same as --integer, even when it is + # not positive. + for command in ["--integer 0", "0", "--integer -5", "-5"]: + with self.subTest(command=command): + with self.assertRaisesRegex(ValueError, "empty range"): + random.main(shlex.split(command)) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst b/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst new file mode 100644 index 00000000000000..7ac5f49096c540 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst @@ -0,0 +1,3 @@ +Fix the :mod:`random` :ref:`command-line interface ` +printing a random float for a zero or negative integer input instead of +failing like ``--integer`` does. From 7443cc8a6ebdbe2074dc041bca61bb54a6824dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Fri, 6 Nov 2026 21:44:20 -0300 Subject: [PATCH 2/4] Address review: use else block and report a short CLI error Move the uniform() call to an else block too, matching the integer branch. When run from the command line, catch the ValueError for an empty integer range and exit with a one-line error message instead of a traceback. Co-Authored-By: Claude Opus 5.5 --- Lib/random.py | 9 +++++++-- Lib/test/test_random.py | 12 ++++++++++++ .../2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst | 3 ++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Lib/random.py b/Lib/random.py index da36aeceb46dc4..7cf18ceee5482d 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -1071,10 +1071,11 @@ def main(arg_list: list[str] | None = None) -> int | str: try: # Is it a float? val = float(val) - return uniform(0, val) except ValueError: # Split in case of space-separated string: "a b c" return choice(val.split()) + else: + return uniform(0, val) else: return randint(1, val) @@ -1085,4 +1086,8 @@ def main(arg_list: list[str] | None = None) -> int | str: if __name__ == '__main__': - print(main()) + import sys + try: + print(main()) + except ValueError as exc: + sys.exit(f"error: {exc}") diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 0f1f2f8166b317..32f2686fa787e2 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -15,6 +15,7 @@ from collections import abc, Counter from test.support import warnings_helper +from test.support.script_helper import assert_python_failure class MyIndex: @@ -1490,6 +1491,17 @@ def test_main_empty_integer_range(self): with self.assertRaisesRegex(ValueError, "empty range"): random.main(shlex.split(command)) + def test_cli_empty_integer_range(self): + # The command line reports a short error message, not a traceback. + for command in ["--integer 0", "0", "--integer -5", "-5"]: + with self.subTest(command=command): + args = shlex.split(command) + rc, out, err = assert_python_failure("-m", "random", *args) + self.assertEqual(rc, 1) + self.assertEqual(out, b"") + expected = f"error: empty range in randint(1, {args[-1]})" + self.assertEqual(err.decode().rstrip(), expected) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst b/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst index 7ac5f49096c540..f8b9e245e6f441 100644 --- a/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst +++ b/Misc/NEWS.d/next/Library/2026-11-05-22-26-44.gh-issue-161452.YfFfjq.rst @@ -1,3 +1,4 @@ Fix the :mod:`random` :ref:`command-line interface ` printing a random float for a zero or negative integer input instead of -failing like ``--integer`` does. +failing like ``--integer`` does. Both now report a short error message +instead of a traceback. From a4053f7d6be25b99c12d507f94745caa82879c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Fri, 6 Nov 2026 23:11:36 -0300 Subject: [PATCH 3/4] Update Lib/test/test_random.py Co-authored-by: Victor Stinner --- Lib/test/test_random.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 32f2686fa787e2..5230ff9c1a3de9 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -1491,16 +1491,17 @@ def test_main_empty_integer_range(self): with self.assertRaisesRegex(ValueError, "empty range"): random.main(shlex.split(command)) - def test_cli_empty_integer_range(self): - # The command line reports a short error message, not a traceback. - for command in ["--integer 0", "0", "--integer -5", "-5"]: - with self.subTest(command=command): - args = shlex.split(command) - rc, out, err = assert_python_failure("-m", "random", *args) - self.assertEqual(rc, 1) - self.assertEqual(out, b"") - expected = f"error: empty range in randint(1, {args[-1]})" - self.assertEqual(err.decode().rstrip(), expected) + def test_empty_integer_range_error(self): + # An integer input is the same as --integer, even when it is + # not positive. + for value in ["0", "-5"]: + for args in [(value,), ("--integer", value)]: + with self.subTest(args=args): + rc, out, err = assert_python_failure("-m", "random", *args) + self.assertEqual(rc, 1) + self.assertEqual(out, b"") + expected = f"error: empty range in randint(1, {value})" + self.assertEqual(err.decode().rstrip(), expected) if __name__ == "__main__": From a61d062af203f199bc907a592106eaf1eac2688e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Fri, 6 Nov 2026 23:13:43 -0300 Subject: [PATCH 4/4] Remove test_main_empty_integer_range --- Lib/test/test_random.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 5230ff9c1a3de9..5fb24b380df751 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -1483,14 +1483,6 @@ def test_main(self): random.seed(0) self.assertEqual(random.main(shlex.split(command)), expected) - def test_main_empty_integer_range(self): - # An integer input is the same as --integer, even when it is - # not positive. - for command in ["--integer 0", "0", "--integer -5", "-5"]: - with self.subTest(command=command): - with self.assertRaisesRegex(ValueError, "empty range"): - random.main(shlex.split(command)) - def test_empty_integer_range_error(self): # An integer input is the same as --integer, even when it is # not positive.