Skip to content

Instantly share code, notes, and snippets.

@duellsy
Forked from kbl/import.py
Last active October 2, 2019 12:58
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save duellsy/1031e84c7c7a9c199145 to your computer and use it in GitHub Desktop.
Save duellsy/1031e84c7c7a9c199145 to your computer and use it in GitHub Desktop.
Import tasks and notes from wunderlist dump to todoist (and mark completed tasks as completed)
# -*- coding: utf8 -*-
import json
import urllib2
import urllib
import sys
import os
from argparse import ArgumentParser
from collections import defaultdict
def log(message):
sys.stdout.write(message + os.linesep)
class TodoistAPI(object):
def __init__(self, email, password):
self.token = self._api_call('login', {'email': email, 'password': password}, add_token=False)['token']
def _api_call(self, api_method, parameters, add_token=True):
parameters = dict(parameters)
if add_token:
parameters.update({'token': self.token})
params = urllib.urlencode(parameters)
url = u'https://todoist.com/API/%s?%s' % (api_method, params)
log('Calling url %s' % url)
return_value = json.load(urllib2.urlopen(url))
if type(return_value) is unicode:
if return_value != "ok":
raise Exception('Call finished with error! %s' % return_value)
return return_value
def add_list(self, list_name):
list_name = list_name.encode("utf-8")
log('Adding list %s' % list_name)
return self._api_call('addProject', {'name': list_name})['id']
def add_task(self, list_id, task_name, completed):
task_name = task_name.encode("utf-8")
log('Adding task %s to list %d' % (task_name, list_id))
task = self._api_call('addItem', {'project_id': list_id, 'content': task_name})['id']
if completed:
self._api_call('completeItems', {'ids': [task]})
return task
def add_note(self, item_id, note):
note = note.encode("utf-8")
log('Adding note %s' % note)
return self._api_call('addNote', {'item_id': item_id, 'content': note})['id']
def create_parser():
parser = ArgumentParser()
parser.add_argument('wunderlist_dump_json')
parser.add_argument('todoist_email')
parser.add_argument('todoist_password')
return parser
if __name__ == '__main__':
parser = create_parser()
args = parser.parse_args()
todoist_api = TodoistAPI(args.todoist_email, args.todoist_password)
with open(args.wunderlist_dump_json) as f:
j = json.load(f)
lists = {}
items = {}
for l in j['data']['lists']:
lists[l['id']] = todoist_api.add_list(l['title'])
for t in j['data']['tasks']:
items[t['id']] = todoist_api.add_task(lists[t['list_id']], t['title'], t['completed'])
for n in j['data']['notes']:
todoist_api.add_note(items[n['task_id']], n['content'])
@duellsy
Copy link
Author

duellsy commented Oct 2, 2014

Usage:

python import.py [wunderlist_export.json] [todist_email] [todiost_password]

@jalyst
Copy link

jalyst commented Dec 18, 2014

Trying to do this in the terminal in OSX, but it keeps wanting to use python 2.7 (apple's default env).
How do I get it to use 3.4.2? For example when I type "Python" it comes up with:

Python 2.7.5 (default, Mar 9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

I know it probably doesn't matter if I use 2.7, but I want to use 3.4.2, unless there's any issue with that IYO?

@manontop
Copy link

I installed python and run the command in terminal and I got this:

Calling url https://todoist.com/API/login?password=%5B234234246645%5D&email=%5Bmyemailaddress%40gmail.com%5D
Traceback (most recent call last):
  File "import.py", line 62, in <module>
    todoist_api = TodoistAPI(args.todoist_email, args.todoist_password)
  File "import.py", line 16, in __init__
    self.token = self._api_call('login', {'email': email, 'password': password}, add_token=False)['token']
  File "import.py", line 28, in _api_call
    raise Exception('Call finished with error! %s' % return_value)
Exception: Call finished with error! LOGIN_ERROR

The login info is correct I typed it as you advised:
python import.py [wunderlist_dump.json] [wrote my email here] [wrote my password here]

Is it required to type the email and password somewhere inside .py file as well? Please advice what am I doing wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment