3

I call an external program and raise an error when it fails. The problem is I can't catch my custom exception.

from subprocess import Popen, PIPE

class MyCustomError(Exception):
    def __init__(self, value): self.value = value
    def __str__(self): return repr(self.value)

def call():
    p = Popen(some_command, stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate()
    if stderr is not '':
        raise MyCustomError('Oops, something went wrong: ' + stderr)

try:
    call()
except MyCustomError:
    print 'This message is never displayed'

In this case, python prints Oops, something went wrong: [the sderr message] with a stack-trace.

roipoussiere
  • 5,142
  • 3
  • 28
  • 37
  • The code works as you expect for me. I note that `self` is not defined in the `if` line. Also, when subclassing, you normally want to call the parent class's `__init__` also. – mdurant Sep 29 '15 at 13:10
  • You would need to provide a [MCVE] . – Anand S Kumar Sep 29 '15 at 13:12
  • You are catching the exception as you should, there is not error in your code, please add the stacktrace. The problem is that another exception is happening which you are not catching. – avenet Sep 29 '15 at 13:19
  • 2
    Side-note: Don't do `if stderr is not '':`; that's relying on an object identity test that works by coincidence, but there are no guarantees. Since you know it's a `str`, and the empty `str` is falsy (and all others truthy), you can test it much more simply/efficiently with `if stderr:`. Example of where this would break: If you move to Python 3, the return from `communicate` is `bytes` by default, not `str`. `b''` would be an error free completion that would behave properly with `if stderr:`, but not with `if stderr is not '':`. – ShadowRanger Sep 29 '15 at 14:17
  • 2
    Separate side-note: Your custom error is doing what `Exception` would do for you (you just give the argument passed the wrong name). Just use `class MyCustomError(Exception): pass` and it will work just fine (and be properly interoperable with other `Exception`s by using the common variable names); no need for redundant `__init__` or `__str__` definitions. – ShadowRanger Sep 29 '15 at 14:23
  • I re-writen a Minimal, Complete and Verifiable code for this problem, which works perfectly. My problem was somewhere else: see http://stackoverflow.com/questions/32809894/do-not-print-stack-trace-using-pool-python. I used cg909 solution and now I can correctly catch my raise exceptions. Thanks for side nodes! – roipoussiere Sep 29 '15 at 14:59

1 Answers1

1

Try this:

from subprocess import Popen, PIPE

class MyCustomError(Exception):
    def __init__(self, value): self.value = value
    def __str__(self): return repr(self.value)

def call():
    p = Popen(['ls', '-la'], stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate()
    if self.stderr is not '':
        raise MyCustomError('Oops, something went wrong: ' + stderr)

try:
    call()
except MyCustomError:
    print 'This message is never displayed'
except Exception, e:
    print 'This message should display when your custom error does not happen'
    print 'Exception details', type(e), e.message

Take a look at the type of the exception type (denoted by type(e)) value. Looks like it's an exception you will need to catch...

Hope it helps,

avenet
  • 2,894
  • 1
  • 19
  • 26