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
  • Select an option

  • Save duellsy/1031e84c7c7a9c199145 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
Author

duellsy commented Oct 2, 2014

Usage:

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

@jalyst
Copy link
Copy Markdown

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?

@abbaszpro
Copy link
Copy Markdown

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