Skip to content

Commit 8cdb300

Browse files
committed
Use FD=0/1/2 for subprocess(stdio=None)
This aligns uvloop with the same behavior in asyncio - when stdin, stdout or stderr is None, the subprocess will use FD 0, 1 or 2 now instead of sys.stdin, sys.stdout or sys.stderr. Fixes #136
1 parent 8c471f8 commit 8cdb300

File tree

2 files changed

+48
-35
lines changed

2 files changed

+48
-35
lines changed

tests/test_process.py

+45-32
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
from uvloop import _testbase as tb
1616

1717

18+
class _RedirectFD(contextlib.AbstractContextManager):
19+
def __init__(self, old_file, new_file):
20+
self._old_fd = old_file.fileno()
21+
self._old_fd_save = os.dup(self._old_fd)
22+
self._new_fd = new_file.fileno()
23+
24+
def __enter__(self):
25+
os.dup2(self._new_fd, self._old_fd)
26+
27+
def __exit__(self, exc_type, exc_val, exc_tb):
28+
os.dup2(self._old_fd_save, self._old_fd)
29+
os.close(self._old_fd_save)
30+
31+
1832
class _TestProcess:
1933
def get_num_fds(self):
2034
return psutil.Process(os.getpid()).num_fds()
@@ -407,6 +421,36 @@ async def main():
407421

408422
self.loop.run_until_complete(main())
409423

424+
def test_process_streams_redirect(self):
425+
async def test():
426+
prog = bR'''
427+
import sys
428+
print('out', flush=True)
429+
print('err', file=sys.stderr, flush=True)
430+
'''
431+
432+
proc = await asyncio.create_subprocess_exec(
433+
sys.executable, b'-W', b'ignore', b'-c', prog)
434+
435+
out, err = await proc.communicate()
436+
self.assertIsNone(out)
437+
self.assertIsNone(err)
438+
439+
with tempfile.NamedTemporaryFile('w') as stdout:
440+
with tempfile.NamedTemporaryFile('w') as stderr:
441+
with _RedirectFD(sys.stdout, stdout):
442+
with _RedirectFD(sys.stderr, stderr):
443+
self.loop.run_until_complete(test())
444+
445+
stdout.flush()
446+
stderr.flush()
447+
448+
with open(stdout.name, 'rb') as so:
449+
self.assertEqual(so.read(), b'out\n')
450+
451+
with open(stderr.name, 'rb') as se:
452+
self.assertEqual(se.read(), b'err\n')
453+
410454

411455
class _AsyncioTests:
412456

@@ -752,38 +796,7 @@ async def test():
752796

753797

754798
class Test_UV_Process(_TestProcess, tb.UVTestCase):
755-
756-
def test_process_streams_redirect(self):
757-
# This won't work for asyncio implementation of subprocess
758-
759-
async def test():
760-
prog = bR'''
761-
import sys
762-
print('out', flush=True)
763-
print('err', file=sys.stderr, flush=True)
764-
'''
765-
766-
proc = await asyncio.create_subprocess_exec(
767-
sys.executable, b'-W', b'ignore', b'-c', prog)
768-
769-
out, err = await proc.communicate()
770-
self.assertIsNone(out)
771-
self.assertIsNone(err)
772-
773-
with tempfile.NamedTemporaryFile('w') as stdout:
774-
with tempfile.NamedTemporaryFile('w') as stderr:
775-
with contextlib.redirect_stdout(stdout):
776-
with contextlib.redirect_stderr(stderr):
777-
self.loop.run_until_complete(test())
778-
779-
stdout.flush()
780-
stderr.flush()
781-
782-
with open(stdout.name, 'rb') as so:
783-
self.assertEqual(so.read(), b'out\n')
784-
785-
with open(stderr.name, 'rb') as se:
786-
self.assertEqual(se.read(), b'err\n')
799+
pass
787800

788801

789802
class Test_AIO_Process(_TestProcess, tb.AIOTestCase):

uvloop/handles/process.pyx

+3-3
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ cdef class UVProcessTransport(UVProcess):
452452
else:
453453
io[0] = self._file_redirect_stdio(_stdin)
454454
else:
455-
io[0] = self._file_redirect_stdio(sys.stdin.fileno())
455+
io[0] = self._file_redirect_stdio(0)
456456

457457
if _stdout is not None:
458458
if _stdout == subprocess_PIPE:
@@ -480,7 +480,7 @@ cdef class UVProcessTransport(UVProcess):
480480
else:
481481
io[1] = self._file_redirect_stdio(_stdout)
482482
else:
483-
io[1] = self._file_redirect_stdio(sys.stdout.fileno())
483+
io[1] = self._file_redirect_stdio(1)
484484

485485
if _stderr is not None:
486486
if _stderr == subprocess_PIPE:
@@ -508,7 +508,7 @@ cdef class UVProcessTransport(UVProcess):
508508
else:
509509
io[2] = self._file_redirect_stdio(_stderr)
510510
else:
511-
io[2] = self._file_redirect_stdio(sys.stderr.fileno())
511+
io[2] = self._file_redirect_stdio(2)
512512

513513
assert len(io) == 3
514514
for idx in range(3):

0 commit comments

Comments
 (0)