How to get comments from Google Docs API by Python? - python-3.x

I have one document on google drive and there are notes, comments, that I want to get. Can anyone say, is there a way to do it?
For example, lets start with this
import httplib2
import googleapiclient.discovery
from oauth2client.service_account import ServiceAccountCredentials
from google.oauth2 import service_account
from googleapiclient.http import MediaIoBaseDownload,MediaFileUpload
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = r'C:\Users\Idensas\PycharmProjects\protest\Google\creds.json'
credentials = ServiceAccountCredentials('creds.json',['https://www.googleapis.com/auth/drive'])
httpAuth = credentials.authorize(httplib2.Http())
drive = googleapiclient.discovery.build('drive','v3')
a = drive.files().list(pageSize=10,fields='files(id, name, mimeType,parents)').execute()['files'][0]
print(a)
Here is the output, this is the file where are comments that I want to get.
{'id': '1PsV3D0CrCfTpjkbateXiLZIOsoDVV5ha_WV9FFZ2QEM', 'name': 'task', 'mimeType': 'application/vnd.google-apps.document'}

Comments can be fetch using Drive API Comments.list.
Try appending this to your code:
file_id = a['id']
try:
comments = drive.comments().list(fileId=file_id,fields='comments').execute()
for comment in comments.get('comments'):
print(comment['content'])
except errors.HttpError as error:
print('An error occurred: %s' % error)
Sample Doc:
Output:
Note: If the value of a in your code is {'id': '1PsV3D0CrCfTpjkbateXiLZIOsoDVV5ha_WV9FFZ2QEM', 'name': 'task', 'mimeType': 'application/vnd.google-apps.document'}, just append the whole code, else replace the file_id with the id of the document. Also, since you are using service account, you need to share the document to the service account email which can be found in the credentials json file. Another option is to use OAuth 2.0 Client ID which can be found in this Demo.

Related

Kucoin API get advanced orders

I've been using KuCoin API with python for a while now, but stuck trying to get advanced orders form the API. For reference, 'advanced orders' are what stop limit orders are called within KuCoin dash.
I've used the endpoint: api/v1/orders
. I've experimented with this but it only shows 'normal' orders or the order history if 'status' is set to 'done'. Ref: https://docs.kucoin.com/#list-orders
I'm wondering if instead I should use: /api/v1/limit/orders. This endpoint has an option to return stop_limit orders. But when I try, I get response:
{"code":"400007","msg":"Access denied, require more permission."}'
I checked my API permissions and its 'General' permission is set to 'read only' which is the only option. Read only would be fine for me because I only want to get the list of all 'Advanced orders'
See https://docs.kucoin.com/#recent-orders
Does anyone know how to get all open limit orders please? The reason I want this is I have placed many limit orders. I want to collect the orderid's of all stop limit orders so I can clean out just the ones not associated to an active trade.
my code is as follows:
import requests
import json
import hmac
import hashlib
import base64
from urllib.parse import urlencode
import time
from urllib.request import urlretrieve
'''working code to get active orders'''
api_key = 'api_key'
api_secret = 'api_secret'
api_passphrase = 'api_passphrase' # this is NOT trading password
base_uri = 'https://api.kucoin.com'
def get_headers(method, endpoint):
now = int(time.time() * 1000)
str_to_sign = str(now) + method + endpoint
signature = base64.b64encode(hmac.new(api_secret.encode(), str_to_sign.encode(), hashlib.sha256).digest()).decode()
passphrase = base64.b64encode(hmac.new(api_secret.encode(), api_passphrase.encode(), hashlib.sha256).digest()).decode()
return {'KC-API-KEY': api_key,
'KC-API-KEY-VERSION': '2',
'KC-API-PASSPHRASE': passphrase,
'KC-API-SIGN': signature,
'KC-API-TIMESTAMP': str(now)
}
#List Orders
method = 'GET'
endpoint = '/api/v1/limit/orders/' # main
# params = {'type': 'stop_limit'}
params = {}
# # if params :
qstr = '?' + urlencode(params)if params else ''
active_orders = requests.get(url=base_uri+endpoint+qstr, headers=get_headers(method,endpoint+qstr))

Youtube data api error when changing video title

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.

Create an event with conference using python and Google Calendar API creates the event but not the conference

