Can't reach except block in python - python-3.x

I want to loop through a certain line of code until any exception or keyboard interruption occurs. But I can not reach the exception block whenever any exception occurs or due to keyboard interruption.
How can I modify my code so that I could actually reach in case of exception being thrown?
def run():
lidar = RPLidar(PORT_NAME)
iterator = lidar.iter_scans(50000)
time.sleep(2)
environment(iterator)
while True:
try:
print('Hi')
update_line(iterator)
except Exception or KeyboardInterrupt:
print("exception occur. Run again")
#lidar = RPLidar(PORT_NAME)
lidar.stop_motor()
lidar.stop()
lidar.disconnect()
break
if __name__ == '__main__':
run()

I'm surprised that code actually runs. When you say except Exception or KeyboardInterrupt you are saying only take the first thing here that evaluates to True. Since bool(Exception) is True you are only going to catch Exceptions. To catch multiple types of exceptions you would write it like this:
try:
except (Exception, KeyboardInterrupt):
It might not be triggering or non-keyboard exceptions because the exception you are trying to catch derives from BaseException and not Exception. To fix that change Exception to BaseException.

def run():
while True:
try:
print('Hi')
function_doesnt_exist(iterator)
except Exception or KeyboardInterrupt:
print("exception occur. Run again")
break
if __name__ == '__main__':
run()
When I intentionally call function that doesn't exist in your while loop it calls exception : exception occur. Run again
Perhaps you didn't generate an error properly therefore no exception is called
Also , Exception or KeyboardInterrupt means Exception since Exception includes KeyboardInterrupt and u handle them in same manner
so If you just want to catch Keyboard Interrupt then go for:
except KeyboardInterrupt:
pass
Or if you want to handle general exception and Keyboard one different do something like this:
except KeyboardInterrupt:
print("don't press ctrl+C")
pass
except:
print("exception occured")
pass

Related

How do test the side effects of an except block with pytest?

My goal is to throw an exception during a test to trigger an except block, then wait for the except block to complete, and then assert stuff.
This is the method that needs to be tested
def main(args, symbol_store):
t = None
try:
t = parse_and_download(args.output, args.symbols, symbol_store)
t.wait()
except KeyboardInterrupt:
if t is not None:
t.set()
print(string_downloads_cancelled, flush=True)
The test method should do something like this
raise KeyboardInterrupt
assert not os.path.exists(test_symbol_store)
The assertion is clearly unreachable, and even if it was, I am certain that it would not wait for the except block to complete.
Following the advice of MrBean Breman I mocked the wait function with pytest_mocker.
mocker.patch('main.DownloadManager.DownloadThread.wait', side_effect=KeyboardInterrupt)
This works as intended.

Retrieve Python exception object

I have a piece of code that I don't control and while running it raises an error. I'd like to capture the value of exc object inside the exc_func method.
As you can see exc_func raises two exceptions, one of which is handled. What I care about is the value of the exc object, but so far have little luck retrieving it. The value does not exist in exc_traceback object and the exception message is not very helpful.
import traceback
import sys
def exc_func():
try:
a = 1
a.length()
except Exception as exc:
exc.with_not_existing()
def main():
try:
exc_func()
except Exception as exc:
exc_type, exc_value, exc_traceback = sys.exc_info()
tb_walk = traceback.walk_tb(exc_traceback)
# Need this in order to pickle traceback
tb_summary = traceback.StackSummary.extract(tb_walk, capture_locals=True)
if __name__ == '__main__':
main()
EDIT:
For instance, the exc object in main is AttributeError("'AttributeError' object has no attribute 'with_not_existing'"). What I really want to see is the exc object inside exc_func. Just to be clear, I need the exc object itself, something like traceback.format_exc() is not helpful in my case, due to the nature of the exception (it's a C lib that raises this exception)
When an exception is raised during handling another exception, the initial exception is stored as the __context__. It can be extracted when handling the new exception.
try:
exc_func()
except Exception as exc:
parent = exc.__context__ # the previously handled exception
print(type(parent), parent)
Note that an exception handler may also explicitly chain exceptions via __cause__.
Built-in Exceptions
[...]
When raising (or re-raising) an exception in an except or finally clause __context__ is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.
The raise statement
[...]
The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable).
[...]
A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

Catching Outer Exceptions in Python

