Repository navigation
gh-161452: Fix python -m random with a non-positive integer input - #161453
andresdelfino wants to merge 4 commits into
Conversation
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 <[email protected]>
| @@ -1076,6 +1075,8 @@ def main(arg_list: list[str] | None = None) -> int | str: | |||
There was a problem hiding this comment.
Don't you want to move this to an (inner) else: block too?
There was a problem hiding this comment.
FWIW, I think it's the right place: uniform() not raises (c.f. randint).
So, here we have only parsing failures for floats. In that case it's reasonable to try choice() as a fallback.
There was a problem hiding this comment.
While Sergey is right, it would be easier to read if the same pattern is followed. Let's to think of. Let me know what you prefer.
There was a problem hiding this comment.
I agree with @gvanrossum, it's better to move return uniform(0, val) to an else: block as well.
There was a problem hiding this comment.
This change is backward incompatible, but it respects the documentation: https://docs.python.org/dev/library/random.html#command-line-usage
If no options are given, the output depends on the input:
Integer: same as --integer.
Hum. Displaying a long traceback is not really user friendly. Can you catch the exception and display a (short) error message instead?
$ ./python -m random -3
Traceback (most recent call last):
File "/home/vstinner/python/main/Lib/runpy.py", line 201, in _run_module_as_main
return _run_code(code, main_globals, None,
"__main__", mod_spec)
File "/home/vstinner/python/main/Lib/runpy.py", line 87, in _run_code
exec(code, run_globals)
~~~~^^^^^^^^^^^^^^^^^^^
File "/home/vstinner/python/main/Lib/random.py", line 1088, in <module>
print(main())
~~~~^^
File "/home/vstinner/python/main/Lib/random.py", line 1079, in main
return randint(1, val)
File "/home/vstinner/python/main/Lib/random.py", line 341, in randint
raise ValueError(f"empty range in randint({a}, {b})")
ValueError: empty range in randint(1, -3)cc @hugovk who authored this feature.
|
Yes, a short error message would be better than the traceback. |
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 <[email protected]>
|
@vstinner I applied your suggestion, handling the exception in the block that calls main. Changing the main function itself would involve more changes in the tests. Would it be better to go that way? |
|
Some general notes on
There is a surprising behavior when the integer is larger than sys.get_int_max_str_digits(). int() raises By the way, it's possible to pass special float values: It seems like Ok, maybe it can return And |
Co-authored-by: Victor Stinner <[email protected]>
vstinner
left a comment
There was a problem hiding this comment.
LGTM. I just have a last suggestion about adding a "real" random.main() function.
| import sys | ||
| try: | ||
| print(main()) | ||
| except ValueError as exc: | ||
| sys.exit(f"error: {exc}") |
There was a problem hiding this comment.
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.
When
python -m randomgets a single integer input,main()calledrandint()inside thetryblock that converts the input withint(). For an integerN <= 0, theValueErrorthatrandint()raises for an empty range was taken to mean that the input is not an integer, sopython -m random 0printed0.0and a negativeNprinted a random negative float. This keeps only the conversions inside thetryblocks (therandint()anduniform()calls move toelse:blocks), so an integer input now behaves like--integer N, as documented.Run from the command line, both forms now print a one-line error and exit with status 1, instead of a traceback:
main()itself still raises theValueError; only the__main__block catches it.The new tests check that
0and-5raise the sameValueErrorfrommain()with and without--integer, and that the command line reports the short error message.🤖 Generated with Claude Code
python -m random Nprints a float for an integer N <= 0 #161452