why did i get this error on the script given below:
Traceback (most recent call last):
File "C:\Path\YoutubeApi\main.py", line 54, in <module>
main()
File "C:\Path\YoutubeApi\main.py", line 49, in main
response = request.execute()
File "C:\Users\$user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\googleapiclient\_helpers.py", line 131, in positional_wrapper
return wrapped(*args, **kwargs)
File "C:\Users\$user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\googleapiclient\http.py", line 937, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://youtube.googleapis.com/youtube/v3/videos?part=snippet&alt=json returned "The <code>snippet.categoryId</code> property specifies an invalid category ID. Use the <code>videoCategories.list</code> method to retrieve supported categories.". Details: "[{'message': 'The <code>snippet.categoryId</code> property specifies an invalid category ID. Use the <code>videoCategories.list</code> method to retrieve supported categories.', 'domain': 'youtube.video', 'reason': 'invalidCategoryId', 'location': 'body.snippet.categoryId', 'locationType': 'other'}]">
Main.py
import os
import pickle
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
def main():
credentials = None
# token.pickle stores the user's credentials from previously successful logins
if os.path.exists('token.pickle'):
print('Loading Credentials From File...')
with open('token.pickle', 'rb') as token:
credentials = pickle.load(token)
if not credentials or not credentials.valid:
if credentials and credentials.expired and credentials.refresh_token:
print('Refreshing Access Token...')
credentials.refresh(Request())
else:
print('Fetching New Tokens...')
flow = InstalledAppFlow.from_client_secrets_file(
'client_secrets.json',
scopes=[
'https://www.googleapis.com/auth/youtube.force-ssl'
]
)
flow.run_local_server(port=8080, prompt='consent',
authorization_prompt_message='')
credentials = flow.credentials
# Save the credentials for the next run
with open('token.pickle', 'wb') as f:
print('Saving Credentials for Future Use...')
pickle.dump(credentials, f)
youtube = build('youtube','v3',credentials=credentials)
request = youtube.videos().update(
part = 'snippet',
body={
"id": "OSxK-tscmVA",
"snippet":{
"title":"It's changed",
}
}
)
response = request.execute()
print(response)
if __name__ == '__main__':
main()
Script Explanation:
What the script does is that if there's no file named token.pickle it will ask the user to authorize the application and the script will store the user credentials in token.pickle file so that the user doesn't have to authorize the application on every single run and the part 2 of the script changes my YouTube video's title.
Unfortunately, you seem not inclined to make use of the official specification of the Videos.update API endpoint:
The request body of your call to the endpoint needs to specify the video category ID too for to be accepted by the API back-end.
Note that the update_video.py sample code from Google -- that I indicated you at the beginning of your series of posts as valuable source of information -- has all these required things in it.
Again, please acknowledge that you have to absorb (i.e. understand) that code. There's no other way than going through reading carefully the official documentation.
Related
I registered my first app, and it looks like this:
All of the fields are populated below the screen shot.
Now, I have some basic python code using the examples found on their repo.
I create the following test script:
import traceback
app_id = 'FAKE.VALUE'
client_id = 'FAKE.VALUE'
client_secret = 'FAKE.VALUE'
signin_secret = 'FAKE.VALUE'
verification_token = 'FAKE.VALUE'
items = locals()
import os
import slack
items = locals().copy()
for k in items:
if '__' not in k:
val = items[k]
try:
client = slack.WebClient(token=val)
response = client.chat_postMessage(
channel='CE476K9HT',
text='Hello-----' + str(val))
print(response)
except:
print(k)
traceback.print_exc()
print('-'*50)
But all of the responses I get say:
The server responses with: {'ok':False,'error':'invalid_auth'}
For some reason, is it necessary to use path variables?
It is unclear to me what type of auth is required here.
After doing what Erik suggested,
I have a xoxp code and registered the redirect url to http://localhost.
and added the following scopes:
and updated my code to look like:
oauth_token ='xoxp-*****************'
import os
import slack
items = locals().copy()
client = slack.WebClient(token=oauth_token)
response = client.chat_postMessage(
channel='my_channel_id',
text='Hello-----')
I got my channel ID from the url:
https://app.slack.com/client/FOO/my_channel_id
When I run my code, I get the following back:
Traceback (most recent call last):
File "/home/usr/git/slack_messaging/slack_messaging.py", line 20, in <module>
text='Hello-----')
File "/home/usr/git/python-slackclient/slack/web/client.py", line 382, in chat_postMessage
return self.api_call("chat.postMessage", json=kwargs)
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 172, in api_call
return self._event_loop.run_until_complete(future)
File "/home/usr/anaconda2/envs/beer/lib/python3.7/asyncio/base_events.py", line 573, in run_until_complete
return future.result()
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 241, in _send
return SlackResponse(**{**data, **res}).validate()
File "/home/usr/git/python-slackclient/slack/web/slack_response.py", line 176, in validate
raise e.SlackApiError(message=msg, response=self)
slack.errors.SlackApiError: The request to the Slack API failed.
The server responded with: {'ok': False, 'error': 'missing_scope', 'needed': 'chat:write:user', 'provided': 'admin,identify'}
Process finished with exit code 1
You need two things to make your script work.
1. OAuth token
You need a valid OAuth token and provide it when initializing the Slack Client:
client = slack.WebClient(token="xoxb-xxx")
To get a token you need to install your Slack app to a workspace. You can do that on the app management page under "Install App". Your OAuth token will also be displayed on that page once you installed it.
2. Permissions
Your Oauth Token / Slack app needs to have the permission to post messages. On the app management pages go to "OAuth & permission" and add the needed permission to your app:. e.g. chat:write:user for user tokens.
Note that you need to reinstall your app every time to add a permission.
Overview
I am creating a folder and spreadsheets using API I can access all files inside that folder using google spreadsheet API
(problem) But then I upload the file from the front, Now this file can not be accessed via spreadsheet API, I have given full permission(owner) to the user.
So basically the problem is that I want to let other user drop spreadsheets in my shared drive and want to access these files via python API
error message "This operation is not supported for this document"
JSON RESPONSE
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"status": "PERMISSION_DENIED"
}
}
Background:
I am using python to create folders and sheets, and I wanted to share the folder for other users to update the spreadsheet files so I gave permissions to other users, but when they dropped the files in the drive I can access the file metadata but not the contents of the spreadsheets
Relevant Code:
`SCOPES =
['https://www.googleapis.com/auth/drive.appdata','https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
sheet_service = build('sheets', 'v4', credentials=get_Service())
drive_service = build('drive', 'v3',credentials=get_Service())
def get_values(self,SAMPLE_SPREADSHEET_ID, SAMPLE_RANGE_NAME):
sheet = sheet_service.spreadsheets()
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
range=SAMPLE_RANGE_NAME).execute()`
Expected help > bypass these permission restrictions
I have noticed something when I drop the file the sheet id is different from when I create it with API or from google drive
{ "error": { "code": 403, "message": "The request is missing a valid API key.", "status": "PERMISSION_DENIED" } }
Means that you are not sending any authorization with your request. Your request needs to be authorized before you can do anything. Notice how the credentials have been added to the service variable in the code below.
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']
# The ID and range of a sample spreadsheet.
SAMPLE_SPREADSHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'
SAMPLE_RANGE_NAME = 'Class Data!A2:E'
def main():
"""Shows basic usage of the Sheets API.
Prints values from a sample spreadsheet.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('sheets', 'v4', credentials=creds)
# Call the Sheets API
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
range=SAMPLE_RANGE_NAME).execute()
values = result.get('values', [])
if not values:
print('No data found.')
else:
print('Name, Major:')
for row in values:
# Print columns A and E, which correspond to indices 0 and 4.
print('%s, %s' % (row[0], row[4]))
if __name__ == '__main__':
main()
Code ripped from Python quickstart
Also note that you cant create a folder in Google drive with the Sheets api you will need to use the Google drive api to create files. Sheets just lets you edit them.
converting files
When you upload the files to Google drive you need to convert them to sheet at that time Import doc types
file_metadata = {
'name': 'My Report',
'mimeType': 'application/vnd.google-apps.spreadsheet'
}
media = MediaFileUpload('files/report.csv',
mimetype='text/csv',
resumable=True)
file = drive_service.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
print 'File ID: %s' % file.get('id')
I am new in Python and trying use Google Drive Apis, but facing this issue. Error I am getting after running python quickstart.py
Traceback (most recent call last):
File "quickstart.py", line 9, in <module>
creds = store.get()
File "/usr/local/lib/python3.6/site-packages/oauth2client/client.py", line 407, in get
return self.locked_get()
File "/usr/local/lib/python3.6/site-packages/oauth2client/file.py", line 54, in locked_get
credentials = client.Credentials.new_from_json(content)
File "/usr/local/lib/python3.6/site-packages/oauth2client/client.py", line 302, in new_from_json
module_name = data['_module']
KeyError: '_module'
I have generated client_secret.json file as per the Python Quickstart tutorial.
All the file are in the same directory as that of quickstart.py.
Here is how my quickstart.py file looks.
from __future__ import print_function
from apiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
# Setup the Drive v3 API
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
store = file.Storage('credentials.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('drive', 'v3', http=creds.authorize(Http()))
# Call the Drive v3 API
results = service.files().list(
pageSize=10, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
print('{0} ({1})'.format(item['name'], item['id']))
UPDATE:
I checked and it turns out that credentials.json file is auto-generated on the first run and for some reason, this is not happening.
KeyError: '_module'
This key _module is suppose to be present in credentials.json file and that is why this error is thrown. Not sure what is missing. Can someone please tell me how to resolve this issue.
Similar issue here Try to remove both files from your directory - "credentials.json" and "client_secret.json". Then re-generate your credentials and re-create "client_secret.json", this worked for me.
I am trying to write a small script in python to connect to BOX, but it keeps giving me this error: 'NoneType' object has no attribute 'encode'
At first I thought it was caused when I encoded the Passphrase, but it seems that's not the case. The script fails when I try to authenticate with access_token = auth.authenticate_instance(). If I run the script without that it seems to work. What could be causing this?
Thanks in advance for any help you can provide.
This is what I have:
import keyring
from boxsdk import JWTAuth
from boxsdk import Client
def read_tokens():
"""Reads authorisation tokens from keyring"""
# Use keyring to read the tokens
auth_token = keyring.get_password('Box_Auth', 'mybox#box.com')
refresh_token = keyring.get_password('Box_Refresh', 'mybox#box.com')
return auth_token, refresh_token
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox#box.com', access_token)
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
Passphrase = 'xxxxxxx';
my_str_as_bytes = Passphrase.encode('UTF-8','strict')
auth = JWTAuth(
client_id='xxxxxxxxxx',
client_secret='xxxxxxxx',
enterprise_id='xxxxxxx',
jwt_key_id='xxxxxxx',
rsa_private_key_file_sys_path='/home/Marketscale/keys/private_key2.pem',
rsa_private_key_passphrase=my_str_as_bytes,
store_tokens=store_tokens,
)
access_token = auth.authenticate_instance()
This is the full text of the error:
Traceback (most recent call last):
File "/home/Marketscale/Tests/JWTTest.py", line 37, in <module>
access_token = auth.authenticate_instance()
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 186, in authenticate_instance
return self._auth_with_jwt(self._enterprise_id, 'enterprise')
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt
return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0]
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request
self._store_tokens(access_token, refresh_token)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens
self._store_tokens_callback(access_token, refresh_token)
File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password
_keyring_backend.set_password(service_name, username, password)
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password
password_encrypted = self.encrypt(password.encode('utf-8'), assoc)
AttributeError: 'NoneType' object has no attribute 'encode'
I don't know the API you're using at all, but a few thoughts based on looking at the code:
Working through the stack trace from the bottom up, you have:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyrings/alt/file_base.py", line 128, in set_password
password_encrypted = self.encrypt(password.encode('utf-8'), assoc)
AttributeError: 'NoneType' object has no attribute 'encode'
That code is at https://github.com/jaraco/keyrings.alt/blob/master/keyrings/alt/file_base.py, and the password (which we know is None) is the last parameter passed in to the set_password function. That is called from:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/keyring/core.py", line 48, in set_password
_keyring_backend.set_password(service_name, username, password)
That code is at https://github.com/jaraco/keyring/blob/master/keyring/core.py, and the password is again the last parameter to the set_password function. Next, we have:
File "/home/Marketscale/Tests/JWTTest.py", line 22, in store_tokens
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
....which is your code, so refresh_token must have been None. This means that your store_tokens must have been called with a refresh_token of None. Next:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 233, in _store_tokens
self._store_tokens_callback(access_token, refresh_token)
This is at https://github.com/box/box-python-sdk/blob/master/boxsdk/auth/oauth2.py, and once again means that _store_tokens was called with refresh_token set to None. Onwards...
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/oauth2.py", line 298, in send_token_request
self._store_tokens(access_token, refresh_token)
Code on the same page as the last, but now it's a bit more interesting:
url = '{base_auth_url}/token'.format(base_auth_url=API.OAUTH2_API_URL)
headers = {'content-type': 'application/x-www-form-urlencoded'}
network_response = self._network_layer.request(
'POST',
url,
data=data,
headers=headers,
access_token=access_token,
)
if not network_response.ok:
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
try:
response = network_response.json()
access_token = response['access_token']
refresh_token = response.get('refresh_token', None)
if refresh_token is None and expect_refresh_token:
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
except (ValueError, KeyError):
raise BoxOAuthException(network_response.status_code, network_response.content, url, 'POST')
self._store_tokens(access_token, refresh_token)
return self._access_token, self._refresh_token
So we know that self._store_tokens was called with refresh_token set to None, which means that expect_refresh_token must have been False, as otherwise the BoxOAuthException would have been raised. And, indeed, if we look at the next line up in the stack trace we can see that:
File "/home/Marketscale/.virtualenvs/myvirtualenv/lib/python3.5/site-packages/boxsdk/auth/jwt_auth.py", line 158, in _auth_with_jwt
return self.send_token_request(data, access_token=None, expect_refresh_token=False)[0]
That suggests to me that when you're using JWT Auth, you should not expect a refresh token. And given that the file backend for the keyring explodes when you pass it a None as a password, it sounds like you need to handle the None case differently. So, I'd suggest changing the store_tokens function you provide so that either it ignores the refresh token if it's None, ie:
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox#box.com', access_token)
if refresh_token is not None:
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
...or so that it converts None into something that the keyring file backend can gracefully handle -- maybe an empty string would do the trick:
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox#box.com', access_token)
if refresh_token is None:
refresh_token = ""
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
A caveat -- like I said, I don't know these APIs -- neither the box one, nor the keyring one you're using. But based on the code that's there, doing something like that sounds like it's well worth a try.
I am using python 3.4 to leverage the Google API to access and read files from a users google drive. If a user has already used the app before they should have a credentials file so I was hoping to be able to test if the credentials are still valid by attempting to list the files on the users drive. The idea being if this errors then the app knows it needs to ask for access again.
After a lot of searching I've tried to piece together code from the following Examples:
Google API commands
Google Example
I currently have the following pieces of code:
import httplib2
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import AccessTokenRefreshError
from oauth2client.client import OAuth2WebServerFlow
def getAccess():
flow = OAuth2WebServerFlow(client_id, client_secret, scope, redirect_uri="urn:ietf:wg:oauth:2.0:oob")
auth_uri = flow.step1_get_authorize_url()
print("Please go to the following webpage and copy and paste the access key onto the command line:\n" + auth_uri + "\n")
code = input("Please enter your access code:\n")
credentials = flow.step2_exchange(code)
storage.put(credentials)
client_id = MYCLIENT_ID
client_secret = MYCLIENT_SECRET
scope = "https://www.googleapis.com/auth/drive"
storage = Storage('~/credentials.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
getAccess()
else:
try:
http = httplib2.Http()
http = credentials.authorize(http)
service = build('drive', 'v2', http=http)
param = {}
service.files().list(**param).execute()
except:
getAccess()
However the service.files().list(**param).execute() line produces the following error message:
Traceback (most recent call last):
File "GoogleAuth.py", line 64, in <module>
service.files().list(**param).execute()
File "C:\Anaconda3\lib\site-packages\oauth2client\util.py", line 137, in positional_wrapper
return wrapped(*args, **kwargs)
File "C:\Anaconda3\lib\site-packages\googleapiclient\http.py", line 729, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError
I've tried playing around with a few different combinations such as:
service.files().list().execute()
service.apps().list().execute()
However I still get the same error message. Any idea what's going on ?
Issue was that
service = build('drive', 'v2')
Should have been
service = build('drive', 'v2', http=http)