FAQ
I need to catch exceptions thrown by programs started by the os.system function,
as indicated by a non-zero return code (e.g. the mount utility). For example,
if I get the following results in a bash shell:

$mount test
mount: can't find /home/marty/test in /etc/fstab or /etc/mtab

then I want to catch the same exception from the corresponding os.system() call,
i.e. "os.system('mount test')", but it doesn't work as expected:

import os, sys
try: os.system('mount test')
... except: print 'error'
...
mount: can't find /home/marty/test in /etc/fstab or /etc/mtab
256
>>>

I get the same results with popon, popen2, popen3, etc. Apparently these also
work only when the program does not generate an exception. Is there any way to
catch the return code. or if not, a workaround?

Search Discussions

  • Gabriel Genellina at Jan 2, 2008 at 12:13 am

    En Tue, 01 Jan 2008 20:57:44 -0200, Marty <martyb1 at earthlink.net> escribi?:

    I need to catch exceptions thrown by programs started by the os.system
    function,
    as indicated by a non-zero return code (e.g. the mount utility). For
    Notice that these are two different things. You can wait until the
    external program ends, and get its return code; and you can sometimes read
    a message from its stderr. But none of these things by itself throws an
    exception in Python.
    example,
    if I get the following results in a bash shell:

    $mount test
    mount: can't find /home/marty/test in /etc/fstab or /etc/mtab

    then I want to catch the same exception from the corresponding
    os.system() call,
    i.e. "os.system('mount test')", but it doesn't work as expected:
    Perhaps it doesn't work as *you* expected, but it does work as specified.
    From the os.system description at
    http://docs.python.org/lib/os-process.html
    "On Unix, the return value is the exit status of the process encoded in
    the format specified for wait(). [...] [That return value] is
    system-dependent."
    Later on the same page, describing the wait function, says that the return
    value is "a 16-bit number, whose low byte is the signal number that killed
    the process, and whose high byte is the exit status (if the signal number
    is zero)"
    So os.system does NOT raise an exception when the executed program ends
    with a non-zero exit code.
    I get the same results with popon, popen2, popen3, etc. Apparently
    these also
    work only when the program does not generate an exception.
    An external program cannot generate an exception inside the Python
    program. Only Python itself can do that.
    Is there any way to
    catch the return code. or if not, a workaround?
    From the description above, you could do some math to obtain the exit code
    looking at the os.system return value.
    But perhaps it's easier to use subprocess.check_call, see "Convenience
    functions" at http://docs.python.org/lib/module-subprocess.html

    --
    Gabriel Genellina
  • Ben Finney at Jan 2, 2008 at 12:53 am

    Marty <martyb1 at earthlink.net> writes:

    I need to catch exceptions thrown by programs started by the os.system
    function, as indicated by a non-zero return code (e.g. the mount
    utility).
    That's not an exception. It's referred to as an "exit status" or
    (often) some short form or variation of that term.

    Python can make available the exit status value of an external
    process, but isn't going to interpret them to the point of raising
    exceptions that you can catch.

    The exit status is always available to the parent process, but the
    *meaning* of any given value of that status is highly dependent on the
    program that was running.

    If you want to respond to particular values, you'll have to do so by
    explicitly testing the exit status against values to which you've
    assigned meaning -- hopefully meanings documented in the manual page
    for the program which generates the exit status.
    For example, if I get the following results in a bash
    shell:

    $mount test
    mount: can't find /home/marty/test in /etc/fstab or /etc/mtab

    then I want to catch the same exception
    What's happening isn't an exception. It's a message being emitted to
    an output stream (likely the stderr stream of the mount process,
    though some programs will put error messages on stdout), followed by
    an exit of that process.

    The parent of that process will receive an exit status from the
    process when it terminates; it will also (on Unix-like systems)
    receive a separate value indicating the OS signal that caused the
    process to exit. Python's 'os.system' function makes both these values
    available as the return value of the function.

    <URL:http://docs.python.org/lib/os-process.html#l2h-2761>
    from the corresponding os.system() call, i.e. "os.system('mount
    test')", but it doesn't work as expected:

    import os, sys
    try: os.system('mount test')
    ... except: print 'error'
    ...
    mount: can't find /home/marty/test in /etc/fstab or /etc/mtab
    256
    The statement within the 'try' block executes the 'os.system()' call;
    since you're running inside the interpreter, the return value from
    that function is displayed.

    The return value, as documented in the 'os.system' documentation,
    encodes both the signal number (the low 8 bits, in this case (256 &
    0x0F) == 0) and, since the signal number is zero ("no signal
    received") the exit status value (the high 8 bits, in this case (256
    8) == 1).
    No exception is being raised, so the 'try' block completes
    successfully and the 'except' block is not invoked.


    So, instead of testing for an exception, you should instead be testing
    the exit status code returned by the 'os.system' call. First, read the
    documentation for the command you're running::

    $ man mount
    [...]

    Unfortunately the 'mount(8)' manual page doesn't (on my system)
    mention possible values for the exit status. So, you'll just have to
    deduce it, or go with the common convention of "zero status ==
    success, non-zero status == error".

    MountFailedError = OSError
    import os
    return_value = os.system('mount test')
    signal_number = (return_value & 0x0F)
    if not signal_number:
    exit_status = (return_value >> 8)
    if exit_status:
    raise MountFailedError("Oh no!")

    Why isn't this standardised? Because the process-call interface is
    inconsistent between operating systems, and there's even less
    consistency in the implementations of the programs that return these
    values.

    The Zen of Python says: "In the face of ambiguity, refuse the
    temptation to guess." Thus, Python can do little more than present the
    values it received from the process call; anything further would be
    guessing.

    --
    \ "I bought some batteries, but they weren't included; so I had |
    `\ to buy them again." -- Steven Wright |
    _o__) |
    Ben Finney

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJan 1, '08 at 10:57p
activeJan 2, '08 at 12:53a
posts3
users3
websitepython.org

People

Translate

site design / logo © 2022 Grokbase