From a23810f86a53e394936b38ed9c6104fe2cc592cf Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 26 May 2008 19:04:21 +0000 Subject: [PATCH] The commands module has been removed. The getoutput() and getstatusoutput() functions have been added to the subprocess module. The fixer for this still needs to be written and proper Py3K deprecation warnings for the functions that didn't make the transition need to be done in 2.6. This is all part of trying to close issue #2872. --- Demo/tkinter/guido/kill.py | 4 +- Demo/tkinter/guido/svkill.py | 4 +- Doc/library/commands.rst | 53 ------------------------- Doc/library/subprocess.rst | 32 ++++++++++++++- Doc/library/unix.rst | 1 - Lib/commands.py | 77 ------------------------------------ Lib/subprocess.py | 76 +++++++++++++++++++++++++++++++++-- Lib/test/regrtest.py | 3 -- Lib/test/test___all__.py | 1 - Lib/test/test_commands.py | 47 ---------------------- Lib/test/test_subprocess.py | 34 ++++++++++++++-- Misc/NEWS | 3 ++ Misc/cheatsheet | 1 - 13 files changed, 140 insertions(+), 196 deletions(-) delete mode 100644 Doc/library/commands.rst delete mode 100644 Lib/commands.py delete mode 100644 Lib/test/test_commands.py diff --git a/Demo/tkinter/guido/kill.py b/Demo/tkinter/guido/kill.py index dd0dbf4f9d2..36b479d8e27 100755 --- a/Demo/tkinter/guido/kill.py +++ b/Demo/tkinter/guido/kill.py @@ -4,7 +4,7 @@ from Tkinter import * from string import splitfields from string import split -import commands +import subprocess import os class BarButton(Menubutton): @@ -31,7 +31,7 @@ class Kill(Frame): self.do_update() def do_update(self): name, option, column = self.format_list[self.format.get()] - s = commands.getoutput('ps -w ' + option) + s = subprocess.getoutput('ps -w ' + option) list = splitfields(s, '\n') self.header.set(list[0]) del list[0] diff --git a/Demo/tkinter/guido/svkill.py b/Demo/tkinter/guido/svkill.py index 378d58f5756..b9d82abe974 100755 --- a/Demo/tkinter/guido/svkill.py +++ b/Demo/tkinter/guido/svkill.py @@ -9,7 +9,7 @@ if TkVersion < 4.0: from string import splitfields from string import split -import commands +import subprocess import os user = os.environ['LOGNAME'] @@ -46,7 +46,7 @@ class Kill(Frame): def do_update(self): format = self.format_list[self.format.get()][1] view = self.view_list[self.view.get()][1] - s = commands.getoutput('ps %s %s' % (view, format)) + s = subprocess.getoutput('ps %s %s' % (view, format)) list = splitfields(s, '\n') self.header.set(list[0] + ' ') del list[0] diff --git a/Doc/library/commands.rst b/Doc/library/commands.rst deleted file mode 100644 index 79e3d73da73..00000000000 --- a/Doc/library/commands.rst +++ /dev/null @@ -1,53 +0,0 @@ - -:mod:`commands` --- Utilities for running commands -================================================== - -.. module:: commands - :platform: Unix - :synopsis: Utility functions for running external commands. -.. sectionauthor:: Sue Williams - - -The :mod:`commands` module contains wrapper functions for :func:`os.popen` which -take a system command as a string and return any output generated by the command -and, optionally, the exit status. - -The :mod:`subprocess` module provides more powerful facilities for spawning new -processes and retrieving their results. Using the :mod:`subprocess` module is -preferable to using the :mod:`commands` module. - -The :mod:`commands` module defines the following functions: - - -.. function:: getstatusoutput(cmd) - - Execute the string *cmd* in a shell with :func:`os.popen` and return a 2-tuple - ``(status, output)``. *cmd* is actually run as ``{ cmd ; } 2>&1``, so that the - returned output will contain output or error messages. A trailing newline is - stripped from the output. The exit status for the command can be interpreted - according to the rules for the C function :cfunc:`wait`. - - -.. function:: getoutput(cmd) - - Like :func:`getstatusoutput`, except the exit status is ignored and the return - value is a string containing the command's output. - -Example:: - - >>> import commands - >>> commands.getstatusoutput('ls /bin/ls') - (0, '/bin/ls') - >>> commands.getstatusoutput('cat /bin/junk') - (256, 'cat: /bin/junk: No such file or directory') - >>> commands.getstatusoutput('/bin/junk') - (256, 'sh: /bin/junk: not found') - >>> commands.getoutput('ls /bin/ls') - '/bin/ls' - - -.. seealso:: - - Module :mod:`subprocess` - Module for spawning and managing subprocesses. - diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index b08b4ef19ef..38f40633a95 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -14,7 +14,6 @@ replace several other, older modules and functions, such as:: os.system os.spawn* - commands.* Information about how the :mod:`subprocess` module can be used to replace these modules and functions can be found in the following sections. @@ -113,7 +112,7 @@ This module defines one class called :class:`Popen`: Convenience Functions ^^^^^^^^^^^^^^^^^^^^^ -This module also defines two shortcut functions: +This module also defines four shortcut functions: .. function:: call(*popenargs, **kwargs) @@ -138,6 +137,35 @@ This module also defines two shortcut functions: check_call(["ls", "-l"]) +.. function:: getstatusoutput(cmd) + Return ``(status, output)`` of executing *cmd* in a shell. + + Execute the string *cmd* in a shell with :func:`os.popen` and return a 2-tuple + ``(status, output)``. *cmd* is actually run as ``{ cmd ; } 2>&1``, so that the + returned output will contain output or error messages. A trailing newline is + stripped from the output. The exit status for the command can be interpreted + according to the rules for the C function :cfunc:`wait`. Example:: + + >>> import subprocess + >>> subprocess.getstatusoutput('ls /bin/ls') + (0, '/bin/ls') + >>> subprocess.getstatusoutput('cat /bin/junk') + (256, 'cat: /bin/junk: No such file or directory') + >>> subprocess.getstatusoutput('/bin/junk') + (256, 'sh: /bin/junk: not found') + + +.. function:: getoutput(cmd) + Return output ``(stdout or stderr)`` of executing *cmd* in a shell. + + Like :func:`getstatusoutput`, except the exit status is ignored and the return + value is a string containing the command's output. Example:: + + >>> import subprocess + >>> subprocess.getoutput('ls /bin/ls') + '/bin/ls' + + Exceptions ^^^^^^^^^^ diff --git a/Doc/library/unix.rst b/Doc/library/unix.rst index 1b1592e1612..7cb54c2d38c 100644 --- a/Doc/library/unix.rst +++ b/Doc/library/unix.rst @@ -25,4 +25,3 @@ of it. Here's an overview: resource.rst nis.rst syslog.rst - commands.rst diff --git a/Lib/commands.py b/Lib/commands.py deleted file mode 100644 index ee4db8595ac..00000000000 --- a/Lib/commands.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Execute shell commands via os.popen() and return status, output. - -Interface summary: - - import commands - - outtext = commands.getoutput(cmd) - (exitstatus, outtext) = commands.getstatusoutput(cmd) - outtext = commands.getstatus(file) # returns output of "ls -ld file" - -A trailing newline is removed from the output string. - -Encapsulates the basic operation: - - pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') - text = pipe.read() - sts = pipe.close() - - [Note: it would be nice to add functions to interpret the exit status.] -""" - -__all__ = ["getstatusoutput", "getoutput"] - -# Module 'commands' -# -# Various tools for executing commands and looking at their output and status. -# -# NB This only works (and is only relevant) for UNIX. - - -# Get the output from a shell command into a string. -# The exit status is ignored; a trailing newline is stripped. -# Assume the command will work with '{ ... ; } 2>&1' around it.. -# -def getoutput(cmd): - """Return output (stdout or stderr) of executing cmd in a shell.""" - return getstatusoutput(cmd)[1] - - -# Ditto but preserving the exit status. -# Returns a pair (sts, output) -# -def getstatusoutput(cmd): - """Return (status, output) of executing cmd in a shell.""" - import os - pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') - text = pipe.read() - sts = pipe.close() - if sts is None: sts = 0 - if text[-1:] == '\n': text = text[:-1] - return sts, text - - -# Make command argument from directory and pathname (prefix space, add quotes). -# -def mk2arg(head, x): - import os - return mkarg(os.path.join(head, x)) - - -# Make a shell command argument from a string. -# Return a string beginning with a space followed by a shell-quoted -# version of the argument. -# Two strategies: enclose in single quotes if it contains none; -# otherwise, enclose in double quotes and prefix quotable characters -# with backslash. -# -def mkarg(x): - if '\'' not in x: - return ' \'' + x + '\'' - s = ' "' - for c in x: - if c in '\\$"`': - s = s + '\\' - s = s + c - s = s + '"' - return s diff --git a/Lib/subprocess.py b/Lib/subprocess.py index d39eb195913..ba4fac09a26 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -17,7 +17,6 @@ intends to replace several other, older modules and functions, like: os.system os.spawn* -commands.* Information about how the subprocess module can be used to replace these modules and functions can be found below. @@ -105,7 +104,7 @@ appearance of the main window and priority for the new process. (Windows only) -This module also defines two shortcut functions: +This module also defines four shortcut functions: call(*popenargs, **kwargs): Run command with arguments. Wait for command to complete, then @@ -125,6 +124,34 @@ check_call(*popenargs, **kwargs): check_call(["ls", "-l"]) +getstatusoutput(cmd): + Return (status, output) of executing cmd in a shell. + + Execute the string 'cmd' in a shell with os.popen() and return a 2-tuple + (status, output). cmd is actually run as '{ cmd ; } 2>&1', so that the + returned output will contain output or error messages. A trailing newline + is stripped from the output. The exit status for the command can be + interpreted according to the rules for the C function wait(). Example: + + >>> import subprocess + >>> subprocess.getstatusoutput('ls /bin/ls') + (0, '/bin/ls') + >>> subprocess.getstatusoutput('cat /bin/junk') + (256, 'cat: /bin/junk: No such file or directory') + >>> subprocess.getstatusoutput('/bin/junk') + (256, 'sh: /bin/junk: not found') + +getoutput(cmd): + Return output (stdout or stderr) of executing cmd in a shell. + + Like getstatusoutput(), except the exit status is ignored and the return + value is a string containing the command's output. Example: + + >>> import subprocess + >>> subprocess.getoutput('ls /bin/ls') + '/bin/ls' + + Exceptions ---------- Exceptions raised in the child process, before the new program has @@ -336,7 +363,8 @@ else: import fcntl import pickle -__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"] +__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", + "getoutput", "CalledProcessError"] try: MAXFD = os.sysconf("SC_OPEN_MAX") @@ -458,6 +486,48 @@ def list2cmdline(seq): return ''.join(result) +# Various tools for executing commands and looking at their output and status. +# +# NB This only works (and is only relevant) for UNIX. + +def getstatusoutput(cmd): + """Return (status, output) of executing cmd in a shell. + + Execute the string 'cmd' in a shell with os.popen() and return a 2-tuple + (status, output). cmd is actually run as '{ cmd ; } 2>&1', so that the + returned output will contain output or error messages. A trailing newline + is stripped from the output. The exit status for the command can be + interpreted according to the rules for the C function wait(). Example: + + >>> import subprocess + >>> subprocess.getstatusoutput('ls /bin/ls') + (0, '/bin/ls') + >>> subprocess.getstatusoutput('cat /bin/junk') + (256, 'cat: /bin/junk: No such file or directory') + >>> subprocess.getstatusoutput('/bin/junk') + (256, 'sh: /bin/junk: not found') + """ + pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') + text = pipe.read() + sts = pipe.close() + if sts is None: sts = 0 + if text[-1:] == '\n': text = text[:-1] + return sts, text + + +def getoutput(cmd): + """Return output (stdout or stderr) of executing cmd in a shell. + + Like getstatusoutput(), except the exit status is ignored and the return + value is a string containing the command's output. Example: + + >>> import subprocess + >>> subprocess.getoutput('ls /bin/ls') + '/bin/ls' + """ + return getstatusoutput(cmd)[1] + + class Popen(object): def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 41772c662da..032cac019ca 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -868,7 +868,6 @@ _expectations = { """ test__locale test_bsddb3 - test_commands test_crypt test_curses test_dbm @@ -910,7 +909,6 @@ _expectations = { test_bsddb test_bsddb3 test_bz2 - test_commands test_crypt test_curses test_dbm @@ -1060,7 +1058,6 @@ _expectations = { """ test_audioop test_bsddb3 - test_commands test_curses test_dl test_epoll diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py index 89395bec0f6..e33c54aa62b 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -50,7 +50,6 @@ class AllTest(unittest.TestCase): self.check_all("codecs") self.check_all("codeop") self.check_all("colorsys") - self.check_all("commands") self.check_all("compileall") self.check_all("copy") self.check_all("copyreg") diff --git a/Lib/test/test_commands.py b/Lib/test/test_commands.py deleted file mode 100644 index b4e48ced7da..00000000000 --- a/Lib/test/test_commands.py +++ /dev/null @@ -1,47 +0,0 @@ -''' - Tests for commands module - Nick Mathewson -''' -import unittest -import os, tempfile, re - -from test.support import TestSkipped, run_unittest, reap_children -from commands import * - -# The module says: -# "NB This only works (and is only relevant) for UNIX." -# -# Actually, getoutput should work on any platform with an os.popen, but -# I'll take the comment as given, and skip this suite. - -if os.name != 'posix': - raise TestSkipped('Not posix; skipping test_commands') - - -class CommandTests(unittest.TestCase): - - def test_getoutput(self): - self.assertEquals(getoutput('echo xyzzy'), 'xyzzy') - self.assertEquals(getstatusoutput('echo xyzzy'), (0, 'xyzzy')) - - # we use mkdtemp in the next line to create an empty directory - # under our exclusive control; from that, we can invent a pathname - # that we _know_ won't exist. This is guaranteed to fail. - dir = None - try: - dir = tempfile.mkdtemp() - name = os.path.join(dir, "foo") - - status, output = getstatusoutput('cat ' + name) - self.assertNotEquals(status, 0) - finally: - if dir is not None: - os.rmdir(dir) - - -def test_main(): - run_unittest(CommandTests) - reap_children() - -if __name__ == "__main__": - test_main() diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3f877f20081..c9a3e1b6982 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -702,10 +702,36 @@ class ProcessTestCase(unittest.TestCase): p.terminate() self.assertNotEqual(p.wait(), 0) +class CommandTests(unittest.TestCase): +# The module says: +# "NB This only works (and is only relevant) for UNIX." +# +# Actually, getoutput should work on any platform with an os.popen, but +# I'll take the comment as given, and skip this suite. + if os.name == 'posix': + + def test_getoutput(self): + self.assertEquals(subprocess.getoutput('echo xyzzy'), 'xyzzy') + self.assertEquals(subprocess.getstatusoutput('echo xyzzy'), + (0, 'xyzzy')) + + # we use mkdtemp in the next line to create an empty directory + # under our exclusive control; from that, we can invent a pathname + # that we _know_ won't exist. This is guaranteed to fail. + dir = None + try: + dir = tempfile.mkdtemp() + name = os.path.join(dir, "foo") + + status, output = subprocess.getstatusoutput('cat ' + name) + self.assertNotEquals(status, 0) + finally: + if dir is not None: + os.rmdir(dir) + def test_main(): - support.run_unittest(ProcessTestCase) - if hasattr(support, "reap_children"): - support.reap_children() + support.run_unittest(ProcessTestCase, CommandTests) + support.reap_children() if __name__ == "__main__": - unittest.main() # XXX test_main() + test_main() diff --git a/Misc/NEWS b/Misc/NEWS index 6e92df2099f..343bc01c9ea 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,9 @@ Extension Modules Library ------- +- The ``commands`` module has been removed. Its getoutput() and + getstatusoutput() functions have been moved to the ``subprocess`` module. + - The ``http`` package was created; it contains the old ``httplib`` as ``http.client``, ``Cookie`` as ``http.cookies``, ``cookielib`` as ``http.cookiejar``, and the content of the three ``HTTPServer`` diff --git a/Misc/cheatsheet b/Misc/cheatsheet index e9a2639e799..4ae5439c200 100644 --- a/Misc/cheatsheet +++ b/Misc/cheatsheet @@ -1811,7 +1811,6 @@ datetime Basic date and time types. code Utilities needed to emulate Python's interactive interpreter codecs Lookup existing Unicode encodings and register new ones. colorsys Conversion functions between RGB and other color systems. -commands Tools for executing UNIX commands . compileall Force "compilation" of all .py files in a directory. configparser Configuration file parser (much like windows .ini files) copy Generic shallow and deep copying operations.