32

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
  • 23,210
  • 7
  • 49
  • 68
Hammerite
  • 20,746
  • 4
  • 67
  • 87
  • 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

54

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
  • 57,917
  • 18
  • 142
  • 218
Hammerite
  • 20,746
  • 4
  • 67
  • 87
  • 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
  • 4
    [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
2

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...')
user60561
  • 1,813
  • 2
  • 22
  • 29
-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.

Subham
  • 304
  • 1
  • 5
  • 13
  • 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