Marty said:
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.
said:
from the corresponding os.system() call, i.e. "os.system('mount
test')", but it doesn't work as expected:
... 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
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.