2
from test import test_support
11
mswindows = (sys.platform == "win32")
14
# Depends on the following external programs: Python
18
SETBINARY = ('import msvcrt; msvcrt.setmode(sys.stdout.fileno(), '
23
# In a debug build, stuff like "[6580 refs]" is printed to stderr at
24
# shutdown time. That frustrates tests trying to check stderr produced
25
# from a spawned Python process.
26
def remove_stderr_debug_decorations(stderr):
27
return re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr)
29
class ProcessTestCase(unittest.TestCase):
31
"""wrapper for mkstemp, calling mktemp if mkstemp is not available"""
32
if hasattr(tempfile, "mkstemp"):
33
return tempfile.mkstemp()
35
fname = tempfile.mktemp()
36
return os.open(fname, os.O_RDWR|os.O_CREAT), fname
41
def test_call_seq(self):
42
# call() function with sequence argument
43
rc = subprocess.call([sys.executable, "-c",
44
"import sys; sys.exit(47)"])
45
self.assertEqual(rc, 47)
47
def test_call_kwargs(self):
48
# call() function with keyword args
49
newenv = os.environ.copy()
50
newenv["FRUIT"] = "banana"
51
rc = subprocess.call([sys.executable, "-c",
53
'sys.exit(os.getenv("FRUIT")=="banana")'],
55
self.assertEqual(rc, 1)
57
def test_stdin_none(self):
58
# .stdin is None when not redirected
59
p = subprocess.Popen([sys.executable, "-c", 'print "banana"'],
60
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
62
self.assertEqual(p.stdin, None)
64
def test_stdout_none(self):
65
# .stdout is None when not redirected
66
p = subprocess.Popen([sys.executable, "-c",
67
'print " this bit of output is from a '
68
'test of stdout in a different '
70
stdin=subprocess.PIPE, stderr=subprocess.PIPE)
72
self.assertEqual(p.stdout, None)
74
def test_stderr_none(self):
75
# .stderr is None when not redirected
76
p = subprocess.Popen([sys.executable, "-c", 'print "banana"'],
77
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
79
self.assertEqual(p.stderr, None)
81
def test_executable(self):
82
p = subprocess.Popen(["somethingyoudonthave",
83
"-c", "import sys; sys.exit(47)"],
84
executable=sys.executable)
86
self.assertEqual(p.returncode, 47)
88
def test_stdin_pipe(self):
90
p = subprocess.Popen([sys.executable, "-c",
91
'import sys; sys.exit(sys.stdin.read() == "pear")'],
92
stdin=subprocess.PIPE)
96
self.assertEqual(p.returncode, 1)
98
def test_stdin_filedes(self):
99
# stdin is set to open file descriptor
100
tf = tempfile.TemporaryFile()
104
p = subprocess.Popen([sys.executable, "-c",
105
'import sys; sys.exit(sys.stdin.read() == "pear")'],
108
self.assertEqual(p.returncode, 1)
110
def test_stdin_fileobj(self):
111
# stdin is set to open file object
112
tf = tempfile.TemporaryFile()
115
p = subprocess.Popen([sys.executable, "-c",
116
'import sys; sys.exit(sys.stdin.read() == "pear")'],
119
self.assertEqual(p.returncode, 1)
121
def test_stdout_pipe(self):
123
p = subprocess.Popen([sys.executable, "-c",
124
'import sys; sys.stdout.write("orange")'],
125
stdout=subprocess.PIPE)
126
self.assertEqual(p.stdout.read(), "orange")
128
def test_stdout_filedes(self):
129
# stdout is set to open file descriptor
130
tf = tempfile.TemporaryFile()
132
p = subprocess.Popen([sys.executable, "-c",
133
'import sys; sys.stdout.write("orange")'],
137
self.assertEqual(os.read(d, 1024), "orange")
139
def test_stdout_fileobj(self):
140
# stdout is set to open file object
141
tf = tempfile.TemporaryFile()
142
p = subprocess.Popen([sys.executable, "-c",
143
'import sys; sys.stdout.write("orange")'],
147
self.assertEqual(tf.read(), "orange")
149
def test_stderr_pipe(self):
151
p = subprocess.Popen([sys.executable, "-c",
152
'import sys; sys.stderr.write("strawberry")'],
153
stderr=subprocess.PIPE)
154
self.assertEqual(remove_stderr_debug_decorations(p.stderr.read()),
157
def test_stderr_filedes(self):
158
# stderr is set to open file descriptor
159
tf = tempfile.TemporaryFile()
161
p = subprocess.Popen([sys.executable, "-c",
162
'import sys; sys.stderr.write("strawberry")'],
166
self.assertEqual(remove_stderr_debug_decorations(os.read(d, 1024)),
169
def test_stderr_fileobj(self):
170
# stderr is set to open file object
171
tf = tempfile.TemporaryFile()
172
p = subprocess.Popen([sys.executable, "-c",
173
'import sys; sys.stderr.write("strawberry")'],
177
self.assertEqual(remove_stderr_debug_decorations(tf.read()),
180
def test_stdout_stderr_pipe(self):
181
# capture stdout and stderr to the same pipe
182
p = subprocess.Popen([sys.executable, "-c",
184
'sys.stdout.write("apple");' \
185
'sys.stdout.flush();' \
186
'sys.stderr.write("orange")'],
187
stdout=subprocess.PIPE,
188
stderr=subprocess.STDOUT)
189
output = p.stdout.read()
190
stripped = remove_stderr_debug_decorations(output)
191
self.assertEqual(stripped, "appleorange")
193
def test_stdout_stderr_file(self):
194
# capture stdout and stderr to the same open file
195
tf = tempfile.TemporaryFile()
196
p = subprocess.Popen([sys.executable, "-c",
198
'sys.stdout.write("apple");' \
199
'sys.stdout.flush();' \
200
'sys.stderr.write("orange")'],
206
stripped = remove_stderr_debug_decorations(output)
207
self.assertEqual(stripped, "appleorange")
210
tmpdir = os.getenv("TEMP", "/tmp")
211
# We cannot use os.path.realpath to canonicalize the path,
212
# since it doesn't expand Tru64 {memb} strings. See bug 1063571.
217
p = subprocess.Popen([sys.executable, "-c",
219
'sys.stdout.write(os.getcwd())'],
220
stdout=subprocess.PIPE,
222
normcase = os.path.normcase
223
self.assertEqual(normcase(p.stdout.read()), normcase(tmpdir))
226
newenv = os.environ.copy()
227
newenv["FRUIT"] = "orange"
228
p = subprocess.Popen([sys.executable, "-c",
230
'sys.stdout.write(os.getenv("FRUIT"))'],
231
stdout=subprocess.PIPE,
233
self.assertEqual(p.stdout.read(), "orange")
235
def test_communicate(self):
236
p = subprocess.Popen([sys.executable, "-c",
238
'sys.stderr.write("pineapple");' \
239
'sys.stdout.write(sys.stdin.read())'],
240
stdin=subprocess.PIPE,
241
stdout=subprocess.PIPE,
242
stderr=subprocess.PIPE)
243
(stdout, stderr) = p.communicate("banana")
244
self.assertEqual(stdout, "banana")
245
self.assertEqual(remove_stderr_debug_decorations(stderr),
248
def test_communicate_returns(self):
249
# communicate() should return None if no redirection is active
250
p = subprocess.Popen([sys.executable, "-c",
251
"import sys; sys.exit(47)"])
252
(stdout, stderr) = p.communicate()
253
self.assertEqual(stdout, None)
254
self.assertEqual(stderr, None)
256
def test_communicate_pipe_buf(self):
257
# communicate() with writes larger than pipe_buf
258
# This test will probably deadlock rather than fail, if
259
# communicate() does not work properly.
264
pipe_buf = os.fpathconf(x, "PC_PIPE_BUF")
267
p = subprocess.Popen([sys.executable, "-c",
269
'sys.stdout.write(sys.stdin.read(47));' \
270
'sys.stderr.write("xyz"*%d);' \
271
'sys.stdout.write(sys.stdin.read())' % pipe_buf],
272
stdin=subprocess.PIPE,
273
stdout=subprocess.PIPE,
274
stderr=subprocess.PIPE)
275
string_to_write = "abc"*pipe_buf
276
(stdout, stderr) = p.communicate(string_to_write)
277
self.assertEqual(stdout, string_to_write)
279
def test_writes_before_communicate(self):
280
# stdin.write before communicate()
281
p = subprocess.Popen([sys.executable, "-c",
283
'sys.stdout.write(sys.stdin.read())'],
284
stdin=subprocess.PIPE,
285
stdout=subprocess.PIPE,
286
stderr=subprocess.PIPE)
287
p.stdin.write("banana")
288
(stdout, stderr) = p.communicate("split")
289
self.assertEqual(stdout, "bananasplit")
290
self.assertEqual(remove_stderr_debug_decorations(stderr), "")
292
def test_universal_newlines(self):
293
p = subprocess.Popen([sys.executable, "-c",
294
'import sys,os;' + SETBINARY +
295
'sys.stdout.write("line1\\n");'
296
'sys.stdout.flush();'
297
'sys.stdout.write("line2\\r");'
298
'sys.stdout.flush();'
299
'sys.stdout.write("line3\\r\\n");'
300
'sys.stdout.flush();'
301
'sys.stdout.write("line4\\r");'
302
'sys.stdout.flush();'
303
'sys.stdout.write("\\nline5");'
304
'sys.stdout.flush();'
305
'sys.stdout.write("\\nline6");'],
306
stdout=subprocess.PIPE,
307
universal_newlines=1)
308
stdout = p.stdout.read()
309
if hasattr(open, 'newlines'):
310
# Interpreter with universal newline support
311
self.assertEqual(stdout,
312
"line1\nline2\nline3\nline4\nline5\nline6")
314
# Interpreter without universal newline support
315
self.assertEqual(stdout,
316
"line1\nline2\rline3\r\nline4\r\nline5\nline6")
318
def test_universal_newlines_communicate(self):
319
# universal newlines through communicate()
320
p = subprocess.Popen([sys.executable, "-c",
321
'import sys,os;' + SETBINARY +
322
'sys.stdout.write("line1\\n");'
323
'sys.stdout.flush();'
324
'sys.stdout.write("line2\\r");'
325
'sys.stdout.flush();'
326
'sys.stdout.write("line3\\r\\n");'
327
'sys.stdout.flush();'
328
'sys.stdout.write("line4\\r");'
329
'sys.stdout.flush();'
330
'sys.stdout.write("\\nline5");'
331
'sys.stdout.flush();'
332
'sys.stdout.write("\\nline6");'],
333
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
334
universal_newlines=1)
335
(stdout, stderr) = p.communicate()
336
if hasattr(open, 'newlines'):
337
# Interpreter with universal newline support
338
self.assertEqual(stdout,
339
"line1\nline2\nline3\nline4\nline5\nline6")
341
# Interpreter without universal newline support
342
self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6")
344
def test_no_leaking(self):
345
# Make sure we leak no resources
346
if test_support.is_resource_enabled("subprocess") and not mswindows:
347
max_handles = 1026 # too much for most UNIX systems
350
for i in range(max_handles):
351
p = subprocess.Popen([sys.executable, "-c",
352
"import sys;sys.stdout.write(sys.stdin.read())"],
353
stdin=subprocess.PIPE,
354
stdout=subprocess.PIPE,
355
stderr=subprocess.PIPE)
356
data = p.communicate("lime")[0]
357
self.assertEqual(data, "lime")
360
def test_list2cmdline(self):
361
self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']),
363
self.assertEqual(subprocess.list2cmdline(['ab"c', '\\', 'd']),
365
self.assertEqual(subprocess.list2cmdline(['a\\\\\\b', 'de fg', 'h']),
366
'a\\\\\\b "de fg" h')
367
self.assertEqual(subprocess.list2cmdline(['a\\"b', 'c', 'd']),
369
self.assertEqual(subprocess.list2cmdline(['a\\\\b c', 'd', 'e']),
371
self.assertEqual(subprocess.list2cmdline(['a\\\\b\\ c', 'd', 'e']),
376
p = subprocess.Popen([sys.executable,
377
"-c", "import time; time.sleep(1)"])
379
while p.poll() is None:
382
# We expect that the poll loop probably went around about 10 times,
383
# but, based on system scheduling we can't control, it's possible
384
# poll() never returned None. It "should be" very rare that it
385
# didn't go around at least twice.
386
self.assert_(count >= 2)
387
# Subsequent invocations should just return the returncode
388
self.assertEqual(p.poll(), 0)
392
p = subprocess.Popen([sys.executable,
393
"-c", "import time; time.sleep(2)"])
394
self.assertEqual(p.wait(), 0)
395
# Subsequent invocations should just return the returncode
396
self.assertEqual(p.wait(), 0)
399
def test_invalid_bufsize(self):
400
# an invalid type of the bufsize argument should raise
403
subprocess.Popen([sys.executable, "-c", "pass"], "orange")
407
self.fail("Expected TypeError")
413
def test_exceptions(self):
414
# catched & re-raised exceptions
416
p = subprocess.Popen([sys.executable, "-c", ""],
417
cwd="/this/path/does/not/exist")
419
# The attribute child_traceback should contain "os.chdir"
421
self.assertNotEqual(e.child_traceback.find("os.chdir"), -1)
423
self.fail("Expected OSError")
425
def test_run_abort(self):
426
# returncode handles signal termination
427
p = subprocess.Popen([sys.executable,
428
"-c", "import os; os.abort()"])
430
self.assertEqual(-p.returncode, signal.SIGABRT)
432
def test_preexec(self):
434
p = subprocess.Popen([sys.executable, "-c",
436
'sys.stdout.write(os.getenv("FRUIT"))'],
437
stdout=subprocess.PIPE,
438
preexec_fn=lambda: os.putenv("FRUIT", "apple"))
439
self.assertEqual(p.stdout.read(), "apple")
441
def test_args_string(self):
443
f, fname = self.mkstemp()
444
os.write(f, "#!/bin/sh\n")
445
os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" %
448
os.chmod(fname, 0700)
449
p = subprocess.Popen(fname)
452
self.assertEqual(p.returncode, 47)
454
def test_invalid_args(self):
455
# invalid arguments should raise ValueError
456
self.assertRaises(ValueError, subprocess.call,
458
"-c", "import sys; sys.exit(47)"],
460
self.assertRaises(ValueError, subprocess.call,
462
"-c", "import sys; sys.exit(47)"],
465
def test_shell_sequence(self):
466
# Run command through the shell (sequence)
467
newenv = os.environ.copy()
468
newenv["FRUIT"] = "apple"
469
p = subprocess.Popen(["echo $FRUIT"], shell=1,
470
stdout=subprocess.PIPE,
472
self.assertEqual(p.stdout.read().strip(), "apple")
474
def test_shell_string(self):
475
# Run command through the shell (string)
476
newenv = os.environ.copy()
477
newenv["FRUIT"] = "apple"
478
p = subprocess.Popen("echo $FRUIT", shell=1,
479
stdout=subprocess.PIPE,
481
self.assertEqual(p.stdout.read().strip(), "apple")
483
def test_call_string(self):
484
# call() function with string argument on UNIX
485
f, fname = self.mkstemp()
486
os.write(f, "#!/bin/sh\n")
487
os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" %
490
os.chmod(fname, 0700)
491
rc = subprocess.call(fname)
493
self.assertEqual(rc, 47)
500
def test_startupinfo(self):
501
# startupinfo argument
502
# We uses hardcoded constants, because we do not want to
503
# depend on win32all.
504
STARTF_USESHOWWINDOW = 1
506
startupinfo = subprocess.STARTUPINFO()
507
startupinfo.dwFlags = STARTF_USESHOWWINDOW
508
startupinfo.wShowWindow = SW_MAXIMIZE
509
# Since Python is a console process, it won't be affected
510
# by wShowWindow, but the argument should be silently
512
subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"],
513
startupinfo=startupinfo)
515
def test_creationflags(self):
516
# creationflags argument
517
CREATE_NEW_CONSOLE = 16
518
sys.stderr.write(" a DOS box should flash briefly ...\n")
519
subprocess.call(sys.executable +
520
' -c "import time; time.sleep(0.25)"',
521
creationflags=CREATE_NEW_CONSOLE)
523
def test_invalid_args(self):
524
# invalid arguments should raise ValueError
525
self.assertRaises(ValueError, subprocess.call,
527
"-c", "import sys; sys.exit(47)"],
528
preexec_fn=lambda: 1)
529
self.assertRaises(ValueError, subprocess.call,
531
"-c", "import sys; sys.exit(47)"],
534
def test_shell_sequence(self):
535
# Run command through the shell (sequence)
536
newenv = os.environ.copy()
537
newenv["FRUIT"] = "physalis"
538
p = subprocess.Popen(["set"], shell=1,
539
stdout=subprocess.PIPE,
541
self.assertNotEqual(p.stdout.read().find("physalis"), -1)
543
def test_shell_string(self):
544
# Run command through the shell (string)
545
newenv = os.environ.copy()
546
newenv["FRUIT"] = "physalis"
547
p = subprocess.Popen("set", shell=1,
548
stdout=subprocess.PIPE,
550
self.assertNotEqual(p.stdout.read().find("physalis"), -1)
552
def test_call_string(self):
553
# call() function with string argument on Windows
554
rc = subprocess.call(sys.executable +
555
' -c "import sys; sys.exit(47)"')
556
self.assertEqual(rc, 47)
560
test_support.run_unittest(ProcessTestCase)
562
if __name__ == "__main__":