How to use nested try except properly in python3.7? - python

I have situation where I wanted to run some line of code and if those lines runs successfully then run another few lines. In both cases there are possibilities of errors/exceptions. So I wanted to know which would be the best way to use try catch between two I mentioned below
def function_name1():
try:
*Run first few lines*
try:
*Run second few lines*
except Exception as ex2:
raise Exception("second Exception - wdjk")
except Exception as ex1:
raise Exception("first Exception - wejk")
def function_name2():
try:
*Run first few lines*
except Exception as ex1:
raise Exception("first Exception - wejk")
try:
*Run second few lines*
except Exception as ex2:
raise Exception("second Exception - wdjk")
In function_name1, I faced one issue that even if I get excption in second line i.e raise Exception("second Exception - wdjk"), code is returning or raising exception from raise Exception("first Exception - wejk").
So what would be the best way to handle this case?

The cleanest solution would be to run the second try/except in the else suite of the first:
try:
# first stuff
except SomeException:
# error handling
else: # no error occurred
try:
# second stuff
except OtherException:
# more error handling

If the code blocks are independent from one another, I don't see why you would nest them. The second option would be better. You can learn more about exceptions in this post by Real Python: https://realpython.com/python-exceptions/ There they talk about how try-except works.

Related

How to catch PyGetWindowException when using pygetwindow in Python?

I have a script which uses pygetwindow module to do some operations on a specific window. While the script runs, I get the following exception:
File "C:\Program Files (x86)\Python38-32\lib\site-packages\pygetwindow\_pygetwindow_win.py", line 237, in activate
_raiseWithLastError()
File "C:\Program Files (x86)\Python38-32\lib\site-packages\pygetwindow\_pygetwindow_win.py", line 97, in _raiseWithLastError
raise PyGetWindowException('Error code from Windows: %s - %s' % (errorCode, _formatMessage(errorCode)))
pygetwindow.PyGetWindowException: Error code from Windows: 0 - The operation completed successfully.
I'm okay with the exception occurring but I want to catch this exception explicitly. I have done the following to try and catch this exception:
try:
#implementation
except pygetwindow.PyGetWindowException:
#handle exception
and
try:
#implementation
except PyGetWindowException:
#handle exception
Neither of the above catches the exception. If I use either of the above, I get another exception:
NameError: name 'PyGetWindowException' is not defined
or
NameError: name 'pygetwindow' is not defined
I don't want to catch the general Exception and then handle it since in case of other exceptions, I want to handle it differently. Is there something wrong in how I'm trying to catch this exception or is there a way to avoid this exception altogether?
EDIT: To be very clear, I have already imported pygetwindow.
You should have import pygetwindow at the begging of your script. It complains about not knowing what pygetwindow is.
Update
From the source file, it was clear that in order to use PyGetWindowException, you need to import the exception specifically (and not just import pygetwindow). Therefore, in order to catch the exception, one will have to do:
from pygetwindow import PyGetWindowException
After this import, you can use the exception in the normal way:
try:
#implementation
except PyGetWindowException:
#handle exception
Update 2
Another general way to do this would be to get the exception name from general exception and compare.
try:
try:
#implementation
except Exception as e:
if e.__class__.__name__ == 'PyGetWindowException':
#handle exception
else:
raise e
except Exception as e:
#handle other exceptions except pygetwindow exception
Original answer (not recommended)
Found a way to solve this question in this answer.
From the source of pygetwindow, it was clear that, whenever PyGetWindowException is raised, it is accompanied by the text:
"Error code from Windows:"
which indicates the error code given by Windows.
Based on this information, I did the following:
try:
try:
#Implementation
except Exception as e:
if "Error code from Windows" in str(e)
# Handle pygetwindow exception
else:
raise e
except Exception as e:
#handle other exceptions
This is another way (although the first one and second one are the correct and straightforward solutions) to solve the problem.

Is there a way in python to execute a piece of code only if any exception is raised in a try/except block?

