summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-05-06 13:22:17 (GMT)
committerGitHub <noreply@github.com>2020-05-06 13:22:17 (GMT)
commit2668a9a5aa506a048aef7b4881c8dcf6b81c6870 (patch)
tree114505d2feded932eae50177d9a705269784762d
parenteff870b618ca6f6b7a60a271f15af7e54b8a1b97 (diff)
downloadcpython-2668a9a5aa506a048aef7b4881c8dcf6b81c6870.zip
cpython-2668a9a5aa506a048aef7b4881c8dcf6b81c6870.tar.gz
cpython-2668a9a5aa506a048aef7b4881c8dcf6b81c6870.tar.bz2
bpo-40527: Fix command line argument parsing (GH-19955)
-rw-r--r--Lib/test/test_cmd_line.py11
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst2
-rw-r--r--Python/getopt.c23
3 files changed, 29 insertions, 7 deletions
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index ee96473..7244025 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -756,6 +756,17 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.returncode, 0, proc)
self.assertEqual(proc.stdout.strip(), b'0')
+ def test_parsing_error(self):
+ args = [sys.executable, '-I', '--unknown-option']
+ proc = subprocess.run(args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True)
+ err_msg = "unknown option --unknown-option\nusage: "
+ self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr)
+ self.assertNotEqual(proc.returncode, 0)
+
+
@unittest.skipIf(interpreter_requires_environment(),
'Cannot run -I tests when PYTHON env vars are required.')
class IgnoreEnvironmentTest(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst
new file mode 100644
index 0000000..19b8888
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-05-06-14-52-35.bpo-40527.gTNKuy.rst
@@ -0,0 +1,2 @@
+Fix command line argument parsing: no longer write errors multiple times
+into stderr.
diff --git a/Python/getopt.c b/Python/getopt.c
index 708d9ce..2e3891a 100644
--- a/Python/getopt.c
+++ b/Python/getopt.c
@@ -101,7 +101,9 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
if (option == L'-') {
// Parse long option.
if (*opt_ptr == L'\0') {
- fprintf(stderr, "expected long option\n");
+ if (_PyOS_opterr) {
+ fprintf(stderr, "expected long option\n");
+ }
return -1;
}
*longindex = 0;
@@ -111,7 +113,9 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
break;
}
if (!opt->name) {
- fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]);
+ if (_PyOS_opterr) {
+ fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]);
+ }
return '_';
}
opt_ptr = L"";
@@ -119,8 +123,10 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
return opt->val;
}
if (_PyOS_optind >= argc) {
- fprintf(stderr, "Argument expected for the %ls options\n",
- argv[_PyOS_optind - 1]);
+ if (_PyOS_opterr) {
+ fprintf(stderr, "Argument expected for the %ls options\n",
+ argv[_PyOS_optind - 1]);
+ }
return '_';
}
_PyOS_optarg = argv[_PyOS_optind++];
@@ -128,14 +134,16 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
}
if (option == 'J') {
- if (_PyOS_opterr)
+ if (_PyOS_opterr) {
fprintf(stderr, "-J is reserved for Jython\n");
+ }
return '_';
}
if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) {
- if (_PyOS_opterr)
+ if (_PyOS_opterr) {
fprintf(stderr, "Unknown option: -%c\n", (char)option);
+ }
return '_';
}
@@ -147,9 +155,10 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
else {
if (_PyOS_optind >= argc) {
- if (_PyOS_opterr)
+ if (_PyOS_opterr) {
fprintf(stderr,
"Argument expected for the -%c option\n", (char)option);
+ }
return '_';
}