Migrating from 2Do to TaskPaper

Python script to help migrate from 2Do to TaskPaper

Task management seems like something that should be fairly straightforward. You have a list of things to do, and you check them off when done. Of course, the computer world is full of people trying to optimize and enhance absolutely everything including managing the things we do. That led to an explosion in task managers and todo lists across many different platforms.

For the Mac specifically, I remember being awed by the power of OmniOutliner and Kinkless GTD many years ago! Iterations on this concept, including different styles and approaches, have been the basis for the numerous offerings we’ve seen over the years. Some examples include: The Hit List, Things, OmniFocus, Reminders, Wunderlist, and 2Do among many others.

I’ve typically kept to the “simple is better” strategy for many things, including my typical workflows, opting for tools such as Markdown and nvALT over the more “feature filled” alternatives. However, I started to drift a little bit when it came to task management, and I’ve recently ended up using 2Do. 2Do is an extremely powerful and excellent application, but I’ve found that over time, I don’t ever stick with consistently using the advanced features like tags, priorities, or even due dates.

Because I wasn’t really using 2Do to it’s full potential, I decided to simplify this setup. I settled on TaskPaper, which uses the very interesting idea of taking a well formatted plain text file, and allowing the user to display interesting things and interact with it in certain ways without modifying the underlying files. That’s right, no database, no proprietary format, just text files all the way down.

I’ve taken a similar approach to my blog (presumably where you are reading this), where the articles are written in Markdown. This is important for me since I’m sure software will exist in 20 years that will be able to view and modify text files. However, I’m not so sure about the proprietary databases and websites used by many other todo list managers.

To illustrate, here’s an example of a few tasks in both TaskPaper and in the plain text file. TaskPaper takes that plain text, and allows extra features such as organizing tasks into projects, marking items as complete, setting due dates, arranging tasks, etc. The syntax and format also allow for an extremely powerful search syntax, and crazy flexibility around tags and other classification.


Great, so I’ve found the software I’d like to use, and understand the format that this software uses. Now it’s time to migrate my 576 items into TaskPaper. Should be easy, right? Just export data from 2Do and reformat it as plain text.

Ironically, when I tried to export my data from 2Do, I couldn’t for the life of me find an option to do so from within the Mac app! Just the kind of thing I’m trying to get away from by moving to plain text. Thankfully, the iOS app does provide an export-to-csv option, which seems a bit backwards since the iOS apps typically have fewer features, but I can work with it. I selected all of my todo items I wanted to export like in the screenshot, exported it, and used AirDrop to get it to my Mac.

Now that I had my data in csv format, I needed to find a way to import it into TaskPaper. The format itself is straightforward (again, yay plain text!), so it just takes a bit of text manipulation to get it into the proper format. I wrote a quick and dirty script in Python 3 to take the csv file, format it the way I want, add the proper tags, and write it out to a .taskpaper file. While it won’t work for everyone (anyone?), it should provide a good starting point. You might use tags differently than I do, or have start dates, etc. All of that can easily be edited to match your preferred format. Even for my setup, I had to go back through and clean up a few minor areas, but it was much better than retyping everything into TaskPaper by hand.

#! /usr/bin/env python3

import csv, os

filename = "Todo.taskpaper"
taskCSV = open('tasks.csv')
taskReader = csv.reader(taskCSV)
taskData = list(taskReader)

taskPaperFile = open(filename, 'w')
section = ""

for row in taskData[1:]: # Skip first row, which is the HEADER
    task = row[0]
    todoListName = row[1]
    startDate = row[2]
    dueDate = row[3]
    dueTime = row[4]
    repeat = row[5]
    priority = row[6]
    tag = row[7]
    location = row[8]
    completed = row[9]
    star = row[10]
    note = row[11]

    if section != todoListName:
        section = todoListName
        sectionHead = "\n" + section + ":"
        taskPaperFile.write(sectionHead)

    entry = "\n\t- " + task

    if startDate: entry += " @start(" + startDate + ")"
    if dueDate: entry += " @due(" + dueDate + ")"
    if star: entry += " @high"
    if tag: entry += " @tag(" + tag + ")"
    if completed: entry += " @done"
    if note: entry += "\n\t\t\t" + note

    taskPaperFile.write(entry)