mirror of https://github.com/python/cpython
Issue #15533: Merge fix from 3.2.
This commit is contained in:
commit
28714c8c26
|
@ -484,10 +484,10 @@ functions.
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
The *pass_fds* parameter was added.
|
The *pass_fds* parameter was added.
|
||||||
|
|
||||||
If *cwd* is not ``None``, the child's current directory will be changed to *cwd*
|
If *cwd* is not ``None``, the function changes the working directory to
|
||||||
before it is executed. Note that this directory is not considered when
|
*cwd* before executing the child. In particular, the function looks for
|
||||||
searching the executable, so you can't specify the program's path relative to
|
*executable* (or for the first item in *args*) relative to *cwd* if the
|
||||||
*cwd*.
|
executable path is a relative path.
|
||||||
|
|
||||||
If *restore_signals* is True (the default) all signals that Python has set to
|
If *restore_signals* is True (the default) all signals that Python has set to
|
||||||
SIG_IGN are restored to SIG_DFL in the child process before the exec.
|
SIG_IGN are restored to SIG_DFL in the child process before the exec.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
from test import script_helper
|
||||||
from test import support
|
from test import support
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
@ -191,15 +192,101 @@ class ProcessTestCase(BaseTestCase):
|
||||||
p.wait()
|
p.wait()
|
||||||
self.assertEqual(p.stderr, None)
|
self.assertEqual(p.stderr, None)
|
||||||
|
|
||||||
|
# For use in the test_cwd* tests below.
|
||||||
|
def _normalize_cwd(self, cwd):
|
||||||
|
# Normalize an expected cwd (for Tru64 support).
|
||||||
|
# We can't use os.path.realpath since it doesn't expand Tru64 {memb}
|
||||||
|
# strings. See bug #1063571.
|
||||||
|
original_cwd = os.getcwd()
|
||||||
|
os.chdir(cwd)
|
||||||
|
cwd = os.getcwd()
|
||||||
|
os.chdir(original_cwd)
|
||||||
|
return cwd
|
||||||
|
|
||||||
|
# For use in the test_cwd* tests below.
|
||||||
|
def _split_python_path(self):
|
||||||
|
# Return normalized (python_dir, python_base).
|
||||||
|
python_path = os.path.realpath(sys.executable)
|
||||||
|
return os.path.split(python_path)
|
||||||
|
|
||||||
|
# For use in the test_cwd* tests below.
|
||||||
|
def _assert_cwd(self, expected_cwd, python_arg, **kwargs):
|
||||||
|
# Invoke Python via Popen, and assert that (1) the call succeeds,
|
||||||
|
# and that (2) the current working directory of the child process
|
||||||
|
# matches *expected_cwd*.
|
||||||
|
p = subprocess.Popen([python_arg, "-c",
|
||||||
|
"import os, sys; "
|
||||||
|
"sys.stdout.write(os.getcwd()); "
|
||||||
|
"sys.exit(47)"],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
**kwargs)
|
||||||
|
self.addCleanup(p.stdout.close)
|
||||||
|
p.wait()
|
||||||
|
self.assertEqual(47, p.returncode)
|
||||||
|
normcase = os.path.normcase
|
||||||
|
self.assertEqual(normcase(expected_cwd),
|
||||||
|
normcase(p.stdout.read().decode("utf-8")))
|
||||||
|
|
||||||
|
def test_cwd(self):
|
||||||
|
# Check that cwd changes the cwd for the child process.
|
||||||
|
temp_dir = tempfile.gettempdir()
|
||||||
|
temp_dir = self._normalize_cwd(temp_dir)
|
||||||
|
self._assert_cwd(temp_dir, sys.executable, cwd=temp_dir)
|
||||||
|
|
||||||
|
def test_cwd_with_relative_arg(self):
|
||||||
|
# Check that Popen looks for args[0] relative to cwd if args[0]
|
||||||
|
# is relative.
|
||||||
|
python_dir, python_base = self._split_python_path()
|
||||||
|
rel_python = os.path.join(os.curdir, python_base)
|
||||||
|
with support.temp_cwd() as wrong_dir:
|
||||||
|
# Before calling with the correct cwd, confirm that the call fails
|
||||||
|
# without cwd and with the wrong cwd.
|
||||||
|
self.assertRaises(FileNotFoundError, subprocess.Popen,
|
||||||
|
[rel_python])
|
||||||
|
self.assertRaises(FileNotFoundError, subprocess.Popen,
|
||||||
|
[rel_python], cwd=wrong_dir)
|
||||||
|
python_dir = self._normalize_cwd(python_dir)
|
||||||
|
self._assert_cwd(python_dir, rel_python, cwd=python_dir)
|
||||||
|
|
||||||
|
def test_cwd_with_relative_executable(self):
|
||||||
|
# Check that Popen looks for executable relative to cwd if executable
|
||||||
|
# is relative (and that executable takes precedence over args[0]).
|
||||||
|
python_dir, python_base = self._split_python_path()
|
||||||
|
rel_python = os.path.join(os.curdir, python_base)
|
||||||
|
doesntexist = "somethingyoudonthave"
|
||||||
|
with support.temp_cwd() as wrong_dir:
|
||||||
|
# Before calling with the correct cwd, confirm that the call fails
|
||||||
|
# without cwd and with the wrong cwd.
|
||||||
|
self.assertRaises(FileNotFoundError, subprocess.Popen,
|
||||||
|
[doesntexist], executable=rel_python)
|
||||||
|
self.assertRaises(FileNotFoundError, subprocess.Popen,
|
||||||
|
[doesntexist], executable=rel_python,
|
||||||
|
cwd=wrong_dir)
|
||||||
|
python_dir = self._normalize_cwd(python_dir)
|
||||||
|
self._assert_cwd(python_dir, doesntexist, executable=rel_python,
|
||||||
|
cwd=python_dir)
|
||||||
|
|
||||||
|
def test_cwd_with_absolute_arg(self):
|
||||||
|
# Check that Popen can find the executable when the cwd is wrong
|
||||||
|
# if args[0] is an absolute path.
|
||||||
|
python_dir, python_base = self._split_python_path()
|
||||||
|
abs_python = os.path.join(python_dir, python_base)
|
||||||
|
rel_python = os.path.join(os.curdir, python_base)
|
||||||
|
with script_helper.temp_dir() as wrong_dir:
|
||||||
|
# Before calling with an absolute path, confirm that using a
|
||||||
|
# relative path fails.
|
||||||
|
self.assertRaises(FileNotFoundError, subprocess.Popen,
|
||||||
|
[rel_python], cwd=wrong_dir)
|
||||||
|
wrong_dir = self._normalize_cwd(wrong_dir)
|
||||||
|
self._assert_cwd(wrong_dir, abs_python, cwd=wrong_dir)
|
||||||
|
|
||||||
@unittest.skipIf(sys.base_prefix != sys.prefix,
|
@unittest.skipIf(sys.base_prefix != sys.prefix,
|
||||||
'Test is not venv-compatible')
|
'Test is not venv-compatible')
|
||||||
def test_executable_with_cwd(self):
|
def test_executable_with_cwd(self):
|
||||||
python_dir = os.path.dirname(os.path.realpath(sys.executable))
|
python_dir, python_base = self._split_python_path()
|
||||||
p = subprocess.Popen(["somethingyoudonthave", "-c",
|
python_dir = self._normalize_cwd(python_dir)
|
||||||
"import sys; sys.exit(47)"],
|
self._assert_cwd(python_dir, "somethingyoudonthave",
|
||||||
executable=sys.executable, cwd=python_dir)
|
executable=sys.executable, cwd=python_dir)
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 47)
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.base_prefix != sys.prefix,
|
@unittest.skipIf(sys.base_prefix != sys.prefix,
|
||||||
'Test is not venv-compatible')
|
'Test is not venv-compatible')
|
||||||
|
@ -208,11 +295,7 @@ class ProcessTestCase(BaseTestCase):
|
||||||
def test_executable_without_cwd(self):
|
def test_executable_without_cwd(self):
|
||||||
# For a normal installation, it should work without 'cwd'
|
# For a normal installation, it should work without 'cwd'
|
||||||
# argument. For test runs in the build directory, see #7774.
|
# argument. For test runs in the build directory, see #7774.
|
||||||
p = subprocess.Popen(["somethingyoudonthave", "-c",
|
self._assert_cwd('', "somethingyoudonthave", executable=sys.executable)
|
||||||
"import sys; sys.exit(47)"],
|
|
||||||
executable=sys.executable)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 47)
|
|
||||||
|
|
||||||
def test_stdin_pipe(self):
|
def test_stdin_pipe(self):
|
||||||
# stdin redirection
|
# stdin redirection
|
||||||
|
@ -369,24 +452,6 @@ class ProcessTestCase(BaseTestCase):
|
||||||
p.wait()
|
p.wait()
|
||||||
self.assertEqual(p.stdin, None)
|
self.assertEqual(p.stdin, None)
|
||||||
|
|
||||||
def test_cwd(self):
|
|
||||||
tmpdir = tempfile.gettempdir()
|
|
||||||
# We cannot use os.path.realpath to canonicalize the path,
|
|
||||||
# since it doesn't expand Tru64 {memb} strings. See bug 1063571.
|
|
||||||
cwd = os.getcwd()
|
|
||||||
os.chdir(tmpdir)
|
|
||||||
tmpdir = os.getcwd()
|
|
||||||
os.chdir(cwd)
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;'
|
|
||||||
'sys.stdout.write(os.getcwd())'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
cwd=tmpdir)
|
|
||||||
self.addCleanup(p.stdout.close)
|
|
||||||
normcase = os.path.normcase
|
|
||||||
self.assertEqual(normcase(p.stdout.read().decode("utf-8")),
|
|
||||||
normcase(tmpdir))
|
|
||||||
|
|
||||||
def test_env(self):
|
def test_env(self):
|
||||||
newenv = os.environ.copy()
|
newenv = os.environ.copy()
|
||||||
newenv["FRUIT"] = "orange"
|
newenv["FRUIT"] = "orange"
|
||||||
|
|
|
@ -105,6 +105,9 @@ Build
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
- Issue #15533: Clarify docs and add tests for subprocess.Popen()'s cwd
|
||||||
|
argument.
|
||||||
|
|
||||||
- Issue #16036: Improve documentation of built-in int()'s signature and
|
- Issue #16036: Improve documentation of built-in int()'s signature and
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue