]> granicus.if.org Git - python/commitdiff
Merged revisions 75143 via svnmerge from
authorPhilip Jenvey <pjenvey@underboss.org>
Tue, 29 Sep 2009 19:18:11 +0000 (19:18 +0000)
committerPhilip Jenvey <pjenvey@underboss.org>
Tue, 29 Sep 2009 19:18:11 +0000 (19:18 +0000)
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
........

Doc/library/subprocess.rst
Lib/os.py
Lib/subprocess.py
Lib/test/test_popen2.py
Misc/NEWS

index 2bc8f74bec2c05c183381d35b383c7d909fd4e9b..c6bd07bea397fe2126279d65563bee284d88c0a4 100644 (file)
@@ -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)
    (child_stdin, child_stdout) = (p.stdin, p.stdout)
 
@@ -440,9 +440,9 @@ Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3`
 
    (child_stdin,
     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)
    (child_stdin,
     child_stdout,
@@ -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)
    (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')
+   pipe = os.popen("cmd", 'w')
    ...
    rc = pipe.close()
-   if  rc != None and rc % 256:
+   if rc != None and rc % 256:
        print "There were some errors"
    ==>
-   process = Popen(cmd, 'w', stdin=PIPE)
+   process = Popen("cmd", 'w', shell=True, stdin=PIPE)
    ...
    process.stdin.close()
    if process.wait() != 0:
@@ -474,11 +486,6 @@ Return code handling translates as follows::
 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)
@@ -487,9 +494,12 @@ Replacing functions from the :mod:`popen2` module
              stdin=PIPE, stdout=PIPE, close_fds=True)
    (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,
              stdin=PIPE, stdout=PIPE, close_fds=True)
index abbadc41e44b0a44d09f04504f8554655fe3f36b..94476a3e70738f7bf4e1753115c1c95c921ad30f 100644 (file)
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -670,8 +670,9 @@ if _exists("fork"):
 
             import subprocess
             PIPE = subprocess.PIPE
-            p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
-                                 stdin=PIPE, stdout=PIPE, close_fds=True)
+            p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
+                                 bufsize=bufsize, stdin=PIPE, stdout=PIPE,
+                                 close_fds=True)
             return p.stdin, p.stdout
         __all__.append("popen2")
 
@@ -689,9 +690,9 @@ if _exists("fork"):
 
             import subprocess
             PIPE = subprocess.PIPE
-            p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
-                                 stdin=PIPE, stdout=PIPE, stderr=PIPE,
-                                 close_fds=True)
+            p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
+                                 bufsize=bufsize, stdin=PIPE, stdout=PIPE,
+                                 stderr=PIPE, close_fds=True)
             return p.stdin, p.stdout, p.stderr
         __all__.append("popen3")
 
@@ -709,8 +710,8 @@ if _exists("fork"):
 
             import subprocess
             PIPE = subprocess.PIPE
-            p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
-                                 stdin=PIPE, stdout=PIPE,
+            p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring),
+                                 bufsize=bufsize, stdin=PIPE, stdout=PIPE,
                                  stderr=subprocess.STDOUT, close_fds=True)
             return p.stdin, p.stdout
         __all__.append("popen4")
index 5f73ab846cd6e44513d89951adde7e310420014d..477af3875f059af2123e5c446a5c9ed4541da183 100644 (file)
@@ -287,54 +287,80 @@ Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
 
 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)
 (child_stdin, child_stdout) = (p.stdin, p.stdout)
 
 
 (child_stdin,
  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)
 (child_stdin,
  child_stdout,
  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)
 (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.*
 ------------------
-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)
 ==>
 p = Popen(["somestring"], shell=True, bufsize=bufsize
           stdin=PIPE, stdout=PIPE, close_fds=True)
 (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,
           stdin=PIPE, stdout=PIPE, close_fds=True)
index 023871f598b2bca69e3fce6b2037a44e950265e8..2b7c30d371d3ab631b8ffeb9e03ba5dedb4a800a 100644 (file)
@@ -78,6 +78,14 @@ class Popen2Test(unittest.TestCase):
 
     def test_os_popen2(self):
         # 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)
         self.validate_output(self.teststr, self.expected, r, w)
 
@@ -87,9 +95,27 @@ class Popen2Test(unittest.TestCase):
             w, r, e = os.popen3([self.cmd])
             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)
         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():
     run_unittest(Popen2Test)
index 917e5d56edbbb16b4b456355b3cb882a985ae6cf..c91edeb7b550f17d04803b25a17526d6b4a7606d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,10 @@ What's New in Python 2.6.3
 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
   after a reference cycle GC which could be recycled by new locals.