-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
argparse support for "python -m module" in help #66436
Comments
"python -m module -h" starts with It should be |
I suspect resolving this will actually need special casing on the argparse side - __main__.__spec__ will have the original details for __main__ when executed via -m of zipfile/directory execution. Things to check for:
In the latter two cases, sys.executable can be used to figure out what to put before the "-m" (we don't expose the raw C level argv to Python, although there is an open RFE to do so somewhere on the tracker). |
For zip file the help should probably be: |
New patch with handling of zip files. |
The patch tests assume the test is being run in a particular way:
But I often use
or
both of which fail these tests. Testing this change might be more difficult than implementing it. |
What if the package is run without |
Made the test more robust by using sys.executable in the comparison. |
How can you run a package without -m? |
Package might be the wrong term. How about a directory with a |
If you have: <curdir> Then in 3.3+, both of the following will work:
They do slightly different things, though. In the first case, "subdir" will be added to sys.path, and then python will execute the equivalent of "python3 -m __main__" In the second case, the current directory will be added to sys.path, and python will execute the equivalent of "python3 -m subdir.__main__" The first case is the directory execution support that was added way back in Python 2.6. The second case is a combination of the package execution support added in Python 2.7/3.1 and the implicit namespace packages support that was added in Python 3.3. Interesting find - the possibility of the latter situation hadn't occurred to me before :) |
Support for directory invocation as well. |
Anything else I need to solve to get this patch accepted? |
When I apply
I get 2 failures, both over 'usage: python3 -m [unit]test'. It also fails with
I suspect it would also fail if I ran the tests with |
In argparse.py, I would put a utility function like In test_argparse.py, I don't see the purpose of the Most tests for 'usage' and 'help', use 'prog="PROG"' to get around the various ways that the tests can be run. I don't see what TestParentParsers gains by not doing the same. The 'prog' attribute has nothing to do with 'parents', at least not that I can tell. I think a patch like this needs a new test(s), one that fails with existing code, and run fine with the patch. It also needs to work with almost any method of running the tests. But writing such a test might be lot harder than writing the fix, since it involves system issues, and possibly mocking a package and a zip file. Nick's suggestion regarding '__spec__' also needs to be considered. It is an area of active development. I'm not sure that 'argparse' should be getting into these details regarding how the script is invoked and/or packaged. Finally, does this patch accomplish anything that the user can't do by directly setting the 'prog' attribute? The user could even use a function like '_prog_name' to create that name on the fly. 'unittest.__main__' is an example of a package that gets around this '__main__' problem by redefining 'sys.argv[0]' before invoking the parser (optparse). 'Nose' also does this. |
Thanks Paul, will work on that. |
One way to reduce the testing burden, and to be extra safe regarding backward compatibility is to make this action optional, rather than the default. For example, make parser = argparse.ArgumentParser(prog=argparse.prog_name(), ...) and leave the This would require an addition to the documentation. The user can then check for themselves whether The added tests, if any, can focus on the output of this function, rather than the output of the 'print_help'. |
I don't like changing code just to accommodate testing. Will try to think of a way to solve this. |
Until this is accepted, I've modified my codebase:
|
See https://bugs.python.org/msg353987 for manual test |
I am not sure if the patch correctly handles calling a nested module (e.g. |
I expanded the patch from tebeka to also work with invocations like However due to the import of zipfile which itself imports binascii the build of CPython itself fails at the
I guess this is because binascii is a c module and not yet build at that point in time. Does anyone who knows more about the build system have an idea how to resolve this? --- Resolving this bug would also allow the removal of several workarounds for this in the stdlib:
|
(Note: this is an old enough ticket that it started out with patch files on the tracker rather than PRs on GitHub. That's just a historical artifact, so feel free to open a PR as described in the devguide if you would prefer to work that way) There are two common ways of solving import bootstrapping problems that affect the build process:
However, I think in this case it should be possible to avoid the zipfile dependency entirely, and instead make the determination based on the contents of __main__ and __main__.__spec__ using the suggestions I noted in an earlier comment (see https://docs.python.org/3/library/importlib.html#importlib.machinery.ModuleSpec for the info the module spec makes available). This should also solve a problem I believe the current patch has, where I think directory execution will give the wrong result (returning "python -m __main__" as the answer instead of the path to the directory containing the __main__.py file). The three cases to cover come from https://docs.python.org/3/using/cmdline.html#interface-options:
The patch gets the three potential results right, but it gets the check for the second case wrong by looking specifically for zipfiles instead of looking at the contents of __main__.__spec__ and seeing if it refers to a __main__.py file located inside the sys.argv[0] path (which may be a directory, zipfile, or any other valid sys.path entry). For writing robust automated tests, I'd suggest either looking at test.support.script_helper for programmatic creation of executable zipfiles and directories ( cpython/Lib/test/support/script_helper.py Line 209 in 208a7e9
The latter approach would require some up front manual testing to ensure the behaviour of the different scenarios was being emulated correctly, but would execute a lot faster than actually running subprocesses would. |
I implemented the logic and adjusted the existing tests to have a fixed program name. I also fixed the build error by changing how zip files are detected. Based on you comment Nick you however even had a different idea. Currently I check if __spec__.__loader__ is a zip loader but if I understood correct you suggest the check if __spec__.__location__ is a proper subdir of sys.argv[0]? septatrix/cpython@main...septatrix:enhance/argparse-prog-name. When I have some more time I will check whether mocking works and otherwise checkout test.support.script_helper or making the function accept spec/argv0 |
It can now have one of three forms: * basename(argv0) -- for simple scripts * python arv0 -- for directories, ZIP files, etc * python -m module -- for imported modules
#124799 mostly implements @ncoghlan's algorithm from #66436 (comment) and adds tests and documentation. @ncoghlan, I would appreciate your review of the documentation, as it is difficult to me. Feel free to rewrite it completely. |
It can now have one of three forms: * basename(argv0) -- for simple scripts * python arv0 -- for directories, ZIP files, etc * python -m module -- for imported modules
It looks to me that testing |
…-124799) It can now have one of three forms: * basename(argv0) -- for simple scripts * python arv0 -- for directories, ZIP files, etc * python -m module -- for imported modules Co-authored-by: Alyssa Coghlan <[email protected]>
python -m
syntax in argument parser ouptutNote: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: