I'm using the python-twitter (not tweepy) module in my application.
I have a script set up (maketweet.py) that, when I run it from bash / console, works successfully (i.e. it makes a tweet).
The problem I'm having is that when I run the same script as a scheduled task, I get an error:
Traceback (most recent call last):
File "/home/dir1/dir2/proj/maketweet.py", line 21, in <module>
api = create_api()
File "/home/dir1/dir2/proj/config.py", line 31, in create_api
if api.VerifyCredentials():
File "/home/dir1/.local/lib/python3.8/site-packages/twitter/api.py", line 4699, in VerifyCredentials
resp = self._RequestUrl(url, 'GET', data)
File "/home/dir1/.local/lib/python3.8/site-packages/twitter/api.py", line 4959, in _RequestUrl
raise TwitterError("The twitter.Api instance must be authenticated.")
twitter.error.TwitterError: The twitter.Api instance must be authenticated.
The other problem I'm having is that I can't conceive why it would make a difference that I'm using a scheduled task, rather than running the file directly from bash. Here are the contents of config.py:
#!/usr/bin/python3.8
import twitter
import os
import logging
from dotenv import load_dotenv
logger = logging.getLogger()
# project folder is one level up from file location
project_folder = pathlib.Path(__file__).parent.absolute()
load_dotenv(os.path.join(project_folder, '.env'))
# Authenticate to Twitter and create API object
TWITTER_CONSUMER_API_KEY = os.getenv("TWITTER_CONSUMER_API_KEY")
TWITTER_CONSUMER_API_SECRET = os.getenv("TWITTER_CONSUMER_API_SECRET")
TWITTER_ACCESS_TOKEN = os.getenv("TWITTER_ACCESS_TOKEN")
TWITTER_ACCESS_SECRET = os.getenv("TWITTER_ACCESS_SECRET")
def create_api():
# Create API object
api = twitter.Api(
access_token_key = TWITTER_ACCESS_TOKEN,
access_token_secret = TWITTER_ACCESS_SECRET,
consumer_key = TWITTER_CONSUMER_API_KEY,
consumer_secret = TWITTER_CONSUMER_API_SECRET,
sleep_on_rate_limit=True)
# test API object
if api.VerifyCredentials():
pass
else:
logger.error("Error creating API", exc_info=True)
raise Exception("Twitter user authentication error")
logger.info("API created")
return api
Obviously there's an error in creating the API. I imagine this has something to do with the environment variables and how they are accessed through scheduled tasks vs. bash. Just really not sure how to figure this one out...
Related
I have created an Azure Cognitive Services resource following the tutorial 1
Then I have created the environment and run the following code (from tutorial 2):
# Import required modules.
from azure.cognitiveservices.search.websearch import WebSearchAPI
from azure.cognitiveservices.search.websearch.models import SafeSearch
from msrest.authentication import CognitiveServicesCredentials
# Replace with your subscription key.
subscription_key = "YOUR_SUBSCRIPTION_KEY"
# Instantiate the client and replace with your endpoint.
client = WebSearchAPI(CognitiveServicesCredentials(subscription_key), base_url = "YOUR_ENDPOINT")
# Make a request. Replace Yosemite if you'd like.
web_data = client.web.search(query="Yosemite")
print("\r\nSearched for Query# \" Yosemite \"")
However, it seems the generaed Subscription key and endpoint are not correctly read by the script since I get the following error:
File "azu_scrapper.py", line 17, in
web_data = client.web.search(query="Yosemite") File "/home/user/.local/share/virtualenvs/linkedin-CHSAGU1d/lib/python3.7/site-packages/azure/cognitiveservices/search/websearch/operations/web_operations.py",
line 365, in search
raise models.ErrorResponseException(self._deserialize, response) azure.cognitiveservices.search.websearch.models.error_response_py3.ErrorResponseException:
Operation returned an invalid status code 'Resource Not Found'
Any idea why it is not working?
The base_url value should be :
https://<your endpoint>/bing/v7.0
I have tested on my side and it works for me :
I've been trying to get my authorization working using the Authorization Code Flow with the example from Spotipy API, as seen below.
import sys
import spotipy
import spotipy.util as util
scope = 'user-library-read playlist-read-private' # or else
if len(sys.argv) > 1:
username = sys.argv[1]
else:
print("Usage: %s username" % (sys.argv[0],))
sys.exit()
token = util.prompt_for_user_token(username, scope)
if token:
sp = spotipy.Spotify(auth=token)
results = sp.current_user_saved_tracks()
for item in results['items']:
track = item['track']
print(track['name'] + ' - ' + track['artists'][0]['name'])
else:
print("Can't get token for", username)
I managed to get it working just fine with the scope being 'user-library-read', but upon changing the scope or adding another, I get the request to re-authenticate. I copy the redirect URL in the editor as usual and get the following error:
Traceback (most recent call last):
File "C:/Users/Joel/PycharmProjects/untitled1/test.py", line 13, in <module>
token = util.prompt_for_user_token(username, scope)
File "C:\Users\Joel\.virtualenvs\untitled1-1cFj5f_i\lib\site-packages\spotipy\util.py", line 86, in prompt_for_user_token
token_info = sp_oauth.get_access_token(code)
File "C:\Users\Joel\.virtualenvs\untitled1-1cFj5f_i\lib\site-packages\spotipy\oauth2.py", line 217, in get_access_token
raise SpotifyOauthError(response.reason)
spotipy.oauth2.SpotifyOauthError: Bad Request
Any ideas what I'm doing wrong here? I'm stumped, since it works just fine with that one specific scope (and doesn't require me to authorize since I've already done it), but with others I get this.
Also, when running the code in my terminal, it requires me to authorize as well, only I get the following error in the browser: INVALID_CLIENT: Invalid redirect URI
I have a Flask application where I let users access third party applications and fetch data from them and perform some visualizations.Now the user has to provide the application name and it's credentials in order to fetch the data.Now I want to avoid putting the application name in the url and rather all of the data should be sent as a POST request where I will parse the POST data, connect to the required app with the given credentials and perform some visualizations.This is what the user will send as a POST data
{
"application_name": "appdynamics",
"account_id": "sdf632sef",
"username": "kuhku86tg",
"password": "oihsd832"
}
Now I want to trigger my particular REST API class based on the application name provided by the user.
The way I planned was to create a seperate file that involves getting the POST data using request parser and then calling it in the main application where I will trigger my REST API class with a if condition based on the application name.Below is the file parse.py
from flask_restful import reqparse
# create a parser object
parser = reqparse.RequestParser()
# add agruments to the parser object
parser.add_argument('account_id', type=str, required=False, help="Please define 'account_id'")
parser.add_argument('username', type=str, required=False, help="Please define 'username'")
parser.add_argument('password', type=str, required=False, help="Please define 'password'")
parser.add_argument('application_name', type=str, required=False, help="Please define 'application name'")
data = parser.parse_args()
Now I call it in the main application app.py
from parser import data
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
# create an API for the Flask app
api = Api(app)
# if the user demands info for appdynamics, trigger the Appdynamics API class
if data['application_name'] == "appdynamics":
api.add_resource(AppdynamicsAPI, "/<string:name>") # the string will contain the metric requirement
if __name__ == "__main__":
app.run(port=5000, debug=True)
Below is the section where the logic for the REST API is written
from parser import data
from flask_restful import Resource, reqparse
from fetch_data.appdynamics import fetch_all_apps, fetch_avg_resp_time, calls_per_min
from models.user import *
class AppdynamicsAPI(Resource):
# authenticate users
def post(self, name):
first_data = data
# if the user passes the credentials, insert it into the database otherwise use the last known credentials
# ensure you only insert valid credentials
if all([first_data['account_id'], first_data['password'], first_data['username']]):
users.update(first_data, {i: j for i, j in first_data.items()}, upsert=True)
print({i: j for i, j in first_data.items()})
credentials = users.find_one({})
print("Credentials", credentials)
account_id = credentials['account_id']
username = credentials['username']
password = credentials['password']
t_duration = first_data['t_duration']
if name == "allapps":
status_code, result = fetch_all_apps(account_id, username, password)
if status_code == 200:
return {"information": result}, status_code
return {"message": "Please enter correct credentials"}, status_code
However I receive the below error
Traceback (most recent call last):
File "/home/souvik/PycharmProjects/ServiceHandler/app.py", line 3, in <module>
from resource.appdynamics_resource import AppdynamicsAPI
File "/home/souvik/PycharmProjects/ServiceHandler/resource/appdynamics_resource.py", line 4, in <module>
from authentication.parser import data
File "/home/souvik/PycharmProjects/ServiceHandler/authentication/parser.py", line 14, in <module>
data = parser.parse_args()
File "/home/souvik/utorapp/lib/python3.5/site-packages/flask_restful/reqparse.py", line 302, in parse_args
req.unparsed_arguments = dict(self.argument_class('').source(req)) if strict else {}
File "/home/souvik/utorapp/lib/python3.5/site-packages/werkzeug/local.py", line 364, in <lambda>
__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)
File "/home/souvik/utorapp/lib/python3.5/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/home/souvik/utorapp/lib/python3.5/site-packages/flask/globals.py", line 37, in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
You currently call data = parser.parse_args() in top-level code of a module. This runs at import time, but there is nothing to parse while your module gets imported, since this happens during startup and not while handling a request.
Call this from your view function (ie the code that runs while handling a request) instead. You will also need to restructure your code - calling api.add_resource() is something you do during startup/initialization time, not while handling a request.
The important thing to understand is that this is not PHP where all your code runs when a request is received. Instead, the Python modules are imported when you start your application (flask run, app.run(), or running it in a WSGI container). When a request is received only the code related to handling that request runs.
Just getting started on the Adwords API, for some reason I can't seem to connect at all.
The code below, straight from the tutorial throws the error:
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
client = AdWordsClient(path=os.path.join('Users', 'ravinthambapillai', 'Google Drive', 'client_secrets.json'))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/adspygoogle/adwords/AdWordsClient.py", line 151, in __init__
self._headers = self.__LoadAuthCredentials()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/adspygoogle/adwords/AdWordsClient.py", line 223, in __LoadAuthCredentials
return super(AdWordsClient, self)._LoadAuthCredentials()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/adspygoogle/common/Client.py", line 94, in _LoadAuthCredentials
raise ValidationError(msg)
**ValidationError: Authentication data is missing.**
from adspygoogle.adwords.AdWordsClient import AdWordsClient
from adspygoogle.common import Utils
client = AdWordsClient(path=os.path.join('Users', 'this-user', 'this-folder', 'client_secrets.json'))
It looks like there's two issues. First, try removing the last path element, as far as I recall, the path parameter expects a directory that contains the authentication pickle, logs etc. This approach requires that you already have a valid auth_token.pkl.
Second, it appears that you're using OAuth2 for authentication (I'm guessing by the client_secrets.json file). For this to work, you'll need to use the oauth2client library and provide an oauth2credentials instance in the headers parameter to AdWordsClient.
The following is straight from the file examples/adspygoogle/adwords/v201302/misc/use_oauth2.py in the client distribution and should give you an idea how it works:
# We're using the oauth2client library:
# http://code.google.com/p/google-api-python-client/downloads/list
flow = OAuth2WebServerFlow(
client_id=oauth2_client_id,
client_secret=oauth2_client_secret,
# Scope is the server address with '/api/adwords' appended.
scope='https://adwords.google.com/api/adwords',
user_agent='oauth2 code example')
# Get the authorization URL to direct the user to.
authorize_url = flow.step1_get_authorize_url()
print ('Log in to your AdWords account and open the following URL: \n%s\n' %
authorize_url)
print 'After approving the token enter the verification code (if specified).'
code = raw_input('Code: ').strip()
credential = None
try:
credential = flow.step2_exchange(code)
except FlowExchangeError, e:
sys.exit('Authentication has failed: %s' % e)
# Create the AdWordsUser and set the OAuth2 credentials.
client = AdWordsClient(headers={
'developerToken': '%s++USD' % email,
'clientCustomerId': client_customer_id,
'userAgent': 'OAuth2 Example',
'oauth2credentials': credential
})
I am not familiar with the AdWordsClient api but are you sure your path is correct?
your current join produces a relative path, do you need an absolute one?
>>> import os
>>> os.path.join('Users', 'this-user')
'Users/this-user'
For testing you could hardcode the absoulte path in to make sure it is not a path issue
I would also make sure that 'client_secrets.json exists, and that it is readable by the user executing python
Hi i have just started to evaluate different options for python>Twitter api:s.
I have written some code looking at the examples in the Twython package but i always end up getting the same error.
AttributeError: 'Twython' object has no attribute 'auth'
I also get the same error running the included core_example files.
I am running "2.0.0" from git.
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python /Users/skjortan/dev/trunk/3rdPartyLibs/twython/core_examples/current_trends.py
Traceback (most recent call last):
File "/Users/skjortan/dev/trunk/3rdPartyLibs/twython/core_examples/current_trends.py", line 5, in <module>
trends = twitter.getCurrentTrends()
File "/Library/Python/2.7/site-packages/twython-2.0.0-py2.7.egg/twython/twython.py", line 167, in <lambda>
return lambda **kwargs: self._constructFunc(key, **kwargs)
File "/Library/Python/2.7/site-packages/twython-2.0.0-py2.7.egg/twython/twython.py", line 188, in _constructFunc
content = self._request(url, method=method, params=kwargs)
File "/Library/Python/2.7/site-packages/twython-2.0.0-py2.7.egg/twython/twython.py", line 205, in _request
response = func(url, data=myargs, auth=self.auth)
AttributeError: 'Twython' object has no attribute 'auth'
Process finished with exit code 1
I noticed your question - I'm the author of Twython. A fix has been committed and pushed out for a 2.0.1 release. If you update your installation this should no longer be an issue.
Thanks, sorry for the hassle! Bug that slipped by our 2.0.0 release.
But its really has no attribute 'auth' but it has methods like:
def get_authentication_tokens(self):
"""Returns an authorization URL for a user to hit."""
def get_authorized_tokens(self):
"""Returns authorized tokens after they go through the auth_url phase."""
And this is sample from django-twython how its author make auth
def begin_auth(request):
"""
The view function that initiates the entire handshake.
For the most part, this is 100% drag and drop.
"""
# Instantiate Twython with the first leg of our trip.
twitter = Twython(
twitter_token = settings.TWITTER_KEY,
twitter_secret = settings.TWITTER_SECRET,
callback_url = request.build_absolute_uri(reverse('twython_django_oauth.views.thanks')))
# Request an authorization url to send the user to...
auth_props = twitter.get_authentication_tokens()
# Then send them over there, durh.
request.session['request_token'] = auth_props
return HttpResponseRedirect(auth_props['auth_url'])
apparently twitter api and does not allow normal login, just for oauth, creates the application on Twitter and OAuth Settings tab from there takes the data from OAuth Settings, and methods of oauth in:
http://pydoc.net/twython/1.4.5/twython.twitter_endpoints