import json
from httplib2 import Http
from oauth2client.client import SignedJwtAssertionCredentials
from googleapiclient.discovery import build
json_file = 'my.json'
client_email = json.loads(open(json_file).read())['client_email']
private_key = json.loads(open(json_file).read())['private_key']
cloud_storage_bucket = 'my_bucket'
report_to_download = 'sales/salesreport_201907.zip'
credentials = SignedJwtAssertionCredentials(client_email, private_key,['https://www.googleapis.com/auth/devstorage.read_only','https://www.googleapis.com/auth/devstorage.read_write','https://www.googleapis.com/auth/devstorage.full_control'])
storage = build('storage', 'v1', http=credentials.authorize(Http()))
object_metadata = storage.objects().get(bucket = cloud_storage_bucket, object = report_to_download).execute()
object_content = storage.objects().get_media(bucket = cloud_storage_bucket, object = report_to_download).execute()
I can read the object_metadata, but when requesting object content I get:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/storage/v1/b/my_bucket/o/sales%2Fsalesreport_201907.zip?alt=media returned "Forbidden">
As u can see I added the three scopes in the credentials sections just to ensure to have all the permissions. Despite that I still getting the error.
I am using Python 2.7.
Edit:
I tried to download the file using gsutil and it works. So it isn't related with permissions.
Edit 2:
Changed the code to use a non deprecated library.
from logs import logger
import google.auth
import google.auth.transport.requests as tr_requests
from google.resumable_media.requests import Download
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="my.json"
ro_scope=u'https://www.googleapis.com/auth/devstorage.full_control'
credentials,_ = google.auth.default(scopes=(ro_scope,))
transport = tr_requests.AuthorizedSession(credentials)
cloud_storage_bucket = 'pubsite_prod_rev_xxxx'
report_to_download = 'sales/salesreport_201907.zip'
#option 1
media_url='https://www.googleapis.com/download/storage/v1/b/pubsite_prod_rev_xxxx/o/sales%2Fsalesreport_201907.zip?generation=1234&alt=media'
#option 2
media_url='https://www.googleapis.com/storage/v1/b/pubsite_prod_rev_xxxx/o/sales%2Fsalesreport_201907.zip'
download = Download(media_url)
response = download.consume(transport)
print download.finished
When running the code with option 1 url the status is 200 but the response.content is just the metadata, has happened before with the get method.
When running the option 2, like get_media method, the error stills 403.
File "/anaconda2/envs/enviro27/lib/python2.7/site-packages/google/resumable_media/_helpers.py", line 93, in require_status_code
status_code, u'Expected one of', *status_codes)
google.resumable_media.common.InvalidResponse: (u'Request failed with status code', 403, u'Expected one of', 200, 206)
The doc of this code.
The solution has been to discover the true admin account.
Despite Google Play shows contact information to one email (the one that we believe to be the admin), the real admin is anothe account. After find it, we applied all the process explained here.
And with this code we are able to access the content:
from logs import logger
import google.auth
import google.auth.transport.requests as tr_requests
from google.resumable_media.requests import Download
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="my.json"
ro_scope=u'https://www.googleapis.com/auth/devstorage.full_control'
credentials,_ = google.auth.default(scopes=(ro_scope,))
transport = tr_requests.AuthorizedSession(credentials)
cloud_storage_bucket = 'pubsite_prod_rev_xxxx'
report_to_download = 'sales/salesreport_201907.zip'
#option 1
media_url='https://www.googleapis.com/download/storage/v1/b/pubsite_prod_rev_xxxx/o/sales%2Fsalesreport_201907.zip?generation=1234&alt=media'
#option 2
media_url='https://www.googleapis.com/storage/v1/b/pubsite_prod_rev_xxxx/o/sales%2Fsalesreport_201907.zip'
download = Download(media_url)
response = download.consume(transport)
print download.finished
Related
I am trying to include TWILIO API to my project. It should send sms. I have finished tutorial, but then i get error Credentials are required to create a TwilioClient. I have credentials in .env file and then i try to import them to settings and then get this credentials from settings to views.
This is when i get error.
.env
TWILIO_ACCOUNT_SID= 'xxxxxxxxxxxxxxxxxxxxxx'
TWILIO_AUTH_TOKEN= 'xxxxxxxxxxxxxxxxxxxxxxx'
TWILIO_NUMBER= 'xxxxxxxxxxxxxxxxxx'
settings.py
import os
TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
TWILIO_NUMBER = os.getenv('TWILIO_NUMBER')
SMS_BROADCAST_TO_NUMBERS = [
'+111111111',
]
views
from django.conf import settings
from django.http import HttpResponse
from twilio.rest import Client
def broadcast_sms(request):
message_to_broadcast = ("Have you played the incredible TwilioQuest "
"yet? Grab it here: https://www.twilio.com/quest")
client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
for recipient in settings.SMS_BROADCAST_TO_NUMBERS:
if recipient:
client.messages.create(to=recipient,
from_=settings.TWILIO_NUMBER,
body=message_to_broadcast)
return HttpResponse("messages sent!", 200)
and here is when code work, but i want to import this from settings..
# def sms(request):
# TWILIO_ACCOUNT_SID = "xxxxxxxxxxxxxxxxxxxxxxx"
# TWILIO_AUTH_TOKEN = "xxxxxxxxxxxxxxxxx"
# TWILIO_NUMBER = "xxxxxxxxxxxxx"
# message_to_broadcast = ("Have you played the incredible TwilioQuest "
# "yet? Grab it here: https://www.twilio.com/quest")
#
# client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
# for recipient in settings.SMS_BROADCAST_TO_NUMBERS:
# if recipient:
# client.messages.create(to=+xxxxxxxxx,
# from_=+xxxxxxxxxx,
# body=message_to_broadcast)
# return HttpResponse("messages sent!", 200)
Any idea how to solve this?
So you are using a .env file rather than setting your OS's environmental variables? If so, there is and article below, pointing to https://github.com/theskumar/python-dotenv.
How To Set Environment Variables
I am using the following code in my windows which works but as soon as I deploy it as cloud function on GCP I get this error? How do I get around it? What I am trying to do is read a google sheet and use it in my function.
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = credentials.with_subject(EMAIL_FROM)
the google function logs give the following error
textPayload: "ModuleNotFoundError: No module named 'oauth2client'"
ImportError: file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth
How do I resolve it?
You have to change your dependency oauth2client, it is deprecated as mentioned here
You can prefer google-auth==1.13.1 and it should work
So, your next question will be: why it works on my local environment? I think you have installed google-auth globally and your code take this dependency even if it's not in the requirements.txt. I recommend you to work with virtual environment and to install the dependencies only in this venv.
Hope this helps, by the way target audience is the url that you want to access.
import argparse
import google.auth
import google.auth.app_engine
import google.auth.compute_engine.credentials
import google.auth.iam
from google.auth.transport.requests import Request
import google.oauth2.credentials
from google.oauth2 import service_account
class AuthenticationConstants:
AUTHENTICATION_SCOPES_URL = 'https://www.googleapis.com/auth/cloud-platform'
OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'
class JWT(object):
def __init__(self, service_account_key_path):
self.service_account_key_path = service_account_key_path
self.credentials = service_account.Credentials.from_service_account_file(
self.service_account_key_path)
self.scoped_credentials = self.credentials.with_scopes(
[AuthenticationConstants.OAUTH_TOKEN_URI])
def get_google_open_id_connect_token(self, target_audience):
signer_email = self.scoped_credentials.service_account_email
signer = self.scoped_credentials.signer
service_account_credentials = google.oauth2.service_account.Credentials(
signer,
signer_email,
token_uri=AuthenticationConstants.OAUTH_TOKEN_URI,
additional_claims={
'target_audience': target_audience
}
)
service_account_jwt = service_account_credentials._make_authorization_grant_assertion()
request = google.auth.transport.requests.Request()
body = {
'assertion': service_account_jwt,
'grant_type': google.oauth2._client._JWT_GRANT_TYPE,
}
token_response = google.oauth2._client._token_endpoint_request(
request, AuthenticationConstants.OAUTH_TOKEN_URI, body)
return token_response['id_token']
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--service-account-path")
parser.add_argument("--target-audience")
result = parser.parse_args()
jwt = JWT(result.service_account_path)
print(jwt.get_google_open_id_connect_token(result.target_audience))
The following is the requirements.txt that I use:
google-api-python-client==1.7.11
Unable to get all results of mediaItems.search:
photos = google.get_service(credentials, 'photoslibrary', 'v1')
request = photos.albums().list(pageSize=50)
while request is not None:
result = request.execute()
for album in result['albums']:
request2 = photos.mediaItems().search(body={'albumId': album['id']})
while request2 is not None:
result2 = request2.execute()
request2 = photos.mediaItems().search_next(request2, result2)
print('nextpageToken' in result2, request2)
request = photos.albums().list_next(request, result)
Running this fails on the first search_next() call with
[...]
File "/usr/local/lib/python3.7/dist-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
return wrapped(*args, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/googleapiclient/http.py", line 851, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://photoslibrary.googleapis.com/v1/mediaItems:search?alt=json returned "Invalid JSON payload received. Unexpected end of string. Expected an object key or }.
That library isn't really supported it seems, so that might be the problem, or am I missing something here?
The google-api-python-client is generic client for all the Google's discovery based APIs and as such it supports all the API based on this protocol including the Photos one.
The correct way to use the services is to invoke the build method and after that use the available methods of the services.
Beside this you always want to use list_next as search_next does not exists.
Here is an example of the photos API working on my laptop (python 3.6)
import os
import pickle
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
SCOPES = ['https://www.googleapis.com/auth/photoslibrary.readonly', ]
# we check if we save the credentials in the past and we reuse them
if not os.path.exists('credentials.dat'):
# no credentials found, we run the standard auth flow
flow = InstalledAppFlow.from_client_secrets_file('client_id.json', SCOPES)
credentials = flow.run_local_server()
with open('credentials.dat', 'wb') as credentials_dat:
pickle.dump(credentials, credentials_dat)
else:
with open('credentials.dat', 'rb') as credentials_dat:
credentials = pickle.load(credentials_dat)
if credentials.expired:
credentials.refresh(Request())
photos_sdk = build('photoslibrary', 'v1', credentials=credentials)
# photos API
photos_albums_api = photos_sdk.albums()
photos_mediaitems_api = photos_sdk.mediaItems()
albums_list_params = {
'pageSize': 50,
}
# first request
albums_list_req = photos_albums_api.list(**albums_list_params)
while albums_list_req is not None:
photos_albums_list = albums_list_req.execute()
# print(photos_albums_list)
for album in photos_albums_list['albums']:
print(album['title'])
mediaitems_search_req = photos_mediaitems_api.search(body={'albumId': album['id']})
while mediaitems_search_req is not None:
mediaitems_search = mediaitems_search_req.execute()
print(mediaitems_search)
# mediaItems pagination management
mediaitems_search_req = photos_mediaitems_api.list_next(mediaitems_search_req, mediaitems_search)
# albums pagination handling
albums_list_req = photos_albums_api.list_next(albums_list_req, photos_albums_list)
If there are more results than the specified pageSize, the API returns a pageToken, you should use to request the next part. See the example here Access Google Photo API with Python using google-api-python-client
I have been getting this error trying to print my friends list for awhile. I am fairly certain I am providing a token. Any idea's on this?
import facebook
import urllib
import urllib2
import json
import urlparse
import subprocess
import warnings
import urllib2
import json
#https://developers.facebook.com/tools/access_token/
# Parameters of your app and the id of the profile you want to mess with.
FACEBOOK_APP_ID = '{app_id}'
FACEBOOK_APP_SECRET = '{app_secret}'
FACEBOOK_PROFILE_ID = 'my-id-number-here'
# Trying to get an access token. Very awkward.
oauth_args = dict(client_id = FACEBOOK_APP_ID,
client_secret = FACEBOOK_APP_SECRET,
grant_type = 'client_credentials')
oauth_curl_cmd = ['curl',
'https://graph.facebook.com/oauth/access_token?' + urllib.urlencode(oauth_args)]
oauth_response = subprocess.Popen(oauth_curl_cmd,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE).communicate()[0]
try:
oauth_access_token = urlparse.parse_qs(str(oauth_response))['access_token'][0]
except KeyError:
print('Unable to grab an access token!')
exit()
facebook_graph = facebook.GraphAPI(oauth_access_token)
# Print friends list.
profile = facebook_graph.get_object("me")
friends = facebook_graph.get_connections("me", "friends")
friend_list = [friend['name'] for friend in friends['data']]
print friend_list
You are getting this error cause you are using an access token not a user token.
The user token can be generated by using facebook developers
https://developers.facebook.com/tools/explorer/145634995501895/
Just click Get Token > Get User Access Token
This does the trick for me
Probably your short-lived access token has expired. You can check this via
https://developers.facebook.com/tools/debug/accesstoken/
and review the validity of the access token.
Can a Python script upload a photo to photo bucket and then retrieve the URL for it? Is so how?
I found a script at this link: http://www.democraticunderground.com/discuss/duboard.php?az=view_all&address=240x677
But I just found that confusing.
many thanks,
Phil
Yes, you can. Photobucket has a well-documented API, and someone wrote a wrapper around it.
Download the it and put it into your Python path, then download httplib2 (you can use easy_install or pip for this one).
Then, you have to request a key for the Photobucket API.
If you did everything right, you can write your script now. The Python wrapper is great, but is not documented at all which makes it very difficult to use it. I spent hours on understanding it (compare the question and response time here). As example, the script even has form/multipart support, but I had to read the code to find out how to use it. I had to prefix the filename with a #.
This library is a great example how you should NOT document your code!
I finally got it working, enjoy the script: (it even has oAuth handling!)
import pbapi
import webbrowser
import cPickle
import os
import re
import sys
from xml.etree import ElementTree
__author__ = "leoluk"
###############################################
## CONFIGURATION ##
###############################################
# File in which the oAuth token will be stored
TOKEN_FILE = "token.txt"
IMAGE_PATH = r"D:\Eigene Dateien\Bilder\SC\foo.png"
IMAGE_RECORD = {
"type": 'image',
"uploadfile": '#'+IMAGE_PATH,
"title": "My title", # <---
"description": "My description", # <---
}
ALBUM_NAME = None # default album if None
API_KEY = "149[..]"
API_SECRET = "528[...]"
###############################################
## SCRIPT ##
###############################################
api = pbapi.PbApi(API_KEY, API_SECRET)
api.pb_request.connection.cache = None
# Test if service online
api.reset().ping().post()
result = api.reset().ping().post().response_string
ET = ElementTree.fromstring(result)
if ET.find('status').text != 'OK':
sys.stderr.write("error: Ping failed \n"+result)
sys.exit(-1)
try:
# If there is already a saved oAuth token, no need for a new one
api.username, api.pb_request.oauth_token = cPickle.load(open(TOKEN_FILE))
except (ValueError, KeyError, IOError, TypeError):
# If error, there's no valid oAuth token
# Getting request token
api.reset().login().request().post().load_token_from_response()
# Requesting user permission (you have to login with your account)
webbrowser.open_new_tab(api.login_url)
raw_input("Press Enter when you finished access permission. ")
#Getting oAuth token
api.reset().login().access().post().load_token_from_response()
# This is needed for getting the right subdomain
infos = api.reset().album(api.username).url().get().response_string
ET = ElementTree.fromstring(infos)
if ET.find('status').text != 'OK':
# Remove the invalid oAuth
os.remove(TOKEN_FILE)
# This happend is user deletes the oAuth permission online
sys.stderr.write("error: Permission deleted. Please re-run.")
sys.exit(-1)
# Fresh values for username and subdomain
api.username = ET.find('content/username').text
api.set_subdomain(ET.find('content/subdomain/api').text)
# Default album name
if not ALBUM_NAME:
ALBUM_NAME = api.username
# Debug :-)
print "User: %s" % api.username
# Save the new, valid oAuth token
cPickle.dump((api.username, api.oauth_token), open(TOKEN_FILE, 'w'))
# Posting the image
result = (api.reset().album(ALBUM_NAME).
upload(IMAGE_RECORD).post().response_string)
ET = ElementTree.fromstring(result)
if ET.find('status').text != 'OK':
sys.stderr.write("error: File upload failed \n"+result)
sys.exit(-1)
# Now, as an example what you could do now, open the image in the browser
webbrowser.open_new_tab(ET.find('content/browseurl').text)
Use the python API by Ron White that was written to do just this