Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Lib/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -1067,15 +1067,17 @@ 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?
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)

if len(args.input) >= 2:
return choice(args.input)
Expand All @@ -1084,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}")
Comment on lines +1089 to +1093

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might rename main() to _main() and wrap these lines into a new main() function. So for example, you can call the new main() function in tests instead of having to spawn a new process.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I do like gzip instead, and call sys.exit directly from main? So we get the benefit you mention, and follow an existing pattern (personally I always find _main/main confusing).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I suggest is to have a main() function which does everything: parse command line arguments, compute a random value, display the random value, call sys.exit() on error:

if __name__ == '__main__':
    main()

I don't care too much of how main() code would look like :-)

13 changes: 13 additions & 0 deletions Lib/test/test_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -1482,6 +1483,18 @@ def test_main(self):
random.seed(0)
self.assertEqual(random.main(shlex.split(command)), 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__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix the :mod:`random` :ref:`command-line interface <random-cli>`
printing a random float for a zero or negative integer input instead of
failing like ``--integer`` does. Both now report a short error message
instead of a traceback.
Loading