Issue45580
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2021-10-22 19:31 by AbcSxyZ, last changed 2022-04-11 14:59 by admin.
Messages (4) | |||
---|---|---|---|
msg404815 - (view) | Author: AbcSxyZ (AbcSxyZ) | Date: 2021-10-22 19:31 | |
Hi, I'm getting a kind of undefined behavior where parenthesis seem handled in a strange way. On display, it has a conflict between parenthesis of the option, and nested parenthesis within a metavar. ## Reproduction script ``` import argparse def main(): parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument("-p", "--path", metavar="/var/www/html", help="DocumentRoot path") group.add_argument("-r", "--reverse", metavar="http)s(://Host:Port", help="Reverse proxy address") parser.add_argument("--last-args") return parser.parse_args() main() ``` ## Output of help menu ``` usage: crash.py [-h] (-p /var/www/html | -r http)s://Host:Port [--last-args LAST_ARGS] ``` ## Expected behavior ``` usage: crash.py [-h] (-p /var/www/html | -r http)s(://Host:Port) [--last-args LAST_ARGS] ``` |
|||
msg404891 - (view) | Author: Nikita Sobolev (sobolevn) * | Date: 2021-10-23 16:11 | |
I confirm this happens on all recent Python versions. The source of this problem is that `argparse` uses `regex` module to replace some substrings. Direct link: https://github.com/python/cpython/blame/8ce20bbdd6d2b1277a5e74154fcdcef2cb0fee49/Lib/argparse.py#L487 Quick debug showed that without this line these tests fail: ``` ====================================================================== FAIL: test_help_when_required (test.test_argparse.TestMutuallyExclusiveFirstSuppressed) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/sobolev/Desktop/cpython/Lib/test/test_argparse.py", line 2649, in test_help_when_required self.assertEqual(format_help(), textwrap.dedent(help)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError: 'usage: PROG [-h] (-y)\n\noptions:\n -h, --help show this[42 chars]lp\n' != 'usage: PROG [-h] -y\n\noptions:\n -h, --help show this h[40 chars]lp\n' - usage: PROG [-h] (-y) ? - - + usage: PROG [-h] -y options: -h, --help show this help message and exit -y y help ====================================================================== FAIL: test_usage_when_required (test.test_argparse.TestMutuallyExclusiveFirstSuppressed) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/sobolev/Desktop/cpython/Lib/test/test_argparse.py", line 2639, in test_usage_when_required self.assertEqual(format_usage(), textwrap.dedent(expected_usage)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError: 'usage: PROG [-h] (-y)\n' != 'usage: PROG [-h] -y\n' - usage: PROG [-h] (-y) ? - - + usage: PROG [-h] -y ====================================================================== FAIL: test_help_when_required (test.test_argparse.TestMutuallyExclusiveFirstSuppressedParent) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/sobolev/Desktop/cpython/Lib/test/test_argparse.py", line 2649, in test_help_when_required self.assertEqual(format_help(), textwrap.dedent(help)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError: 'usage: PROG [-h] (-y)\n\noptions:\n -h, --help show this[42 chars]lp\n' != 'usage: PROG [-h] -y\n\noptions:\n -h, --help show this h[40 chars]lp\n' - usage: PROG [-h] (-y) ? - - + usage: PROG [-h] -y options: -h, --help show this help message and exit -y y help ====================================================================== FAIL: test_usage_when_required (test.test_argparse.TestMutuallyExclusiveFirstSuppressedParent) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/sobolev/Desktop/cpython/Lib/test/test_argparse.py", line 2639, in test_usage_when_required self.assertEqual(format_usage(), textwrap.dedent(expected_usage)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError: 'usage: PROG [-h] (-y)\n' != 'usage: PROG [-h] -y\n' - usage: PROG [-h] (-y) ? - - + usage: PROG [-h] -y ---------------------------------------------------------------------- Ran 1672 tests in 23.258s FAILED (failures=4) test test_argparse failed test_argparse failed (4 failures) == Tests result: FAILURE == 1 test failed: test_argparse Total duration: 25.6 sec Tests result: FAILURE ``` |
|||
msg404893 - (view) | Author: Nikita Sobolev (sobolevn) * | Date: 2021-10-23 16:25 | |
Maybe instead we can show users something like: ``` usage: ex.py [-h] (-p '/var/www/html' | -r 'http)s(://Host:Port') [--last-args LAST_ARGS] ``` ? |
|||
msg404981 - (view) | Author: paul j3 (paul.j3) * | Date: 2021-10-25 16:32 | |
The usage formatting is fragile, with many associated bug reports. Until someone does a major rewrite, it is best to avoid special characters, especially `()` and `[]` in the `dest` or `metavar`. Usage uses () to encolde mutually_exclusive_groups and [] to mark non-required arguments. Don't confuse your users (or argparse) with other uses of these characters. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:51 | admin | set | github: 89743 |
2021-10-25 16:32:34 | paul.j3 | set | nosy:
+ paul.j3 messages: + msg404981 |
2021-10-23 16:25:01 | sobolevn | set | type: behavior messages: + msg404893 components: + Library (Lib), - Parser versions: + Python 3.10, Python 3.11 |
2021-10-23 16:11:02 | sobolevn | set | nosy:
+ sobolevn messages: + msg404891 |
2021-10-22 19:31:30 | AbcSxyZ | create |