11import unittest
2+ from test import script_helper
23from test import support
34import subprocess
45import sys
@@ -191,15 +192,101 @@ def test_stderr_none(self):
191192 p .wait ()
192193 self .assertEqual (p .stderr , None )
193194
195+ # For use in the test_cwd* tests below.
196+ def _normalize_cwd (self , cwd ):
197+ # Normalize an expected cwd (for Tru64 support).
198+ # We can't use os.path.realpath since it doesn't expand Tru64 {memb}
199+ # strings. See bug #1063571.
200+ original_cwd = os .getcwd ()
201+ os .chdir (cwd )
202+ cwd = os .getcwd ()
203+ os .chdir (original_cwd )
204+ return cwd
205+
206+ # For use in the test_cwd* tests below.
207+ def _split_python_path (self ):
208+ # Return normalized (python_dir, python_base).
209+ python_path = os .path .realpath (sys .executable )
210+ return os .path .split (python_path )
211+
212+ # For use in the test_cwd* tests below.
213+ def _assert_cwd (self , expected_cwd , python_arg , ** kwargs ):
214+ # Invoke Python via Popen, and assert that (1) the call succeeds,
215+ # and that (2) the current working directory of the child process
216+ # matches *expected_cwd*.
217+ p = subprocess .Popen ([python_arg , "-c" ,
218+ "import os, sys; "
219+ "sys.stdout.write(os.getcwd()); "
220+ "sys.exit(47)" ],
221+ stdout = subprocess .PIPE ,
222+ ** kwargs )
223+ self .addCleanup (p .stdout .close )
224+ p .wait ()
225+ self .assertEqual (47 , p .returncode )
226+ normcase = os .path .normcase
227+ self .assertEqual (normcase (expected_cwd ),
228+ normcase (p .stdout .read ().decode ("utf-8" )))
229+
230+ def test_cwd (self ):
231+ # Check that cwd changes the cwd for the child process.
232+ temp_dir = tempfile .gettempdir ()
233+ temp_dir = self ._normalize_cwd (temp_dir )
234+ self ._assert_cwd (temp_dir , sys .executable , cwd = temp_dir )
235+
236+ def test_cwd_with_relative_arg (self ):
237+ # Check that Popen looks for args[0] relative to cwd if args[0]
238+ # is relative.
239+ python_dir , python_base = self ._split_python_path ()
240+ rel_python = os .path .join (os .curdir , python_base )
241+ with support .temp_cwd () as wrong_dir :
242+ # Before calling with the correct cwd, confirm that the call fails
243+ # without cwd and with the wrong cwd.
244+ self .assertRaises (FileNotFoundError , subprocess .Popen ,
245+ [rel_python ])
246+ self .assertRaises (FileNotFoundError , subprocess .Popen ,
247+ [rel_python ], cwd = wrong_dir )
248+ python_dir = self ._normalize_cwd (python_dir )
249+ self ._assert_cwd (python_dir , rel_python , cwd = python_dir )
250+
251+ def test_cwd_with_relative_executable (self ):
252+ # Check that Popen looks for executable relative to cwd if executable
253+ # is relative (and that executable takes precedence over args[0]).
254+ python_dir , python_base = self ._split_python_path ()
255+ rel_python = os .path .join (os .curdir , python_base )
256+ doesntexist = "somethingyoudonthave"
257+ with support .temp_cwd () as wrong_dir :
258+ # Before calling with the correct cwd, confirm that the call fails
259+ # without cwd and with the wrong cwd.
260+ self .assertRaises (FileNotFoundError , subprocess .Popen ,
261+ [doesntexist ], executable = rel_python )
262+ self .assertRaises (FileNotFoundError , subprocess .Popen ,
263+ [doesntexist ], executable = rel_python ,
264+ cwd = wrong_dir )
265+ python_dir = self ._normalize_cwd (python_dir )
266+ self ._assert_cwd (python_dir , doesntexist , executable = rel_python ,
267+ cwd = python_dir )
268+
269+ def test_cwd_with_absolute_arg (self ):
270+ # Check that Popen can find the executable when the cwd is wrong
271+ # if args[0] is an absolute path.
272+ python_dir , python_base = self ._split_python_path ()
273+ abs_python = os .path .join (python_dir , python_base )
274+ rel_python = os .path .join (os .curdir , python_base )
275+ with script_helper .temp_dir () as wrong_dir :
276+ # Before calling with an absolute path, confirm that using a
277+ # relative path fails.
278+ self .assertRaises (FileNotFoundError , subprocess .Popen ,
279+ [rel_python ], cwd = wrong_dir )
280+ wrong_dir = self ._normalize_cwd (wrong_dir )
281+ self ._assert_cwd (wrong_dir , abs_python , cwd = wrong_dir )
282+
194283 @unittest .skipIf (sys .base_prefix != sys .prefix ,
195284 'Test is not venv-compatible' )
196285 def test_executable_with_cwd (self ):
197- python_dir = os .path .dirname (os .path .realpath (sys .executable ))
198- p = subprocess .Popen (["somethingyoudonthave" , "-c" ,
199- "import sys; sys.exit(47)" ],
200- executable = sys .executable , cwd = python_dir )
201- p .wait ()
202- self .assertEqual (p .returncode , 47 )
286+ python_dir , python_base = self ._split_python_path ()
287+ python_dir = self ._normalize_cwd (python_dir )
288+ self ._assert_cwd (python_dir , "somethingyoudonthave" ,
289+ executable = sys .executable , cwd = python_dir )
203290
204291 @unittest .skipIf (sys .base_prefix != sys .prefix ,
205292 'Test is not venv-compatible' )
@@ -208,11 +295,7 @@ def test_executable_with_cwd(self):
208295 def test_executable_without_cwd (self ):
209296 # For a normal installation, it should work without 'cwd'
210297 # argument. For test runs in the build directory, see #7774.
211- p = subprocess .Popen (["somethingyoudonthave" , "-c" ,
212- "import sys; sys.exit(47)" ],
213- executable = sys .executable )
214- p .wait ()
215- self .assertEqual (p .returncode , 47 )
298+ self ._assert_cwd ('' , "somethingyoudonthave" , executable = sys .executable )
216299
217300 def test_stdin_pipe (self ):
218301 # stdin redirection
@@ -369,24 +452,6 @@ def test_stdin_devnull(self):
369452 p .wait ()
370453 self .assertEqual (p .stdin , None )
371454
372- def test_cwd (self ):
373- tmpdir = tempfile .gettempdir ()
374- # We cannot use os.path.realpath to canonicalize the path,
375- # since it doesn't expand Tru64 {memb} strings. See bug 1063571.
376- cwd = os .getcwd ()
377- os .chdir (tmpdir )
378- tmpdir = os .getcwd ()
379- os .chdir (cwd )
380- p = subprocess .Popen ([sys .executable , "-c" ,
381- 'import sys,os;'
382- 'sys.stdout.write(os.getcwd())' ],
383- stdout = subprocess .PIPE ,
384- cwd = tmpdir )
385- self .addCleanup (p .stdout .close )
386- normcase = os .path .normcase
387- self .assertEqual (normcase (p .stdout .read ().decode ("utf-8" )),
388- normcase (tmpdir ))
389-
390455 def test_env (self ):
391456 newenv = os .environ .copy ()
392457 newenv ["FRUIT" ] = "orange"
0 commit comments