summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_cmd_line.py39
-rw-r--r--Misc/NEWS4
-rw-r--r--Python/pythonrun.c31
3 files changed, 59 insertions, 15 deletions
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 8167e78..2fca25e 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -291,6 +291,45 @@ class CmdLineTest(unittest.TestCase):
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(b'', err)
+ # Issue #7111: Python should work without standard streams
+
+ @unittest.skipIf(os.name != 'posix', "test needs POSIX semantics")
+ def _test_no_stdio(self, streams):
+ code = """if 1:
+ import os, sys
+ for i, s in enumerate({streams}):
+ if getattr(sys, s) is not None:
+ os._exit(i + 1)
+ os._exit(42)""".format(streams=streams)
+ def preexec():
+ if 'stdin' in streams:
+ os.close(0)
+ if 'stdout' in streams:
+ os.close(1)
+ if 'stderr' in streams:
+ os.close(2)
+ p = subprocess.Popen(
+ [sys.executable, "-E", "-c", code],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ preexec_fn=preexec)
+ out, err = p.communicate()
+ self.assertEqual(test.support.strip_python_stderr(err), b'')
+ self.assertEqual(p.returncode, 42)
+
+ def test_no_stdin(self):
+ self._test_no_stdio(['stdin'])
+
+ def test_no_stdout(self):
+ self._test_no_stdio(['stdout'])
+
+ def test_no_stderr(self):
+ self._test_no_stdio(['stderr'])
+
+ def test_no_std_streams(self):
+ self._test_no_stdio(['stdin', 'stdout', 'stderr'])
+
def test_main():
test.support.run_unittest(CmdLineTest)
diff --git a/Misc/NEWS b/Misc/NEWS
index 3041a73..f79e57a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ What's New in Python 3.2.3?
Core and Builtins
-----------------
+- Issue #7111: Python can now be run without a stdin, stdout or stderr
+ stream. It was already the case with Python 2. However, the corresponding
+ sys module entries are now set to None (instead of an unusable file object).
+
- Issue #13436: Fix a bogus error message when an AST object was passed
an invalid integer value.
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index fe92d30..4b0ac13 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -892,6 +892,19 @@ error:
return NULL;
}
+static int
+is_valid_fd(int fd)
+{
+ int dummy_fd;
+ if (fd < 0 || !_PyVerify_fd(fd))
+ return 0;
+ dummy_fd = dup(fd);
+ if (dummy_fd < 0)
+ return 0;
+ close(dummy_fd);
+ return 1;
+}
+
/* Initialize sys.stdin, stdout, stderr and builtins.open */
static int
initstdio(void)
@@ -951,13 +964,9 @@ initstdio(void)
* and fileno() may point to an invalid file descriptor. For example
* GUI apps don't have valid standard streams by default.
*/
- if (fd < 0) {
-#ifdef MS_WINDOWS
+ if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
-#else
- goto error;
-#endif
}
else {
std = create_stdio(iomod, fd, 0, "<stdin>", encoding, errors);
@@ -970,13 +979,9 @@ initstdio(void)
/* Set sys.stdout */
fd = fileno(stdout);
- if (fd < 0) {
-#ifdef MS_WINDOWS
+ if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
-#else
- goto error;
-#endif
}
else {
std = create_stdio(iomod, fd, 1, "<stdout>", encoding, errors);
@@ -990,13 +995,9 @@ initstdio(void)
#if 1 /* Disable this if you have trouble debugging bootstrap stuff */
/* Set sys.stderr, replaces the preliminary stderr */
fd = fileno(stderr);
- if (fd < 0) {
-#ifdef MS_WINDOWS
+ if (!is_valid_fd(fd)) {
std = Py_None;
Py_INCREF(std);
-#else
- goto error;
-#endif
}
else {
std = create_stdio(iomod, fd, 1, "<stderr>", encoding, "backslashreplace");