6
6
import subprocess
7
7
import sys
8
8
import tempfile
9
+ import textwrap
9
10
import unittest
10
11
from test import support
12
+ from test .support import os_helper
11
13
from test .support .script_helper import (
12
14
spawn_python , kill_python , assert_python_ok , assert_python_failure ,
13
15
interpreter_requires_environment
14
16
)
15
- from test .support import os_helper
16
17
18
+ if not support .has_subprocess_support :
19
+ raise unittest .SkipTest ("test module requires subprocess" )
17
20
18
21
# Debug build?
19
22
Py_DEBUG = hasattr (sys , "gettotalrefcount" )
@@ -25,38 +28,63 @@ def _kill_python_and_exit_code(p):
25
28
returncode = p .wait ()
26
29
return data , returncode
27
30
31
+
28
32
class CmdLineTest (unittest .TestCase ):
29
33
def test_directories (self ):
30
34
assert_python_failure ('.' )
31
35
assert_python_failure ('< .' )
32
36
33
37
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 )
35
39
self .assertTrue (out == b'' or out .endswith (b'\n ' ))
36
40
self .assertNotIn (b'Traceback' , out )
37
41
self .assertNotIn (b'Traceback' , err )
42
+ return out
38
43
39
44
# TODO: RUSTPYTHON
40
45
@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 )
44
55
45
56
# TODO: RUSTPYTHON
46
57
@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 )
49
67
50
68
# TODO: RUSTPYTHON
51
69
@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 ' )
54
72
lines = out .splitlines ()
55
73
self .assertIn (b'usage' , lines [0 ])
74
+ self .assertIn (b'PYTHONHOME' , out )
75
+ self .assertIn (b'-X dev' , out )
76
+
56
77
# The first line contains the program name,
57
78
# but the rest should be ASCII-only
58
79
b'' .join (lines [1 :]).decode ('ascii' )
59
80
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
+
60
88
# NOTE: RUSTPYTHON version never starts with Python
61
89
@unittest .expectedFailure
62
90
def test_version (self ):
@@ -114,13 +142,32 @@ def run_python(*args):
114
142
self .assertEqual (out .rstrip (), b'{}' )
115
143
self .assertEqual (err , b'' )
116
144
# "-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 )
118
146
self .assertEqual (out .rstrip (), b"{'showrefcount': True}" )
119
147
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\]' )
121
152
else :
122
153
self .assertEqual (err , b'' )
123
154
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
+
124
171
def test_run_module (self ):
125
172
# Test expected operation of the '-m' switch
126
173
# Switch needs an argument
@@ -146,6 +193,16 @@ def test_run_module_bug1764407(self):
146
193
self .assertTrue (data .find (b'1 loop' ) != - 1 )
147
194
self .assertTrue (data .find (b'__main__.Timer' ) != - 1 )
148
195
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
+
149
206
def test_run_code (self ):
150
207
# Test expected operation of the '-c' switch
151
208
# Switch needs an argument
@@ -162,6 +219,14 @@ def test_non_ascii(self):
162
219
% (os_helper .FS_NONASCII , ord (os_helper .FS_NONASCII )))
163
220
assert_python_ok ('-c' , command )
164
221
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\n print(ascii('{ ch } '))"
227
+ res = assert_python_ok ('-c' , cmd )
228
+ self .assertEqual (res .out .rstrip (), ascii (ch ).encode ('ascii' ))
229
+
165
230
# On Windows, pass bytes to subprocess doesn't test how Python decodes the
166
231
# command line, but how subprocess does decode bytes to unicode. Python
167
232
# doesn't decode the command line because Windows provides directly the
@@ -179,7 +244,7 @@ def test_undecodable_code(self):
179
244
code = (
180
245
b'import locale; '
181
246
b'print(ascii("' + undecodable + b'"), '
182
- b'locale.getpreferredencoding ())' )
247
+ b'locale.getencoding ())' )
183
248
p = subprocess .Popen (
184
249
[sys .executable , "-c" , code ],
185
250
stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
@@ -214,7 +279,6 @@ def test_invalid_utf8_arg(self):
214
279
#
215
280
# Test with default config, in the C locale, in the Python UTF-8 Mode.
216
281
code = 'import sys, os; s=os.fsencode(sys.argv[1]); print(ascii(s))'
217
- base_cmd = [sys .executable , '-c' , code ]
218
282
219
283
# TODO: RUSTPYTHON
220
284
@unittest .expectedFailure
@@ -277,6 +341,23 @@ def test_osx_android_utf8(self):
277
341
self .assertEqual (stdout , expected )
278
342
self .assertEqual (p .returncode , 0 )
279
343
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
+
280
361
# TODO: RUSTPYTHON
281
362
@unittest .expectedFailure
282
363
def test_unbuffered_output (self ):
@@ -320,6 +401,8 @@ def test_large_PYTHONPATH(self):
320
401
self .assertIn (path1 .encode ('ascii' ), out )
321
402
self .assertIn (path2 .encode ('ascii' ), out )
322
403
404
+ @unittest .skipIf (sys .flags .safe_path ,
405
+ 'PYTHONSAFEPATH changes default sys.path' )
323
406
def test_empty_PYTHONPATH_issue16309 (self ):
324
407
# On Posix, it is documented that setting PATH to the
325
408
# empty string is equivalent to not setting PATH at all,
@@ -369,23 +452,25 @@ def check_input(self, code, expected):
369
452
stdout , stderr = proc .communicate ()
370
453
self .assertEqual (stdout .rstrip (), expected )
371
454
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" )
373
457
def test_stdin_readline (self ):
374
458
# Issue #11272: check that sys.stdin.readline() replaces '\r\n' by '\n'
375
459
# on Windows (sys.stdin is opened in binary mode)
376
460
self .check_input (
377
461
"import sys; print(repr(sys.stdin.readline()))" ,
378
462
b"'abc\\ n'" )
379
463
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" )
381
466
def test_builtin_input (self ):
382
467
# Issue #11272: check that input() strips newlines ('\n' or '\r\n')
383
468
self .check_input (
384
469
"print(repr(input()))" ,
385
470
b"'abc'" )
386
471
387
472
# TODO: RUSTPYTHON
388
- @unittest .expectedFailure
473
+ @unittest .skipIf ( sys . platform . startswith ( 'win' ), "TODO: RUSTPYTHON windows has \n troubles" )
389
474
def test_output_newline (self ):
390
475
# Issue 13119 Newline for print() should be \r\n on Windows.
391
476
code = """if 1:
@@ -398,10 +483,10 @@ def test_output_newline(self):
398
483
399
484
if sys .platform == 'win32' :
400
485
self .assertEqual (b'1\r \n 2\r \n ' , out )
401
- self .assertEqual (b'3\r \n 4' , err )
486
+ self .assertEqual (b'3\r \n 4\r \n ' , err )
402
487
else :
403
488
self .assertEqual (b'1\n 2\n ' , out )
404
- self .assertEqual (b'3\n 4' , err )
489
+ self .assertEqual (b'3\n 4\n ' , err )
405
490
406
491
def test_unmached_quote (self ):
407
492
# Issue #10206: python program starting with unmatched quote
@@ -459,7 +544,7 @@ def preexec():
459
544
stderr = subprocess .PIPE ,
460
545
preexec_fn = preexec )
461
546
out , err = p .communicate ()
462
- self .assertEqual (support . strip_python_stderr ( err ) , b'' )
547
+ self .assertEqual (err , b'' )
463
548
self .assertEqual (p .returncode , 42 )
464
549
465
550
# TODO: RUSTPYTHON
@@ -527,7 +612,7 @@ def test_del___main__(self):
527
612
# the dict whereas the module was destroyed
528
613
filename = os_helper .TESTFN
529
614
self .addCleanup (os_helper .unlink , filename )
530
- with open (filename , "w" ) as script :
615
+ with open (filename , "w" , encoding = "utf-8" ) as script :
531
616
print ("import sys" , file = script )
532
617
print ("del sys.modules['__main__']" , file = script )
533
618
assert_python_ok (filename )
@@ -558,24 +643,25 @@ def test_unknown_options(self):
558
643
'Cannot run -I tests when PYTHON env vars are required.' )
559
644
def test_isolatedmode (self ):
560
645
self .verify_valid_flag ('-I' )
561
- self .verify_valid_flag ('-IEs ' )
646
+ self .verify_valid_flag ('-IEPs ' )
562
647
rc , out , err = assert_python_ok ('-I' , '-c' ,
563
648
'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 )' ,
565
650
# dummyvar to prevent extraneous -E
566
651
dummyvar = "" )
567
- self .assertEqual (out .strip (), b'1 1 1' )
652
+ self .assertEqual (out .strip (), b'1 1 1 True ' )
568
653
with os_helper .temp_cwd () as tmpdir :
569
654
fake = os .path .join (tmpdir , "uuid.py" )
570
655
main = os .path .join (tmpdir , "main.py" )
571
- with open (fake , "w" ) as f :
656
+ with open (fake , "w" , encoding = "utf-8" ) as f :
572
657
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 :
574
659
f .write ("import uuid\n " )
575
660
f .write ("print('ok')\n " )
661
+ # Use -E to ignore PYTHONSAFEPATH env var
576
662
self .assertRaises (subprocess .CalledProcessError ,
577
663
subprocess .check_output ,
578
- [sys .executable , main ], cwd = tmpdir ,
664
+ [sys .executable , '-E' , main ], cwd = tmpdir ,
579
665
stderr = subprocess .DEVNULL )
580
666
out = subprocess .check_output ([sys .executable , "-I" , main ],
581
667
cwd = tmpdir )
@@ -716,7 +802,8 @@ def test_xdev(self):
716
802
717
803
def check_warnings_filters (self , cmdline_option , envvar , use_pywarning = False ):
718
804
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; "
720
807
"warnings = import_fresh_module('warnings', blocked=['_warnings']); " )
721
808
else :
722
809
code = "import sys, warnings; "
@@ -846,6 +933,43 @@ def test_parsing_error(self):
846
933
self .assertTrue (proc .stderr .startswith (err_msg ), proc .stderr )
847
934
self .assertNotEqual (proc .returncode , 0 )
848
935
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
+
849
973
850
974
@unittest .skipIf (interpreter_requires_environment (),
851
975
'Cannot run -I tests when PYTHON env vars are required.' )
@@ -874,20 +998,41 @@ def test_sys_flags_not_set(self):
874
998
# Issue 31845: a startup refactoring broke reading flags from env vars
875
999
expected_outcome = """
876
1000
(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)
878
1003
"""
879
1004
self .run_ignoring_vars (
880
1005
expected_outcome ,
881
1006
PYTHONDEBUG = "1" ,
882
1007
PYTHONOPTIMIZE = "1" ,
883
1008
PYTHONDONTWRITEBYTECODE = "1" ,
884
1009
PYTHONVERBOSE = "1" ,
1010
+ PYTHONSAFEPATH = "1" ,
885
1011
)
886
1012
887
1013
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"\n SyntaxError" , 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 ():
890
1034
support .reap_children ()
891
1035
1036
+
892
1037
if __name__ == "__main__" :
893
- test_main ()
1038
+ unittest . main ()
0 commit comments