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
Related
Hi guys i'm trying to make the bot send a message automatically in a specific channel. I took the channel ID and pass it in the if condition (a_string.find ('data: []')! = -1). However this code gives me this error. See OUTPU ERROR.
P.S. I'm using Replit and Live is the file name (Live.py)
from discord.ext import commands
from Naked.toolshed.shell import execute_js, muterun_js
import sys
class Live(commands.Cog):
def __init__(self,client):
self.client=client
#commands.Cog.listener()
async def on_ready(self):
channel = self.get_channel(828711580434169858)
response = muterun_js('serverJs.js')
original_stdout = sys.stdout # Save a reference to the original standard output
if response.exitcode == 0:
a_string= str(response.stdout)#stampa in console
if (a_string.find('data: []') != -1):
print("Streamer: Offline ")
else:
print("Streamer: Online")
await channel.send('Live Link: https://...link....')
else:
sys.stderr.write(response.stderr)
#commands.command()
async def Live(self,ctx):
await ctx.send('')
def setup(client):
client.add_cog(Live(client))
OUTPUT ERROR:
Ignoring exception in on_ready
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/runner/Solaris-IA/cogs/Live.py", line 12, in on_ready
channel = self.get_channel(828711580434169858)
AttributeError: 'Live' object has no attribute 'get_channel'
It's self.client.get_channel, not self.get_channel, you haven't defined that function
channel = self.client.get_channel(828711580434169858)
Im trying to accelerate multiple get requests to a web service using asyncio and aiohttp.
For that im fetching my data from a postgresql database using psycopg2 module .fetchmany() inside a function and constructing a dictionary of 100 records to send as lists of dictionary urls to an async function named batch() . batch by batch process.
The problem im facing in batch() function is that some requests are logging the message below although the script continues and dont fail but im not able to catch and log this exceptions to later reprocess them.
Task exception was never retrieved
future: <Task finished coro=<batch.<locals>.fetch() done, defined at C:/PythonProjects/bindings/batch_fetch.py:34> exception=ClientOSError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)>
Traceback (most recent call last):
File "C:/PythonProjects/bindings/batch_fetch.py", line 36, in fetch
async with session.get(url) as resp:
File "C:\Miniconda3\lib\site-packages\aiohttp\client.py", line 1005, in __aenter__
self._resp = await self._coro
File "C:\Miniconda3\lib\site-packages\aiohttp\client.py", line 497, in _request
await resp.start(conn)
File "C:\Miniconda3\lib\site-packages\aiohttp\client_reqrep.py", line 844, in start
message, payload = await self._protocol.read() # type: ignore # noqa
File "C:\Miniconda3\lib\site-packages\aiohttp\streams.py", line 588, in read
await self._waiter
aiohttp.client_exceptions.ClientOSError: [WinError 10054] An existing connection was forcibly closed by the remote host
Task exception was never retrieved
future: <Task finished coro=<batch.<locals>.fetch() done, defined at C:/PythonProjects/bindings/batch_fetch.py:34> exception=ClientConnectorError(10060, "Connect call failed ('xx.xxx.xx.xxx', 80)")>
Traceback (most recent call last):
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 924, in _wrap_create_connection
await self._loop.create_connection(*args, **kwargs))
File "C:\Miniconda3\lib\asyncio\base_events.py", line 778, in create_connection
raise exceptions[0]
File "C:\Miniconda3\lib\asyncio\base_events.py", line 765, in create_connection
yield from self.sock_connect(sock, address)
File "C:\Miniconda3\lib\asyncio\selector_events.py", line 450, in sock_connect
return (yield from fut)
File "C:\Miniconda3\lib\asyncio\selector_events.py", line 480, in _sock_connect_cb
raise OSError(err, 'Connect call failed %s' % (address,))
TimeoutError: [Errno 10060] Connect call failed ('xx.xxx.xx.xxx', 80)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:/PythonProjects/bindings/batch_fetch.py", line 36, in fetch
async with session.get(url) as resp:
File "C:\Miniconda3\lib\site-packages\aiohttp\client.py", line 1005, in __aenter__
self._resp = await self._coro
File "C:\Miniconda3\lib\site-packages\aiohttp\client.py", line 476, in _request
timeout=real_timeout
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 522, in connect
proto = await self._create_connection(req, traces, timeout)
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 854, in _create_connection
req, traces, timeout)
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 992, in _create_direct_connection
raise last_exc
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 974, in _create_direct_connection
req=req, client_error=client_error)
File "C:\Miniconda3\lib\site-packages\aiohttp\connector.py", line 931, in _wrap_create_connection
raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host cms-uat.cme.in.here.com:80 ssl:None [Connect call failed ('xx.xxx.xx.xxx', 80)]
Im just entering into asyncio world as you can depict from my code, so all the advises on the full code approach for this scenario are very welcomme.
Thank you
full code below.
import psycopg2.extras
import asyncio
import json
from aiohttp import ClientSession
from aiohttp import TCPConnector
base_url = 'http://url-example/{}'
def query_db():
urls = []
# connection to postgres table , fetch data.
conn = psycopg2.connect("dbname='pac' user='user' host='db'")
cursor = conn.cursor('psycopg2 request', cursor_factory=psycopg2.extras.NamedTupleCursor)
sql = "select gid, paid from table"
cursor.execute(sql)
while True:
rec = cursor.fetchmany(100)
for item in rec:
record = {"gid": item.gid, "url": base_url.format(item.paid)}
urls.append(record.get('url'))
if not rec:
break
# send batch for async batch request
batch(urls)
# empty list of urls for new async batch request
urls = []
def batch(urls):
async def fetch(url):
async with ClientSession() as session:
async with session.get(url) as resp:
if resp.status == 200:
response = await resp.json()
# parse the url to fetch the point address id.
paid = str(resp.request_info.url).split('/')[4].split('?')[0]
# build the dictionary with pa id and full response.
resp_dict = {'paid': paid, 'response': response}
with open('sucessful.json', 'a') as json_file:
json.dump(resp_dict, json_file)
json_file.write("\n")
elif resp.status is None:
print(resp.status)
elif resp.status != 200:
print(resp.status)
response = await resp.json()
# parse the url to fetch the paid.
paid = str(resp.request_info.url).split('/')[4].split('?')[0]
# build the dictionary with paid and full response.
resp_dict = {'paid': paid, 'response': response}
with open('failed.json', 'a') as json_file:
json.dump(resp_dict, json_file)
json_file.write("\n")
loop = asyncio.get_event_loop()
tasks = []
for url in urls:
task = asyncio.ensure_future(fetch(url))
tasks.append(task)
try:
loop.run_until_complete(asyncio.wait(tasks))
except Exception:
print("exception consumed")
if __name__ == "__main__":
query_db()
Task exception was never retrieved
You see this warning when you've created some task, it finished with exception, but you never explicitly retrieved (awaited) for its result. Here's related doc section.
I bet in your case problem is with the line
loop.run_until_complete(asyncio.wait(tasks))
asyncio.wait() by default just waits when all tasks are done. It doesn't distinguish tasks finished normally or with exception, it just blocks until everything finished. In this case it's you job to retrieve exceptions from finished tasks and following part won't help you with this since asyncio.wait() will never raise an error:
try:
loop.run_until_complete(asyncio.wait(tasks))
except Exception:
print('...') # You will probably NEVER see this message
If you want to catch error as soon as it happened in one of tasks I can advice you to use asyncio.gather(). By default it will raise first happened exception. Note however that it is you job to cancel pending tasks if you want their graceful shutdown.
I'm trying to display an error if there is an exception in my asynchronous
send_email function but even after an exception is occurred in the background thread the data still gets stored in the database. The except block never gets executed.
I'm trying to prevent the database commit and redirect to a page with an error message
send_email function file
from threading import Thread
from flask import current_app,render_template,flash
from flask_mail import Message
from feedback import mail
def send_async_email(app, msg):
try:
with app.app_context():
mail.send(msg)
except:
raise Exception("Exception occurred in Mail")
return False
def send_email(to,subject,template,**kwargs):
app = current_app._get_current_object()
msg=Message(current_app.config['MAIL_SUBJECT_PREFIX'] + subject,
sender=current_app.config['MAIL_SENDER'],recipients=[to])
msg.body=render_template(template +'.txt',**kwargs)
msg.html=render_template(template +'.html',**kwargs)
try:
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
return thr
except:
raise Exception("Error occured")
views.py
#home.route('/register',methods=["GET","POST"])
def register():
# form=LoginForm()
form=LoginForm(prefix="login")
form1=RegisterForm(prefix="register")
print(form1.errors)
if form1.validate_on_submit():
users=Users(email=form1.email.data.strip())
users.set_password(form1.password.data.strip())
organization=Organization(organization_name=form1.org_name.data.strip())
organization.userorg.append(users)
db.session.add(users)
db.session.add(organization)
db.session.flush()
token=users.generate_confirmation_token()
try:
print("INSIDE TRY BLOCK")
email=send_email(users.email,'Confirm your account','email/confirm_email',user=users,token=token)
except Exception as e:
print("INSIDE Exception BLOCK")
print(e)
flash("Errors","danger")
db.session.rollback()
return redirect(url_for('home.home_view'))
db.session.commit()
flash("A confirmation email has been sent")
return redirect(url_for('home.home_view'))
return render_template('home/landing-semi.html',form=form,form1=form1)
Errors recieved
raise SMTPSenderRefused(code, resp, from_addr)
smtplib.SMTPSenderRefused: (530, b'5.5.1 Authentication Required. Learn more at\n5.5.1 https://support.google.com/mail/?p=WantAuthError g10-v6sm7818697pfi.148 - gsmtp', '=?utf-8?q?Osfapp_Admin?= <lmnography#gmail.com>')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib64/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/lib64/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/leon/Leon/Projects/fmsappv/feedback/modules/utilties.py", line 12, in send_async_email
raise Exception("Exception occurred in Mail")
Exception: Exception occurred in Mail
I have a python server setup with aiohttp that is accepting files POST'd to a specific endpoint. I only want to accept a json body, or gzip'd json files. My code is as follows:
class Uploader(View):
async def post(self):
if not self.request.can_read_body:
return json_response({'message': 'Cannot read body'}, status=400)
elif self.request.content_type != 'application/json' and self.request.content_type != 'multipart/form-data':
return json_response({'message': 'Incorrect data type sent to the server'}, status=400)
try:
json_body = await self.request.json()
# Other bits of code using the json body
except RequestPayloadError as e:
# Internal logging here
return json_response({'message': 'Unable to read payload'}, status=400)
# Other code for handling ValidationError, JSONDecodeError, Exception
return json_response({'message': 'File successfully uploaded'}, status=201)
When I test this by uploading something that isn't json or gzip'd json, the RequestPayloadError exception is correctly being hit, the internal logging is being done as expected, and the client is being returned the expected response. However, I'm also seeing the following unhandled exception:
Unhandled exception
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 428, in start
await payload.readany()
File "/usr/local/lib/python3.6/site-packages/aiohttp/streams.py", line 325, in readany
raise self._exception
File "/web_api/app/views/resources/Uploader.py", line 49, in post
json_body = await self.request.json()
File "/usr/local/lib/python3.6/site-packages/aiohttp/web_request.py", line 512, in json
body = await self.text()
File "/usr/local/lib/python3.6/site-packages/aiohttp/web_request.py", line 506, in text
bytes_body = await self.read()
File "/usr/local/lib/python3.6/site-packages/aiohttp/web_request.py", line 494, in read
chunk = await self._payload.readany()
File "/usr/local/lib/python3.6/site-packages/aiohttp/streams.py", line 325, in readany
raise self._exception
aiohttp.web_protocol.RequestPayloadError: 400, message='Can not decode content-encoding: gzip'
How am I supposed to handle this currently unhandled exception given that it doesn't seem to be originating in my code, and I'm already handling the one that I'm expecting? Can I suppress aiohttp exceptions somehow?
EDIT: I'm using version 3.1.1 of aiohttp
Can not decode content-encoding: gzip points on the problem source.
Your peer sends data with Content-Encoding: gzip HTTP header but actually the data is not gzip compressed (other compressor is used or no compressor at all).
As result aiohttp fails on decompressing such data with RequestPayloadError exception.
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)