8000 bpo-40527: Fix command line argument parsing (GH-19955) · python/cpython@2668a9a · GitHub
[go: up one dir, main page]

Skip to content

Commit 2668a9a

Browse files
authored
bpo-40527: Fix command line argument parsing (GH-19955)
1 parent eff870b commit 2668a9a

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

Lib/test/test_cmd_line.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,17 @@ def test_argv0_normalization(self):
756756
self.assertEqual(proc.returncode, 0, proc)
757757
self.assertEqual(proc.stdout.strip(), b'0')
758758

759+
def test_parsing_error(self):
760+
args = [sys.executable, '-I', '--unknown-option']
761+
proc = subprocess.run(args,
762+
stdout=subprocess.PIPE,
763+
stderr=subprocess.PIPE,
764+
text=True)
765+
err_msg = "unknown option --unknown-option\nusage: "
766+
self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr)
767+
self.assertNotEqual(proc.returncode, 0)
768+
769+
759770
@unittest.skipIf(interpreter_requires_environment(),
760771
'Cannot run -I tests when PYTHON env vars are required.')
761772
class IgnoreEnvironmentTest(unittest.TestCase):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix command line argument parsing: no longer write errors multiple times
2+
into stderr.

Python/getopt.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
101101
if (option == L'-') {
102102
// Parse long option.
103103
if (*opt_ptr == L'\0') {
104-
fprintf(stderr, "expected long option\n");
104+
if (_PyOS_opterr) {
105+
fprintf(stderr, "expected long option\n");
106+
}
105107
return -1;
106108
}
107109
*longindex = 0;
@@ -111,31 +113,37 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
111113
break;
112114
}
113115
if (!opt->name) {
114-
fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]);
116+
if (_PyOS_opterr) {
117+
fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]);
118+
}
115119
return '_';
116120
}
117121
opt_ptr = L"";
118122
if (!opt->has_arg) {
119123
return opt->val;
120124
}
121125
if (_PyOS_optind >= argc) {
122-
fprintf(stderr, "Argument expected for the %ls options\n",
123-
argv[_PyOS_optind - 1]);
126+
if (_PyOS_opterr) {
127+
fprintf(stderr, "Argument expected for the %ls options\n",
128+
argv[_PyOS_optind - 1]);
129+
}
124130
return '_';
125131
}
126132
_PyOS_optarg = argv[_PyOS_optind++];
127133
return opt->val;
128134
}
129135

130136
if (option == 'J') {
131-
if (_PyOS_opterr)
137+
if (_PyOS_opterr) {
132138
fprintf(stderr, "-J is reserved for Jython\n");
139+
}
133140
return '_';
134141
}
135142

136143
if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) {
137-
if (_PyOS_opterr)
144+
if (_PyOS_opterr) {
138145
fprintf(stderr, "Unknown option: -%c\n", (char)option);
146+
}
139147
return '_';
140148
}
141149

@@ -147,9 +155,10 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
147155

148156
else {
149157
if (_PyOS_optind >= argc) {
150-
if (_PyOS_opterr)
158+
if (_PyOS_opterr) {
151159
fprintf(stderr,
152160
"Argument expected for the -%c option\n", (char)option);
161+
}
153162
return '_';
154163
}
155164

0 commit comments

Comments
 (0)
0