Skip to content

Commit 251d3a2

Browse files
committed
return the new file descriptor from os.dup2 (closes bpo-32441)
1 parent e5f7dcc commit 251d3a2

File tree

4 files changed

+17
-14
lines changed

4 files changed

+17
-14
lines changed

Doc/library/os.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,17 @@ as internal buffering of data.
735735

736736
.. function:: dup2(fd, fd2, inheritable=True)
737737

738-
Duplicate file descriptor *fd* to *fd2*, closing the latter first if necessary.
739-
The file descriptor *fd2* is :ref:`inheritable <fd_inheritance>` by default,
740-
or non-inheritable if *inheritable* is ``False``.
738+
Duplicate file descriptor *fd* to *fd2*, closing the latter first if
739+
necessary. Return *fd2*. The new file descriptor is :ref:`inheritable
740+
<fd_inheritance>` by default or non-inheritable if *inheritable*
741+
is ``False``.
741742

742743
.. versionchanged:: 3.4
743744
Add the optional *inheritable* parameter.
744745

746+
.. versionchanged:: 3.7
747+
Return *fd2* on success. Previously, ``None`` was always returned.
748+
745749

746750
.. function:: fchmod(fd, mode)
747751

Lib/test/test_os.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,19 +3079,15 @@ def test_dup2(self):
30793079

30803080
# inheritable by default
30813081
fd2 = os.open(__file__, os.O_RDONLY)
3082-
try:
3083-
os.dup2(fd, fd2)
3084-
self.assertEqual(os.get_inheritable(fd2), True)
3085-
finally:
3086-
os.close(fd2)
3082+
self.addCleanup(os.close, fd2)
3083+
self.assertEqual(os.dup2(fd, fd2), fd2)
3084+
self.assertTrue(os.get_inheritable(fd2))
30873085

30883086
# force non-inheritable
30893087
fd3 = os.open(__file__, os.O_RDONLY)
3090-
try:
3091-
os.dup2(fd, fd3, inheritable=False)
3092-
self.assertEqual(os.get_inheritable(fd3), False)
3093-
finally:
3094-
os.close(fd3)
3088+
self.addCleanup(os.close, fd3)
3089+
self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3)
3090+
self.assertFalse(os.get_inheritable(fd3))
30953091

30963092
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
30973093
def test_openpty(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Return the new file descriptor (i.e., the second argument) from ``os.dup2``.
2+
Previously, ``None`` was always returned.

Modules/posixmodule.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7804,6 +7804,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78047804
Py_END_ALLOW_THREADS
78057805
if (res < 0)
78067806
return posix_error();
7807+
res = fd2; // msvcrt dup2 returns 0 on success.
78077808

78087809
/* Character files like console cannot be make non-inheritable */
78097810
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
@@ -7855,7 +7856,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
78557856

78567857
#endif
78577858

7858-
Py_RETURN_NONE;
7859+
return PyLong_FromLong(res);
78597860
}
78607861

78617862

0 commit comments

Comments
 (0)