From 40e5fcb07e317efdcc4a12f9c517c5613fc45944 Mon Sep 17 00:00:00 2001 From: Matt Snider Date: Fri, 16 Nov 2018 02:11:57 +0100 Subject: [PATCH] Handle recurring tasks from date_string (recur) --- migrate.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/migrate.py b/migrate.py index f5b0ca1..6f9a892 100644 --- a/migrate.py +++ b/migrate.py @@ -1,4 +1,5 @@ import click +import re from datetime import datetime from taskw import TaskWarrior from todoist.api import TodoistAPI @@ -40,14 +41,15 @@ def migrate(interactive, no_sync): ] entry = taskwarrior_date(task['date_added']) due = taskwarrior_date(task['due_date_utc']) + recur = taskwarrior_recur(task['date_string']) if interactive and not click.confirm(f"Import '{name}'?"): continue - add_task(tid, name, project, tags, priority, entry, due) + add_task(tid, name, project, tags, priority, entry, due, recur) -def add_task(tid, name, project, tags, priority, entry, due): +def add_task(tid, name, project, tags, priority, entry, due, recur): """Add a taskwarrior task from todoist task Returns the taskwarrior task. @@ -55,7 +57,7 @@ def add_task(tid, name, project, tags, priority, entry, due): info(f"Importing '{name}' ({project}) - ", nl=False) try: tw_task = taskwarrior.task_add(name, project=project, tags=tags, - priority=priority, entry=entry, due=due) + priority=priority, entry=entry, due=due, recur=recur) except: error('FAILED') else: @@ -83,7 +85,7 @@ def taskwarrior_priority(priority): return PRIORITIES[priority] def taskwarrior_date(date): - """ Converts a date from Todist to taskwarrior + """ Converts a date from Todoist to taskwarrior Todoist: Fri 26 Sep 2014 08:25:05 +0000 (what is this called)? taskwarrior: ISO-8601 @@ -92,6 +94,54 @@ def taskwarrior_date(date): return None return datetime.strptime(date, '%a %d %b %Y %H:%M:%S %z').isoformat() + +def taskwarrior_recur(desc): + """ Converts a repeating interval from Todoist to taskwarrior. + + Field: + - Todoist: date_string + - taskwarrior: recur + + Examples: + - every other `interval` `period` -> 2 `period` + - every `interval` `period` -> `interval` `period` + - every `day of week` -> weekly + + _Note_: just because Todoist sets `date_string` doesn't mean + that the task is repeating. Mostly it just indicates that the + user input via string and not date selector. + """ + if not desc: + return + return _match_every(desc) or _match_weekly(desc) + + +RE_INTERVAL = 'other|\d+' +RE_PERIOD = 'day|week|month|year' +RE_REPEAT_EVERY = re.compile( + f'^\s*every\s+((?P{RE_INTERVAL})\s+)?(?P{RE_PERIOD})s?\s*$' +) + +def _match_every(desc): + match = RE_REPEAT_EVERY.match(desc.lower()) + if not match: + return + + interval = match.group('interval') + period = match.group('period') + if interval == 'other': + interval = 2 + return f'{interval} {period}' + + +RE_REPEAT_WEEKLY = re.compile( + '^\s*every\s+(mon|monday|tues|tuesday|weds|wednesday|thurs|thursday|fri|friday|sat|saturday|sun|sunday)\s*' +) + +def _match_weekly(desc): + return ('weekly' if RE_REPEAT_WEEKLY.match(desc.lower()) else None) + + """ Entrypoint """ if __name__ == '__main__':