Check if needed modules imported before run method
Example::
@require_module(['time'],exception=Exception)
def get_time():
return time.time()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import sys
def require_module(names,exception=None):
"""
Check if needed modules imported before run method
Example::
@require_module(['time'],exception=Exception)
def get_time():
return time.time()
"""
def check_module(f):
def new_f(*args, **kwds):
for module_name in names:
if module_name not in sys.modules.keys():
if exception:
raise exception('Module %s is required for %s' % (module_name,f.func_name))
else:
return None
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_module
@require_module(['time'],exception=Exception)
def aaa():
print time.time()
aaa()
|
I don't understand the need for this decorator. If you haven't already imported a module, Python will automatically give you a NameError when you try to use it:
This works no matter how you import the module:
and gives you a standard exception that any experienced Python programmer should be able to recognize and debug in a second, rather than some arbitrary exception like Exception. As far as I can see, all your decorator does is shift the check from when the function is used, to when the function is defined.
Oh, I was mistaken about that last point -- the decorator doesn't move the check from when the function is called to when it is defined. The check still occurs when the function is called. That actually makes it worse, it means that perfectly good functions like this will fail:
This decorator also fails to detect functions that won't work. Using your example:
Why did the decorator wrongly pass, but the function call fail? The decorator passed because something else has already imported the
time
module, sotime
is cached insys.modules
. But just because the time module has been cached doesn't mean I can use it! It still needs to be imported, and I failed to import time before use. Because the decorator only looks in the cache, it fails to notice that the module hasn't been imported and so cannot be used.One last comment: by default, your decorator turns immediate, obvious, easy to debug exceptions into delayed, confusing, hard to debug silent errors. For example, define a function using the default setting for the exception:
That looks promising: I have no errors, so I think everything must be good. Then, sometime later, perhaps a couple of lines away, perhaps hundreds of lines, in a different function or even a different module:
Arrgggh!!! How did the variable "num" end up having the value None instead of a number, like I expected? I now have to try and work backwards, finding out where num came from ("oh, it came from module 'foo', where I called function test") and try to understand why it has the value None instead of the expected value 6.283...
If I had skipped the decorator, and just written the function, I would have had an immediate exception as soon as I tried to use it:
So instead of helping, by default require_module actually makes debugging code harder.
Thanks for your bug report, i will fix it soon and give you know.