Kaydet (Commit) 7865296c authored tarafından Philip Jenvey's avatar Philip Jenvey

Merged revisions 75143 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r75143 | philip.jenvey | 2009-09-29 12:10:15 -0700 (Tue, 29 Sep 2009) | 5 lines

  #5329: fix os.popen* regression from 2.5: don't execute commands as a sequence
  through the shell. also document the correct subprocess replacement for this
  case
  patch from Jean-Paul Calderone and Jani Hakala
........
üst b4b94ef4
...@@ -418,21 +418,21 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3` ...@@ -418,21 +418,21 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3`
:: ::
pipe = os.popen(cmd, 'r', bufsize) pipe = os.popen("cmd", 'r', bufsize)
==> ==>
pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
:: ::
pipe = os.popen(cmd, 'w', bufsize) pipe = os.popen("cmd", 'w', bufsize)
==> ==>
pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin
:: ::
(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) (child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout) (child_stdin, child_stdout) = (p.stdin, p.stdout)
...@@ -440,9 +440,9 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3` ...@@ -440,9 +440,9 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3`
(child_stdin, (child_stdin,
child_stdout, child_stdout,
child_stderr) = os.popen3(cmd, mode, bufsize) child_stderr) = os.popen3("cmd", mode, bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin, (child_stdin,
child_stdout, child_stdout,
...@@ -450,21 +450,33 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3` ...@@ -450,21 +450,33 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3`
:: ::
(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) (child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode,
bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
On Unix, os.popen2, os.popen3 and os.popen4 also accept a sequence as
the command to execute, in which case arguments will be passed
directly to the program without shell intervention. This usage can be
replaced as follows::
(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode,
bufsize)
==>
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
Return code handling translates as follows:: Return code handling translates as follows::
pipe = os.popen(cmd, 'w') pipe = os.popen("cmd", 'w')
... ...
rc = pipe.close() rc = pipe.close()
if rc != None and rc % 256: if rc != None and rc % 256:
print "There were some errors" print "There were some errors"
==> ==>
process = Popen(cmd, 'w', stdin=PIPE) process = Popen("cmd", 'w', shell=True, stdin=PIPE)
... ...
process.stdin.close() process.stdin.close()
if process.wait() != 0: if process.wait() != 0:
...@@ -474,11 +486,6 @@ Return code handling translates as follows:: ...@@ -474,11 +486,6 @@ Return code handling translates as follows::
Replacing functions from the :mod:`popen2` module Replacing functions from the :mod:`popen2` module
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
If the cmd argument to popen2 functions is a string, the command is executed
through /bin/sh. If it is a list, the command is directly executed.
:: ::
(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
...@@ -487,9 +494,12 @@ Replacing functions from the :mod:`popen2` module ...@@ -487,9 +494,12 @@ Replacing functions from the :mod:`popen2` module
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin) (child_stdout, child_stdin) = (p.stdout, p.stdin)
:: On Unix, popen2 also accepts a sequence as the command to execute, in
which case arguments will be passed directly to the program without
shell intervention. This usage can be replaced as follows::
(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize,
mode)
==> ==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize, p = Popen(["mycmd", "myarg"], bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
......
...@@ -670,8 +670,9 @@ if _exists("fork"): ...@@ -670,8 +670,9 @@ if _exists("fork"):
import subprocess import subprocess
PIPE = subprocess.PIPE PIPE = subprocess.PIPE
p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
stdin=PIPE, stdout=PIPE, close_fds=True) bufsize=bufsize, stdin=PIPE, stdout=PIPE,
close_fds=True)
return p.stdin, p.stdout return p.stdin, p.stdout
__all__.append("popen2") __all__.append("popen2")
...@@ -689,9 +690,9 @@ if _exists("fork"): ...@@ -689,9 +690,9 @@ if _exists("fork"):
import subprocess import subprocess
PIPE = subprocess.PIPE PIPE = subprocess.PIPE
p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=bufsize, stdin=PIPE, stdout=PIPE,
close_fds=True) stderr=PIPE, close_fds=True)
return p.stdin, p.stdout, p.stderr return p.stdin, p.stdout, p.stderr
__all__.append("popen3") __all__.append("popen3")
...@@ -709,8 +710,8 @@ if _exists("fork"): ...@@ -709,8 +710,8 @@ if _exists("fork"):
import subprocess import subprocess
PIPE = subprocess.PIPE PIPE = subprocess.PIPE
p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
stdin=PIPE, stdout=PIPE, bufsize=bufsize, stdin=PIPE, stdout=PIPE,
stderr=subprocess.STDOUT, close_fds=True) stderr=subprocess.STDOUT, close_fds=True)
return p.stdin, p.stdout return p.stdin, p.stdout
__all__.append("popen4") __all__.append("popen4")
......
...@@ -287,54 +287,80 @@ Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) ...@@ -287,54 +287,80 @@ Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
Replacing os.popen* Replacing os.popen*
------------------- -------------------
pipe = os.popen(cmd, mode='r', bufsize) pipe = os.popen("cmd", mode='r', bufsize)
==> ==>
pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
pipe = os.popen(cmd, mode='w', bufsize) pipe = os.popen("cmd", mode='w', bufsize)
==> ==>
pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin
(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) (child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout) (child_stdin, child_stdout) = (p.stdin, p.stdout)
(child_stdin, (child_stdin,
child_stdout, child_stdout,
child_stderr) = os.popen3(cmd, mode, bufsize) child_stderr) = os.popen3("cmd", mode, bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin, (child_stdin,
child_stdout, child_stdout,
child_stderr) = (p.stdin, p.stdout, p.stderr) child_stderr) = (p.stdin, p.stdout, p.stderr)
(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) (child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode,
bufsize)
==> ==>
p = Popen(cmd, shell=True, bufsize=bufsize, p = Popen("cmd", shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
On Unix, os.popen2, os.popen3 and os.popen4 also accept a sequence as
the command to execute, in which case arguments will be passed
directly to the program without shell intervention. This usage can be
replaced as follows:
(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode,
bufsize)
==>
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
Return code handling translates as follows:
pipe = os.popen("cmd", 'w')
...
rc = pipe.close()
if rc != None and rc % 256:
print "There were some errors"
==>
process = Popen("cmd", 'w', shell=True, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
print "There were some errors"
Replacing popen2.* Replacing popen2.*
------------------ ------------------
Note: If the cmd argument to popen2 functions is a string, the command
is executed through /bin/sh. If it is a list, the command is directly
executed.
(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
==> ==>
p = Popen(["somestring"], shell=True, bufsize=bufsize p = Popen(["somestring"], shell=True, bufsize=bufsize
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin) (child_stdout, child_stdin) = (p.stdout, p.stdin)
On Unix, popen2 also accepts a sequence as the command to execute, in
which case arguments will be passed directly to the program without
shell intervention. This usage can be replaced as follows:
(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize,
mode)
==> ==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize, p = Popen(["mycmd", "myarg"], bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True) stdin=PIPE, stdout=PIPE, close_fds=True)
......
...@@ -78,6 +78,14 @@ class Popen2Test(unittest.TestCase): ...@@ -78,6 +78,14 @@ class Popen2Test(unittest.TestCase):
def test_os_popen2(self): def test_os_popen2(self):
# same test as test_popen2(), but using the os.popen*() API # same test as test_popen2(), but using the os.popen*() API
if os.name == 'posix':
w, r = os.popen2([self.cmd])
self.validate_output(self.teststr, self.expected, r, w)
w, r = os.popen2(["echo", self.teststr])
got = r.read()
self.assertEquals(got, self.teststr + "\n")
w, r = os.popen2(self.cmd) w, r = os.popen2(self.cmd)
self.validate_output(self.teststr, self.expected, r, w) self.validate_output(self.teststr, self.expected, r, w)
...@@ -87,9 +95,27 @@ class Popen2Test(unittest.TestCase): ...@@ -87,9 +95,27 @@ class Popen2Test(unittest.TestCase):
w, r, e = os.popen3([self.cmd]) w, r, e = os.popen3([self.cmd])
self.validate_output(self.teststr, self.expected, r, w, e) self.validate_output(self.teststr, self.expected, r, w, e)
w, r, e = os.popen3(["echo", self.teststr])
got = r.read()
self.assertEquals(got, self.teststr + "\n")
got = e.read()
self.assertFalse(got, "unexpected %r on stderr" % got)
w, r, e = os.popen3(self.cmd) w, r, e = os.popen3(self.cmd)
self.validate_output(self.teststr, self.expected, r, w, e) self.validate_output(self.teststr, self.expected, r, w, e)
def test_os_popen4(self):
if os.name == 'posix':
w, r = os.popen4([self.cmd])
self.validate_output(self.teststr, self.expected, r, w)
w, r = os.popen4(["echo", self.teststr])
got = r.read()
self.assertEquals(got, self.teststr + "\n")
w, r = os.popen4(self.cmd)
self.validate_output(self.teststr, self.expected, r, w)
def test_main(): def test_main():
run_unittest(Popen2Test) run_unittest(Popen2Test)
......
...@@ -12,6 +12,10 @@ What's New in Python 2.6.3 ...@@ -12,6 +12,10 @@ What's New in Python 2.6.3
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #5329: Fix os.popen* regression from 2.5 with commands as a
sequence running through the shell. Patch by Jean-Paul Calderone
and Jani Hakala.
- Issue #6990: Fix threading.local subclasses leaving old state around - Issue #6990: Fix threading.local subclasses leaving old state around
after a reference cycle GC which could be recycled by new locals. after a reference cycle GC which could be recycled by new locals.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment