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
20 changes: 14 additions & 6 deletions Lib/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -1041,18 +1041,24 @@ def _parse_args(arg_list: list[str] | None):
integer: same as `--integer`
float: same as `--float`""")
args = parser.parse_args(arg_list)
return args, parser.format_help()
return args, parser


def _randint_cli(parser, n: int) -> int:
if n < 1:
parser.error(f"integer must be 1 or greater, got {n}")
return randint(1, n)


def main(arg_list: list[str] | None = None) -> int | str:
args, help_text = _parse_args(arg_list)
args, parser = _parse_args(arg_list)

# Explicit arguments
if args.choice:
return choice(args.choice)

if args.integer is not None:
return randint(1, args.integer)
return _randint_cli(parser, args.integer)

if args.float is not None:
return uniform(0, args.float)
Expand All @@ -1067,20 +1073,22 @@ 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_cli(parser, val)

if len(args.input) >= 2:
return choice(args.input)

return help_text
return parser.format_help()


if __name__ == '__main__':
Expand Down
32 changes: 20 additions & 12 deletions Lib/test/test_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -1443,29 +1443,23 @@ def test_after_fork(self):
class CommandLineTest(unittest.TestCase):
@support.force_not_colorized
def test_parse_args(self):
args, help_text = random._parse_args(shlex.split("--choice a b c"))
args, parser = random._parse_args(shlex.split("--choice a b c"))
self.assertEqual(args.choice, ["a", "b", "c"])
self.assertStartsWith(help_text, "usage: ")

args, help_text = random._parse_args(shlex.split("--integer 5"))
args, parser = random._parse_args(shlex.split("--integer 5"))
self.assertEqual(args.integer, 5)
self.assertStartsWith(help_text, "usage: ")

args, help_text = random._parse_args(shlex.split("--float 2.5"))
args, parser = random._parse_args(shlex.split("--float 2.5"))
self.assertEqual(args.float, 2.5)
self.assertStartsWith(help_text, "usage: ")

args, help_text = random._parse_args(shlex.split("a b c"))
args, parser = random._parse_args(shlex.split("a b c"))
self.assertEqual(args.input, ["a", "b", "c"])
self.assertStartsWith(help_text, "usage: ")

args, help_text = random._parse_args(shlex.split("5"))
args, parser = random._parse_args(shlex.split("5"))
self.assertEqual(args.input, ["5"])
self.assertStartsWith(help_text, "usage: ")

args, help_text = random._parse_args(shlex.split("2.5"))
args, parser = random._parse_args(shlex.split("2.5"))
self.assertEqual(args.input, ["2.5"])
self.assertStartsWith(help_text, "usage: ")

def test_main(self):
for command, expected in [
Expand All @@ -1482,6 +1476,20 @@ def test_main(self):
random.seed(0)
self.assertEqual(random.main(shlex.split(command)), expected)

@support.force_not_colorized
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"]:
err_msg = f"error: integer must be 1 or greater, got {value}\n"
for args in [[value], ["--integer", value]]:
with self.subTest(args=args):
with (support.captured_stderr() as stderr,
self.assertRaises(SystemExit) as cm):
random.main(args)
self.assertEqual(cm.exception.code, 2)
self.assertEndsWith(stderr.getvalue(), err_msg)


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
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.
Loading