|
14 | 14 | from test import support |
15 | 15 | from test.support import os_helper |
16 | 16 | from test.support import force_not_colorized |
| 17 | +from test.support import import_helper |
17 | 18 | from test.support import threading_helper |
18 | 19 | from test.support.script_helper import ( |
19 | 20 | spawn_python, kill_python, assert_python_ok, assert_python_failure, |
@@ -60,14 +61,17 @@ def verify_valid_flag(self, cmd_line): |
60 | 61 | @support.cpython_only |
61 | 62 | @support.force_not_colorized |
62 | 63 | def test_help(self): |
63 | | - self.verify_valid_flag('-h') |
64 | | - self.verify_valid_flag('-?') |
65 | | - out = self.verify_valid_flag('--help') |
66 | | - lines = out.splitlines() |
67 | | - self.assertIn(b'usage', lines[0]) |
68 | | - self.assertNotIn(b'PYTHONHOME', out) |
69 | | - self.assertNotIn(b'-X dev', out) |
70 | | - self.assertLess(len(lines), 50) |
| 64 | + options = ['-h', '-?', '--help'] |
| 65 | + if support.MS_WINDOWS: |
| 66 | + options.append('/?') |
| 67 | + for opt in options: |
| 68 | + with self.subTest(opt=opt): |
| 69 | + out = self.verify_valid_flag(opt) |
| 70 | + lines = out.splitlines() |
| 71 | + self.assertIn(b'usage', lines[0]) |
| 72 | + self.assertNotIn(b'PYTHONHOME', out) |
| 73 | + self.assertNotIn(b'-X dev', out) |
| 74 | + self.assertLess(len(lines), 50) |
71 | 75 |
|
72 | 76 | @support.cpython_only |
73 | 77 | @support.force_not_colorized |
@@ -680,16 +684,22 @@ def test_del___main__(self): |
680 | 684 |
|
681 | 685 | @support.cpython_only |
682 | 686 | def test_unknown_options(self): |
683 | | - rc, out, err = assert_python_failure('-E', '-z') |
684 | | - self.assertIn(b'Unknown option: -z', err) |
685 | | - self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) |
686 | | - self.assertEqual(b'', out) |
| 687 | + # Test unknown option -a |
| 688 | + for option in ('-z', '--long-option', '---'): |
| 689 | + with self.subTest(option=option): |
| 690 | + rc, out, err = assert_python_failure('-E', option) |
| 691 | + errmsg = f'Unknown option: {option}'.encode() |
| 692 | + self.assertIn(errmsg, err) |
| 693 | + self.assertEqual(err.splitlines().count(errmsg), 1) |
| 694 | + self.assertEqual(b'', out) |
| 695 | + |
687 | 696 | # Add "without='-E'" to prevent _assert_python to append -E |
688 | 697 | # to env_vars and change the output of stderr |
689 | 698 | rc, out, err = assert_python_failure('-z', without='-E') |
690 | 699 | self.assertIn(b'Unknown option: -z', err) |
691 | 700 | self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) |
692 | 701 | self.assertEqual(b'', out) |
| 702 | + |
693 | 703 | rc, out, err = assert_python_failure('-a', '-z', without='-E') |
694 | 704 | self.assertIn(b'Unknown option: -a', err) |
695 | 705 | # only the first unknown option is reported |
@@ -1403,6 +1413,97 @@ def test_dump_path_config(self): |
1403 | 1413 | self.assertIn(b'Python path configuration:', proc.err) |
1404 | 1414 | self.assertIn(f"PYTHONHOME = '{nonexistent}'".encode(), proc.err) |
1405 | 1415 |
|
| 1416 | + def test_short_options(self): |
| 1417 | + # Skip the test if _testcapi cannot be imported: |
| 1418 | + # the test uses _testcapi.config_get(). |
| 1419 | + import_helper.import_module('_testcapi') |
| 1420 | + |
| 1421 | + # Test short command line options |
| 1422 | + def check(options, config_names, expected): |
| 1423 | + if isinstance(config_names, str): |
| 1424 | + config_names = (config_names,) |
| 1425 | + if isinstance(options, str): |
| 1426 | + options = (options,) |
| 1427 | + expr = ', '.join(f'config_get({name!a})' for name in config_names) |
| 1428 | + code = f'from _testcapi import config_get; print({expr})' |
| 1429 | + args = options + ("-c", code) |
| 1430 | + proc = assert_python_ok(*args) |
| 1431 | + self.assertEqual(proc.out.rstrip(), expected.encode()) |
| 1432 | + |
| 1433 | + def check_ignored(option): |
| 1434 | + # Just test that passing the option doesn't fail |
| 1435 | + assert_python_ok(option, "-c", "pass") |
| 1436 | + |
| 1437 | + check('-b', 'bytes_warning', '1') |
| 1438 | + check('-bb', 'bytes_warning', '2') |
| 1439 | + check('-B', 'write_bytecode', 'False') |
| 1440 | + check('-d', 'parser_debug', 'True') |
| 1441 | + check('-E', 'use_environment', 'False') |
| 1442 | + check('-i', ('inspect', 'interactive'), 'True True') |
| 1443 | + check('-I', 'isolated', 'True') |
| 1444 | + check('-O', 'optimization_level', '1') |
| 1445 | + check('-OO', 'optimization_level', '2') |
| 1446 | + check('-P', 'safe_path', 'True') |
| 1447 | + check('-q', 'quiet', 'True') |
| 1448 | + check('-R', 'use_hash_seed', 'False') |
| 1449 | + check('-s', 'user_site_directory', 'False') |
| 1450 | + check('-S', 'site_import', 'False') |
| 1451 | + check_ignored('-t') |
| 1452 | + check('-u', 'buffered_stdio', 'False') |
| 1453 | + check('-v', 'verbose', '1') |
| 1454 | + check('-Wignore', 'warnoptions', "['ignore']") |
| 1455 | + check('-x', 'skip_source_first_line', 'True') |
| 1456 | + check(('-X', 'xoption=value'), 'xoptions', |
| 1457 | + # assert_python_ok() adds -X faulthandler |
| 1458 | + "{'faulthandler': True, 'xoption': 'value'}") |
| 1459 | + |
| 1460 | + # Short options can be combined |
| 1461 | + check('-bIs', ('bytes_warning', 'isolated', 'user_site_directory'), |
| 1462 | + '1 True False') |
| 1463 | + |
| 1464 | + # -c, -h, -m, -V and -? are tested elsewhere |
| 1465 | + |
| 1466 | + def test_missing_argument(self): |
| 1467 | + def check_missing_arg(option): |
| 1468 | + proc = assert_python_failure(option) |
| 1469 | + self.assertEqual(proc.rc, 2) |
| 1470 | + errmsg = f"Argument expected for the {option} option" |
| 1471 | + self.assertStartsWith(proc.err.rstrip(), errmsg.encode()) |
| 1472 | + |
| 1473 | + check_missing_arg('-c') |
| 1474 | + check_missing_arg('-m') |
| 1475 | + check_missing_arg('-W') |
| 1476 | + check_missing_arg('-X') |
| 1477 | + check_missing_arg('--check-hash-based-pycs') |
| 1478 | + |
| 1479 | + def test_long_options(self): |
| 1480 | + # Test long command line options |
| 1481 | + |
| 1482 | + # Test --check-hash-based-pycs option |
| 1483 | + code = 'import _imp; print(_imp.check_hash_based_pycs)' |
| 1484 | + opt = f"--check-hash-based-pycs" |
| 1485 | + for value in ('always', 'never', 'default'): |
| 1486 | + with self.subTest(value=value): |
| 1487 | + proc = assert_python_ok(opt, value, "-c", code) |
| 1488 | + self.assertEqual(proc.out.rstrip(), value.encode()) |
| 1489 | + |
| 1490 | + # "Expected long option" error |
| 1491 | + proc = assert_python_ok("-b-") |
| 1492 | + self.assertEqual(proc.out, b'') |
| 1493 | + self.assertEqual(proc.err.rstrip(), b"Expected long option") |
| 1494 | + |
| 1495 | + # Other long options --help-all, --help-env, --help-xoptions |
| 1496 | + # and --version are tested elsewhere |
| 1497 | + |
| 1498 | + def test_dash_option(self): |
| 1499 | + # Test -- in the command line |
| 1500 | + code = ( |
| 1501 | + 'import sys; ' |
| 1502 | + 'print(sys.flags.isolated, sys.flags.optimize, sys.argv)' |
| 1503 | + ) |
| 1504 | + proc = assert_python_ok('-I', '-c', code, '--', '-O') |
| 1505 | + self.assertEqual(proc.out.rstrip(), b"1 0 ['-c', '--', '-O']") |
| 1506 | + |
1406 | 1507 |
|
1407 | 1508 | @unittest.skipIf(interpreter_requires_environment(), |
1408 | 1509 | 'Cannot run -I tests when PYTHON env vars are required.') |
|
0 commit comments