@@ -238,37 +238,37 @@ def test_coding(self):
238238 @unittest .skipIf (sys .platform == 'win32' ,
239239 'Windows has a native unicode API' )
240240 def test_undecodable_code (self ):
241- undecodable = b" \xff "
242- env = os . environ . copy ()
243- # Use C locale to get ascii for the locale encoding
244- env ['LC_ALL' ] = 'C'
245- env ['PYTHONCOERCECLOCALE' ] = '0 '
246- code = (
247- b'import locale; '
248- b'print(ascii("' + undecodable + b'"), '
249- b'locale.getencoding())' )
250- p = subprocess .Popen (
251- [sys .executable , "-c" , code ],
252- stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
253- env = env )
254- stdout , stderr = p .communicate ()
255- if p .returncode == 1 :
256- # _Py_char2wchar() decoded b'\xff' as '\udcff' (b'\xff' is not
257- # decodable from ASCII) and run_command() failed on
258- # PyUnicode_AsUTF8String(). This is the expected behaviour on
259- # Linux.
260- pattern = b"Unable to decode the command from the command line:"
261- elif p .returncode == 0 :
262- # _Py_char2wchar() decoded b'\xff' as '\xff' even if the locale is
263- # C and the locale encoding is ASCII. It occurs on FreeBSD, Solaris
264- # and Mac OS X.
265- pattern = b"'\\ xff' "
266- # The output is followed by the encoding name, an alias to ASCII.
267- # Examples: "US-ASCII" or "646" (ISO 646, on Solaris).
268- else :
269- raise AssertionError ("Unknown exit code: %s, output=%a" % (p .returncode , stdout ))
270- if not stdout .startswith (pattern ):
271- raise AssertionError ("%a doesn't start with %a" % (stdout , pattern ))
241+ with os_helper . EnvironmentVarGuard () as env :
242+ undecodable = b" \xff "
243+ # Use C locale to get ascii for the locale encoding
244+ env ['LC_ALL' ] = 'C'
245+ env ['PYTHONCOERCECLOCALE' ] = '1 '
246+ code = (
247+ b'import locale; '
248+ b'print(ascii("' + undecodable + b'"), '
249+ b'locale.getencoding())' )
250+ p = subprocess .Popen (
251+ [sys .executable , "-c" , code ],
252+ stdout = subprocess .PIPE , stderr = subprocess .STDOUT
253+ )
254+ stdout , stderr = p .communicate ()
255+ if p .returncode == 1 :
256+ # _Py_char2wchar() decoded b'\xff' as '\udcff' (b'\xff' is not
257+ # decodable from ASCII) and run_command() failed on
258+ # PyUnicode_AsUTF8String(). This is the expected behaviour on
259+ # Linux.
260+ pattern = b"Unable to decode the command from the command line:"
261+ elif p .returncode == 0 :
262+ # _Py_char2wchar() decoded b'\xff' as '\xff' even if the locale is
263+ # C and the locale encoding is ASCII. It occurs on FreeBSD, Solaris
264+ # and Mac OS X.
265+ pattern = b"'\\ xff' "
266+ # The output is followed by the encoding name, an alias to ASCII.
267+ # Examples: "US-ASCII" or "646" (ISO 646, on Solaris).
268+ else :
269+ raise AssertionError ("Unknown exit code: %s, output=%a" % (p .returncode , stdout ))
270+ if not stdout .startswith (pattern ):
271+ raise AssertionError ("%a doesn't start with %a" % (stdout , pattern ))
272272
273273 @unittest .skipIf (sys .platform == 'win32' ,
274274 'Windows has a native unicode API' )
@@ -287,10 +287,10 @@ def run_default(arg):
287287
288288 def run_c_locale (arg ):
289289 cmd = [sys .executable , '-c' , code , arg ]
290- env = dict ( os . environ )
291- env ['LC_ALL' ] = 'C'
292- return subprocess .run (cmd , stdout = subprocess .PIPE ,
293- text = True , env = env )
290+ with os_helper . EnvironmentVarGuard () as env :
291+ env ['LC_ALL' ] = 'C'
292+ return subprocess .run (cmd , stdout = subprocess .PIPE ,
293+ text = True )
294294
295295 def run_utf8_mode (arg ):
296296 cmd = [sys .executable , '-X' , 'utf8' , '-c' , code , arg ]
@@ -323,18 +323,18 @@ def test_osx_android_utf8(self):
323323 decoded = text .decode ('utf-8' , 'surrogateescape' )
324324 expected = ascii (decoded ).encode ('ascii' ) + b'\n '
325325
326- env = os . environ . copy ()
327- # C locale gives ASCII locale encoding, but Python uses UTF-8
328- # to parse the command line arguments on Mac OS X and Android.
329- env ['LC_ALL' ] = 'C'
326+ with os_helper . EnvironmentVarGuard () as env :
327+ # C locale gives ASCII locale encoding, but Python uses UTF-8
328+ # to parse the command line arguments on Mac OS X and Android.
329+ env ['LC_ALL' ] = 'C'
330330
331- p = subprocess .Popen (
332- (sys .executable , "-c" , code , text ),
333- stdout = subprocess .PIPE ,
334- env = env )
335- stdout , stderr = p .communicate ()
336- self .assertEqual (stdout , expected )
337- self .assertEqual (p .returncode , 0 )
331+ p = subprocess .Popen (
332+ (sys .executable , "-c" , code , text ),
333+ stdout = subprocess .PIPE ,
334+ )
335+ stdout , stderr = p .communicate ()
336+ self .assertEqual (stdout , expected )
337+ self .assertEqual (p .returncode , 0 )
338338
339339 def test_non_interactive_output_buffering (self ):
340340 code = textwrap .dedent ("""
@@ -412,22 +412,22 @@ def test_empty_PYTHONPATH_issue16309(self):
412412 self .assertEqual (out1 , out2 )
413413
414414 def test_displayhook_unencodable (self ):
415- for encoding in ( 'ascii' , 'latin-1' , 'utf-8' ) :
416- env = os . environ . copy ()
417- env ['PYTHONIOENCODING' ] = encoding
418- p = subprocess .Popen (
419- [sys .executable , '-i' ],
420- stdin = subprocess .PIPE ,
421- stdout = subprocess .PIPE ,
422- stderr = subprocess .STDOUT ,
423- env = env )
424- # non-ascii, surrogate, non-BMP printable, non-BMP unprintable
425- text = "a=\xe9 b=\uDC80 c=\U00010000 d=\U0010FFFF "
426- p .stdin .write (ascii (text ).encode ('ascii' ) + b"\n " )
427- p .stdin .write (b'exit()\n ' )
428- data = kill_python (p )
429- escaped = repr (text ).encode (encoding , 'backslashreplace' )
430- self .assertIn (escaped , data )
415+ with os_helper . EnvironmentVarGuard () as env :
416+ for encoding in ( 'ascii' , 'latin-1' , 'utf-8' ):
417+ env ['PYTHONIOENCODING' ] = encoding
418+ p = subprocess .Popen (
419+ [sys .executable , '-i' ],
420+ stdin = subprocess .PIPE ,
421+ stdout = subprocess .PIPE ,
422+ stderr = subprocess .STDOUT ,
423+ )
424+ # non-ascii, surrogate, non-BMP printable, non-BMP unprintable
425+ text = "a=\xe9 b=\uDC80 c=\U00010000 d=\U0010FFFF "
426+ p .stdin .write (ascii (text ).encode ('ascii' ) + b"\n " )
427+ p .stdin .write (b'exit()\n ' )
428+ data = kill_python (p )
429+ escaped = repr (text ).encode (encoding , 'backslashreplace' )
430+ self .assertIn (escaped , data )
431431
432432 def check_input (self , code , expected ):
433433 with tempfile .NamedTemporaryFile ("wb+" ) as stdin :
@@ -684,23 +684,23 @@ def test_set_pycache_prefix(self):
684684 assert_python_ok (* args , ** env )
685685
686686 def run_xdev (self , * args , check_exitcode = True , xdev = True ):
687- env = dict ( os . environ )
688- env . pop ( 'PYTHONWARNINGS' , None )
689- env . pop ( 'PYTHONDEVMODE' , None )
690- env . pop ( 'PYTHONMALLOC' , None )
687+ with os_helper . EnvironmentVarGuard () as env :
688+ del env [ 'PYTHONWARNINGS' ]
689+ del env [ 'PYTHONDEVMODE' ]
690+ del env [ 'PYTHONMALLOC' ]
691691
692- if xdev :
693- args = (sys .executable , '-X' , 'dev' , * args )
694- else :
695- args = (sys .executable , * args )
696- proc = subprocess .run (args ,
697- stdout = subprocess .PIPE ,
698- stderr = subprocess .STDOUT ,
699- universal_newlines = True ,
700- env = env )
701- if check_exitcode :
702- self .assertEqual (proc .returncode , 0 , proc )
703- return proc .stdout .rstrip ()
692+ if xdev :
693+ args = (sys .executable , '-X' , 'dev' , * args )
694+ else :
695+ args = (sys .executable , * args )
696+ proc = subprocess .run (args ,
697+ stdout = subprocess .PIPE ,
698+ stderr = subprocess .STDOUT ,
699+ universal_newlines = True ,
700+ )
701+ if check_exitcode :
702+ self .assertEqual (proc .returncode , 0 , proc )
703+ return proc .stdout .rstrip ()
704704
705705 @support .cpython_only
706706 def test_xdev (self ):
@@ -774,16 +774,16 @@ def check_warnings_filters(self, cmdline_option, envvar, use_pywarning=False):
774774 code += ("print(' '.join('%s::%s' % (f[0], f[2].__name__) "
775775 "for f in warnings.filters))" )
776776 args = (sys .executable , '-W' , cmdline_option , '-bb' , '-c' , code )
777- env = dict ( os . environ )
778- env . pop ( 'PYTHONDEVMODE' , None )
779- env ["PYTHONWARNINGS" ] = envvar
780- proc = subprocess .run (args ,
781- stdout = subprocess .PIPE ,
782- stderr = subprocess .STDOUT ,
783- universal_newlines = True ,
784- env = env )
785- self .assertEqual (proc .returncode , 0 , proc )
786- return proc .stdout .rstrip ()
777+ with os_helper . EnvironmentVarGuard () as env :
778+ del env [ 'PYTHONDEVMODE' ]
779+ env ["PYTHONWARNINGS" ] = envvar
780+ proc = subprocess .run (args ,
781+ stdout = subprocess .PIPE ,
782+ stderr = subprocess .STDOUT ,
783+ universal_newlines = True ,
784+ )
785+ self .assertEqual (proc .returncode , 0 , proc )
786+ return proc .stdout .rstrip ()
787787
788788 def test_warnings_filter_precedence (self ):
789789 expected_filters = ("error::BytesWarning "
@@ -808,20 +808,20 @@ def test_warnings_filter_precedence(self):
808808
809809 def check_pythonmalloc (self , env_var , name ):
810810 code = 'import _testinternalcapi; print(_testinternalcapi.pymem_getallocatorsname())'
811- env = dict ( os . environ )
812- env . pop ( 'PYTHONDEVMODE' , None )
813- if env_var is not None :
814- env ['PYTHONMALLOC' ] = env_var
815- else :
816- env . pop ( 'PYTHONMALLOC' , None )
817- args = (sys .executable , '-c' , code )
818- proc = subprocess .run (args ,
819- stdout = subprocess .PIPE ,
820- stderr = subprocess .STDOUT ,
821- universal_newlines = True ,
822- env = env )
823- self .assertEqual (proc .stdout .rstrip (), name )
824- self .assertEqual (proc .returncode , 0 )
811+ with os_helper . EnvironmentVarGuard () as env :
812+ del env [ 'PYTHONDEVMODE' ]
813+ if env_var is not None :
814+ env ['PYTHONMALLOC' ] = env_var
815+ else :
816+ del env [ 'PYTHONMALLOC' ]
817+ args = (sys .executable , '-c' , code )
818+ proc = subprocess .run (args ,
819+ stdout = subprocess .PIPE ,
820+ stderr = subprocess .STDOUT ,
821+ universal_newlines = True ,
822+ )
823+ self .assertEqual (proc .stdout .rstrip (), name )
824+ self .assertEqual (proc .returncode , 0 )
825825
826826 @support .cpython_only
827827 def test_pythonmalloc (self ):
@@ -866,20 +866,20 @@ def test_pythonmalloc(self):
866866 def test_pythondevmode_env (self ):
867867 # Test the PYTHONDEVMODE environment variable
868868 code = "import sys; print(sys.flags.dev_mode)"
869- env = dict ( os . environ )
870- env . pop ( 'PYTHONDEVMODE' , None )
871- args = (sys .executable , '-c' , code )
869+ with os_helper . EnvironmentVarGuard () as env :
870+ del env [ 'PYTHONDEVMODE' ]
871+ args = (sys .executable , '-c' , code )
872872
873- proc = subprocess .run (args , stdout = subprocess .PIPE ,
874- universal_newlines = True , env = env )
875- self .assertEqual (proc .stdout .rstrip (), 'False' )
876- self .assertEqual (proc .returncode , 0 , proc )
873+ proc = subprocess .run (args , stdout = subprocess .PIPE ,
874+ universal_newlines = True , env = env )
875+ self .assertEqual (proc .stdout .rstrip (), 'False' )
876+ self .assertEqual (proc .returncode , 0 , proc )
877877
878- env ['PYTHONDEVMODE' ] = '1'
879- proc = subprocess .run (args , stdout = subprocess .PIPE ,
880- universal_newlines = True , env = env )
881- self .assertEqual (proc .stdout .rstrip (), 'True' )
882- self .assertEqual (proc .returncode , 0 , proc )
878+ env ['PYTHONDEVMODE' ] = '1'
879+ proc = subprocess .run (args , stdout = subprocess .PIPE ,
880+ universal_newlines = True )
881+ self .assertEqual (proc .stdout .rstrip (), 'True' )
882+ self .assertEqual (proc .returncode , 0 , proc )
883883
884884 def test_python_gil (self ):
885885 cases = [
@@ -905,24 +905,24 @@ def test_python_gil(self):
905905 ]
906906 )
907907 code = "import sys; print(sys.flags.gil)"
908- environ = dict ( os . environ )
909-
910- for env , opt , expected , msg in cases :
911- with self .subTest (msg , env = env , opt = opt ):
912- environ . pop ( 'PYTHON_GIL' , None )
913- if env is not None :
914- environ ['PYTHON_GIL' ] = env
915- extra_args = []
916- if opt is not None :
917- extra_args = ['-X' , f'gil={ opt } ' ]
918-
919- proc = subprocess .run ([sys .executable , * extra_args , '-c' , code ],
920- stdout = subprocess .PIPE ,
921- stderr = subprocess .PIPE ,
922- text = True , env = environ )
923- self .assertEqual (proc .returncode , 0 , proc )
924- self .assertEqual (proc .stdout .rstrip (), expected )
925- self .assertEqual (proc .stderr , '' )
908+
909+ with os_helper . EnvironmentVarGuard () as environ :
910+ for env , opt , expected , msg in cases :
911+ with self .subTest (msg , env = env , opt = opt ):
912+ del environ [ 'PYTHON_GIL' ]
913+ if env is not None :
914+ environ ['PYTHON_GIL' ] = env
915+ extra_args = []
916+ if opt is not None :
917+ extra_args = ['-X' , f'gil={ opt } ' ]
918+
919+ proc = subprocess .run ([sys .executable , * extra_args , '-c' , code ],
920+ stdout = subprocess .PIPE ,
921+ stderr = subprocess .PIPE ,
922+ text = True )
923+ self .assertEqual (proc .returncode , 0 , proc )
924+ self .assertEqual (proc .stdout .rstrip (), expected )
925+ self .assertEqual (proc .stderr , '' )
926926
927927 def test_python_asyncio_debug (self ):
928928 code = "import asyncio; print(asyncio.new_event_loop().get_debug())"
0 commit comments