Hi im currently doing a program like this.
class MyError(Exception):
def __init__(self, text = "Correct")
self.text = text
def __str__(self):
return (self.kod)
class Atom(self):
.
.
.
try:
function()
else:
raise MyError("Incorrect use of function")
def main():
try:
a = Atom()
except:
# Here i want to print the error that was raised
What I think I understand is that the error is raised in an object created in Atom().
But I want to send it to my main program and do the print of the error MyError there.
Is it possible to do this and how should I write it so that the correct text of exception is printed since i will have several different error messages.
If i come to the except statement I would want to get the message "Incorrect use of function" printed.
It seems that you're pretty close:
class MyError(Exception):
def __init__(self, text = "Correct")
self.text = text
def __str__(self):
return (self.kod)
class Atom(self):
.
.
.
try:
function()
except: # try: ... else: raise ... seems a bit funky to me.
raise MyError("Incorrect use of function")
def main():
try:
a = Atom()
except Exception as err: # Possibly `except MyError as err` to be more specific
print err
The trick is that when you catch the error, you want to bind the exception instance to a name using the as clause. Then you can print it, look at it's attributes, re-raise or pretty much do anything you choose with it.
Please note that this code still isn't "clean". Generally, you want to limit exception handling as much as possible -- only catch exceptions that expect to see and that you know how to handle. Otherwise, you can sometimes mask hard to find bugs in your code. Because of this:
try:
do_something()
except:
...
is discouraged (it catches all sorts of things like KeyboardInterrupt and SystemExit) ... Instead:
try:
do_something()
except ExceptionIKnowHowToHandle:
...
is advised.
Firstly, never do a blank except. That will catch all errors, including things like KeyboardInterrupt - so you won't be able to ctrl-c out of your program. Here you should just catch MyError.
The except clause also allows you to assign the actual exception to a variable, which you can then print or do anything else with. So you can do:
try:
...
except MyError as e:
print e.text
Related
For example, my function call make look like the following:
def parse(self, text):
...
return self.parse_helper(text)
#staticmethod
def parser_helper(text):
...
return normalize(text)
#staticmethod
def normalize(text):
...
try:
...
except:
raise ValueError('normalize failed.')
If the 'parse' is the function to be provided to users to call, if an exception occurs in normalize(), the whole program terminates. To avoid this, to let users decide what to do when exception occurs, do I have to and try ... except blocks into both 'parser_helper' and 'parse', and let use to use try...except when 'parse' is called?
What's the normal practice of handling this? If there are a few more layers of function calls embedded other than 3 as shown below, do I have to use try ... except block in each layer of function, in order to transfer the handling of exception to the end users at the very top?
The practice to pass a parameter to decide wether to raise or be silent regarding an exception, is something that exists, for example in os.makedirs
You could do
def parse(self, text, error_silent=False):
...
try:
return self.parse_helper(text)
except ValueError as e:
if error_silent:
return None
raise e
I am teaching myself python and I am still an amateur at remembering all the keywords.
So; simple question, is there to way to use an if statement for an exception?
I can make the exception(NameError) print something. However, I want to use an if statement for if the exception is executed, then do this.
Help would be greatly appreciated!
try-except blocks were designed specifically for the purpose of catching exceptions. if statements are conditionals and are not designed to work with exceptions.
Here's a simple program to demonstrate exception handling:
class SomeException(Exception):
pass
try:
print("In try block.")
raise SomeException()
except SomeException:
print("In except block.")
Additionally, if you need information about the exception, you can use a special except block:
class SomeException(Exception):
pass
try:
print("In try block.")
raise SomeException()
except SomeException as exc: #exc is the exception object
print("In except block.")
When creating exceptions, you can optionally pass one or more arguments to indicate why the exception was raised:
class SomeException(Exception):
pass
try:
print("In try block.")
raise SomeException("message")
except SomeException as exc:
print(exc.args[0]) #Prints "message"
Here's a tutorial on exceptions that I found particularly useful.
A "try-except" block is exactly what you're looking for. Any code in the "try" part is executed normally, but if there's an exception, instead of returning back, it goes to the "except" block.
To phrase it how you were asking, any code in an "except" block runs IF the specific exception was raised/excecuted.
Instead of an error like this:
print(x)
NameError: name 'x' is not defined
You could do this:
try:
print(x)
except NameError:
print("error!")
error!
It will print "error!" IF anything in the try: block resulted in a NameError.
You can also use "else" and "finally" for more control.
Any code in the Else block runs if there were no errors.
try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
Hello
Nothing went wrong
Anything in a "finally" block runs after regardless of if there was an error or not.
try:
print(x)
except:
print("Something went wrong")
finally:
print("The 'try except' is finished")
Something went wrong
The 'try except' is finished
I recommend reading the W3 Schools page on Try Except.
https://www.w3schools.com/python/python_try_except.asp
Protip: you can do something like except Exception as e which will save info about the exception to e.
Is it possible to tell if there was an exception once you're in the finally clause? Something like:
try:
funky code
finally:
if ???:
print('the funky code raised')
I'm looking to make something like this more DRY:
try:
funky code
except HandleThis:
# handle it
raised = True
except DontHandleThis:
raised = True
raise
else:
raised = False
finally:
logger.info('funky code raised %s', raised)
I don't like that it requires to catch an exception, which you don't intend to handle, just to set a flag.
Since some comments are asking for less "M" in the MCVE, here is some more background on the use-case. The actual problem is about escalation of logging levels.
The funky code is third party and can't be changed.
The failure exception and stack trace does not contain any useful diagnostic information, so using logger.exception in an except block is not helpful here.
If the funky code raised then some information which I need to see has already been logged, at level DEBUG. We do not and can not handle the error, but want to escalate the DEBUG logging because the information needed is in there.
The funky code does not raise, most of the time. I don't want to escalate logging levels for the general case, because it is too verbose.
Hence, the code runs under a log capture context (which sets up custom handlers to intercept log records) and some debug info gets re-logged retrospectively:
try:
with LogCapture() as log:
funky_code() # <-- third party badness
finally:
# log events are buffered in memory. if there was an exception,
# emit everything that was captured at a WARNING level
for record in log.captured:
if <there was an exception>:
log_fn = mylogger.warning
else:
log_fn = getattr(mylogger, record.levelname.lower())
log_fn(record.msg, record.args)
Using a contextmanager
You could use a custom contextmanager, for example:
class DidWeRaise:
__slots__ = ('exception_happened', ) # instances will take less memory
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# If no exception happened the `exc_type` is None
self.exception_happened = exc_type is not None
And then use that inside the try:
try:
with DidWeRaise() as error_state:
# funky code
finally:
if error_state.exception_happened:
print('the funky code raised')
It's still an additional variable but it's probably a lot easier to reuse if you want to use it in multiple places. And you don't need to toggle it yourself.
Using a variable
In case you don't want the contextmanager I would reverse the logic of the trigger and toggle it only in case no exception has happened. That way you don't need an except case for exceptions that you don't want to handle. The most appropriate place would be the else clause that is entered in case the try didn't threw an exception:
exception_happened = True
try:
# funky code
except HandleThis:
# handle this kind of exception
else:
exception_happened = False
finally:
if exception_happened:
print('the funky code raised')
And as already pointed out instead of having a "toggle" variable you could replace it (in this case) with the desired logging function:
mylog = mylogger.WARNING
try:
with LogCapture() as log:
funky_code()
except HandleThis:
# handle this kind of exception
else:
# In case absolutely no exception was thrown in the try we can log on debug level
mylog = mylogger.DEBUG
finally:
for record in log.captured:
mylog(record.msg, record.args)
Of course it would also work if you put it at the end of your try (as other answers here suggested) but I prefer the else clause because it has more meaning ("that code is meant to be executed only if there was no exception in the try block") and may be easier to maintain in the long run. Although it's still more to maintain than the context manager because the variable is set and toggled in different places.
Using sys.exc_info (works only for unhandled exceptions)
The last approach I want to mention is probably not useful for you but maybe useful for future readers who only want to know if there's an unhandled exception (an exception that was not caught in any except block or has been raised inside an except block). In that case you can use sys.exc_info:
import sys
try:
# funky code
except HandleThis:
pass
finally:
if sys.exc_info()[0] is not None:
# only entered if there's an *unhandled* exception, e.g. NOT a HandleThis exception
print('funky code raised')
raised = True
try:
funky code
raised = False
except HandleThis:
# handle it
finally:
logger.info('funky code raised %s', raised)
Given the additional background information added to the question about selecting a log level, this seems very easily adapted to the intended use-case:
mylog = WARNING
try:
funky code
mylog = DEBUG
except HandleThis:
# handle it
finally:
mylog(...)
You can easily assign your caught exception to a variable and use it in the finally block, eg:
>>> x = 1
>>> error = None
>>> try:
... x.foo()
... except Exception as e:
... error = e
... finally:
... if error is not None:
... print(error)
...
'int' object has no attribute 'foo'
Okay, so what it sounds like you actually just want to either modify your existing context manager, or use a similar approach: logbook actually has something called a FingersCrossedHandler that would do exactly what you want. But you could do it yourself, like:
#contextmanager
def LogCapture():
# your existing buffer code here
level = logging.WARN
try:
yield
except UselessException:
level = logging.DEBUG
raise # Or don't, if you just want it to go away
finally:
# emit logs here
Original Response
You're thinking about this a bit sideways.
You do intend to handle the exception - you're handling it by setting a flag. Maybe you don't care about anything else (which seems like a bad idea), but if you care about doing something when an exception is raised, then you want to be explicit about it.
The fact that you're setting a variable, but you want the exception to continue on means that what you really want is to raise your own specific exception, from the exception that was raised:
class MyPkgException(Exception): pass
class MyError(PyPkgException): pass # If there's another exception type, you can also inherit from that
def do_the_badness():
try:
raise FileNotFoundError('Or some other code that raises an error')
except FileNotFoundError as e:
raise MyError('File was not found, doh!') from e
finally:
do_some_cleanup()
try:
do_the_badness()
except MyError as e:
print('The error? Yeah, it happened')
This solves:
Explicitly handling the exception(s) that you're looking to handle
Making the stack traces and original exceptions available
Allowing your code that's going to handle the original exception somewhere else to handle your exception that's thrown
Allowing some top-level exception handling code to just catch MyPkgException to catch all of your exceptions so it can log something and exit with a nice status instead of an ugly stack trace
If it was me, I'd do a little re-ordering of your code.
raised = False
try:
# funky code
except HandleThis:
# handle it
raised = True
except Exception as ex:
# Don't Handle This
raise ex
finally:
if raised:
logger.info('funky code was raised')
I've placed the raised boolean assignment outside of the try statement to ensure scope and made the final except statement a general exception handler for exceptions that you don't want to handle.
This style determines if your code failed. Another approach might me to determine when your code succeeds.
success = False
try:
# funky code
success = True
except HandleThis:
# handle it
pass
except Exception as ex:
# Don't Handle This
raise ex
finally:
if success:
logger.info('funky code was successful')
else:
logger.info('funky code was raised')
If exception happened --> Put this logic in the exception block(s).
If exception did not happen --> Put this logic in the try block after the point in code where the exception can occur.
Finally blocks should be reserved for "cleanup actions," according to the Python language reference. When finally is specified the interpreter proceeds in the except case as follows: Exception is saved, then the finally block is executed first, then lastly the Exception is raised.
I am trying to execute a loop while ignoring exceptions. I think pass or continue will allow me to ignore exceptions in a loop. Where should I put the pass or continue?
class KucoinAPIException(Exception):
"""Exception class to handle general API Exceptions
`code` values
`message` format
"""
def __init__(self, response):
self.code = ''
self.message = 'Unknown Error'
try:
json_res = response.json()
except ValueError:
self.message = response.content
pass
else:
if 'error' in json_res:
self.message = json_res['error']
if 'msg' in json_res:
self.message = json_res['msg']
if 'message' in json_res and json_res['message'] != 'No message available':
self.message += ' - {}'.format(json_res['message'])
if 'code' in json_res:
self.code = json_res['code']
if 'data' in json_res:
try:
self.message += " " + json.dumps(json_res['data'])
except ValueError:
pass
self.status_code = response.status_code
self.response = response
self.request = getattr(response, 'request', None)
def __str__(self):
return 'KucoinAPIException {}: {}'.format(self.code, self.message)
And this doesn't work:
from kucoin.exceptions import KucoinAPIException, KucoinRequestException, KucoinResolutionException
for i in range(10):
# Do kucoin stuff, which might raise an exception.
continue
Quick solution:
Catching the exceptions inside your loop.
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except Exception as e:
print(e)
pass
Adopting best practices:
Note that it is generally considered bad practice to catch all exceptions that inherit from Exception. Instead, determine which exceptions might be raised and handle those. In this case, you probably want to handle your Kucoin exceptions. (KucoinAPIException, KucoinResolutionException, and KucoinRequestException. In which case your loop should look like this:
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except (KucoinAPIException, KucoinRequestException, KucoinResolutionException) as e:
print(e)
pass
We can make the except clause less verbose by refactoring your custom exception hierarchy to inherit from a custom exception class. Say, KucoinException.
class KucoinException(Exception):
pass
class KucoinAPIException(KucoinException):
# ...
class KucoinRequestException(KucoinException):
# ...
class KucoinResolutionException(KucoinException):
# ...
And then your loop would look like this:
for i in range(10):
try:
# Do kucoin stuff, which might raise an exception.
except KucoinException as e:
print(e)
pass
Exception classes aren't designed to handle exceptions. They shouldn't actually have any logic in them. Exception classes essentially function like enums to allow us to quickly and easily differentiate between different types of exceptions.
The logic you have to either raise or ignore an exception should be in your main code flow, not in the exception itself.
You can use finally block to execute the block no matter what.
for i in range(10):
try:
#do something
except:
#catch exceptions
finally:
#do something no matter what
Is that is what you were looking for?
use try except in main block where KucoinAPIException is thrown
for i in range(10):
try:
# do kucoin stuff
# .
# .
# .
except:
pass
Since you mentioned ignoring exceptions I am assuming you would pass all exceptions. So no need to mention individual exceptions at except: line.
I have a try/except where I repeat the except portion frequently in my code. This led me to believe that it would be better to separate the except portion into a function.
Below is my use case:
try:
...
except api.error.ReadError as e:
...
except api.error.APIConnectionError as e:
...
except Exception as e:
...
How would I go about separating this logic into a function so I can do something as simple as:
try:
...
except:
my_error_handling_function(e)
Just define the function:
def my_error_handling(e):
#Do stuff
...and pass in the exception object as the parameter:
try:
#some code
except Exception as e:
my_error_handling(e)
Using just a generic Exception type will allow you to have a single except clause and handle and test for different error types within your handling function.
In order to check for the name of the caught exception, you can get it by doing:
type(e).__name__
Which will print the name, such as ValueError, IOError, etc.
I would suggest refactoring your code so the try/except block is only present in a single location.
For instance, an API class with a send() method, seems like a reasonable candidate for containing the error handling logic you have described in your question.
Define your function:
def my_error_handling(e):
#Handle exception
And do what you're proposing:
try:
...
except Exception as e:
my_error_handling_function(e)
You can handle logic by getting the type of the exception 'e' within your function. See: python: How do I know what type of exception occurred?
If you don't like try-catch statement, you can use exception-decouple package and decorator.
from exception_decouple import redirect_exceptions
def my_error_handling(arg, e):
#Do stuff
#redirect_exceptions(my_error_handling, api.error.ReadError, api.error.APIConnectionError)
def foo(arg):
...