27

I am using debug toolbar with django and would like to add it to project if two conditions are true:

  • settings.DEBUG is True
  • module itself exists

It's not hard to do the first one

# adding django debug toolbar
if DEBUG:
    MIDDLEWARE_CLASSES += 'debug_toolbar.middleware.DebugToolbarMiddleware',
    INSTALLED_APPS += 'debug_toolbar',

But how do I check if module exists?

I have found this solution:

try:
    import debug_toolbar
except ImportError:
    pass

But since import happens somewhere else in django, I need if/else logic to check if module exists, so I can check it in settings.py

def module_exists(module_name):
    # ??????

# adding django debug toolbar
if DEBUG and module_exists('debug_toolbar'):
    MIDDLEWARE_CLASSES += 'debug_toolbar.middleware.DebugToolbarMiddleware',
    INSTALLED_APPS += 'debug_toolbar',

Is there a way to do it?

ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
Silver Light
  • 44,202
  • 36
  • 123
  • 164

1 Answers1

47

You can use the same logic inside your function:

def module_exists(module_name):
    try:
        __import__(module_name)
    except ImportError:
        return False
    else:
        return True

There is no performance penalty to this solution because modules are imported only once.

sds
  • 58,617
  • 29
  • 161
  • 278
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • Couldn't you use `__import__(module_name, fromlist=[module_name])` instead of `import debug_toolbar`? – Dan D. May 01 '11 at 11:03
  • @Dan D.: Wouldn't that be equivalent to `from debug_toolbar import debug_toolbar`? But even if it worked, what's the advantage? – Sven Marnach May 01 '11 at 12:34
  • no, oddly it's the same as `import debug_toolbar`; i've tested this on python 2.5.2; the advantage is that you can then use `module_exists("some_other_module")`. – Dan D. May 01 '11 at 12:43
  • @Dan D.: You are right, I'm completely ignoring the parameter to the function! I'll fix it -- I don't need the `fromlist` argument, so I'll just omit it. – Sven Marnach May 01 '11 at 12:47
  • note `fromlist=` argument is required if you want `__import__` to return `email.utils` as without it'll return `email` and not `email.utils`; but this doesn't matter here as although it won't return the right module it will still raise `ImportError` if it doesn't exist. – Dan D. May 01 '11 at 12:57
  • @sven, I'm not sure it's fair to say there is no performance impact... based on my timeit runs, I think `try / except` is still somewhat slower than `.get()` – Mike Pennington May 01 '11 at 14:09
  • @Mike: Well, what I mean is that performance is no major concern here. I interpreted the question differently to you -- I'll comment on your answer. – Sven Marnach May 01 '11 at 14:31
  • I think that is a widely using but defective way. If using this way to check `a.b` module and `a.b` is exists actually, but an error importing happend in `a.b`, then the real error message will be hidden. – Jiangge Zhang Aug 26 '12 at 10:48
  • @TonySeek: If there is an error while importing `a.b`, that error will be shown, unless it is an `ImportError`, in which case it will indeed be ignored. This is *exactly* what the OP asked for, since the failing import happens somewhere in nested module imports, and so we *have to* ignore any `ImportError`. (Moreover, it's a bit pointless to downvote without giving an alternative.) – Sven Marnach Aug 27 '12 at 17:14