Is there a way to shorten the following scenario so i don't have to use an ugly nested try except statement?
class Error(Exception):
def __init__(self):
print("That did not work")
try:
try:
gblgbl
except:
raise Error
except Error:
pass
What i want can be described as following pseudo code:
Try something:
something
if something went wrong:
raise Error
catch Error:
what to do if error occours
I don't want to raise the error if the try statement succeeds, however if i raise an exception in the exception statement like this:
try:
gblgbl
except:
raise Error
except Error:
pass
it can't be caught with an other except, since there is already an except that caught the python exception and the interpreter throws a SyntaxError.
Am i missing something obvious?
I'm aware that you probably would never use this in an actual program, but i'm curious about the theory.
There is no reason to use an exception here. The following (pseudo-)code achieves the same thing.
try:
gblgbl
except:
pass
Note however that it generally is a bad idea to catch all exceptions, since for instance the KeyboardInterrupt Exception will also be caught and the program can thus not be interrupted using Ctrl-c
Create custom exceptions?
The Python Tutorial has a section on User-defined Exceptions
Related
I have a try block case in my code and I want to ignore one particular exception and all the rest should be raised.
For example:
try:
blah
except <exception> as e:
raise Exception(e)
In this kind of case, I want all the exceptions to be raised except for one case, say if the exception is "query not found" I have to ignore it.
How do I ignore that single exception?
I can use multiple except blocks but how to define a exception?
You can give something like this:
try:
print(x)
except NameError:
print("Variable x is not defined")
except:
print("Something else went wrong")
In this case, you want to catch NameError and specify a message. For all others, you want to specify another message.
Let's say you want to ignore NameError, then you can just give continue or pass.
Alternatively, you can also raise an exception.
Example will be:
x = -1
if x < 0:
raise Exception("Sorry, no numbers below zero")
So you can use a combination of all this to get you what you want.
If you want more details on exception, see the below links:
https://docs.python.org/3/tutorial/errors.html
https://www.w3schools.com/python/python_try_except.asp
https://realpython.com/python-exceptions/
And on stack overflow (as Gino highlighted), see
Handling all but one exception
As an alternative to #Joe Ferndz's answer, in case you don't want the exception to be raised but still want the block to exit, you can use suppress from the contextlib module:
from contextlib import suppress
with suppress(ValueError):
print('hello world')
raise ValueError
print('this will not be printed')
In this case, the block still exits on raise ValueError, but an exception is not raised.
I've recently had a problem when coding in Python in the PyCharm editor. Whenever I made a try-except statement, I would for some reason get a warning (yellow line beneath the word: except)
Here is an example:
s = "Text"
try:
print(s[2])
except:
print("There is no character at that index")
When I write this exact code in PyCharm, I get a warning. When I hover my mouse over the warning it says:
Too broad exception clause
PEP 8: E722 do not use bare 'except'
Any idea why this happens?
When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
For example:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException: ).
A good rule of thumb is to limit use of bare 'except' clauses to two cases:
If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better way to handle this case.
so basically I have a loop and for each step, I run a function in a try/except. When there is an error caught, I have a generic error message that doesn't allow me to understand what went wrong.
How do I have the real python built-in error message (raise) and still continue to run the loop?
Thanks.
Sample code:
for i in [...]:
try:
func1(i)
except Exception as ex:
print(ex)
func2(i)
I encountered a small annoyance with this code:
try:
return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
except (OSError, asyncio.TimeoutError) as err:
print(f"Network problem: {err}")
When the timeout occurs, it prints just "Network problem: ". It is caused by an empty value attached to the raised asyncio.TimeoutError:
# inside wait_for():
raise futures.TimeoutError()
It is easy to hadle the TimeoutError separately, but I find the original construct quite idiomatic and now a core library breaks it. Is there a good reason for it? Is my assumption - that printing an exception should give us a clue what went wrong - correct?
Is there a good reason for it?
Yes, what kind of message you expect from TimeoutError? "Timeout occured"? The exception itself is self-explanatory, no need for such redundancy.
Is my assumption - that printing an exception should give us a clue what went wrong - correct?
Yes and no. Clue? Yes. Full information? No. The exception message is not mandatory. And the type of an exception is an important piece of information as well. And in many cases even more then the message itself.
So first of all: using print is wrong to begin with. Python has a very rich logging support. For example logger.exception(str(exc)) solves your problem because it logs entire traceback in addition to the message. At least by default, it can be customized.
But if you still want to use print then consider logging whole traceback:
import traceback
# traceback.print_exc()
print(traceback.format_exc())
If whole traceback is too big then you can always simply print the exception's class name:
# print(f'[{type(exc).__name__}] {exc}')
print(f'[{type(exc)}] {exc}')
or customize by exception:
try:
return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
except OSError as err:
print(f"Network problem: {err}")
except asyncio.TimeoutError:
print('Timeout occured')
The expectation that an exception will provide a message that explains the issue is not part of the general exception contract in Python. It is true for system exceptions such as OSError where the program must be able to get to the error message provided by the operating system, as the program is not qualified to guess the message based on a code or an exception subtype.
But more basic language exceptions do not work like that. Take, for example, KeyError raised by dict.__getitem__:
>>> try:
... d[123]
... except KeyError as err:
... print(f"Dict problem: {err}")
...
Dict problem: 123
In this sense, TimeoutError is much more like KeyError than like OSError. When you catch TimeoutError, you know exactly what happened - a timeout. You typically want to do something based on the fact that a timeout happened, rather than just display a message to the user. And even if you did want to provide a message, you'd use one that would make sense for your application, not a generic one provided by Python. This is in contrast to OSError where you often cannot do anything other than display the message coming from the OS and where that message can prove invaluable for investigating the underlying issue.
To sum it up, the problem is that you are catching two fundamentally different exceptions in the same except clause, and that set you up for trouble. I would restructure the code like this:
try:
return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
except OSError as err:
print(f"Network problem: {err}")
except asyncio.TimeoutError:
print("Operation timed out")
I have a list of functions that may fail and, if one fails, I don't want the script to stop, but to continue with next function.
I am executing it with something like this :
list_of_functions = [f_a, f_b, f_c]
for current_function in list_of_functions:
try:
current_function()
except Exception:
print(traceback.format_exc())
It's working fine, but it is not PEP8 compliant:
When catching exceptions, mention specific exceptions whenever
possible instead of using a bare except: clause.
For example, use:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
A bare except: clause will catch SystemExit and KeyboardInterrupt
exceptions, making it harder to interrupt a program with Control-C,
and can disguise other problems. If you want to catch all exceptions
that signal program errors, use except Exception: (bare except is
equivalent to except BaseException: ).
A good rule of thumb is to limit use of bare 'except' clauses to two
cases:
If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better
way to handle this case.
How can I do this the good way?
The PEP8 guide you quote suggests that it is okay to use a bare exception in your case provided you are logging the errors. I would think that you should cover as many exceptions as you can/know how to deal with and then log the rest and pass, e.g.
import logging
list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
current_function()
except KnownException:
raise
except Exception as e:
logging.exception(e)
Use this to cheat PEP8:
try:
"""code"""
except (Exception,):
pass
I think in some rare cases catching general exception is just justified and there is a way to trick PEP8 inspection:
list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
current_function()
except (ValueError, Exception):
print(traceback.format_exc())
You can replace ValueError by any other. It works for me (at least in PyCharm).
You can just put a comment like except Exception as error: # pylint: disable=broad-except that's worked for me actually. I hope it could be work for you.
From issue PY-9715 on yourtrack.jetbrains.com:
From pep-0348:
BaseException
The superclass that all exceptions must inherit from. It's name was
chosen to reflect that it is at the base of the exception hierarchy
while being an exception itself. "Raisable" was considered as a name,
it was passed on because its name did not properly reflect the fact
that it is an exception itself.
Direct inheritance of BaseException is not expected, and will be
discouraged for the general case. Most user-defined exceptions should
inherit from Exception instead. This allows catching Exception to
continue to work in the common case of catching all exceptions that
should be caught. Direct inheritance of BaseException should only be
done in cases where an entirely new category of exception is desired.
But, for cases where all exceptions should be caught blindly, except
BaseException will work.
You can avoid the error if you then re-raise the Exception. This way you are able to do damage control and not endanger loosing track of its occurance.
Do you perhaps mean that each function can raise different exceptions? When you name the exception type in the except clause it can be any name that refers to an exception, not just the class name.
eg.
def raise_value_error():
raise ValueError
def raise_type_error():
raise TypeError
def raise_index_error():
doesnt_exist
func_and_exceptions = [(raise_value_error, ValueError), (raise_type_error, TypeError),
(raise_index_error, IndexError)]
for function, possible_exception in func_and_exceptions:
try:
function()
except possible_exception as e:
print("caught", repr(e), "when calling", function.__name__)
prints:
caught ValueError() when calling raise_value_error
caught TypeError() when calling raise_type_error
Traceback (most recent call last):
File "run.py", line 14, in <module>
function()
File "run.py", line 8, in raise_index_error
doesnt_exist
NameError: name 'doesnt_exist' is not defined
Of course that leaves you with not knowing what to do when each exception occurs. But since you just want to ignore it and carry on then that's not a problem.
First, generate the pylintrc using the below command
pylint --generate-rcfile > .pylintrc
For reference:
https://learn.microsoft.com/en-us/visualstudio/python/linting-python-code?view=vs-2022
Search for disable (uncomment if needed) in the generate pylintrc file and add the below exception.
broad-except
Rerun the pylint command and see the magic