python-twitter exception handling - python-3.x

Im trying to handle errors with Python-Twitter, for example: when I do the below passing a Twitter account that returns a 404 I get the following response...
import twitter
# API connection
api = twitter.Api(consumer_key='...',
consumer_secret='...',
access_token_key='...',
access_token_secret='...')
try:
data = api.GetUser(screen_name='repcorrinebrown')
Except Exception as err:
print(err)
Response:
twitter.error.TwitterError: [{'code': 50, 'message': 'User not found.'}]
how can I iterate through this list on Except

The message property of the exception object should hold the data you are looking for. Try this:
import twitter
# API connection
api = twitter.Api(consumer_key='...',
consumer_secret='...',
access_token_key='...',
access_token_secret='...')
try:
data = api.GetUser(screen_name='repcorrinebrown')
except Exception as err:
print(err.message)
for i in err.message:
print(i)
However, you may want to except the specific exception rather than all exceptions:
except twitter.error.TwitterError as err:
...

For a more specific exception, I would use twitter.TweepError like this
try:
user = api.get_user('user_handle')
except twitter.TweepError as error: #Speficically twitter errors
print(error)

Related

During handling of the above exception, another exception occurred in python

I have a main function which prepare a customised bigquery and pass it to the another function where actual execution of the query happens:
Main function:
def main(request):
try:
client = bigquery.Client(project=flat_rate_project)
# Executing query and loading data into temporary table.
job_config = {"destination": temp_bq_project_details,
"create_disposition": "CREATE_IF_NEEDED",
"write_disposition": "WRITE_APPEND"}
response = execute_select_bq_query(static_query, bq_location, job_config)
print(response['message'])
except RuntimeError:
print("Exception occurred {}".format(RuntimeError))
except ValueError as error:
print("This is the ValueError", str(error))
finally:
Print("Functionality completed !")
Another function [execute_select_bq_query]:
from google.cloud import bigquery
import math
def execute_select_bq_query(query, location, jobconfig):
try:
# Construct a BigQuery client object.'
client = bigquery.Client(project=queryexcproject)
job_config = bigquery.QueryJobConfig()
dest_table = bq_table_reference(client, jobconfig['destination'])
job_config.destination = dest_table
job_config.create_disposition = jobconfig['create_disposition']
job_config.write_disposition = jobconfig['write_disposition']
query_job = client.query(query, location=location, job_config=job_config)
math.sqrt(-10) # To test if it raises ValueError exception
results = query_job.result()
response = {"message": "Data loaded into BQ table {}".format(jobconfig['destination']), "responseCode": 200}
return response
except RuntimeError:
print("Exception occurred {}".format(RuntimeError))
response = "Exception occurred {}".format(RuntimeError)
return response
except ValueError as error:
raise "Exception occurred while loading data into BQ table {} with error {}".format(jobconfig['destination'], error)
Whenever there is ValueError exception occurred in 'execute_select_bq_query' function I am raising it with customise message and I want my main function should catch that. But it is giving me 'During handling of the above exception, another exception occurred' error.

Python try catch always raising error if previusly exception was raised

