I'm new to Python. I have a working, monolithic Python program that I'm breaking into individual Python functions. I'd like to use the try: - except: pattern to catch specific exceptions for each function.
Example: Create a Key Vault client and retrieve a secret from Key Vault
import logging
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credentials = DefaultAzureCredential()
def create_kv_client(kv_name, credentials):
kv_uri = 'https://' + kv_name + '.vault.azure.net'
kv_client = SecretClient(vault_url=kv_uri, credential=credentials)
return kv_client
kv_client = create_kv_client('mykeyvaultname', credentials)
def retrieve_secret(table_stg_acct_key, kv_client):
retrieved_account_key = kv_client.get_secret(table_stg_acct_key)
return retrieved_account_key
try:
retrieved_account_key = retrieve_secret('mykeyvaultsecretname', kv_client)
print(retrieved_account_key)
except:
logging.error('####### Failed to retrieve key from Key Vault #######')
raise BaseException
Rather than raise BaseException here, I'd like to use the Azure Core exceptions module and log the actual message in the exception.
How is the except: statement handled in the case where two exceptions could be raised?
Example: There could be two exceptions raised by the get_secret method.
If the Key Vault URL is incorrect, a ServiceRequestError is raised:
ServiceRequestError: <urllib3.connection.HTTPSConnection object at 0x000001BFA2299640>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed
If the Key Vault secret name is incorrect, a ResourceNotFoundError is raised:
ResourceNotFoundError: (SecretNotFound) A secret with (name/id) notmykeyvaultsecretname was not found in this key vault. If you recently deleted this secret you may be able to recover it using the correct recovery command. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125182
How is this accomplished?
Do I have to import the azure core exception module?
An example of this pattern would be very helpful.
The exception will be caught in order of "except" clauses, but beware of the subclass tree, since a except will catch all subclasses as well. For instance, this one leads to unreachable code.
try:
# do something
except BaseException:
# do something with
except DerivedException:
# assuming DerivedException is an extension of BaseException, you can't reach that code
So put them in most specific first.
In your Azure situation, this brings to something like:
from azure.core.exceptions import (
ClientAuthenticationError,
HttpResponseError,
ServiceRequestError,
ResourceNotFoundError,
AzureError
)
try:
# do KV stuff
except ClientAuthenticationError as e:
# Can occur if either tenant_id, client_id or client_secret is incorrect
logger.critical("Azure SDK was not able to connect to Key Vault", e)
except HttpResponseError as e:
# One reason is when Key Vault Name is incorrect
logger.critical("Possible wrong Vault name given", e)
except ServiceRequestError:
# Network error, I will let it raise to higher level
raise
except ResourceNotFoundError:
# Let's assume it's not big deal here, just let it go
pass
except AzureError as e:
# Will catch everything that is from Azure SDK, but not the two previous
logger.critical("Azure SDK was not able to deal with my query", e)
raise
except Exception as e:
# Anything else that is not Azure related (network, stdlib, etc.)
logger.critical("Unknown error I can't blame Azure for", e)
raise
Related
when using DataLakeServiceClient from python3.5: how do i check if login was successfull?
following sample works OK for correct Credentials but if using wrong credentials it endless loads after calling create_directory. It does not throw any exception.
how to check if Login-Data is OK bevor calling create_directory?
from azure.storage.filedatalake import DataLakeServiceClient
from azure.core._match_conditions import MatchConditions
from azure.storage.filedatalake._models import ContentSettings
def initialize_storage_account(storage_account_name, storage_account_key):
try:
global service_client
service_client = DataLakeServiceClient(account_url="{}://{}.dfs.core.windows.net".format(
"https", storage_account_name), credential=storage_account_key)
except Exception as e:
print(e)
def create_directory(container_name,dir_name):
try:
file_system_client = service_client.get_file_system_client(file_system=container_name)
print(file_system_client)
file_system_client.create_directory(dir_name)
print("Created Directory")
except Exception as e:
print(e)
initialize_storage_account("wrongaccountname","a0lyWRONGKEYagAAA==")
create_directory("test_fs","test_dir")
how do i check if login was successfull?
To check if you have provided correct credentials, you will need to perform a network operation. It is recommended that you do a read operation like get_service_properties or try to list file systems.
If the operation is successful, that would mean correct credentials are supplied. If the operation fails, you will need to check the status code in the exception. If the operation fails with Authorization (403) error, that would most likely mean an issue with the credentials (there are other reasons as well because of which you can get 403 error).
according to werkzeug docs, InternalServerError has original_exception parameter. That looks cool and I'would like to use it in following way to handle exceptions:
#app.errorhandler(Exception)
def handle_errors(err):
return err if isinstance(err, HTTPException) else InternalServerError(original_exception=err)
and log it in #app.after_request method to pack all additional info from request and response, where standard request logging occurs. Unfortunatelly I'm not able to find out how to use stored original_exception. Where is it stored?
When I check sys.exc_info() in #app.after_request, it's also empty (or (None, None, None)).
One way is probably log exceptions directly in #app.errorhandler, request info should be accessible there and response is not ready (because of error) anyways, but what happens with original_exception after storing in InternalServerError???
Thanks for answer, Michal
I found myself here looking for the same thing - how to access the original_exception, but I eventually gave up and settled on traceback to give me the info I was seeking.
This is the key component, capturing the traceback stack as a list:
formatted_lines = traceback.format_exc().splitlines()
Here's my final code in which I extracted the line number of the error and the specific trigger, then passed them to the page:
from werkzeug.exceptions import InternalServerError
import traceback
#app.errorhandler(InternalServerError)
def handle_500(e):
templateData = {
'errorAt' : 'Internal Server Error',
'errorIs' : 'Check ~/www/gunicorn.error for details'
}
try:
formatted_lines = traceback.format_exc().splitlines()
for error_location in formatted_lines:
if 'intvlm8r.py' in error_location:
templateData['errorAt'] = error_location
templateData['errorIs'] = formatted_lines[-1]
except Exception as e:
app.logger.debug(f'handle_500: Unhandled exception: {e}')
return render_template('500_generic.html', **templateData)
I am using the following approach for handling Twilio exceptions in Python:
try:
#code for sending the sms
print(message.sid)
except TwilioRestException as e:
print(e)
This allows me to send sms and Exceptions are handled by Python.
Now I need to "return" the exceptions codes in order to process them, let's say, give user a message depending on the exception.
How can I achieve that?
If raising exception is not an option you could simply add return under except block.
def func():
# your logic
try:
#code for sending the sms
print(message.sid)
except TwilioRestException as e:
print(e)
return e.code # or whetever attribute e has for it...
By default function will return None if everything goes right. In client code it will be like
err = func()
if err:
# sms wasn't sent, action required
I am learning how to use Zeep as my soap client. I am able to connect to a WSDL and view services, however, I am stuck on how to catch all possible exceptions. I am only able to catch KeyError. I want to be able to catch a few more:
Basically something similar to the below http client example:
except (http.client.HTTPException, ValueError, KeyError, AttributeError) as e
I would want to use try.....except
try:
session = Session()
session.auth = HttpNtlmAuth(username, password)
request_data = {
}
client = Client(wsdl, transport=Transport(session=session))
response = client.service.GetPendingBills(**request_data)
billobj = json.loads(response)
print(billobj)
bills = (len(billobj["Bills"]))
except KeyError as e:
bills = 0
Maybe this is too late, but you can import zeep.exceptions and handle all kinds of exceptions that you have that way. You just need to check the exception and catch it as you have demonstrated above.
Solution is shown in this documentation
I decided to import requests and handle the exceptions as indicated below:
except (requests.exceptions.HTTPError, KeyError, TimeoutError) as e
Thanks
When I have two Python exceptions that are the same exception class but a different error message, how do I catch them separately?
For specific use-case:
I'm using the Facepy library to hit the Facebook Graph API. When the API returns an error that isn't Oauth related, Facepy raises a facepy.exceptions.FacebookError and passes the error message given by the Facebook API.
I'm consistently hitting two different errors that I'd like to treat differently and the only way to parse them is the error message, but I can't figure out how to write my except clause--here it is in pseudo-code:
try:
#api query
except facepy.exceptions.OAuthError and error_message = 'object does not exist':
# do something
except facepy.exceptions.OAuthError and error_message = 'Hit API rate limit':
# do something else
How do I write these except clauses to trigger off both the exception and the error message?
Assuming the Exception's error message is in the error_message attribute (it may be something else — look at the Exception's __dict__ or source to find out):
try:
#api query
except facepy.exceptions.OAuthError as e:
if e.error_message == "object does not exist":
print "Do X"
elif e.error_message == "Hit API rate limit":
print "Do Y"
else:
raise
facepy's OAuthError derives from FacebookError and that has message attribute. https://github.com/jgorset/facepy/blob/master/facepy/exceptions.py#L8. So, you can use if condition with the message like this
try:
#api query
except facepy.exceptions.OAuthError as error:
if 'object does not exist' == error.message:
# do something
elif 'Hit API rate limit' == error.message:
# do something else
else:
raise