update to google tasks on the cli

Update v0.2: I did finally move to github, and rewrote part of the script again too. See more here.

Update v0.3 9-20-2011: Pushed a new update this morning. Feel free to skip everything below and go to the github repo. That’s where all future dev will be.

I’ve updated the script I wrote last week for using google tasks from the cli and with Geek Tool, and added the ability to update or delete tasks from a specified list. In order to do this, I appended a number to each task in a list, which the script then uses to match a task ID for the HTTP call. Just trying to get it all working, I’ve repeated myself a bunch in the code. That’s not very pythonic. But hey, it’ll do for now if you’d like to try managing your lists from the CLI. I’ll clean it up sometime this week and repost it.

To check my tasks, and mark one as completed, I do this:

$ tasks ls

As we speak that gives me this:

    1. Write post on Fulbright Hays.  : 2011-05-23
    2. Write post on RA Police Blotter 1790 : 2011-06-08

    1. Finish 1791 padron transcription. : 2011-06-15
    2. finish 1759-1770 padron transcriptions.  : 2011-06-29

    1. Write code for criminales NCD comparisons. : 2011-06-10

To mark as completed, for example, writing the post on the Fulbright-Hays (which is here), I enter this:

$ tasks u Tasks_Main 1

So, the arguments passed are update, listName, and taskNumber. The task is marked as completed, but to move it off of my task list I then enter this command:

$ tasks c

Finally, if I wanted to delete the task instead of marking it as completed, I would enter:

$ tasks d Tasks_Main 1

So, that would delete the first task on the Tasks_Main list.

Here’s the latest version of the script in all its ugliness:

#!/usr/bin/env python
# encoding: utf-8

Created by Chad Black on 2011-05-15.

Authentication adapted almost completely from Google's example at

I just added keychain storage.

import gflags
import httplib2
import keyring
import sys

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run

FLAGS = gflags.FLAGS