I have try-catch that behaved differently, Once an exception is raised, the next time the try-catch block is called, it's always raising an exception even if the params passed are valid
class Some
def some_method(variable_id: str):
response = requests.request('https://...........)
if response.status_code != 200:
if response.status_code == 404:
raise ClientError(
'_NOT_FOUND', 'Consignment does not exist. Please provide a valid variable_id', 404)
elif response.status_code == 400:
raise ClientError(
'_ALREADY_CANCELLED', f"Cannot print {variable_id}", 400)
raise ClientError(
'ERROR', "ERROR", 400)
return response
try catch
class Other:
def __init__(self):
self.error = False
def somefunc(id: str):
//id = '123' //working one
try:
response = Some().some_method(id)
return self.error, response
except Exception as e:
self.error = True
return error,[]
The weird thing is if I first called the try-catch using the id that the API check as valid, it will return the response in the try-catch block as expected. But when I replace the id with a value that the API is returning 400 status_code, it will always raise the 400 status code exception even if I called the try-catch block with the previous id that should return 200.
So I tried to print the response.status_code, it is correctly 200 for a valid id, and 400 for an invalid id, but I don't know why it always raises the exception after I call the try-catch block with an invalid id, and change again with a valid id instead of returning the response in Some.some_method class method.
What have I done wrong here?
Ah my bad. I need to reset the error
def somefunc(id: str):
//id = '123'
try:
response = Some().some_method(id)
return self.error, response
except Exception as e:
self.error = True
return error,[]
finally:
self.error = False

Failing to send 404 HTTP status on Flask when client tries to get a nonexistent element

In a Python/Flask application, I have defined this endpoint that I expect to return 404 if a client tries to get an id that doesn't exist on my database.
For example:
#app.route('/plants/<int:plant_id>', methods=['GET'])
def get_plant(plant_id):
try:
plant = Plant.query.filter(Plant.id == plant_id).one_or_none()
if plant is None:
abort(404)
return jsonify({
'success': True,
'plant': plant.format()
})
except:
abort(422)
The problem is that when I try to execute it, it always seems to raise an exception and returns 422.
If I remove the try/except syntax, it works as expected and returns the 404. But I lose the capacity of handling exceptions... so it's not a solution for me.
Why am I doing wrong? How could I correctly trigger 404 without setting 404 as the except return?
Thanks!!
Ok, finally I was able to understand it and solve it. I post my findings here so maybe it could help someone in the future. :)
The answer is very basic, actually: every time I abort, I trigger an exception.
So, when I aborted, no matter the status code I used, I fell into my except statement, which was returning 422 by default.
What I did to solve it was to implement a custom RequestError, and every time I have a controlled error, I trigger my custom error, which output I can control separately.
This is the implementation of my custom error:
class RequestError(Exception):
def __init__(self, status):
self.status = status
def __str__(self):
return repr(self.status)
And I've changed my route implementation for something like this:
(note that I'm now handling first the custom error exception, and only then triggering a generic 422 error)
#app.route('/plants/<int:plant_id>', methods=['GET'])
def get_plant(plant_id):
try:
plant = Plant.query.filter(Plant.id == plant_id).one_or_none()
if plant is None:
raise RequestError(404)
return jsonify({
'success': True,
'plant': plant.format()
})
except RequestError as error:
abort(error.status)
except:
abort(422)
And that does it! \o/

Azure Functions HTTP Trigger : How to return exception from python worker log to the API caller

I'm new to Azure functions
Wished to know how to return exception from python worker log to the API caller .
In a HTTP Trigger with COSMOS DB binding , on firing an insert call to the binding , if data already exists , it fails with
"System.Private.CoreLib: Exception while executing function: Functions.insertEntityData. Microsoft.Azure.DocumentDB.Core: Entity with the specified id already exists in the system."
How can this message be sent back to the end user ? It is not getting captured anywhere.
def main(req: func.HttpRequest, cosmosdata: func.Out[func.Document]) -> func.HttpResponse:
try:
message = ""
logging.info('Python HTTP trigger function processed a request.')
entity_name = req.route_params['entity']
status_code = 500
payload = req.get_json()
if payload:
try:
logging.info(payload)
resultant = cosmosdata.set(func.Document.from_dict(payload))
logging.info(resultant)
status_code = 200
message = "Insert Successful to %s" % (entity_name)
except Exception as e:
return func.HttpResponse(str(e), status_code=500)
else:
status_code = 400
message = "Please pass data in the POST Request"
except Exception as e:
return func.HttpResponse(str(e), status_code=500)
return func.HttpResponse(message, status_code=500)
The try / catch block is not working because you're using an Output binding to Cosmos Db, which is the one that is failing. However, it also looks weird to me because by default it performs and Upsert operation.
I believe the problem relates to your partition Key defined in the function.json file.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2#input---python-examples

How do I catch google.auth.exceptions.RefreshError in python subscriber?

I am trying to catch the following exception but am not having any luck.
ERROR 2019-03-04 16:31:50,522 _plugin_wrapping 15 140108141426432 AuthMetadataPluginCallback "<google.auth.transport.grpc.AuthMetadataPlugin object at 0x7f6dd8330b70>" raised exception!
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/grpc/_plugin_wrapping.py", line 79, in __call__
callback_state, callback))
File "/usr/local/lib/python3.6/site-packages/google/auth/transport/grpc.py", line 77, in __call__
callback(self._get_authorization_headers(context), None)
File "/usr/local/lib/python3.6/site-packages/google/auth/transport/grpc.py", line 65, in _get_authorization_headers
headers)
File "/usr/local/lib/python3.6/site-packages/google/auth/credentials.py", line 122, in before_request
self.refresh(request)
File "/usr/local/lib/python3.6/site-packages/google/oauth2/service_account.py", line 322, in refresh
request, self._token_uri, assertion)
File "/usr/local/lib/python3.6/site-packages/google/oauth2/_client.py", line 145, in jwt_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/usr/local/lib/python3.6/site-packages/google/oauth2/_client.py", line 111, in _token_endpoint_request
_handle_error_response(response_body)
File "/usr/local/lib/python3.6/site-packages/google/oauth2/_client.py", line 61, in _handle_error_response
error_details, response_body)
google.auth.exceptions.RefreshError: ('invalid_grant: Invalid JWT Signature.', '{\n "error": "invalid_grant",\n "error_description": "Invalid JWT Signature."\n}')
I am using google cloud pubsub_v1 and this portion is the subscriber.
I want to catch this exception so the client can request the credentials again. Requesting credentials API's we made are working fine. To get this error I manually deleted the key from the SA using google cloud console UI and commented out the startup function call to get credentials. So it is trying to use the old ones.
In the code I think I have what is a pretty basic subscriber.
from google.cloud import pubsub_v1
from google.oauth2 import service_account
from google.api_core.exceptions import NotFound
from google.auth.exceptions import RefreshError
...
def startSubscribe(self):
project, subscription, gauth = self.decryptCreds()
credentials = service_account.Credentials.from_service_account_info(gauth)
subscriber = pubsub_v1.SubscriberClient(credentials=credentials)
subscription_path = subscriber.subscription_path(project, subscription)
self.future = subscriber.subscribe(subscription_path, callback=self.callback)
LOGGER.info('Listening for messages on {}'.format(subscription_path))
while True:
try:
LOGGER.info("Calling future.result()")
self.future.result()
self.future.exception()
# TODO: Need to figure out permission error, etc... and handle them properly. This is just a catch all until
# I figure out more about gcp subscribe and futures
except RefreshError as e:
# Catch permission exception and get creds again
LOGGER.info("Caught the correct error")
LOGGER.error(e, exc_info=True)
except Exception as e:
LOGGER.info("Must be something else")
LOGGER.error(e, exc_info=True)
LOGGER.info("Looping")
The startSubscribe function is also wrapped in a try/except but I do not get the error there either.
Does anyone have any experience or know how to catch this exception or have any insight how to check credentials so I can request new ones?
Thank you.
We contacted google and they reported back that there is a bug in the async (using the futures) version.
So I modified our code to do it synchronously.
subscriber = None
while self.alive:
try:
if subscriber is None:
project, subscription, gauth = self.decryptCreds()
credentials = (service_account.Credentials
.from_service_account_info(gauth))
subscriber = (pubsub_v1
.SubscriberClient(credentials=credentials))
subscription_path = (subscriber
.subscription_path(project,
subscription))
pull_response = subscriber.pull(subscription_path,
max_messages=NUM_MESSAGES,
timeout=60,
retry=None)
for msg in pull_response.received_messages:
msg_id = msg.message.message_id
try:
payload = json.loads(
base64.b64decode(msg.message.data.decode('utf-8'))
.decode('utf-8'))
LOGGER.info("Got Message")
LOGGER.debug(payload)
LOGGER.debug(type(payload))
# Removed for privacy...
except Exception as e:
LOGGER.info(e, exc_info=True)
# Here we are ack-ing the message no matter what
# because if the message itself is bad, there is no way
# to tell the publisher and we do not want bad messages
# continually sent.
subscriber.acknowledge(subscription_path, [msg.ack_id])
except NotFound as nf:
LOGGER.error(nf, exc_info=True)
try:
# If we get here try to get the credentials before remaking
# the subscriber
self.cpps.doGetCreds()
# Close the channel first to make sure not file handlers
# left open
try:
subscriber.api.transport._channel.close()
except Exception as e:
LOGGER.error(e, exc_info=True)
subscriber = None
except Exception as e:
LOGGER.error(
'Exception here may have been crashing firmware.')
LOGGER.error(e, exc_info=True)
except (RefreshError, ServiceUnavailable) as re:
LOGGER.error(re, exc_info=True)
except RetryError as e:
LOGGER.error(e, exc_info=True)
except Exception as e:
LOGGER.error(e, exc_info=True)
time.sleep(10)
LOGGER.info("Exiting Cloud Pull")
try:
subscriber.api.transport._channel.close()
except Exception as e:
LOGGER.error(e, exc_info=True)
The important thing to note here, as it is not described in the documentation is subscriber.api.transport._channel.close(). Otherwise it will leave lots of file handles open.
So basically just switch to synchronous pulling and make sure to close the channel.
I hope that helps #ProGirlXOXO
Oh and the relevant google imports are
from google.cloud import pubsub_v1
from google.oauth2 import service_account
from google.auth.exceptions import RefreshError
from google.api_core.exceptions import RetryError, ServiceUnavailable, NotFound

Resources