Parsing Google Calendar events with Python

This post will show you how to use Python to parse Google Calendar events. Google’s API documentation is good but we haven’t found a realistic example anywhere. So we are sharing what we have. In this post, you will learn to look for all-day events with the word ‘PTO’ in the event title.


Overview

Here are the steps we will perform:

a) Enable the Google Calendar API and download the client secret file
b) Install the Python module google-api-python-client
c) Connect to your Google calendar
d) Fetch all the calendars shared with you
e) Retrieve all-day events for a given time range
f) Filter the events with the words PTO in them


Detailed steps

a) Enable the Google Calendar API and download the client secret
I followed the instructions in Step 1 of this guide to turn on the Google Calendar API. I set my application name to Google Calendar - Raw Python and I named my client secret file client_secret_google_calendar.json. I placed my client secret file in ~/.credentials/. You need these details when you login.

b) Install the Python module google-api-python-client
This is easy: pip install -U google-api-python-client

c) Connect to your Google calendar
Let us try connecting to your Google calendar. I know the script looks large but it is largely boilerplate that I just copied from Google’s quickstart guide. You can blindly copy it too and make just 3 edits: replace two global variables ( CLIENT_SECRET_FILE, APPLICATION_NAME with your details) and change the location of credentials file. If all goes well, you will be prompted to give permission to give your application access to your calendar (first time only).

from __future__ import print_function
import httplib2
import os
 
# from apiclient import discovery
# Commented above import statement and replaced it below because of 
# reader Vishnukumar's comment
# Src: https://stackoverflow.com/a/30811628
 
import googleapiclient.discovery as discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
 
import datetime
 
try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None
 
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/calendar-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'client_secret_google_calendar.json'
APPLICATION_NAME = 'Google Calendar - Raw Python'
 
 
def get_credentials():
    """Gets valid user credentials from storage.
 
    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.
 
    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'calendar-python-quickstart.json')
 
    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials
 
def main():
    """Shows basic usage of the Google Calendar API.
 
    Creates a Google Calendar API service object and outputs a list of the next
    10 events on the user's calendar.
    """
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('calendar', 'v3', http=http)

d) Fetch all the calendars shared with you
Let us first get all the calendars shared with you. We’ll query each of them for events in the next step. BTW, we filter calendars using the string ‘@qxf2.com’ since we are interested only in the calendars of our colleagues.

    # This code is to fetch the calendar ids shared with me
    # Src: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list
    page_token = None
    calendar_ids = []
    while True:
        calendar_list = service.calendarList().list(pageToken=page_token).execute()
        for calendar_list_entry in calendar_list['items']:
            if '@qxf2.com' in calendar_list_entry['id']:
                calendar_ids.append(calendar_list_entry['id'])
        page_token = calendar_list.get('nextPageToken')
        if not page_token:
            break

e) Retrieve all-day events for a given time range
Now, we can filter events any way we like. We are going to use a combination of start-date, end-date and all-day events. For this example, I have hard-coded the dates. You can always make them command line parameters.

    # This code is to look for all-day events in each calendar for the month of September
    # Src: https://developers.google.com/google-apps/calendar/v3/reference/events/list
    # You need to get this from command line
    # Bother about it later!
    start_date = datetime.datetime(
        2017, 10, 30, 00, 00, 00, 0).isoformat() + 'Z'
    end_date = datetime.datetime(2017, 12, 01, 23, 59, 59, 0).isoformat() + 'Z'
 
    for calendar_id in calendar_ids:
        count = 0
        print('\n----%s:\n' % calendar_id)
        eventsResult = service.events().list(
            calendarId=calendar_id,
            timeMin=start_date,
            timeMax=end_date,
            singleEvents=True,
            orderBy='startTime').execute()
        events = eventsResult.get('items', [])

f) Filter the events with the words PTO in them
Now, we simply loop through all the (all-day) events we collected in the previous step and see if the string ‘PTO’ exists in the title.

        if not events:
            print('No upcoming events found.')
        for event in events:
            if event.has_key('summary'):
                if 'PTO' in event['summary']:
                    count += 1
                    start = event['start'].get(
                        'dateTime', event['start'].get('date'))
                    print(start, event['summary'])
        print('Total days off for %s is %d' % (calendar_id, count))

g) Putting it all together:
This is how the complete script looks. To run, simply execute python sample_google_calendar.py

"""
05-Oct-2017: Scratch script for blog post about Google Calendar API
This script is a sample and NOT indicative of Qxf2's programming habits.
 