My code tries to do something, but it triggers an Error... which triggers another Error. So, the error message looks something like this:
SillyError: you can`t do that becuz blablabla
The above exception was the direct cause of the following exception:
LoopyError: you can`t do that becuz blobloblo
I want to create a try except block that only catches this specific duo of errors. However, I am only able to catch the first one, because once I do, the second one never gets a chance to trigger.
This other question is about catching either exception, but I want to catch only if both are triggered in succession. Is there a way?
If you have a try\except, you will always catch the error based on the outer exception. However you do have the option to pass on any exceptions you don't want to process.
In this code, the ZeroDivisionError is caught and wrapped in another exception which is then caught by the calling code. The calling code checks for the inner exception and decides whether to re-raise the exception up the stack.
def xtest():
try:
a = 1/0 # exception - division by zero
except ZeroDivisionError as e:
raise Exception("Outer Exception") from e # wrap exception (e not needed for wrap)
try:
xtest()
except Exception as ex:
print(ex) # Outer Exception
print(ex.__cause__) # division by zero
if (str(ex) == "Outer Exception" and str(ex.__cause__) == "division by zero"):
print("Got both exceptions")
else:
raise # pass exception up the stack
Just for completion, you can do the check based on the exception class name also:
if (type(ex).__name__ == "Exception" and type(ex.__cause__).__name__ == "ZeroDivisionError"):
print("Got both exceptions")
#ShadowRanger pointed out that it may be quicker to just check the class type instead of the class name:
if (type(ex) == Exception and type(ex.__cause__) == ZeroDivisionError):
print("Got both exceptions")

Python3 missing exception when looping

I have to define an attribute in a class and I would like to manage error in the most pythonic way.
Here is the code I have tried so far. I can't figure out why I can not "reach" the exception in the following code.
# global variable to be used in the example
my_dict = {"key1": {"property": 10}, "key2": {}}
class Test(object):
#property
def my_attribute(self):
try:
return self._my_attribute
except AttributeError:
self._my_attribute = {}
for key, value in my_dict.items():
print(key)
self._my_attribute[key] = value['property']
except Exception:
print('error')
# I would like to manage my error here with a log or something
print("I am not reaching here")
finally:
return self._my_attribute
if __name__ == '__main__':
Test().my_attribute
I expected to reach the Exception case in the second iteration of the for loop since it is a KeyError ("key2" has no "property"). But it just passes by it. In this example, if the script is run, it does not print "I am not reaching here". Could anyone explain why I am seeing this wrong? Thanks!
The potential KeyError in self._my_attribute[key] = value['property'] is not covered by the except Exception block. Once it is raised the finally block is executed (as a matter of fact the finally block is always executed, regardless of an exception being raised or even handled). This can be easily verified by using a step-by-step debugger or with a simple print('finally') inside the finally block.
This is (among other reasons) why try blocks should be as minimal as possible. If you know that line might raise a KeyError then explicitly try-except it:
for key, value in my_dict.items():
print(key)
try:
self._my_attribute[key] = value['property']
except KeyError as e:
print('Key ', e, 'does not exist')

Async socket.send() exception

Hello I have the following for my async loop
async def start_process(restore_items, args, loop):
with GlacierRestorer(args.temp_dir, args.error_log_bucket, loop) as restorer:
restorer.initiate_restore_all(restore_items)
tasks = []
semaphore = asyncio.BoundedSemaphore(4)
for item in restore_items:
tasks.append(asyncio.ensure_future(restorer.transfer(item, semaphore)))
await asyncio.gather(*tasks)
def main():
args = get_args()
restore_items = get_restore_items(args)
for item in restore_items:
print(item.source, ':', item.destination)
try:
loop = asyncio.get_event_loop()
loop.run_until_complete(start_process(restore_items, args, loop))
except KeyboardInterrupt:
pass
My job and files get larger I see that I keep getting an
socket.send() exception
After reading the documentation it seems to be coming from loop.run_until_complete
The exception doesn't come the program to crash, but eventually bogs it down so much it gets stuck printing the exception.
How do I modify the current code to fix this?
run_until_complete only propagates the exception raised inside start_process. This means that if an exception happens at any point during start_process, and start_process doesn't catch it, run_until_complete(start_process()) will re-raise the same exception.
In your case the exception likely originally gets raised somewhere in restorer.transfer(). The call to gather returns the results of the coroutines, which includes raising an exception, if one occurred.
The exception doesn't come the program to crash, but eventually bogs it down so much it gets stuck printing the exception. How do I modify the current code to fix this?
Ideally you would fix the cause of the exception - perhaps you are sending in too many requests at once, or you are using the GlacierRestorer API incorrectly. But some exceptions cannot be avoided, e.g. ones caused by a failing network. To ignore such exceptions, you can wrap the call to restorer.transfer in a separate coroutine:
async def safe_transfer(restorer, item, semaphore):
try:
return await restorer.transfer(item, semaphore)
except socket.error as e:
print(e) # here you can choose not to print exceptions you
# don't care about if doing so bogs down the program
In start_process you would call this coroutine instead of restorer_transfer:
coros = []
for item in restore_items:
coros.append(safe_transfer(restorer, item, semaphore))
await asyncio.gather(*coros)
Note that you don't need to call asyncio.ensure_future() to pass a coroutine to asyncio.gather; it will be called automatically.

Resources