Skip to content

Commit f083090

Browse files
committed
Allow file objects to be passed to loop.subprocess* functions.
Fixes #136.
1 parent 572524a commit f083090

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

tests/test_process.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ class _AsyncioTests:
342342
'data = sys.stdin.buffer.read()',
343343
'sys.stdout.buffer.write(data)'))]
344344

345+
PROGRAM_ERROR = [
346+
sys.executable, '-c', '1/0'
347+
]
348+
345349
def test_stdin_not_inheritable(self):
346350
# asyncio issue #209: stdin must not be inheritable, otherwise
347351
# the Process.communicate() hangs
@@ -363,7 +367,7 @@ def len_message(message):
363367
self.assertEqual(output.rstrip(), b'3')
364368
self.assertEqual(exitcode, 0)
365369

366-
def test_stdin_stdout(self):
370+
def test_stdin_stdout_pipe(self):
367371
args = self.PROGRAM_CAT
368372

369373
@asyncio.coroutine
@@ -390,6 +394,57 @@ def run(data):
390394
self.assertEqual(exitcode, 0)
391395
self.assertEqual(stdout, b'some data')
392396

397+
def test_stdin_stdout_file(self):
398+
args = self.PROGRAM_CAT
399+
400+
@asyncio.coroutine
401+
def run(data, stderr):
402+
proc = yield from asyncio.create_subprocess_exec(
403+
*args,
404+
stdin=subprocess.PIPE,
405+
stderr=stdout,
406+
loop=self.loop)
407+
408+
# feed data
409+
proc.stdin.write(data)
410+
yield from proc.stdin.drain()
411+
proc.stdin.close()
412+
413+
exitcode = yield from proc.wait()
414+
return exitcode
415+
416+
with tempfile.TemporaryFile('w+b') as new_stdout:
417+
task = run(b'some data', new_stdout)
418+
task = asyncio.wait_for(task, 60.0, loop=self.loop)
419+
exitcode = self.loop.run_until_complete(task)
420+
self.assertEqual(exitcode, 0)
421+
422+
new_stdout.seek(0)
423+
self.assertEqual(new_stdout.read(), b'some data')
424+
425+
def test_stdin_stderr_file(self):
426+
args = self.PROGRAM_ERROR
427+
428+
@asyncio.coroutine
429+
def run(stderr):
430+
proc = yield from asyncio.create_subprocess_exec(
431+
*args,
432+
stdin=subprocess.PIPE,
433+
stderr=stderr,
434+
loop=self.loop)
435+
436+
exitcode = yield from proc.wait()
437+
return exitcode
438+
439+
with tempfile.TemporaryFile('w+b') as new_stderr:
440+
task = run(new_stderr)
441+
task = asyncio.wait_for(task, 60.0, loop=self.loop)
442+
exitcode = self.loop.run_until_complete(task)
443+
self.assertEqual(exitcode, 1)
444+
445+
new_stderr.seek(0)
446+
self.assertIn(b'ZeroDivisionError', new_stderr.read())
447+
393448
def test_communicate(self):
394449
args = self.PROGRAM_CAT
395450

uvloop/handles/process.pyx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,7 @@ cdef class UVProcessTransport(UVProcess):
424424
raise ValueError(
425425
'subprocess.STDOUT is supported only by stderr parameter')
426426
else:
427-
raise ValueError(
428-
'invalid stdin argument value {!r}'.format(_stdin))
427+
io[0] = self._file_redirect_stdio(_stdin)
429428
else:
430429
io[0] = self._file_redirect_stdio(sys.stdin.fileno())
431430

@@ -453,8 +452,7 @@ cdef class UVProcessTransport(UVProcess):
453452
raise ValueError(
454453
'subprocess.STDOUT is supported only by stderr parameter')
455454
else:
456-
raise ValueError(
457-
'invalid stdout argument value {!r}'.format(_stdout))
455+
io[1] = self._file_redirect_stdio(_stdout)
458456
else:
459457
io[1] = self._file_redirect_stdio(sys.stdout.fileno())
460458

@@ -482,8 +480,7 @@ cdef class UVProcessTransport(UVProcess):
482480
elif _stderr == subprocess_DEVNULL:
483481
io[2] = self._file_devnull()
484482
else:
485-
raise ValueError(
486-
'invalid stderr argument value {!r}'.format(_stderr))
483+
io[2] = self._file_redirect_stdio(_stderr)
487484
else:
488485
io[2] = self._file_redirect_stdio(sys.stderr.fileno())
489486

0 commit comments

Comments
 (0)