I have a script in python which works as shown below. Each function performs a completely different task and not related to each other. My problem is if function2() is having an issue during the execution process then function3(), function4(), function5() will not execute. I know you will say to handle this by catching the exception (try..except) but then i have to catch every exception which is not i am looking for. In a nutshell how do i code where my other functions are not impacted if any of the function is having issue. Ideally it should exclude that problematic function and let the other function to execute.
def function1():
some code
def function2():
some code
def function3():
some code
def function4():
some code
def function5():
some code
if __name__ == '__main__':
function1()
function2()
function3()
function4()
function5()
No need to write multiple try/except. Create a list of your function and execute them. For example, you code should be like:
if __name__ == '__main__':
func_list = [function1, function2, function3, function4, function5]
for my_func in func_list:
try:
my_func()
except:
pass
OR, create a decorator and add that decorator to each of your function. Check A guide to Python's function decorators. For example, your decorator should be like:
def wrap_error(func):
def func_wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
pass
return func_wrapper
Now add this decorator with your function definition as:
#wrap_error
def function1():
some code
Functions having this decorator added to them won't raise any Exception
As of Python 3.4, a new context manager as contextlib.suppress is added which as per the doc:
Return a context manager that suppresses any of the specified exceptions if they occur in the body of a with statement and then resumes execution with the first statement following the end of the with statement.
In order to suppress all the exceptions, you may use it as:
from contextlib import suppress
if __name__ == '__main__':
func_list = [function1, function2, function3, function4, function5]
for my_func in func_list:
with suppress(Exception): # `Exception` to suppress all the exceptions
my_func() # Any exception raised by `my_func()` will be suppressed
You can use exception and catch all sort of exceptions like this
if __name__ == '__main__':
try:
function1()
except:
pass
try:
function2()
except:
pass
try:
function3()
except:
pass
try:
function4()
except:
pass
for large number of functions you can use
func_dict = {
func1 : {
param1 : val
param2 : val
},
func1 : {
param1 : val
param2 : val
}
}
thus you can iterate over the keys of the dictionary for the function and iterate on the parameters
Related
say I have a test file with the following content:
def a():
print('this is a')
def b(x):
print(x)
and also a main file:
import test
def try_cmd(cmd, params):
try:
getattr(functions, cmd)(params)
except Exception as error:
print(error)
while True:
cmd = input('Enter cmd')
params = input('Enter params')
do_command(cmd, params)
The purpose of the code should be to try to call a function from a different file, with the user giving the function name and if needed params for it to take.
What happens is if the value of cmd is 'a' and parmas is a random string do_command will not work because function a doesn't take params. However if cmd will be 'b' and params will be say '5' it will work. How do I get around that without forcing a to take params and not actually using it.
As in my comment on your question, you should write your functions to accept *args and **kwargs, but if you insist on not using this convention, try this:
def try_cmd(cmd, params):
func = getattr(functions, cmd)
try:
func(params)
except TypeError:
func()
except Exception as error:
print(error)
In my opinion, accepting *args and **kwargs is the better practice compared to using exception handling to manage branching.
If you're already importing your "test" file, you can look at locals() and globals(), for example:
getattr(locals()['test'],'a')()
I have a script executing several independent functions in turn. I would like to collect the errors/exceptions happening along the way, in order to send an email with a summary of the errors.
What is the best way to raise these errors/exceptions and collect them, while allowing the script to complete and go through all the steps? They are independent, so it does not matter if one crashes. The remaining ones can still run.
def step_1():
# Code that can raise errors/exceptions
def step_2():
# Code that can raise errors/exceptions
def step_3():
# Code that can raise errors/exceptions
def main():
step_1()
step_2()
step_3()
send_email_with_collected_errors()
if '__name__' == '__main__':
main()
Should I wrap each step in a try..except block in the main() function? Should I use a decorator on each step function, in addition to an error collector?
You could wrap each function in try/except, usually better for small simple scripts.
def step_1():
# Code that can raise errors/exceptions
def step_2():
# Code that can raise errors/exceptions
def step_3():
# Code that can raise errors/exceptions
def main():
try:
step_1_result = step_1()
log.info('Result of step_1 was {}'.format(result))
except Exception as e:
log.error('Exception raised. {}'.format(e))
step_1_result = e
continue
try:
step_2_result = step_2()
log.info('Result of step_2 was {}'.format(result))
except Exception as e:
log.error('Exception raised. {}'.format(e))
step_2_result = e
continue
try:
step_3_result = step_3()
log.info('Result of step_3 was {}'.format(result))
except Exception as e:
log.error('Exception raised. {}'.format(e))
step_3_result = e
continue
send_email_with_collected_errors(
step_1_result,
step_2_result,
step_3_result
)
if '__name__' == '__main__':
main()
For something more elaborate you could use a decorator that'd construct a list of errors/exceptions caught. For example
class ErrorIgnore(object):
def __init__(self, errors, errorreturn=None, errorcall=None):
self.errors = errors
self.errorreturn = errorreturn
self.errorcall = errorcall
def __call__(self, function):
def returnfunction(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception as E:
if type(E) not in self.errors:
raise E
if self.errorcall is not None:
self.errorcall(E, *args, **kwargs)
return self.errorreturn
return returnfunction
Then you could use it like this:
exceptions = []
def errorcall(E, *args):
print 'Exception raised {}'.format(E)
exceptions.append(E)
#ErrorIgnore(errors=[ZeroDivisionError, ValueError], errorreturn=None, errorcall=errorcall)
def step_1():
# Code that can raise errors/exceptions
...
def main():
step_1()
step_2()
step_3()
send_email_with_collected_errors(exceptions)
if '__name__' == '__main__':
main()
use simple try except statements and do logging for the exceptions that would be standard way to collect all your errors.
There are two options:
Use decorator in which you catch all exceptions and save it somewhere.
Add try/except everywhere.
Using decorator might be much better and cleaner, and code will be easier to maintain.
How to store errors? Your decision. You can add them to some list, create logging class receiving exceptions and get them after everything is doneā¦ Depends on your project and size of code.
Simple logging class:
class LoggingClass(object):
def __init__(self):
self.exceptions = []
def add_exception(self, exception):
self.exceptions.append(exception)
def get_all(self):
return self.exceptions
Create instance of class in your script, catch exceptions in decorator and add them to class (however global variable might be also ok).
I have some blocks of code which need to be wrapped by function.
try:
if config.DEVELOPMENT == True:
# do_some_stuff
except:
logger.info("Config is not set for development")
Then I'll do again:
try:
if config.DEVELOPMENT == True:
# do_some_another_stuff
except:
logger.info("Config is not set for development")
So, how can I wrap this "do_some_stuff" and "do_some_another_stuff"?
I'm trying to write function with contextmanager:
#contextmanager
def try_dev_config(name):
try:
if name is not None:
yield
except Exception as e:
print "not dev config"
with try_dev_config("config.DEVELOPMENT"):
# do_some_stuff
And I got an error:
RuntimeError: generator didn't yield
You could pass in a function.
boolean = True
def pass_this_in():
print("I just did some stuff")
def the_try_except_bit(function):
try:
if boolean:
function()
except:
print("Excepted")
# Calling the above code
the_try_except_bit(pass_this_in)
If you want to reduce the "pass_this_in" definition bit, then you can use lambda function definitions:
pass_this_in = lambda : print("I just did some stuff")
I am not sure that a context manager is the good method to achieve what you want. The context manager goal is to provide a mecanism to open/instantiate a resource, give access to it (or not) and close/clean it automatically when you no more need it.
IMHO, what you need is a decorator.
A decorator aims at executing code around a function call. It would force you to put each block of code in a function but I don't think it is so difficult. You can implement it like this:
class Config(object):
"""for demonstration purpose only: used to have a config.DEVELOPMENT value"""
DEVELOPMENT = True
class Logger(object):
"""for demonstration purpose only: used to have a logger.info method"""
#staticmethod
def info(msg):
print("Logged: {}".format(msg))
def check_dev_config(config, logger):
def dev_config_checker(func):
def wrapper(*args, **kwargs):
try:
if config.DEVELOPMENT:
func(*args, **kwargs)
except Exception as err:
logger.info(
"Config is not set for developpement: {}".format(err))
return wrapper
return dev_config_checker
#check_dev_config(Config, Logger)
def do_stuff_1():
print("stuff 1 done")
#check_dev_config(Config, Logger)
def do_stuff_2():
raise Exception("stuff 2 failed")
do_stuff_1()
do_stuff_2()
This code prints
stuff 1 done
Logged: Config is not set for developpement: stuff 2 failed
Explanations:
The check_dev_config function is actually a decorator generator which accepts the config and the logger as arguments.
It returns the dev_config_checker function which is an actual (and parameterised) decorator, and which accepts a function to decorate as argument.
This decorator returns a wrapper function which will actually run code around the decorated function call. In this function, the decorated function is called inside a try/except structure and only if the config.DEVELOPMENT is evaluated to True. In case of exception, the logger is used to log an information.
Each block of code to decorate is put into a function (do_stuff_1, do_stuff_2 and decorated with the check_dev_config decorator generator, giving it the config and the logger.
When decorated functions are called, they are called via their decorator and not directly. As you can see, the do_stuff_2 exception has been catched and the a message has been logged.
I have a number of modules. They all have similar try-except blocks in each file, like this:
from shared.Exceptions import ArgException # and others, as needed
try:
do_the_main_app_here()
except ArgException as e:
Response.result = {
'status': 'error',
'message': str(e)
}
Response.exitcode('USAGE')
# more blocks like the above
with ArgException (and other exceptions) being defined as:
from abc import ABCMeta, abstractmethod
class ETrait(Exception):
__metaclass__ = ABCMeta
#abstractmethod
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class ArgException(ETrait): pass
Since every module uses similar code to catch exceptions, is there a way to put the exception catching into a shared file that is used by all modules?
I would not do that, but you could create a function in a module like :
from shared.Exceptions import ArgException # and others, as needed
def try_exec(execution_function)
try:
execution_function()
except ArgException as e:
Response.result = {
'status': 'error',
'message': str(e)
}
Response.exitcode('USAGE')
and then call try_exec(do_the_main_app_here) whenever you need to try catch your block of instructions, passing the parameters you need to have the correct context.
The answer is Yes, you can create a module to do that.
The easiest way would be to create a function accepting two parameters: another function with the code that you want to "try" and an "action" to be taken in case of exception.
Then:
def myModuleFunction(tryThisCode, doThis):
try:
returnValue = tryThisCode()
return returnValue
except ArgException as e:
if (doThis == "doThat"):
...
else:
...
Then, after importing your new module, you can use your function like this:
myModuleFunction(divideByZero, 'printMe')
Assuming you have a function called divideByZero();
I hope this helps.
I have a requirement to execute multiple Python statements and few of them might fail during execution, even after failing I want the rest of them to be executed.
Currently, I am doing:
try:
wx.StaticBox.Destroy()
wx.CheckBox.Disable()
wx.RadioButton.Enable()
except:
pass
If any one of the statements fails, except will get executed and program exits. But what I need is even though it is failed it should run all three statements.
How can I do this in Python?
Use a for loop over the methods you wish to call, eg:
for f in (wx.StaticBox.Destroy, wx.CheckBox.Disable, wx.RadioButton.Enable):
try:
f()
except Exception:
pass
Note that we're using except Exception here - that's generally much more likely what you want than a bare except.
If an exception occurs during a try block, the rest of the block is skipped. You should use three separate try clauses for your three separate statements.
Added in response to comment:
Since you apparently want to handle many statements, you could use a wrapper method to check for exceptions:
def mytry(functionname):
try:
functionname()
except Exception:
pass
Then call the method with the name of your function as input:
mytry(wx.StaticBox.Destroy)
I would recommend creating a context manager class that suppress any exception and the exceptions to be logged.
Please look at the code below. Would encourage any improvement to it.
import sys
class catch_exception:
def __init__(self, raising=True):
self.raising = raising
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
if issubclass(type, Exception):
self.raising = False
print ("Type: ", type, " Log me to error log file")
return not self.raising
def staticBox_destroy():
print("staticBox_destroy")
raise TypeError("Passing through")
def checkbox_disable():
print("checkbox_disable")
raise ValueError("Passing through")
def radioButton_enable():
print("radioButton_enable")
raise ValueError("Passing through")
if __name__ == "__main__":
with catch_exception() as cm:
staticBox_destroy()
with catch_exception() as cm:
checkbox_disable()
with catch_exception() as cm:
radioButton_enable()