import platform
import signal
import io
+import itertools
import os
import errno
import tempfile
self.check_swap_fds(2, 0, 1)
self.check_swap_fds(2, 1, 0)
+ def _check_swap_std_fds_with_one_closed(self, from_fds, to_fds):
+ saved_fds = self._save_fds(range(3))
+ try:
+ for from_fd in from_fds:
+ with tempfile.TemporaryFile() as f:
+ os.dup2(f.fileno(), from_fd)
+
+ fd_to_close = (set(range(3)) - set(from_fds)).pop()
+ os.close(fd_to_close)
+
+ arg_names = ['stdin', 'stdout', 'stderr']
+ kwargs = {}
+ for from_fd, to_fd in zip(from_fds, to_fds):
+ kwargs[arg_names[to_fd]] = from_fd
+
+ code = textwrap.dedent(r'''
+ import os, sys
+ skipped_fd = int(sys.argv[1])
+ for fd in range(3):
+ if fd != skipped_fd:
+ os.write(fd, str(fd).encode('ascii'))
+ ''')
+
+ skipped_fd = (set(range(3)) - set(to_fds)).pop()
+
+ rc = subprocess.call([sys.executable, '-c', code, str(skipped_fd)],
+ **kwargs)
+ self.assertEqual(rc, 0)
+
+ for from_fd, to_fd in zip(from_fds, to_fds):
+ os.lseek(from_fd, 0, os.SEEK_SET)
+ read_bytes = os.read(from_fd, 1024)
+ read_fds = list(map(int, read_bytes.decode('ascii')))
+ msg = textwrap.dedent(f"""
+ When testing {from_fds} to {to_fds} redirection,
+ parent descriptor {from_fd} got redirected
+ to descriptor(s) {read_fds} instead of descriptor {to_fd}.
+ """)
+ self.assertEqual([to_fd], read_fds, msg)
+ finally:
+ self._restore_fds(saved_fds)
+
+ # Check that subprocess can remap std fds correctly even
+ # if one of them is closed (#32844).
+ def test_swap_std_fds_with_one_closed(self):
+ for from_fds in itertools.combinations(range(3), 2):
+ for to_fds in itertools.permutations(range(3), 2):
+ self._check_swap_std_fds_with_one_closed(from_fds, to_fds)
+
def test_surrogates_error_message(self):
def prepare():
raise ValueError("surrogate:\uDCff")