I have a try/except block with multiple except blocks. I want to be able to execute a piece of code only if any of the exceptions are raised. Kind of like the finally statement, but finally execute regardless of if an exception was raised or not. Do I just have to add that code to each except block?
You can do your own type checking in the exception handler to deal with type-specific and general code.
def it_will_end_in_tears():
raise ValueError("bad value")
try:
val = it_will_end_in_tears()
except (TypeError, ValueError) as e:
if isinstance(e, TypeError):
print("type error stuff")
elif isinstance(e, ValueError):
print("value error stuff")
print("common stuff")
finally:
print("finally")
Instead of copy+pasting the code into each except block, i would declare a boolean execute_code = False and set it to True in each of the except blocks. After the whole try/except, add if execute_code:, then implement the code to execute if an exception occurred once inside the if block.

python: Exception flow: Continue to down catch block after catching?

I am curious if there is a way in python to continue on within try/catch block, after you catch an exception, look at its properties, and if not relevant, then continue down the stack.
try:
# Code
except AppleError as apple_ex:
# look at 'apple_ex.error_code' error body, and if not relevant,
# continue on to next down the catch block...
# In other words, proceed to except BananaError and so on down.
except BananaError as banana_ex:
# ...
except Exception as ex:
# ...
That is not how exceptions are handled in Python. When you raise an exception in a try block, if you handle catching it in the except, it will fall inside that block, but will not continue to the next except at that same level. Observe this functional example:
try:
raise AttributeError()
except AttributeError:
raise TypeError()
except TypeError:
print("it got caught") # will not catch the TypeError raised above
So, in your try, we raise an AttributeError, we catch it, and then raise a TypeError inside catching the AttributeError.
The except TypeError will not catch that TypeError.
Based on how you are explaining your problem, you need to rethink how you are handling your exceptions and see if you can determine the handling of errors somewhere else, and raise the error there.
For example:
def some_func():
try:
thing()
except SomeException:
# analyze the exception here and raise the error you *should* raise
if apple_error_thing:
raise AppleError
elif banana_error_thing:
raise BananaError
else:
raise UnknownException
def your_func():
try:
some_func()
except AppleError as e:
print('Apple')
except BananaError as e:
print('Banana')
except UnknownException as e:
print('Unknown')
An AppleError is still an AppleError and not a BananaError, even if error_code is not relevant, so it makes no sense to fall through to BananaError.
You could instead define specific errors for your different error codes:
GRANNY_SMITH_ERROR = 1
MACINTOSH_ERROR = 2
class AppleError(Exception):
def __init__(self, error_code, *args):
super(AppleError, self).__init__(*args)
self.error_code = error_code
class GrannySmithError(AppleError):
def __init__(self, *args):
super(GrannySmithError, self).__init__(GRANNY_SMITH_ERROR, *args)
class MacintoshError(AppleError):
def __init__(self, *args):
super(MacintoshError, self).__init__(MACINTOSH_ERROR, *args)
Then you can try to match the specific error:
try: raise MacintoshError()
except MacintoshError as exc: print("mac")
except GrannySmithError as exc: print("granny smith")
If you do not care to distinguish between different types of apple errors, you can still trap all apple errors:
try: raise MacintoshError()
except AppleError as exc: print("generic apple")
You can combine these, for example, only doing special processing for GrannySmith, not for Macintosh:
try: raise MacintoshError()
except GrannySmithError as exc: print("granny smith")
except AppleError as exc: print("generic apple")
The important thing is to list the errors from most specific to least specific. If you test for AppleError before GrannySmithError, then it will never enter the GrannySmith block.
No, that isn't possible. After the exception is handled by the inner except it doesn't have the ability to get handled by the outer except:
From the docs on the try statement:
When the end of this block is reached, execution continues normally after the entire try statement. (This means that if two nested handlers exist for the same exception, and the exception occurs in the try clause of the inner handler, the outer handler will not handle the exception.)
In short your only solution might be to have another handler at an outer level and re-raise the exception in the inner handler, that is:
try:
try:
raise ZeroDivisionError
except ZeroDivisionError as e:
print("caught")
raise ZeroDivisionError
except ZeroDivisionError as f:
print("caught")
Now the nested except raises an exception which is consequently caught by a similar handler.

How many exceptions are possible when reading a json in Python/django?

