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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy