Skip to content

Commit f39f103

Browse files
authored
Merge pull request #4801 from Masorubka1/test_cmd_line
Update test_cmd_line from Cpython v3.11.2
2 parents dde92d1 + cf06c25 commit f39f103

File tree

1 file changed

+176
-31
lines changed

1 file changed

+176
-31
lines changed

Lib/test/test_cmd_line.py

+176-31
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
import subprocess
77
import sys
88
import tempfile
9+
import textwrap
910
import unittest
1011
from test import support
12+
from test.support import os_helper
1113
from test.support.script_helper import (
1214
spawn_python, kill_python, assert_python_ok, assert_python_failure,
1315
interpreter_requires_environment
1416
)
15-
from test.support import os_helper
1617

18+
if not support.has_subprocess_support:
19+
raise unittest.SkipTest("test module requires subprocess")
1720

1821
# Debug build?
1922
Py_DEBUG = hasattr(sys, "gettotalrefcount")
@@ -25,38 +28,63 @@ def _kill_python_and_exit_code(p):
2528
returncode = p.wait()
2629
return data, returncode
2730

31+
2832
class CmdLineTest(unittest.TestCase):
2933
def test_directories(self):
3034
assert_python_failure('.')
3135
assert_python_failure('< .')
3236

3337
def verify_valid_flag(self, cmd_line):
34-
rc, out, err = assert_python_ok(*cmd_line)
38+
rc, out, err = assert_python_ok(cmd_line)
3539
self.assertTrue(out == b'' or out.endswith(b'\n'))
3640
self.assertNotIn(b'Traceback', out)
3741
self.assertNotIn(b'Traceback', err)
42+
return out
3843

3944
# TODO: RUSTPYTHON
4045
@unittest.expectedFailure
41-
def test_optimize(self):
42-
self.verify_valid_flag('-O')
43-
self.verify_valid_flag('-OO')
46+
def test_help(self):
47+
self.verify_valid_flag('-h')
48+
self.verify_valid_flag('-?')
49+
out = self.verify_valid_flag('--help')
50+
lines = out.splitlines()
51+
self.assertIn(b'usage', lines[0])
52+
self.assertNotIn(b'PYTHONHOME', out)
53+
self.assertNotIn(b'-X dev', out)
54+
self.assertLess(len(lines), 50)
4455

4556
# TODO: RUSTPYTHON
4657
@unittest.expectedFailure
47-
def test_site_flag(self):
48-
self.verify_valid_flag('-S')
58+
def test_help_env(self):
59+
out = self.verify_valid_flag('--help-env')
60+
self.assertIn(b'PYTHONHOME', out)
61+
62+
# TODO: RUSTPYTHON
63+
@unittest.expectedFailure
64+
def test_help_xoptions(self):
65+
out = self.verify_valid_flag('--help-xoptions')
66+
self.assertIn(b'-X dev', out)
4967

5068
# TODO: RUSTPYTHON
5169
@unittest.expectedFailure
52-
def test_usage(self):
53-
rc, out, err = assert_python_ok('-h')
70+
def test_help_all(self):
71+
out = self.verify_valid_flag('--help-all')
5472
lines = out.splitlines()
5573
self.assertIn(b'usage', lines[0])
74+
self.assertIn(b'PYTHONHOME', out)
75+
self.assertIn(b'-X dev', out)
76+
5677
# The first line contains the program name,
5778
# but the rest should be ASCII-only
5879
b''.join(lines[1:]).decode('ascii')
5980

81+
def test_optimize(self):
82+
self.verify_valid_flag('-O')
83+
self.verify_valid_flag('-OO')
84+
85+
def test_site_flag(self):
86+
self.verify_valid_flag('-S')
87+
6088
# NOTE: RUSTPYTHON version never starts with Python
6189
@unittest.expectedFailure
6290
def test_version(self):
@@ -114,13 +142,32 @@ def run_python(*args):
114142
self.assertEqual(out.rstrip(), b'{}')
115143
self.assertEqual(err, b'')
116144
# "-X showrefcount" shows the refcount, but only in debug builds
117-
rc, out, err = run_python('-X', 'showrefcount', '-c', code)
145+
rc, out, err = run_python('-I', '-X', 'showrefcount', '-c', code)
118146
self.assertEqual(out.rstrip(), b"{'showrefcount': True}")
119147
if Py_DEBUG:
120-
self.assertRegex(err, br'^\[\d+ refs, \d+ blocks\]')
148+
# bpo-46417: Tolerate negative reference count which can occur
149+
# because of bugs in C extensions. This test is only about checking
150+
# the showrefcount feature.
151+
self.assertRegex(err, br'^\[-?\d+ refs, \d+ blocks\]')
121152
else:
122153
self.assertEqual(err, b'')
123154

155+
# TODO: RUSTPYTHON
156+
@unittest.expectedFailure
157+
def test_xoption_frozen_modules(self):
158+
tests = {
159+
('=on', 'FrozenImporter'),
160+
('=off', 'SourceFileLoader'),
161+
('=', 'FrozenImporter'),
162+
('', 'FrozenImporter'),
163+
}
164+
for raw, expected in tests:
165+
cmd = ['-X', f'frozen_modules{raw}',
166+
'-c', 'import os; print(os.__spec__.loader, end="")']
167+
with self.subTest(raw):
168+
res = assert_python_ok(*cmd)
169+
self.assertRegex(res.out.decode('utf-8'), expected)
170+
124171
def test_run_module(self):
125172
# Test expected operation of the '-m' switch
126173
# Switch needs an argument
@@ -146,6 +193,16 @@ def test_run_module_bug1764407(self):
146193
self.assertTrue(data.find(b'1 loop') != -1)
147194
self.assertTrue(data.find(b'__main__.Timer') != -1)
148195

196+
def test_relativedir_bug46421(self):
197+
# Test `python -m unittest` with a relative directory beginning with ./
198+
# Note: We have to switch to the project's top module's directory, as per
199+
# the python unittest wiki. We will switch back when we are done.
200+
projectlibpath = os.path.dirname(__file__).removesuffix("test")
201+
with os_helper.change_cwd(projectlibpath):
202+
# Testing with and without ./
203+
assert_python_ok('-m', 'unittest', "test/test_longexp.py")
204+
assert_python_ok('-m', 'unittest', "./test/test_longexp.py")
205+
149206
def test_run_code(self):
150207
# Test expected operation of the '-c' switch
151208
# Switch needs an argument
@@ -162,6 +219,14 @@ def test_non_ascii(self):
162219
% (os_helper.FS_NONASCII, ord(os_helper.FS_NONASCII)))
163220
assert_python_ok('-c', command)
164221