I am trying to create an event using Google Calendar API in Python 3. I also want to generate a Google Meet conference link for the event. I am using the documentations provided here:
https://developers.google.com/calendar/quickstart/python
https://developers.google.com/calendar/v3/reference/events#conferenceData
https://developers.google.com/calendar/create-events
The event is created without a problem. However, it is missing the conference link. My code so far is as follows:
from pathlib import Path
from pickle import load
from pickle import dump
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from uuid import uuid4
from typing import Dict, List
from oauth2client import file, client, tools
class EventPlanner:
def __init__(self, guests: Dict[str, str], schedule: Dict[str, str]):
guests = [{"email": email} for email in guests.values()]
service = self._authorize()
self.event_states = self._plan_event(guests, schedule, service)
#staticmethod
def _authorize():
scopes = ["https://www.googleapis.com/auth/calendar"]
credentials = None
token_file = Path("./calendar_creds/token.pickle")
if token_file.exists():
with open(token_file, "rb") as token:
credentials = load(token)
if not credentials or not credentials.valid:
if credentials and credentials.expired and credentials.refresh_token:
credentials.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file('calendar_creds/credentials.json', scopes)
credentials = flow.run_local_server(port=0)
with open(token_file, "wb") as token:
dump(credentials, token)
calendar_service = build("calendar", "v3", credentials=credentials)
return calendar_service
#staticmethod
def _plan_event(attendees: List[Dict[str, str]], event_time, service: build):
event = {"summary": "test meeting",
"start": {"dateTime": event_time["start"]},
"end": {"dateTime": event_time["end"]},
"attendees": attendees,
"conferenceData": {"createRequest": {"requestId": f"{uuid4().hex}",
"conferenceSolutionKey": {"type": "hangoutsMeet"}}},
"reminders": {"useDefault": True}
}
event = service.events().insert(calendarId="primary", sendNotifications=True, body=event, conferenceDataVersion=1).execute()
return event
if __name__ == "__main__":
plan = EventPlanner({"test_guest": "test.guest#gmail.com"}, {"start": "2020-07-31T16:00:00",
"end": "2020-07-31T16:30:00"})
print(plan.event_states)
I suspect that the problem is with where I have passed conferenceDataVersion but the docs are not exactly clear about where it has to be passed other than that it must be passed. I also tried putting it in the body of the event or in createRequest. It always creates the event but not the conference. Unfortunately, I could not find anything about this online anywhere. Maybe I'm actually that bad at searching, but I have been testing different things and searching for a solution for several days! If anyone knows what I am missing, I will truly appreciate their assistance.
Thanks to #Tanaike, I found what was the problem. The token which is generated the first time the API is authenticated is very specific. The problem I was having turned out to be just with that. As soon as I removed the token and had it get generated again, the problem was solved. That being said, I have no idea why the problem appeared in the first place. I will update the response if I find the reason behind it. But for now, if you are having the same problem, just remove the token and regenerate it.
With this code we can create the conference (Google meet link) for me it works
"conferenceData": {
"createRequest": {
"requestId": "SecureRandom.uuid"
}
}

Gmail API Reading credentials 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