I have:
MY_PATH_DIR = 'path/to/my/json/file.json'
try:
with open(MY_PATH_DIR, 'r') as f:
MY_PATH_DIR = json.load(f)
except IOError, RuntimeError, ValueError:
pass
except PermissionDenied:
pass
And I want to catch all possible errors. With
IOError - I am catching errors when the file doesn't exist or has a
syntax error (non valid JSON).
RuntimeError - couldn't test it but I think that makes sense from the
documentation in case of an unexpected error
ValueError - I got from here in case nothing got returned
PermissionDenied - is a specific Django error
Are there any other Exceptions that would make sense? I'm not sure if OSError makes sense here. I think that would be raised earlier, right?
The purpose of capturing exceptions is to control the program's behavior when something bad happened, but in an expected way. If you are not even sure what would cause that exception happen, capturing it would only swallow the underlying programming errors you might have.
I wouldn't add as many kinds of exception as possible to that single block of code, you should only add what you care about. To take it to extreme, each line of code would yield certain exceptions but for obvious reason you couldn't do try except for all of them.
Edit:
For the sake of correctness, since you mentioned I don't want my code to break in any case, you could simply do:
try:
# json.load
except Exception as e:
print "Let's just ignore all exceptions, like this one: %s" % str(e)
This is would give you what exception happens as output.
import random
import sys
def main():
"""Demonstrate the handling of various kinds of exceptions."""
# This is like what you are doing in your code.
exceptions = IOError, RuntimeError, ValueError
try:
raise random.choice(exceptions)()
except exceptions as error:
print('Currently handling:', repr(error))
# The following is not much different from Shang Wang's answer.
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# However, the following code will sometimes not handle the exception.
exceptions += SystemExit, KeyboardInterrupt, GeneratorExit
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# The code can be slightly altered to take the new errors into account.
try:
raise random.choice(exceptions)()
except BaseException as error:
print('Currently handling:', repr(error))
# This does not take into account classes not in the exception hierarchy.
class Death:
pass
try:
raise Death()
except BaseException as error:
print('Currently handling:', repr(error))
# If your version of Python does not consider raising an exception from an
# instance of a class not derived from the BaseException class, the way to
# get around this problem would be with the following code instead.
try:
raise Death()
except:
error = sys.exc_info()[1]
print('Currently handling:', repr(error))
if __name__ == '__main__':
main()

Handling all but one exception

How to handle all but one exception?
try:
something
except <any Exception except for a NoChildException>:
# handling
Something like this, except without destroying the original traceback:
try:
something
except NoChildException:
raise NoChildException
except Exception:
# handling
The answer is to simply do a bare raise:
try:
...
except NoChildException:
# optionally, do some stuff here and then ...
raise
except Exception:
# handling
This will re-raise the last thrown exception, with original stack trace intact (even if it's been handled!).
New to Python ... but is not this a viable answer?
I use it and apparently works.... and is linear.
try:
something
except NoChildException:
assert True
except Exception:
# handling
E.g., I use this to get rid of (in certain situation useless) return exception FileExistsError from os.mkdir.
That is my code is:
try:
os.mkdir(dbFileDir, mode=0o700)
except FileExistsError:
assert True
and I simply accept as an abort to execution the fact that the dir is not somehow accessible.
I'd offer this as an improvement on the accepted answer.
try:
dosomestuff()
except MySpecialException:
ttype, value, traceback = sys.exc_info()
raise ttype, value, traceback
except Exception as e:
mse = convert_to_myspecialexception_with_local_context(e, context)
raise mse
This approach improves on the accepted answer by maintaining the original stacktrace when MySpecialException is caught, so when your top-level exception handler logs the exception you'll get a traceback that points to where the original exception was thrown.
You can do type checking on exceptions! Simply write
try:
...
except Exception as e:
if type(e) == NoChildException:
raise
It still includes the original stack trace.
I found a context in which catching all errors but one is not a bad thing, namely unit testing.
If I have a method:
def my_method():
try:
something()
except IOError, e:
handle_it()
Then it could plausibly have a unit test that looks like:
def test_my_method():
try:
my_module.my_method()
except IOError, e:
print "shouldn't see this error message"
assert False
except Exception, e:
print "some other error message"
assert False
assert True
Because you have now detected that my_method just threw an unexpected exception.

Categories

Resources