gspread Invalid token: Stateless token expired [duplicate] - django

I am using gspread and a Service Account Key, Other, json file. to continually update a google spreadsheet with python 2.7. I have this running off a Raspberry Pi running the latest Raspian Jessie. my oauth and gspread should all be the latest versions available for my platform. My script runs for one hour(the max token life span),then stops working with the error message : "Invalid token: Statless token expired error" My code is as follows
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from httplib2 import Http
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
def functon()
...
p1.append_row(printing)
Any Help would be greatly appreciated, Thank You.

Authorisation expires every 0.5/1 hour (I think it depends on which of the two available methods you use to connect).
I have a google sheet connected 24/7 that updates every 2 seconds. Almost always the reason for a bad read/write is an authorisation error but also Google API can throw a variety of errors at you too that normally resolve after a few seconds. Here's one of my functions to update a cell, but using your details for auth_for_worksheet. Every operation (update single cell, update a range, read a column of values) has some similar construct as a function, which always returns an authorised worksheet. It's probably not the most elegant solution but the sheet has been connected for 3 months fine with no downtime.
def auth_for_worksheet():
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
return p1
def update_single_cell(worksheet, counter, message):
""" No data to return, update a single cell in column B to reflect this """
single_cell_updated = False
while not single_cell_updated:
try:
cell_location = "B" + str(counter)
worksheet.update_acell(cell_location, message)
single_cell_updated = True
except gspread.exceptions.HTTPError:
logger.critical("Could not update single cell")
time.sleep(10)
worksheet = auth_for_worksheet()
logger.info("Updated single cell")
return worksheet
if __name__ == '__main__':
# your code here, but now to update a single cell
wksheet = update_single_cell(wksheet, x, "NOT FOUND")

Related

Flask session variables cannot be retrieved for various actions on google

I am using Dialogflow to receive user input and the received values are passed to the flask program using a webhook call. Session variables are set for this action on webhook call. For another google action, I am trying to retrieve the session variables. But, I am not able to access them. Let me know where I am going wrong. Thanks in advance.
DialogFlow Intent - setclass
Receives the parameter 'class' (grade) from the User and invokes the Action setclass, which sets the session variables class and grade through webhook call.
Dialogflow Intent - getclass
Action getclass gets the values set in the session through webhook call.
Flask program to store and receive values from session:
from flask import Flask, request, session, jsonify
app = Flask(__name__)
app.secret_key = "abc"
#app.route("/sessiontrial",methods=['POST','GET'])
def sessiontrial():
req = request.get_json(silent=True, force=True)
value = req.get('queryResult')
params = value.get('parameters')
action = value.get('action')
print("Inside sessiontrial")
if (action == "setclass"):
classno = params.get('class')
print (classno)
session['class'] = classno
session['grade'] = str(classno) + " Grade"
print (session['grade'])
res = {"fulfillmentText": classno}
return(jsonify(res))
if (action == "getclass"):
if 'class' in session:
classs = session['class']
print("Class is: ", classs)
gradee = session['grade']
print("Grade is: ", gradee)
res = {"fulfillmentText": gradee}
return(jsonify(res))
else:
print("Class not found in Session")
res = {"fulfillmentText": "Class not found in Session"}
return(jsonify(res))
if __name__ == '__main__':
app.run()
You can use Redis Session Store to solve your problem. Since you've created the session in the webbook without allowing end-users to interact with the application, this could be the culprit.
You can do the following.
Go to the following link: https://github.com/aws-samples/amazon-elasticache-samples/blob/master/session-store/example-4.py
Download the class example-4.py from the session store section
Setup in your flask app.
If you are using Heroku, you can create Heroku Redis by executing the following command:
heroku addons:create heroku-redis:hobby-dev -a your-app-name
Redis Session store requires two input values: TOKEN and REDIS URL.
You can get the REDIS_URL configuration variable in the settings section of Heroku app after you setup the Redis as described in the step 4.
You must create a unique token for each user that remains active for as long as you want by specifying it in the session store. It is known as TTL (remaining time of key expiry in seconds). If you're using the dialogflow-fullfilment package, you can create this in the dialogflow and get it easily by using agent.session. In the example below, I've set the expiration time to one hour.
ttl=3600
Then do the following in your code snippets.
store = SessionStore(token, REDIS_URL)
if (action == "setclass"):
classno = params.get('class')
print (classno)
store.set('class', classno)
#session['class'] = classno
store.set('grade', str(classno) + " Grade")
#session['grade'] = str(classno) + " Grade"
print (store.get('grade'))
res = {"fulfillmentText": classno}
return(jsonify(res))
if (action == "getclass"):
if 'class' in session:
classs = session['class']
print("Class is: ", classs)
gradee = store.get('grade')
#gradee = session['grade']
print("Grade is: ", gradee)
res = {"fulfillmentText": gradee}
return(jsonify(res))
If you get the data in byte format, then you can easily convert this into integers or whatever format you like. Here is an example: How could I convert a bytes to a whole hex string?

