Djanger
Djanger

Reputation: 143

Google Calender API only fetching first event of calendar

I'm trying to make a simple python desktop app that displays my tasks for the day. For that i'm using the Google Calendar API to fetch the events of my personal calendar. I should also mention that am a beginner in python programming and have no experience with the API itself, which is probably why i have ran into this problem. I used the quickstart code from the google developers page for the API. But for some reason it only returns the summary of the first event on the calender when it's supposed to display the first 10. I have a separate file to display the data returned from the quickstart, but the problem shouldn't lie there as a print statement in the quickstart also only prints a single event.

Here is the code i only slightly modified from the quickstart.py from Google:

from __future__ import print_function
import datetime
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials


SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']


def main():
    """Shows basic usage of the Google Calendar API.
    Prints the start and name of the next 10 events on the user's calendar.
    """
    creds = None
    # The file token.json 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.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # 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.json', 'w') as token:
            token.write(creds.to_json())

    service = build('calendar', 'v3', credentials=creds)


    # Call the Calendar API
    now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
    events_result = service.events().list(calendarId='primary', timeMin=now,
                                          maxResults=10, singleEvents=True,
                                          orderBy='startTime').execute()
    events = events_result.get('items', [])


    if not events:
        print('No upcoming events found.')
    for event in events:
        time = event['start'].get('dateTime', event['start'].get('date'))
        title = event['summary']
        # print(event['summary'], time)
        return title, time


if __name__ == '__main__':
    main()

The google developers API reference isn't much help to me either, so does anyone know what causes this problem?

Also, how do i get the data from all the calendars, instead of just the primary one?

Upvotes: 2

Views: 739

Answers (1)

NirO
NirO

Reputation: 217

Execute returns results by pages (size constrained by maxResults) - and the reason you see only the first event is probably due to 2 issues:

  1. You are looking only at the first page of results

  2. Passing singleEvents=True returns only the first instance of recurring events. This means that if your calendar has any recurring event (daily/ weekly etc.) you will get only the first occurrence of the event in the results. If you want to get all the events (and as I understand that's what you want) - you need to remove this parameter. Try incorporating the following code instead to solve your problem:

     result = []
     page_token = None
    
     while True:
         page = service.events().list(calendarId='primary', 
                                      timeMin=now,
                                      maxResults=10,
                                      orderBy='startTime',
                                      pageToken=page_token).execute()
         result.extend(page["item"])
         page_token = page.get('nextPageToken')
    
         if not page_token:
             break
    
     return result
    

Upvotes: 2

Related Questions