How to clear the exception state in Python - python

I have a try/except block around a call to an API. It appears to me that once I get an exception, all valid try cases after that exception will see the same exception. The only way I have been able to get it to work is to re-start my Python script. I googled around and found PyErr_clear() but that is for the C-API. Is there something I can call from plain-old Python that will clear the exception state?
Here is the basic idea of what I am doing:
def get_and_print_data(key):
try:
data = get_data_from_some_3rd_party_api(key)
except Exception as ex:
print("Failed to get data for",key,": ",str(ex))
return
print("data=",data)
Then in main I have
get_and_print_data("Valid Key") ## This works
get_and_print_data("INvalid Key") ## This gets exception, as expected
get_and_print_data("Valid Key") ## This and all subsequent calls to get_and_print_data() fail with the same exception.

As an example of why I think it's the 3rd party API that is having issues:
def get_data_from_some_3rd_party_api(key):
if key == "Valid Key":
return "This is some good data."
else:
raise ValueError("Invalid Key")
def get_and_print_data(key):
try:
data = get_data_from_some_3rd_party_api(key)
except Exception as ex:
print("Failed to get data for",key,": ",str(ex))
return
print("data=",data)
get_and_print_data("Valid Key") ## This works
get_and_print_data("INvalid Key") ## This gets exception, as expected
get_and_print_data("Valid Key") ## This works
Try running this locally, and you should see that the subsequent valid keys still work.

Related

Given error when trying to iterate through an exception

I am making a Reddit bot using PRAW and the code gives me the error that the exception is not iterable. Here is a simplification of my code:
try:
#something with praw that isn't relevant
except Exception as e: #this except error catches the APIexception, APIexpections in PRAW are a wide field of exceptions that dont't always have the same solution, so I scan the text for the error I'm looking for.
print(e)
if "keyword thats in the error" in e:
#fix the problem with the specific error
else:
print("Unkown APIExpection error")
This works fine for me, but when I run this code:
try:
#something
except Exception as e:
for character in e:
print(character)
#I also tried this
try:
#something
except Exception as e:
for character in str(e):
print(character)
#None of the above work but this is my actual code and what I need to do, anything that gets the above to work should work here too, I'm just letting you know this so that I don't get any other errors I have to ask another question for.
try:
#something
except Exception as e:
characterNum = 0
for character in e:
characterNum += 1
print(str(characterNum) + ": " + character)
It gives me a "TypeError: 'RedditAPIException' is not iterable", RedditAPIException can be ignore though as that's just the error I'm catching.
Convert the exception to string and then check in the if statement.
Change to => if "keyword thats in the error" in str(e):

what is the correct way to handle a caught exception and raise it outside of try block

Im just starting my python learning journey and need some help with the correct way to raise an exception.
Consider a block of code which loops thru a list and performs a task. If an exception occurs,continue with the program execution. And execute the rest of the code. At the end of the program raise the exception and system the application with non zero code. The idea is the program should continue executing all the tasks, but exit with a non 0 code for an external application to track and report.
save_exc_info = None
def numMatcher(numbers):
try:
if numbers != 2:
print('number match ' + str(numbers))
else:
raise ValueError('Number not in list. Will be logged for troubleshooting') # raise exception and log it
except ValueError as veer: # exception 1 caught and saved
save_exc_info = sys.exc_info()
except (IOError, OSError) as ioerr: # exception 2 caught and saved
save_exc_info = sys.exc_info()
try:
print('Next step') # Perform rest of the tasks in the code
except Exception as excp: # exception 3 caught and saved
save_exc_info = sys.exc_info()
print('final step')
numlist = [1, 2, 3]
for numbers in numlist:
numMatcher(numbers)
if save_exc_info is not None:
traceback.print_exception(*save_exc_info) # how to return the right exception and print?
sys.exit(1) # At the end of the program, exit with non zero code as there was an exception in the program.
When handling the exception, you can assign it to a variable, e.g.:
except AssertionError as aerr:
saved_exception = aerr
Which you can later access e.g.:
print(saved_exception)
For you code, this gives you an option of not having two variable, and instead of isError just use saved_exception = None and later test if saved_exception is not None: ...
Not sure how useful saving exception for later (using it as general interface to pass information around) is. Perhaps it may be worth rethinking a bit more.
N Chauhan also made a good point int the comment about AssertionError not being very suitable exception to use to convey this type of information.
To your updated question. If you want to print the traceback is you'd see it when the exception was raised, probably the most straightforward would be to save exception information and use print_exception() (or its format_exception friend):
except ValueError:
save_exc_info = sys.exc_info()
...
traceback.print_exception(*save_exc_info)
You could have extracted the same information from / use the saved exception as well, *save_exc_info could have also been: type(saved_exception), saved_exception, saved_exception.__traceback__ (for the saved exception in the first example).

Overpass a custom exception but print all the other exceptions

I am running the following try-except code:
try:
paths = file_system_client.get_paths("{0}/{1}/0/{2}/{3}/{4}".format(container_initial_folder, container_second_folder, chronological_date[0], chronological_date[1], chronological_date[2]), recursive=True)
list_of_paths=["abfss://{0}#{1}.dfs.core.windows.net/".format(storage_container_name, storage_account_name)+path.name for path in paths if ".avro" in path.name]
except Exception as e:
if e=="AccountIsDisabled":
pass
else:
print(e)
I want neither to print the following error if my try-except fells upon it nor to stop my program execution if I fell upon this error:
"(AccountIsDisabled) The specified account is disabled.
RequestId:3159a59e-d01f-0091-5f71-2ff884000000
Time:2020-05-21T13:09:03.3540242Z"
I just want to overpass it and print any other error/exception (eg. TypeError, ValueError, etc) that will occur.
Is this feasible in Python 3?
Please note that the .get_paths() method belongs to the azure.storage.filedatalake module which enables direct connection of Python with Azure Data Lake for path extraction.
I am giving the note to pinpoint that the Exception I am trying to bypass is not a built-in Exception.
[Update] In sort after following the proposed attached answers I modified my code to this:
import sys
from concurrent.futures import ThreadPoolExecutor
from azure.storage.filedatalake._models import StorageErrorException
from azure.storage.filedatalake import DataLakeServiceClient, DataLakeFileClient
storage_container_name="name1" #confidential
storage_account_name="name2" #confidential
storage_account_key="password" #confidential
container_initial_folder="name3" #confidential
container_second_folder="name4" #confidential
def datalake_connector(storage_account_name, storage_account_key):
global service_client
datalake_client = DataLakeServiceClient(account_url="{0}://{1}.dfs.core.windows.net".format("https", storage_account_name), credential=storage_account_key)
print("Client successfuly created!")
return datalake_client
def create_list_paths(chronological_date,
container_initial_folder="name3",
container_second_folder="name4",
storage_container_name="name1",
storage_account_name="name2"
):
list_of_paths=list()
print("1. success")
paths = file_system_client.get_paths("{0}/{1}/0/{2}/{3}/{4}".format(container_initial_folder, container_second_folder, chronological_date[0], chronological_date[1], chronological_date[2]), recursive=True)
print("2. success")
list_of_paths=["abfss://{0}#{1}.dfs.core.windows.net/".format(storage_container_name, storage_account_name)+path.name for path in paths if ".avro" in path.name]
print("3. success")
list_of_paths=functools.reduce(operator.iconcat, result, [])
return list_of_paths
service_client = datalake_connector(storage_account_name, storage_account_key)
file_system_client = service_client.get_file_system_client(file_system=storage_container_name)
try:
list_of_paths=[]
executor=ThreadPoolExecutor(max_workers=8)
print("Start path extraction!")
list_of_paths=[executor.submit(create_list_paths, i, container_initial_folder, storage_container_name, storage_account_name).result() for i in date_list]
except:
print("no success")
print(sys.exc_info())
Unfortunately the StorageErrorException cannot be handled for a reason, I am still getting the following stdout:
Listing [Python 3.Docs]: Compound statements - The try statement.
There are several ways of achieving this. Here's one:
try:
# ...
except StorageErrorException:
pass
except:
print(sys.exc_info()[1])
Note that except: is tricky because you might silently handle exceptions that you shouldn't. Another way would be to catch any exception the code could raise explicitly.
try:
# ...
except StorageErrorException:
pass
except (SomeException, SomeOtherException, SomeOtherOtherException) as e:
print(e)
Quickly browsing [MS.Docs]: filedatalake package and the sourcecode, revealed that StorageErrorException (which extends [MS.Docs]: HttpResponseError class) is the one that you need to handle.
Might want to check [SO]: About catching ANY exception.
Related to the failure of catching the exception, apparently there are 2 having the same name:
azure.storage.blob._generated.models._models_py3.StorageErrorException (currently imported)
azure.storage.filedatalake._generated.models._models_py3.StorageErrorException
I don't know the rationale (I didn't work with the package), but given the fact the package raises an exception defined in another package when it also defines one with the same name, seems lame. Anyway importing the right exception solves the problem.
As a side note, when dealing with this kind of situation, don't only import the base name, but work with the fully qualified one:
import azure.storage.filedatalake._generated.models.StorageErrorException
you want to compare the type of the exception, change your condition to:
if type(e)==AccountIsDisabled:
example:
class AccountIsDisabled(Exception):
pass
print("try #1")
try:
raise AccountIsDisabled
except Exception as e:
if type(e)==AccountIsDisabled:
pass
else:
print(e)
print("try #2")
try:
raise Exception('hi', 'there')
except Exception as e:
if type(e)==AccountIsDisabled:
pass
else:
print(e)
Output:
try #1
try #2
('hi', 'there')

