Command-line interface for the `random` module

Many stdlib libraries have a simple CLI:

Some of my favourites:

$ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

$ python3 -m webbrowser https://www.python.org

$ python3 -m uuid
5f73cb76-01d7-4390-8cda-17fe9672a29f

$ python3 -m calendar
                                  2024

      January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7                1  2  3  4                   1  2  3
[snip]

I think it would be useful to add a CLI to random to be randomly select a choice (using random.choice):

$ python3 -m random curry "fish n chips" tacos
tacos

This wouldn’t be a Python-specific tool, like pdb or pickletools, but a generally useful tool like the ones above. I also can’t think of an existing CLI tool to do this (cross-platform or not).

We could add CLI arguments: if the input is an integer, return a random integer between 1 and the input (via random.randint), if it’s a float, return a raondom float between 0 and the input (via random.uniform).

For example:

$ python3 -m random a b c
b

$ python3 -m random 4
1

$ python3 -m random 2.5
1.5817380334578792

And we could also have explicit arguments:

$ python3 -m random --choice a b c
a

$ python3 -m random --integer 4
3

$ python3 -m random --float 2.5
2.2419142269846186

$ python3 -m random --integer 2
1

$ python3 -m random --float 2
1.4463835577108637

For me, just the random choice would be the most important, but I can see at least picking a random integer would also be useful, like a dice throw.

I’ve implemented this, and it’s about 60 lines of code, and 40 lines of tests.

Currently, python -m random generates some sample test output. We could remove this, or if we still want it, move it to python -m random --test.

What do you think?

(See also the re CLI proposal.)

31 Likes

I like it! It would be good to be able to pipe from stdin, e.g.:

$ python -m random < raffle_entries
Entrant N <entrantN@mailserver.com>
1 Like

At least on Unix system, there’s coreutils shuf, which implements random choices and random integer generation:

$ shuf -n 1 -e a b c
b

$ shuf -n 1 -i 0-4
3

$ python3 -c 'import this' | shuf -n 1
If the implementation is easy to explain, it may be a good idea.
4 Likes

Thanks, at least shuf isn’t natively available on macOS (it’s part of a Homebrew package), and probably not on Windows?

2 Likes

Not natively on Windows, but it’s available via uutils which can be installed using Scoop

+1 on having it as a CLI for the random module, though.

4 Likes

I’m also +1 on this. Being able to do something without Python isn’t IMO a reason why Python shouldn’t do it. After all, python3 -m webbrowser https://www.python.org could just as easily be, say, firefox https://www.python.org.

1 Like

There is also a tool in the num-utils package:
https://suso.suso.org/programs/num-utils/man1/random.html

1 Like

+1, and do the same to the secrets module, without support for float but with support for token generation.

6 Likes

Thanks everyone for the feedback! I’ve opened an issue:

And PR:

1 Like

I think it should default to secure random

1 Like

Personally I don’t think the stdlib shoud also be the provider of basic command-line utilities spread out over many modules as more-or-less official and supported __main__ blocks.

These can be provided by a coreutils package installed in the OS, or the shell itself (sh-like like busybox, or inventing its own language like xonsh or ipython), or one PyPI package.

4 Likes

This is not a good example, as webbrowser is useful there to pick the correct browser for the context.
So it’s similar to exo-open or xdg-open, which are not standad or ubiquitous, hence the value of webbrowser (and its easter egg CLI).

1 Like

Hi, I didn’t test the code but, does the -h or --help print the warning of random — Generate pseudo-random numbers — Python 3.12.3 documentation ?

$ ./python.exe -m random --help
usage: random.py [-h] [-c CHOICE [CHOICE ...] | -i N | -f N] [input ...]

positional arguments:
  input                 if no options given, output depends on the input
                            string or multiple: same as --choice
                            integer: same as --integer
                            float: same as --float

options:
  -h, --help            show this help message and exit
  -c, --choice CHOICE [CHOICE ...]
                        print a random choice
  -i, --integer N       print a random integer between 1 and N inclusive
  -f, --float N         print a random floating point number between 1 and N inclusive

+1 to have a random module cli!
This is a very wonderful idea!

2 Likes

It might be nice if there was a -s/--start param to change the start from 1 to … what the user gives (still defaulting to 1 is fine).

I like this. The implementation is trivial, so there is not much of a maintenance cost. Count me +1.

I agree that we don’t need to add a CLI to every stdlib module, and of course we don’t need to duplicate coreutils or other system utility packages (I don’t think anyone is actually proposing that either), but I find this proposal appealing (as I also do with Serhiy’s proposal to add a re CLI, and the existing json.tool CLI).

3 Likes

I would be interested to have python -m random --bytes 4 to get 4 random bytes written to stdout.

IMO making the assumption of 1 is too specific. I suggest to pass a range instead:

  • python -m random --integer 1 6: dice, [1; 6] range (inclusive)
  • python -m random --integer 0 1: boolean, [0; 1] range (inclusive)
  • python -m random --float -2 3.5: [-2.0; +3.5] range (inclusive)

I’m not sure if --choice CLI is the best CLI. Maybe using sub-commands would create a better CLI to make arguments specific per command. Example:

# [1; 6] inclusive
python -m random integer 6

# [1; 6] inclusive; explicit start-stop CLI
python -m random integer 1 6

# [-2; 3.5] range, inclusive
python -m random float -2 3.5

# [-2; 3.5( range, include -2 but exclude 3.5
python -m random float -2 3.5 --exclude-right

python -m random choice Victor Hugo Brian

# read choices from stdin
python -m random choice --stdin < input  

python -m random bytes 4
# Encode bytes as hexadecimal with spaces,
# such as "0xD3 0x5A 0x90 0xFE"
python -m random bytes 4 --hex

I don’t propose to add all options. I just want to show that there might be more needs in the future, and propose --integer CLI might be too limited.

4 Likes

Éric, people should pay more attention to your comment. It is exactly correct and it seems like it is being casually dismissed or ignored.

We had discussions on this before and the outcome of the discussion was that we are in the language and library business, not in the command-line tool business. Really, that is something best left to packages on PyPI and not something to put in our standard distribution.

Raymond


[RH]

Guido, would you can to opine on this? Every now and then we get a request to make command-line utilities out of tools in the standard library. Whether we should or not depends on whether the standard library intends to be primarily a library for Python code or whether it is also about providing general purpose toolkits that might be helpful in a non-unix environment. We’ve has some of these that have met with success (for example, timeit, json.tool, and SimpleHTTPServer) and others that were just a waste or a were a pale shadow of their full featured Unix counterparts (or left to rot in the Tools directory). If we go further down this road, it would be nice for you to lay out the ground rules for what kind of command line tools would be acceptable, how stable their API would be, and whether they should be separated from the module itself. Do you even want to be in the business of offering command-line APIs that duplicate commonly available Unix tools?

[GvR]

I prefer not to go down this road. The modules that do this where I use it are typically Python specific, e.g. pdb or timeit. In the past we sometimes had little main() functions in modules for testing but I think we have better ways to test modules these days.

3 Likes

FWIW the last time CLI I remember was credible than the currently under consideration. Still, it was rejected:

$ python -m hashlib md5 somefile.txt
$ d985d0ea551c1253c2305140c583d11f
1 Like