222+
@unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII')
223+
def test_coding(self):
224+
# bpo-32381: the -c command ignores the coding cookie
225+
ch = os_helper.FS_NONASCII
226+
cmd = f"# coding: latin1\nprint(ascii('{ch}'))"
227+
res = assert_python_ok('-c', cmd)
228+
self.assertEqual(res.out.rstrip(), ascii(ch).encode('ascii'))
229+
165230
# On Windows, pass bytes to subprocess doesn't test how Python decodes the
166231
# command line, but how subprocess does decode bytes to unicode. Python
167232
# doesn't decode the command line because Windows provides directly the
@@ -179,7 +244,7 @@ def test_undecodable_code(self):
179244
code = (
180245
b'import locale; '
181246
b'print(ascii("' + undecodable + b'"), '
182-
b'locale.getpreferredencoding())')
247+
b'locale.getencoding())')
183248
p = subprocess.Popen(
184249
[sys.executable, "-c", code],
185250
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
@@ -214,7 +279,6 @@ def test_invalid_utf8_arg(self):
214279
#
215280
# Test with default config, in the C locale, in the Python UTF-8 Mode.
216281
code = 'import sys, os; s=os.fsencode(sys.argv[1]); print(ascii(s))'
217-
base_cmd = [sys.executable, '-c', code]
218282

219283
# TODO: RUSTPYTHON
220284
@unittest.expectedFailure
@@ -277,6 +341,23 @@ def test_osx_android_utf8(self):
277341
self.assertEqual(stdout, expected)
278342
self.assertEqual(p.returncode, 0)
279343

344+
# TODO: RUSTPYTHON
345+
@unittest.expectedFailure
346+
def test_non_interactive_output_buffering(self):
347+
code = textwrap.dedent("""
348+
import sys
349+
out = sys.stdout
350+
print(out.isatty(), out.write_through, out.line_buffering)
351+
err = sys.stderr
352+
print(err.isatty(), err.write_through, err.line_buffering)
353+
""")
354+
args = [sys.executable, '-c', code]
355+
proc = subprocess.run(args, stdout=subprocess.PIPE,
356+
stderr=subprocess.PIPE, text=True, check=True)
357+
self.assertEqual(proc.stdout,
358+
'False False False\n'
359+
'False False True\n')
360+
280361
# TODO: RUSTPYTHON
281362
@unittest.expectedFailure
282363
def test_unbuffered_output(self):
@@ -320,6 +401,8 @@ def test_large_PYTHONPATH(self):
320401
self.assertIn(path1.encode('ascii'), out)
321402
self.assertIn(path2.encode('ascii'), out)
322403

404+
@unittest.skipIf(sys.flags.safe_path,
405+
'PYTHONSAFEPATH changes default sys.path')
323406
def test_empty_PYTHONPATH_issue16309(self):
324407
# On Posix, it is documented that setting PATH to the
325408
# empty string is equivalent to not setting PATH at all,
@@ -369,23 +452,25 @@ def check_input(self, code, expected):
369452
stdout, stderr = proc.communicate()
370453
self.assertEqual(stdout.rstrip(), expected)
371454

372-
@unittest.skipIf(sys.platform == "win32", "AssertionError: b"'abc\\r'" != b"'abc'"")
455+
# TODO: RUSTPYTHON
456+
@unittest.skipIf(sys.platform.startswith('win'), "TODO: RUSTPYTHON windows has \n troubles")
373457
def test_stdin_readline(self):
374458
# Issue #11272: check that sys.stdin.readline() replaces '\r\n' by '\n'
375459
# on Windows (sys.stdin is opened in binary mode)
376460
self.check_input(
377461
"import sys; print(repr(sys.stdin.readline()))",
378462
b"'abc\\n'")
379463

380-
@unittest.skipIf(sys.platform == "win32", "AssertionError: b"'abc\\r'" != b"'abc'"")
464+
# TODO: RUSTPYTHON
465+
@unittest.skipIf(sys.platform.startswith('win'), "TODO: RUSTPYTHON windows has \n troubles")
381466
def test_builtin_input(self):
382467
# Issue #11272: check that input() strips newlines ('\n' or '\r\n')
383468
self.check_input(
384469
"print(repr(input()))",
385470
b"'abc'")
386471

387472
# TODO: RUSTPYTHON
388-
@unittest.expectedFailure
473+
@unittest.skipIf(sys.platform.startswith('win'), "TODO: RUSTPYTHON windows has \n troubles")
389474
def test_output_newline(self):
390475
# Issue 13119 Newline for print() should be \r\n on Windows.
391476
code = """if 1:
@@ -398,10 +483,10 @@ def test_output_newline(self):
398483

399484
if sys.platform == 'win32':
400485
self.assertEqual(b'1\r\n2\r\n', out)
401-
self.assertEqual(b'3\r\n4', err)
486+
self.assertEqual(b'3\r\n4\r\n', err)
402487
else:
403488
self.assertEqual(b'1\n2\n', out)
404-
self.assertEqual(b'3\n4', err)
489+
self.assertEqual(b'3\n4\n', err)
405490

406491
def test_unmached_quote(self):
407492
# Issue #10206: python program starting with unmatched quote
@@ -459,7 +544,7 @@ def preexec():
459544
stderr=subprocess.PIPE,
460545
preexec_fn=preexec)
461546
out, err = p.communicate()
462-
self.assertEqual(support.strip_python_stderr(err), b'')
547+
self.assertEqual(err, b'')
463548
self.assertEqual(p.returncode, 42)
464549

465550
# TODO: RUSTPYTHON
@@ -527,7 +612,7 @@ def test_del___main__(self):
527612
# the dict whereas the module was destroyed
528613
filename = os_helper.TESTFN
529614
self.addCleanup(os_helper.unlink, filename)
530-
with open(filename, "w") as script:
615+
with open(filename, "w", encoding="utf-8") as script:
531616
print("import sys", file=script)
532617
print("del sys.modules['__main__']", file=script)
533618
assert_python_ok(filename)
@@ -558,24 +643,25 @@ def test_unknown_options(self):
558643
'Cannot run -I tests when PYTHON env vars are required.')
559644
def test_isolatedmode(self):
560645
self.verify_valid_flag('-I')
561-
self.verify_valid_flag('-IEs')
646+
self.verify_valid_flag('-IEPs')
562647
rc, out, err = assert_python_ok('-I', '-c',
563648
'from sys import flags as f; '
564-
'print(f.no_user_site, f.ignore_environment, f.isolated)',
649+
'print(f.no_user_site, f.ignore_environment, f.isolated, f.safe_path)',
565650
# dummyvar to prevent extraneous -E
566651
dummyvar="")
567-
self.assertEqual(out.strip(), b'1 1 1')
652+
self.assertEqual(out.strip(), b'1 1 1 True')
568653
with os_helper.temp_cwd() as tmpdir:
569654
fake = os.path.join(tmpdir, "uuid.py")
570655
main = os.path.join(tmpdir, "main.py")
571-
with open(fake, "w") as f:
656+
with open(fake, "w", encoding="utf-8") as f:
572657
f.write("raise RuntimeError('isolated mode test')\n")
573-
with open(main, "w") as f:
658+
with open(main, "w", encoding="utf-8") as f:
574659
f.write("import uuid\n")
575660
f.write("print('ok')\n")
661+
# Use -E to ignore PYTHONSAFEPATH env var
576662
self.assertRaises(subprocess.CalledProcessError,
577663
subprocess.check_output,
578-
[sys.executable, main], cwd=tmpdir,
664+
[sys.executable, '-E', main], cwd=tmpdir,
579665
stderr=subprocess.DEVNULL)
580666
out = subprocess.check_output([sys.executable, "-I", main],
581667
cwd=tmpdir)
@@ -716,7 +802,8 @@ def test_xdev(self):
716802

717803
def check_warnings_filters(self, cmdline_option, envvar, use_pywarning=False):
718804
if use_pywarning:
719-
code = ("import sys; from test.support.import_helper import import_fresh_module; "
805+
code = ("import sys; from test.support.import_helper import "
806+
"import_fresh_module; "
720807
"warnings = import_fresh_module('warnings', blocked=['_warnings']); ")
721808
else:
722809
code = "import sys, warnings; "
@@ -846,6 +933,43 @@ def test_parsing_error(self):
846933
self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr)
847934
self.assertNotEqual(proc.returncode, 0)
848935

936+
# TODO: RUSTPYTHON
937+
@unittest.expectedFailure
938+
def test_int_max_str_digits(self):
939+
code = "import sys; print(sys.flags.int_max_str_digits, sys.get_int_max_str_digits())"
940+
941+
assert_python_failure('-X', 'int_max_str_digits', '-c', code)
942+
assert_python_failure('-X', 'int_max_str_digits=foo', '-c', code)
943+
assert_python_failure('-X', 'int_max_str_digits=100', '-c', code)
944+
assert_python_failure('-X', 'int_max_str_digits', '-c', code,
945+
PYTHONINTMAXSTRDIGITS='4000')
946+
947+
assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo')
948+
assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100')
949+
950+
def res2int(res):
951+
out = res.out.strip().decode("utf-8")
952+
return tuple(int(i) for i in out.split())
953+
954+
res = assert_python_ok('-c', code)
955+
self.assertEqual(res2int(res), (-1, sys.get_int_max_str_digits()))
956+
res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code)
957+
self.assertEqual(res2int(res), (0, 0))
958+
res = assert_python_ok('-X', 'int_max_str_digits=4000', '-c', code)
959+
self.assertEqual(res2int(res), (4000, 4000))
960+
res = assert_python_ok('-X', 'int_max_str_digits=100000', '-c', code)
961+
self.assertEqual(res2int(res), (100000, 100000))
962+
963+
res = assert_python_ok('-c', code, PYTHONINTMAXSTRDIGITS='0')
964+
self.assertEqual(res2int(res), (0, 0))
965+
res = assert_python_ok('-c', code, PYTHONINTMAXSTRDIGITS='4000')
966+
self.assertEqual(res2int(res), (4000, 4000))
967+
res = assert_python_ok(
968+
'-X', 'int_max_str_digits=6000', '-c', code,
969+
PYTHONINTMAXSTRDIGITS='4000'
970+
)
971+
self.assertEqual(res2int(res), (6000, 6000))
972+
849973

850974
@unittest.skipIf(interpreter_requires_environment(),
851975
'Cannot run -I tests when PYTHON env vars are required.')
@@ -874,20 +998,41 @@ def test_sys_flags_not_set(self):
874998
# Issue 31845: a startup refactoring broke reading flags from env vars
875999
expected_outcome = """
8761000
(sys.flags.debug == sys.flags.optimize ==
877-
sys.flags.dont_write_bytecode == sys.flags.verbose == 0)
1001+
sys.flags.dont_write_bytecode ==
1002+
sys.flags.verbose == sys.flags.safe_path == 0)
8781003
"""
8791004
self.run_ignoring_vars(
8801005
expected_outcome,
8811006
PYTHONDEBUG="1",
8821007
PYTHONOPTIMIZE="1",
8831008
PYTHONDONTWRITEBYTECODE="1",
8841009
PYTHONVERBOSE="1",
1010+
PYTHONSAFEPATH="1",
8851011
)
8861012

8871013

888-
def test_main():
889-
support.run_unittest(CmdLineTest, IgnoreEnvironmentTest)
1014+
class SyntaxErrorTests(unittest.TestCase):
1015+
def check_string(self, code):
1016+
proc = subprocess.run([sys.executable, "-"], input=code,
1017+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1018+
self.assertNotEqual(proc.returncode, 0)
1019+
self.assertNotEqual(proc.stderr, None)
1020+
self.assertIn(b"\nSyntaxError", proc.stderr)
1021+
1022+
# TODO: RUSTPYTHON
1023+
@unittest.expectedFailure
1024+
def test_tokenizer_error_with_stdin(self):
1025+
self.check_string(b"(1+2+3")
1026+
1027+
# TODO: RUSTPYTHON
1028+
@unittest.expectedFailure
1029+
def test_decoding_error_at_the_end_of_the_line(self):
1030+
self.check_string(br"'\u1f'")
1031+
1032+
1033+
def tearDownModule():
8901034
support.reap_children()
8911035

1036+
8921037
if __name__ == "__main__":
893-
test_main()
1038+
unittest.main()

0 commit comments

Comments
 (0)