Error Pulling Facebook Ad Campaign

I am trying to automate a task for my company. They want me to pull the insights from their ad campaigns and put it in a CSV file. From here I will create a excel sheet that grabs this data and automates the plots that we send to our clients.
I have referenced the example code from the library and I believe where my confusion exists is in who I define 'me' to be in line 14.
token = 'temporary token from facebook API'
VOCO_id = 'AppID'
AppSecret = 'AppSecret'
me = 'facebookuserID'
AppTokensDoNotExpire = 'AppToken'
from facebook_business import FacebookSession
from facebook_business import FacebookAdsApi
from facebook_business.adobjects.campaign import Campaign as AdCampaign
from facebook_business.adobjects.adaccountuser import AdAccountUser as AdUser
session = FacebookSession(VOCO_id,AppSecret,AppTokensDoNotExpire)
api = FacebookAdsApi(session)
FacebookAdsApi.set_default_api(api)
me = AdUser(fbid=VOCO_id)
####my_account = me.get_ad_account()
When I run the following with the hashtag on my_account, I get a return stating that the status is "live" for these but the value of my permissions is not compatible.

fetch the retweets for the tweets using python

I have to fetch the retweets for the tweets and create the JSON file with retweets,user id etc using the python script. Kindly help me to sort it our this issues.
Thanks in advance!!
This task require some fields of knowledge, and since you ask in a general way, I reckon you need a script to run immediately, but setting up this process requires sometime
This part to get connect to twitter API
from twython import Twython, TwythonError
APP_KEY = 'YOUR_APP_KEY'
APP_SECRET = 'YOUR_APP_SECRET'
twitter = Twython(APP_KEY, APP_SECRET)
Use Twitter API call from Twython,
you can find a list here https://twython.readthedocs.io/en/latest/api.html, the param is the same as twitter API
response = twitter.get_retweets(id, 100)
Pagnation
each call to API have limit of returns, in example for engine.get_friends_ids was limited to 5000 (https://dev.twitter.com/rest/reference/get/friends/ids), if you want to get more than 5000, you have to use the cursor in the returned result (if cur = 0 in json returned means no more results), following is example of how to handling cursor
#Set a temp to loop
cur = -1
#Stop when no more result
while cur !=0:
response = twitter.get_friends_ids(user_id=user_id, cursor=cur)
#Some code to handle the response
cur = response["next_cursor"]
API key
Key expires after some calls (https://dev.twitter.com/rest/public/rate-limits), so you need to set some code to auto change your key, or wait for some period (key reached limit return error code 429)
Response
The response from API was in JSON format, which was easy to use, you can access data by selecting base on response[key], in example
reponse["ids"] or response["next_cursor"]

gspread w/ OAuth2Client Service Account Key

I am using gspread and a Service Account Key, Other, json file. to continually update a google spreadsheet with python 2.7. I have this running off a Raspberry Pi running the latest Raspian Jessie. my oauth and gspread should all be the latest versions available for my platform. My script runs for one hour(the max token life span),then stops working with the error message : "Invalid token: Statless token expired error" My code is as follows
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from httplib2 import Http
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
def functon()
...
p1.append_row(printing)
Any Help would be greatly appreciated, Thank You.
Authorisation expires every 0.5/1 hour (I think it depends on which of the two available methods you use to connect).
I have a google sheet connected 24/7 that updates every 2 seconds. Almost always the reason for a bad read/write is an authorisation error but also Google API can throw a variety of errors at you too that normally resolve after a few seconds. Here's one of my functions to update a cell, but using your details for auth_for_worksheet. Every operation (update single cell, update a range, read a column of values) has some similar construct as a function, which always returns an authorised worksheet. It's probably not the most elegant solution but the sheet has been connected for 3 months fine with no downtime.
def auth_for_worksheet():
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(filename.json,scope)
gc = gspread.authorize(credentials)
wks = gc.open('spreadsheet name')
p1 = wks.worksheet('Printer One')
return p1
def update_single_cell(worksheet, counter, message):
""" No data to return, update a single cell in column B to reflect this """
single_cell_updated = False
while not single_cell_updated:
try:
cell_location = "B" + str(counter)
worksheet.update_acell(cell_location, message)
single_cell_updated = True
except gspread.exceptions.HTTPError:
logger.critical("Could not update single cell")
time.sleep(10)
worksheet = auth_for_worksheet()
logger.info("Updated single cell")
return worksheet
if __name__ == '__main__':
# your code here, but now to update a single cell
wksheet = update_single_cell(wksheet, x, "NOT FOUND")

Access Google spreadsheet from Google Appengine with service account : working once per hour

I have implemented the python code here below based on the documentation in order to access a spreadsheet accessible through a public link.
It works once every hour. If I execute a few seconds after a success, I receive an error :
Error opening spreadsheet no element found: line 1, column 0
Assumption:
The access token has an expiry date of 1 hour. So the appengine would proceed to a token refresh after an hour, resetting the whole.
Question:
This code requests a new token for each request. So what should I do ? Save the token ? When I try the token_to_blob in order to save the token, I get an error :
Scope undefined
Thanks in advance for your help !
try :
credentials = AppAssertionCredentials(scope=('https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'))
logging.info("credentials")
http_auth = credentials.authorize(httplib2.Http())
authclient = build('oauth2','v2',http=http_auth)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
except Exception as details:
logging.error("Error Google credentials %s"%details)
return "Error"
try :
gd_client = gdata.spreadsheets.client.SpreadsheetsClient()
gd_client = auth2token.authorize(gd_client)
feed = gd_client.GetListFeed(<spreadsheetKey>,1)
except Exception as details:
logging.error("Error opening spreadsheet %s"%details)
return "Error"
I finally declared the credentials & the token as global.
In this case, it was working for several subsequent requests but after 1 hour, the token was invalid.
I tested with the method access_token_expired but this method always returned false.
So, I finally execute the refresh systematically and it works. Not elegant but functional. Another option would be to store the time of next refresh and only refresh after 1 hour.
Your comments are welcome for elegant alternatives.
I did not try gspread since the rest of the code was already functional for gdata.spreadsheets but perhaps I should.
from oauth2client.contrib.appengine import AppAssertionCredentials
from oauth2client.client import Credentials
from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient.discovery import build
import httplib2
global credentials
global auth2token
try :
credentials = AppAssertionCredentials(scope=('https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'))
http_auth = credentials.authorize(httplib2.Http())
authclient = build('oauth2','v2',http=http_auth)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
except Exception as details:
logging.error("Error Google credentials %s"%details)
class importFromSpreadsheet(webapp2.RequestHandler):
def __importFromSpreadsheet(self,u):
try :
credentials._refresh(httplib2.Http())
except Exception as details:
logging.error("Error refreshing Google credentials %s"%details)
...
try :
gd_client = gdata.spreadsheets.client.SpreadsheetsClient()
gd_client = auth2token.authorize(gd_client)
feed = gd_client.GetListFeed(u,1)
except Exception as details:
logging.error("Error opening 1st spreadsheet %s"%details)
return "Error"