If condition check with python

if not ping_device(ip):
if not reboot_device(device_1)
logger.error("Unable to reboot.. Serious issue")
break
logger.info("HARD Rebooted")
if not ping_device(ip):
logger.error("Ping failed after hard reboot")
else:
logger.info("Pinged success after reboot")
else:
logger.info("Pinged")
logger.info("Reboot passed")
logger.info("Getting uptime")
sw_version_check = get_sw_version(ip)
check_upgrade()
:
:
:
:
Here is my piece of code. Now if the ping_device fn in the first line succeeds, I have no problem. The else part comes into the picture.
Now if my first line ping_device fails, I call a reboot_device fn. after reboot, I again call the ping function to check my device is online.
After the ping success after the reboot, I need to get going with the else part of the first if condition with sw_version_check, check_upgrade() and rest of code traverses as mentioned with :
Will my logic after ping failure continue with sw_version_chec and check_upgrade?
You could have some separate variable, say doUpgrade, initialized to False and set to True at any point(s) in the first section where you have determined you need an upgrade. Then test that variable to see if the upgrade code needs to be executed.
Try using exceptions, they help make this type of control flow easier to reason about and are more "Pythonic":
def reboot_device(device):
if not your_reboot_device_fn(device):
raise DeviceRebootError('Unrecoverable reboot error')
else:
pass # Or anything else you want to do on success.
def ping_device(ip, device, did_try_reboot=False):
if not your_ping_device_fn(ip):
if did_try_reboot:
raise DevicePingError('Ping failed after hard reboot')
else:
try:
reboot_device(device)
except DeviceRebootError as e:
logging.error(e)
raise
else:
logger.info("HARD Rebooted")
ping_device(ip, device, did_try_reboot=True)
else:
pass # Or anything else you want to do on success.
try:
ping_device(ip, device_1)
except DevicePingError as e:
logging.error(e)
# NOTE: DeviceRebootError isn't caught so it will end the program.
else:
logging.info('Pinged')
sw_version_check = get_sw_version(ip)
check_upgrade()

Python trying fails

I am trying in Python.
try:
newbutton['roundcornerradius'] = buttondata['roundcornerradius']
buttons.append(newbutton)
buttons is a list. roundcornerradius is optional in buttondata.
Alas this gives
buttons.append(newbutton)
^ SyntaxError: invalid syntax
I just want to ignore the cases where roundcornerradius does not exist. I don't need any error reported.
why arent you using the except keyword
try:
newbutton['roundcornerradius'] = buttondata['roundcornerradius']
buttons.append(newbutton)
except:
pass
this will try the first part and if an error is thrown it will do the except part
you can also add the disered error you want to except a certain error like this
except AttributeError:
you can also get the excepted error by doing this:
except Exception,e: print str(e)
You should catch a try with exception:
try:
code may through exception
except (DesiredException):
in case of exception
Also you can use else with try if you need to populate new buttons only when try succeeds:
try:
newbutton['roundcornerradius'] = buttondata['roundcornerradius']
except KeyError:
pass
else:
buttons.append(newbutton)
single except: with no exception class defined will catch every exception raised which may not be desired in some cases.
Most probably you will get KeyError on your code but I am not sure.
See here for builtin exceptions:
http://docs.python.org/2/library/exceptions.html
You must close block with except or finally if using try.
try:
newbutton['roundcornerradius'] = buttondata['roundcornerradius']
except KeyError:
pass#omit raise if key 'roundcornerradius' does not exists
buttons.append(newbutton)
If you know default value for 'roundcornerradius' - you dont need no try ... except
newbutton['roundcornerradius'] = buttondata.get('roundcornerradius', DEFAULT_RADIUS)
buttons.append(newbutton)

Categories