This script will:
a) Connect to Google Calendar
b) Get calendar ids for all Qxf2 employees
c) Execute a search in a given hardcoded timeframe for all employees
d) List any event with the word PTO in the summary
 
To setup, I followed this reference:
https://developers.google.com/google-apps/calendar/quickstart/python
 
References:
1. https://developers.google.com/google-apps/calendar/quickstart/python
2. https://developers.google.com/google-apps/calendar/v3/reference/events/list
3. https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list
"""
 
 
from __future__ import print_function
import httplib2
import os
 
# from apiclient import discovery
# Commented above import statement and replaced it below because of
# reader Vishnukumar's comment
# Src: https://stackoverflow.com/a/30811628
 
import googleapiclient.discovery as discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
 
import datetime
 
try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None
 
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/calendar-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'client_secret_google_calendar.json'
APPLICATION_NAME = 'Google Calendar - Raw Python'
 
 
def get_credentials():
    """Gets valid user credentials from storage.
 
    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.
 
    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'calendar-python-quickstart.json')
 
    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else:  # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials
 
 
def main():
    """Shows basic usage of the Google Calendar API.
 
    Creates a Google Calendar API service object and outputs a list of the next
    10 events on the user's calendar.
    """
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('calendar', 'v3', http=http)
 
    # This code is to fetch the calendar ids shared with me
    # Src: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list
    page_token = None
    calendar_ids = []
    while True:
        calendar_list = service.calendarList().list(pageToken=page_token).execute()
        for calendar_list_entry in calendar_list['items']:
            if '@qxf2.com' in calendar_list_entry['id']:
                calendar_ids.append(calendar_list_entry['id'])
        page_token = calendar_list.get('nextPageToken')
        if not page_token:
            break
 
    # This code is to look for all-day events in each calendar for the month of September
    # Src: https://developers.google.com/google-apps/calendar/v3/reference/events/list
    # You need to get this from command line
    # Bother about it later!
    start_date = datetime.datetime(
        2017, 09, 01, 00, 00, 00, 0).isoformat() + 'Z'
    end_date = datetime.datetime(2017, 09, 30, 23, 59, 59, 0).isoformat() + 'Z'
 
    for calendar_id in calendar_ids:
        count = 0
        print('\n----%s:\n' % calendar_id)
        eventsResult = service.events().list(
            calendarId=calendar_id,
            timeMin=start_date,
            timeMax=end_date,
            singleEvents=True,
            orderBy='startTime').execute()
        events = eventsResult.get('items', [])
        if not events:
            print('No upcoming events found.')
        for event in events:
            if event.has_key('summary'):
                if 'PTO' in event['summary']:
                    count += 1
                    start = event['start'].get(
                        'dateTime', event['start'].get('date'))
                    print(start, event['summary'])
        print('Total days off for %s is %d' % (calendar_id, count))
 
 
if __name__ == '__main__':
    main()

If you liked what you read, know more about Qxf2.


References

1. Google’s Calendar API Quickstart
2. API documentation for /events/list
3. API documentation for /calendarList/list


Arunkumar Muralidharan

I want to find out what conditions produce remarkable software. A few years ago, I chose to work as the first professional tester at a startup. I successfully won credibility for testers and established a world-class team. I have lead the testing for early versions of multiple products. Today, I run Qxf2 Services. Qxf2 provides software testing services for startups. If you are interested in what Qxf2 offers or simply want to talk about testing, you can contact me at: mak@qxf2.com. I like testing, math, chess and dogs.

3 Comments

  1. Anonymous said:

    Thanks for this. Made it really easy to put together a simple tool to summarize where the time went over the past week based on google calendar entries. All the best, Soham

    September 8, 2018
    Reply
    • Thank you for bringing the update to my notice, Vishnukumar. I have updated the script to be import googleapiclient.discovery as discovery.

      I have also given you credit in the commented out code.

      September 28, 2018
      Reply

Leave a Reply

Your email address will not be published.