I think there is an issue with Gmail API and Python3.
The original code in the documentation is in Python2, but for several reasons, including that my application is already working with Python3, I was passing the code to python3.
So... after sorting several issues, including a 400 request error, (which was apparently that the auth I provided to google wasn't corretly done) I'm facing (I hope) the final issue that apparently I'm trying to read a file but
Even just doing token.read() generates the same issue.
The token.pickle file is autogenerated once you've authorized google to access your email account and that the app can send emails automatically.
I know the credentials.json file is correct, as that's the point to tell google who you are and it always is reading my credentials correctly, redirecting me to give authorization to my app.
Here's the app to send emails, I think it's pretty straightforward, I followed the documentation and looked at other issues like this one and finally got this far:
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
from googleapiclient.errors import HttpError
# from httplib2 import Http
# from oauth2client import client, tools, file
import base64
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
from apiclient import errors
SCOPES = 'https://mail.google.com/'
def SendMessage(service, user_id, message):
"""Send an email message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
message: Message to be sent.
Returns:
Sent Message.
"""
try:
message = (service.users().messages().send(userId=user_id, body=message)
.execute())
print(f'Message Id: {message["id"]}')
return message
except errors.HttpError as error:
print(f'An error occurred: {error}')
def CreateMessage(sender, to, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
message_bytes = message.as_string().encode('utf-8')
# return { 'raw': base64.urlsafe_b64encode(message.as_string()) }
# return { 'raw': base64.urlsafe_b64encode(message_bytes) }
raw = base64.urlsafe_b64encode(message_bytes)
return raw.decode()
def main():
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', 'r') 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('gmail', 'v1', credentials=creds)
# Create
message = CreateMessage('my-email#gmail.com', 'destination#gmail.com', 'Testing Gmail API', 'Hi GMAIL API')
# Send
SendMessage(service, "me", message)
if __name__ == '__main__':
main()
I truly don't know what to do here, if someone has already solved this issue and how.
THANKS!
In your script, when token.pickle is not created, Gmail API can be used by creating token.pickle at 1st authorization. But an error of 'raw' RFC822 payload message string or uploading message via /upload/* URL required occurs at message = (service.users().messages().send(userId=user_id, body=message).execute()). So in this case, please modify as follows.
From:
raw = base64.urlsafe_b64encode(message_bytes)
return raw.decode()
To:
raw = base64.urlsafe_b64encode(message_bytes).decode('utf-8')
return {'raw': raw}
After above modification, when your script is run as the 2nd run, when token.pickle, which has already been created, is read, an error occurs. I think that this error is in your title. In this case, please modify as follows.
From:
with open('token.pickle', 'r') as token:
To:
with open('token.pickle', 'rb') as token:
By this, I think that the script works.
By the way, if an error occurs when the code is retrieved, also please modify as follows.
From:
creds = flow.run_local_server(port=0)
To:
creds = flow.run_local_server()
Note:
About the authorization, you can see the sample script at the Quickstart of the official document.
If this was not the direction of your issue, I apologize.

How to interact with the Gmail API - Delegate User - Python 3.7

I am trying to write a Python application which simply adds a user as a delegate to another users mailbox.
I am following the API # Google API Documentation - Users.settings.delegates: create
However, I am struggling to find how to the parameters of:
User - an account which is TOBE added to a delegate Mailbox
Mailbox - the account which has the Mailbox I wish the account to become a delegate of.
I have currently tried making an API which has the delegate user. However, it does not seem to be interacting how I would expect. I am hoping Google will create a responsive API for the browser to support this. However, I am struggling with the code:
from googleapiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
def main(user_to_be_added, delegated_mailbox):
service_account_credentials = ServiceAccountCredentials.from_json_keyfile_name('credentials/service_account.json')
service_account_credentials = service_account_credentials.create_scoped('https://mail.google.com/ https://www.googleapis.com/auth/gmail.insert https://www.googleapis.com/auth/gmail.modify')
service_account_credentials = service_account_credentials.create_delegated(user_to_be_added)
service = discovery.build('gmail', 'v1', credentials=service_account_credentials)
response = service.users().settings().delegates().create().execute(userId=delegated_mailbox)
if __name__ == '__main__':
main('some_account_to_be_added#gmail.com', 'delegated_mailbox#gmail.com')
Am I interacting with this API completely wrong? If so, how has anyone else achieved this?
Thank you for your time.
Jordan
Working Solution:
from googleapiclient import discovery
from google.oauth2 import service_account
def _create_client(subject):
credentials = service_account.Credentials
credentials = credentials.from_service_account_file('credentials/service_account.json',
scopes=['https://www.googleapis.com/auth/gmail.settings.sharing',
'https://www.googleapis.com/auth/gmail.settings.basic'],
subject=subject)
service = discovery.build('gmail', 'v1', credentials=credentials)
return service
def add_delegate_to_email(user_to_be_added, delegated_mailbox):
service = _create_client(user_to_be_added)
body = {
"delegateEmail": delegated_mailbox,
"verificationStatus": "accepted"
}
try:
response = service.users().settings().delegates().create(userId='me', body=body).execute()
print(response)
except Exception as e:
print('Exception: {}'.format(e))
Main problem: from oauth2client.service_account import ServiceAccountCredentials is deprecated as Google took ownership with google-auth.

Resources