The program name (referred to as prog_name or info_name) is the name Click uses in usage help text. If it's not specified, Click tries to detect it by looking at sys.argv[0].
This works when the CLI is run as a script, either directly, or indirectly as an entry point, or as a module when the program is a single file, but fails when the program is a package and run with python -m. In that case, Python converts the -m name to the Python file within the package that would be executed. (The use of __file__ there is also incorrect, as that will always point to click/core.py. There should never be a case where sys.argv is empty. make_str is probably not needed either.)
This leads to the following names:
python example.py, executing a script directly - example.pypython -m example, the single file module example.py - example.pypython -m example, a package like example/__main__.py - __main__.pypython -m example.cli, a submodule like example/cli.py - cli.pyexample, an entry point, with any of the layouts above - exampleWhat's usually expected is that executing a script will print the Python file name (example.py), executing an entry point will print the entry point name (example), and executing a module or package will print the Python command (python -m example, python -m example.cli)
This leads to projects that expect to be run as either an entry point or -m writing their own wrapper around the CLI to control what name gets used. For example, Flask uses a wrapper that the entry point will call with no args, while __main__.py or __name__ == "__main__" will pass as_module=True.
def main(as_module=False):
cli.main(prog_name="python -m flask" if as_module else None)
Unfortunately, detecting whether python -m was used is really, really complicated. Luckily, I did the work already in Werkzeug's reloader: https://github.com/pallets/werkzeug/blob/102bcda52176db448d383a9ef1ccf7e406a379eb/src/werkzeug/_reloader.py#L59. It won't be quite the same in Click because we're not concerned with the exact path to the python command or script file, or with arguments, but that should be a good start. Write a function detect_program_name() to detect this and call it in place of the existing code.
I'll look into this!
One more note, there is Windows-specific behavior here, so remember to test the fix against the different cases listed above on both Linux/Mac and Windows.
Here's a simple project to test out the commands with. example.tar.gz
$ tar xf example.tar.gz
$ cd example
$ python3 -m venv venv
$ . venv/bin/activate
$ pip install -e ../click # wherever your click repo is
$ pip install -e .
Now you can do different commands and changes you make to your click repo will be reflected. The command echos the detected program name.
$ python -m example
$ python -m example.cli
$ example
$ python single.py
$ python -m single
I'll look into this!
One more note, there is Windows-specific behavior here, so remember to test the fix against the different cases listed above on both Linux/Mac and Windows.
I was reading the issue and saw that there may be a need for testing on windows. If you need someone with a windows machine, let me know. I know a lot of people use linux/mac.
@ovezovs thanks! @kbanc set up a windows VM and got it done :)
Most helpful comment
Here's a simple project to test out the commands with. example.tar.gz
Now you can do different commands and changes you make to your click repo will be reflected. The command echos the detected program name.