# Set up a Flow object to be used if we need to authenticate. This
# sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with
# the information it needs to authenticate. Note that it is called
# the Web Server Flow, but it can also handle the flow for native
# applications
# The client_id and client_secret are copied from the API Access tab on
# the Google APIs Console
FLOW = OAuth2WebServerFlow(
    client_secret=keyring.get_password('tasksClient', 'chadblack1'),

# To disable the local server feature, uncomment the following line:
FLAGS.auth_local_webserver = False

# If the Credentials don't exist or are invalid, run through the native client
# flow. The Storage object will ensure that if successful the good
# Credentials will get written back to a file.
storage = Storage('tasks.dat')
credentials = storage.get()
if credentials is None or credentials.invalid == True:
  credentials = run(FLOW, storage)

# Create an httplib2.Http object to handle our HTTP requests and authorize it
# with our good Credentials.
http = httplib2.Http()
http = credentials.authorize(http)

# Build a service object for interacting with the API. Visit
# the Google APIs Console
# to get a developerKey for your own application.
service = build(serviceName='tasks', version='v1', http=http,
       developerKey=keyring.get_password('googleDevKey', 'chadblack1'))

def main(*argv):
# Display all tasks in all lists.	
# ex.: tasks ls

	if sys.argv[1] == 'ls':
		tasklists = service.tasklists().list().execute()
		for tasklist in tasklists['items']:
			print tasklist['title']
			tasks = service.tasks().list(tasklist=listID).execute()
			for task in tasks['items']:
				if 'due' in task: 
				task['taskNum'] = n
				print '    '+str(n)+'. '+task['title']+' : '+dueDate
				n += 1

# To add a task, the command is 'n'. Then, pass three arguments-- listName, newTask, dueDate.
# ex: tasks n listName "This is my task." 2011-01-01

	if sys.argv[1] == 'n':
		listName = sys.argv[2]
		task = {
		 	'title': sys.argv[3], 
		 	'due': sys.argv[4]+'T12:00:00.000Z',
		tasklists = service.tasklists().list().execute()
		listID = None
		for tasklist in tasklists['items']:
			if listName == tasklist['title']:
		if listID == None:
			tasklist = {
		  	'title': listName,
			result = service.tasklists().insert(body=tasklist).execute()
			listID = result['id']				
		newTask = service.tasks().insert(tasklist=listID, body=task).execute()

# clear completed tasks from all lists
# tasks c
	if sys.argv[1] == 'c':
		tasklists = service.tasklists().list().execute()
		for tasklist in tasklists['items']:
			listID = tasklist['id']
			service.tasks().clear(tasklist=listID, body='').execute()

# update a task from a specified list - mark completed or delete
# tasks u listName taskNumber
# tasks d listName taskNumber
	if sys.argv[1] == 'd':
		listName= sys.argv[2]
		taskNumber = int(sys.argv[3])

# match list off of list name		
		for tasklist in tasklists['items']:
			if listName == tasklist['title']:
# select and delete task
		tasks = service.tasks().list(tasklist=listID).execute()
		newList = tasks['items']
		selectTask = newList[taskNumber-1]
		taskID = selectTask['id']
		service.tasks().delete(tasklist=listID, task=taskID).execute()
		print "completed"
	if sys.argv[1] == 'u':
		listName = sys.argv[2]
		taskNumber = int(sys.argv[3])		
		for tasklist in tasklists['items']:
			if listName == tasklist['title']:
		tasks = service.tasks().list(tasklist=listID).execute()
		newList = tasks['items']
		selectTask = newList[taskNumber-1]
		taskID = selectTask['id']
		chooseTask = service.tasks().get(tasklist=listID, task=taskID).execute()
		chooseTask['status'] = 'completed'
		markIt = service.tasks().update(tasklist=listID, task=chooseTask['id'], body=chooseTask).execute()
		print "completed"

if __name__ == '__main__':

(I really should put this stuff up on github instead of here. Guess I’ll add that to my task list.)


Associate Professor of Early Latin America Department of History University of Tennessee-Knoxville

Tagged with: , , ,
Posted in programming
14 comments on “update to google tasks on the cli
  1. Thanks Chad for sharing this code. I tried running it on 11.04 Ubuntu. It failed with following message:
    ERROR:root:Failed to retrieve access token: {“error”:”invalid_client”}
    The authentication has failed.
    any ideas, how to proceed?

  2. Ah I needed my own ‘developer key’,client_secret, user_agent as summarised at
    http://code.google.com/apis/tasks/v1/using.html . After putting the right values, the code works :)

  3. ctb says:

    Animesh– glad you got it running. I hope you find it useful!

  4. Alex says:

    Hi! What license the code covers under?

  5. ctb says:

    Everything on this site is under a CC-BY-NC-SA license.

  6. Alex says:

    ctb, OK, thank you.

  7. Is there a way to have tasks ls display check next to completed tasks? such “✓”?

    Thanks for this.

  8. ctb says:

    Sure, you could do that. The JSON object that is returned through the tasks API includes the property “status.” When the JSON object is turned into a python dictionary, that means there is a key:value pair tasklist[‘status’] that returns either ‘needsAction’ or ‘completed’. You put in another conditional loop that says something to the effect of:

    taskStatus = ' '
    if tasklist['status'] == 'completed':
    taskStatus = "✓"

    You would then need to add taskStatus to the print statement that displays each task. I haven’t checked that code, but something like that should work. It would put a check mark by a completed task, and nothing by a needsAttention task. Note, though, that introducing unicode can make things frustrating quickly.

    To see the full list of properties returned by the API, check out the Task Resource List.

  9. Thanks so much. Everything seems to be working great, but it’s definitely choking on that “✓”. I’m not experienced with any of this, so I’ll have to do a little searching. Perhaps another character would make sense?

    Thanks for your help.

  10. ctb says:


    You could play with encoding/decoding and get the check to work with it’s Unicode code point. But, easiest thing would be to use an ASCII character of some sort. I’d probably do + and -, where plus is a needsAttention task and minus is a completed task. There is a great library for dealing with Unicode problems called Kitchen. You could play around with that.

    At any rate, there are a number of useful ASCII possibilities– @, !, #, %, *.

  11. ctb-

    I may play around with it this weekend. As much as I would like a nice, pretty “✓” next to them (I am a graphic designer, after all), at the moment a “X” is working just fine.

    To anyone looking to do the same thing, I did have to alter the code to:

    taskStatus = ‘ ‘
    if task[‘status’] == ‘completed’:
    taskStatus = “✓”

    Thanks again for your time, and for sharing this solution.

  12. ctb says:

    Oops. Not sure where the carriage return came from on that line. Must have been from writing it on the WordPress iPhone app.

  13. […] finally got around to rewriting my google tasks script (see previous posts here and here. The script has generated a fair amount of interest for this blog. After intending to do it for a […]

  14. […] historians, and on making a static-site digital history archive. I did a series of posts (here, here, and here) on integrating Google Tasks on the command line. And, in that never-ending quest for an […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Hacer juicio ú dictamen acerca de alguna cosa... significando que el objeto excita el juicio ú dictamen en la persona que le hace.

Deducir ante el Juez la accion ú derecho que se tiene, ó las excepciones que excluyen la accion contrária.

RAE 1737 Academia autoridades
Buy my book!

Chad Black

I, your humble contributor, am Chad Black. You can also find me on the web here.
%d bloggers like this: