Skip to content

Commit e2d40fd

Browse files
committed
Add more tests
Add comment to _PyOS_GetOpt().
1 parent c214dde commit e2d40fd

4 files changed

Lines changed: 47 additions & 5 deletions

File tree

‎Lib/test/test_cmd_line.py‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,26 @@ def check_ignored(option):
14581458

14591459
# -c, -h, -m, -V and -? are tested elsewhere
14601460

1461+
def test_unknown_options(self):
1462+
for option in ('-a', '--long-option'):
1463+
with self.subTest(option=option):
1464+
proc = assert_python_failure(option)
1465+
errmsg = f'Unknown option: {option}'
1466+
self.assertStartsWith(proc.err.rstrip(), errmsg.encode())
1467+
1468+
def test_missing_argument(self):
1469+
def check_missing_arg(option):
1470+
proc = assert_python_failure(option)
1471+
self.assertEqual(proc.rc, 2)
1472+
errmsg = f"Argument expected for the {option} option"
1473+
self.assertStartsWith(proc.err.rstrip(), errmsg.encode())
1474+
1475+
check_missing_arg('-c')
1476+
check_missing_arg('-m')
1477+
check_missing_arg('-W')
1478+
check_missing_arg('-X')
1479+
check_missing_arg('--check-hash-based-pycs')
1480+
14611481
def test_long_options(self):
14621482
# Test long command line options
14631483

@@ -1469,8 +1489,17 @@ def test_long_options(self):
14691489
proc = assert_python_ok(opt, value, "-c", code)
14701490
self.assertEqual(proc.out.rstrip(), value.encode())
14711491

1472-
# Other long options --help-all, --help-env and --help-xoptions
1473-
# are tested elsewhere
1492+
# Other long options --help-all, --help-env, --help-xoptions
1493+
# and --version are tested elsewhere
1494+
1495+
def test_dash_option(self):
1496+
# Test -- in the command line
1497+
code = (
1498+
'import sys; '
1499+
'print(sys.flags.isolated, sys.flags.optimize, sys.argv)'
1500+
)
1501+
proc = assert_python_ok('-I', '-c', code, '--', '-O')
1502+
self.assertEqual(proc.out.rstrip(), b"1 0 ['-c', '--', '-O']")
14741503

14751504

14761505
@unittest.skipIf(interpreter_requires_environment(),

‎Python/getopt.c‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ _PyOS_GetOpt_Init(struct _PyOS_GetOpt *getopt,
6262
getopt->argv = argv;
6363
}
6464

65+
// Parse a command line option.
66+
//
67+
// Return a character for short option (ex: return 'h' for -h).
68+
// Return a number for long options (see 'longopts' array).
69+
// Return '_' on unknown option or missing argument.
70+
// Return -1 when done.
71+
//
72+
// Return 'h' for --help and return 'V' for --version.
73+
//
74+
// If an option has an argument, set getopt->arg to the argument.
75+
// If getopt->error is non-error, write error messages to stderr.
6576
int
6677
_PyOS_GetOpt(struct _PyOS_GetOpt *getopt)
6778
{

‎Python/initconfig.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3013,7 +3013,7 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
30133013
_PyOS_GetOpt_Init(&getopt, argv->length, argv->items);
30143014
do {
30153015
int c = _PyOS_GetOpt(&getopt);
3016-
if (c == EOF) {
3016+
if (c == -1) {
30173017
break;
30183018
}
30193019

@@ -3257,6 +3257,9 @@ _PyConfig_ProcessDeferredCmdlineOption(PyConfig *config)
32573257
config_xoptions_usage();
32583258
return 0;
32593259

3260+
case '_':
3261+
// Unknown option or missing argument
3262+
_Py_FALLTHROUGH;
32603263
default:
32613264
config_usage(1, program);
32623265
return 2;

‎Python/preconfig.c‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ precmdline_parse_cmdline(_PyPreCmdline *cmdline)
194194
getopt.error = 0;
195195
do {
196196
int c = _PyOS_GetOpt(&getopt);
197-
198-
if (c == EOF || c == 'c' || c == 'm') {
197+
if (c == -1 || c == 'c' || c == 'm') {
199198
break;
200199
}
201200

0 commit comments

Comments
 (0)