36

Consider

try:
   import someProprietaryModule
except ImportError:
   raise ImportError('It appears that <someProprietaryModule> is not installed...')

When run, if someProprietaryModule is not installed, one sees:

(traceback data)
ImportError: unknown module: someProprietaryModule

During handling of the above exception, another exception occurred:

(traceback data)
ImportError: It appears that <someProprietaryModule> is not installed...

Perhaps I don't want the "During handling of the above exception..." line (and the lines above it) to appear. I could do this:

_moduleInstalled = True
try:
   import someProprietaryModule
except ImportError:
   _moduleInstalled = False
if not _moduleInstalled: 
   raise ImportError('It appears that <someProprietaryModule> is not installed...')

But that feels like a bit of a hack. What else might I do?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Hammerite
  • 21,755
  • 6
  • 70
  • 91
  • This might help http://stackoverflow.com/questions/1319615/proper-way-to-declare-custom-exceptions-in-modern-python – Ankur Ankan Jun 13 '13 at 15:57

3 Answers3

64

In Python 3.3 and later raise ... from None may be used in this situation.

try:
   import someProprietaryModule
except ImportError:
   raise ImportError('It appears that <someProprietaryModule> is not installed...') from None

This has the desired results.

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
Hammerite
  • 21,755
  • 6
  • 70
  • 91
  • Was just about to post the same thing. See also [PEP3134](http://www.python.org/dev/peps/pep-3134/). – Aya Jun 13 '13 at 16:16
  • 5
    [PEP 409](https://docs.python.org/3.3/whatsnew/3.3.html#pep-409-suppressing-exception-context) is what added the `from None` syntax. – Ethan Furman Jun 25 '14 at 21:31
3

This can be done like this in Python 2.7 and Python 3:

try:
    import someProprietaryModule
except ImportError as e:
    raised_error = e

if isinstance(raised_error, ImportError):
    raise ImportError('It appears that <someProprietaryModule> is not installed...')
flaviut
  • 2,007
  • 3
  • 23
  • 32
-1

You can try logging module as well

Original Answer: Perhaps I don't want the "During handling of the above exception..." line (and the lines above it) to appear.

import logging

try:
    import someProprietaryModule
    
except Exception as e:
    
    if hasattr(e, 'message'):
        logging.warning('python2')
        logging.error(e.message)
        
    else:
        
        logging.warning('python3')
        logging.error('It appears that <someProprietaryModule> is not installed...')

gives

WARNING:root:python3
ERROR:root:It appears that <someProprietaryModule> is not installed...

[Program finished]

Edit:

import logging

class MyExceptionType(Exception):
    """Base class for other exceptions"""
    pass

try:
    from someProprietaryModule import *
except Exception as e:
        logging.warning('python3')
        logging.exception("Failed to import <someProprietaryModule>. Is it installed?", exc_info=False)
        raise MyExceptionType from e

logging.exception will emit the stacktrace alongside the localized error message, which makes it quite useful.

Casting an exception to a string to print it removes 90% of the useful information.

Silently suppressing exceptions is almost always an error and is most commonly a footgun.

Edit 2:

import logging

class MyExceptionType(Exception):
    """Base class for other exceptions"""
    pass

try:
    import someProprietaryModule
    
except Exception as e:
    error_message = "Failed to import <someProprietaryModule>. Is it installed?"
    logging.warning('python3')
    logging.error(error_message, exc_info=True)  # Log the stacktrace along with the message
    raise MyExceptionType(error_message) from e

The exc_info parameter in the logging.error call is set to True, allowing the logging module to include the exception information, including the traceback, in the log output. The localized error message is stored in a variable error_message, which makes the code more readable and allows for easy changes if needed.

Subham
  • 397
  • 1
  • 6
  • 14
  • An error message is not the same thing as an exception. The main difference is that execution continues. So in your script, if you put, say, `print('got here')` after that code, the output will contain `got here`. Or, more on-topic, if you put `someProprietaryModule.do_a_thing()`, you'll get `NameError: name 'someProprietaryModule' is not defined`. – wjandrea May 09 '22 at 22:44
  • I thought the objective is to intercept the import error and raise a different error. This code only handles exceptions when importing. If you catch an exception but don't reraise it, it is suppressed. – Subham May 10 '22 at 04:28
  • *"intercept the import error and raise a different error."* -- Yes, the problem is that your code doesn't raise anything. (At least not before your edit.) *"This code only handles exceptions when importing."* -- It doesn't really *handle* them, it only *logs* them. *"If you catch an exception but don't reraise it, it is suppressed."* -- Which is exactly the problem I'm pointing out, although at least at least you're logging it. – wjandrea May 10 '22 at 04:36
  • is it OK now, or requires more work? – Subham May 10 '22 at 07:28
  • Well the first snippet still doesn't raise anything... – wjandrea May 10 '22 at 16:05
  • Basically my code now: (1) Does something that will fail. (2) Catch any error that occurs. (3) Mess around with that error a bit. (4) Emit that altered error. Am I missing something here? – Subham May 11 '22 at 06:36
  • I guess what I'm trying to say is that this fundamentally doesn't answer OP's question. OP wants `raise ... from None`, which is exactly what the top answer says. Logging is a separate matter. But I'm open to being wrong. – wjandrea May 11 '22 at 17:29
  • Also, now, if `hasattr(e, 'message')`, nothing is raised. And why do you do `from e` when OP explicitly wants to suppress `e`? – wjandrea May 11 '22 at 17:30
  • Oh actually, [`raise` `from` isn't even valid syntax in Python 2](https://peps.python.org/pep-3134/) – wjandrea May 11 '22 at 17:36
  • "Yes, the problem is that your code doesn't raise anything ". if e is to be suppressed then don't raise anything. from e attaches the original exception to the new one. – Subham May 12 '22 at 02:06