def force_load_tw(self, **kw): """ Force lazy loading of TaskWarrior object, possibly with custom extra arguments. This is used in tests to instantiate TaskWarrior objects pointing to the test TaskWarrior configuration. """ self._tw = taskw.TaskWarrior(marshal=True, **kw)
def testCreateFromTW(self): """ Test import of new taskwarrior tasks in egt """ import taskw tw = taskw.TaskWarrior(marshal=True, config_filename=self.taskrc) new_task = tw.task_add("new task", ["tag", "testtag1"], project="testprj") tw.task_add("new parent task", project="testprj", depends=[new_task["uuid"]]) tw = None self.write_project([ "body line1", "body line2", ]) proj = Project(self.projectfile, statedir=self.workdir.name) proj.body.force_load_tw(config_filename=self.taskrc) proj.load() self.assertEqual(len(proj.body.content), 2) self.assertEqual(len(proj.body.tasks), 0) proj.body.sync_tasks() self.assertEqual(len(proj.body.content), 5) self.assertEqual(len(proj.body.tasks), 2) task = proj.body.tasks[0] self.assertIsNotNone(task.task) self.assertFalse(task.is_new) self.assertIsNotNone(task.id) self.assertEqual(task.task["description"], "new task") self.assertEqual(task.task["tags"], ["tag", "testtag1"]) self.assertEqual(task.task["project"], "testprj") with io.StringIO() as out: proj.body.print(out) body_lines = out.getvalue().splitlines() self.assertEqual(len(body_lines), 5) self.assertRegex(body_lines[0], r"^t\d+ \[[^]]+\] new task \+tag$") self.assertRegex(body_lines[1], r"^t\d+ \[[^]]+\] new parent task depends:1$") self.assertEqual(body_lines[2], "") self.assertEqual(body_lines[3], "body line1") self.assertEqual(body_lines[4], "body line2") with open(os.path.join(self.workdir.name, "project-testprj.json"), "rt") as fd: state = json.load(fd) tasks = state["tasks"] ids = tasks["ids"] self.assertEqual(len(ids), 2) self.assertEqual(ids[str(task.task["id"])], str(task.task["uuid"]))
def main(): tw_cli = taskw.TaskWarrior() ti_cli = todoist.login_with_api_token(TODOIST_API_TOKEN) ti_tasks = ti_cli.get_tasks() tw_tasks = tw_cli.load_tasks() # NOTE: todoist only returns uncompleted tasks whereas taskwarrier returns # all for ti_task in ti_tasks: if ti_task.project.name in SKIP_TODOIST_PROJECT_NAMES: continue if not ti_task_synced_to_tw(ti_task=ti_task): create_tw_task(ti_task=ti_task, tw_cli=tw_cli) for tw_task in tw_tasks['pending']: if not tw_task_synced_to_ti(tw_task=tw_task): create_ti_task(tw_task=tw_task, ti_cli=ti_cli) else: # check if task has been marked completed on todoist by seeing if # it's in the list returned from todoist sync_rec = TodoistTaskWarrierSyncModel.get( taskwarrier=tw_task['uuid']) if not sync_rec.completed: ti_id = sync_rec.todoist if not ti_id in map(lambda t: t.id, ti_tasks): mark_tw_task_complete(tw_task=tw_task, tw_cli=tw_cli) sync_rec.update(completed=True) for tw_task in tw_tasks['completed']: if tw_task_synced_to_ti(tw_task=tw_task): sync_rec = TodoistTaskWarrierSyncModel.get( taskwarrier=tw_task['uuid']) if not sync_rec.completed: ti_id = sync_rec.todoist mark_ti_task_complete(ti_id=ti_id, ti_tasks=ti_tasks, tw_task=tw_task) sync_rec.update(completed=True)
def main(): """ Main function """ taskwarrior = taskw.TaskWarrior() tasks = taskwarrior.load_tasks() # Only (over-)due and recurring tasks are considered for deletion: due_before = datetime.datetime.utcnow() due_before = due_before.replace(tzinfo=pytz.utc) # datetime.datetime.now() recurring_tasks_due = [ task for task in tasks['completed'] if 'recur' in task and 'parent' in task and 'due' in task and dateparse(task['due']) < due_before ] # Delete all but the first of all (over-)due and duplicate tasks: parents = collections.Counter( [task['parent'] for task in recurring_tasks_due]) for parent in parents: count = parents[parent] if count > 1: dupe_tasks = [ task for task in recurring_tasks_due if task['parent'] == parent ] dupe_tasks = sorted(dupe_tasks, key=lambda t: t['due']) # dupe_tasks_to_keep = dupe_tasks[0:1] dupe_tasks_to_trash = dupe_tasks[1:] print('Deleting {} duplicate due tasks: "{}"'.format( len(dupe_tasks_to_trash), dupe_tasks_to_trash[0]['description'])) for task in dupe_tasks_to_trash: task_delete(task['uuid'])
def __init__(self): self.client = taskw.TaskWarrior() self.tasks = self.client.load_tasks()
def tw(self) -> taskw.TaskWarrior: if self._tw is None: self._tw = taskw.TaskWarrior(marshal=True) return self._tw
def testSyncDone(self): """ Test handling of tasks present both in taskwarrior and in egt, when a task is marked done on taskwarrior """ import taskw tw = taskw.TaskWarrior(marshal=True, config_filename=self.taskrc) new_task = tw.task_add("task", ["tag", "testtag1"], project="testprj") egt_id = new_task["id"] + 10 # Add the task to egt's state using a different number than taskwarrior # has with open(os.path.join(self.workdir.name, "project-testprj.json"), "wt") as fd: json.dump({"tasks": { "ids": { egt_id: str(new_task["uuid"]), } }}, fd, indent=1) self.write_project([ "body line1", " t{} foo the bar".format(egt_id), "body line3", ]) # Mark the task as done tw.task_done(uuid=new_task["uuid"]) tw = None # Load the project and see proj = Project(self.projectfile, statedir=self.workdir.name) proj.body.force_load_tw(config_filename=self.taskrc) proj.load() self.assertEqual(len(proj.body.content), 3) self.assertEqual(len(proj.body.tasks), 1) self.assertEqual(proj.body.tasks[0], proj.body.content[1]) task = proj.body.tasks[0] self.assertEqual(task.indent, " ") self.assertIsNone(task.task) self.assertFalse(task.is_new) self.assertEqual(task.id, egt_id) self.assertEqual(task.desc, "foo the bar") self.assertEqual(task.tags, set()) self.assertFalse(task.is_orphan) proj.body.sync_tasks() self.assertEqual(len(proj.body.tasks), 1) self.assertEqual(task, proj.body.tasks[0]) self.assertIsNotNone(task.task) self.assertFalse(task.is_new) self.assertIsNone(task.id) self.assertEqual(task.task["description"], "task") self.assertEqual(task.task["tags"], ["tag", "testtag1"]) self.assertEqual(task.task["project"], "testprj") with io.StringIO() as out: proj.body.print(out) body_lines = out.getvalue().splitlines() self.assertEqual(len(body_lines), 3) self.assertEqual(body_lines[0], "body line1") self.assertRegex(body_lines[1], r"^ - \[[^]]+\] task \+tag$") self.assertEqual(body_lines[2], "body line3") with open(os.path.join(self.workdir.name, "project-testprj.json"), "rt") as fd: state = json.load(fd) tasks = state["tasks"] ids = tasks["ids"] self.assertEqual(len(ids), 0)
def get_reminder() -> typing.Text: logger = logging.getLogger(__name__) today = datetime.now(tzlocal()).replace(hour=0, minute=0, second=0, microsecond=0) tomorrow = today + ONE_DAY overmorrow = today + TWO_DAY next_monday = _get_next_monday(today) two_mondays_from_now = _get_two_mondays_from_now(today) logger.debug("Today is {}".format(today)) logger.debug("Tomorrow is {}".format(tomorrow)) logger.debug("Overmorrow is {}".format(overmorrow)) logger.debug("Next Monday is {}".format(next_monday)) logger.debug("Two Mondays from now is {}".format(two_mondays_from_now)) task_warrior = taskw.TaskWarrior(marshal=True) all_tasks = task_warrior.load_tasks() buffer = StringIO() tasks: typing.Dict[typing.Text, typing.List[typing.Any]] = { "no_deadline": [], "due_today": [], "due_tomorrow": [], "due_this_week": [], "due_next_week": [], "future": [], } for task in all_tasks["pending"]: if "wait" in task and task["wait"] is not None and task["wait"] > today: continue if "due" not in task: logger.debug("This task does not have a due date") logger.debug(" {}".format(task["description"])) tasks["no_deadline"].append(task) elif today < task["due"] <= tomorrow: logger.debug("This task is due today") logger.debug(" {}: {}".format(task["due"], task["description"])) tasks["due_today"].append(task) elif tomorrow < task["due"] <= overmorrow: logger.debug("This task is due tomorrow") logger.debug(" {}: {}".format(task["due"], task["description"])) tasks["due_tomorrow"].append(task) elif overmorrow < task["due"] <= next_monday: logger.debug("This task is due this week") logger.debug(" {}: {}".format(task["due"], task["description"])) tasks["due_this_week"].append(task) elif next_monday < task["due"] <= two_mondays_from_now: logger.debug("This task is due next week") logger.debug(" {}: {}".format(task["due"], task["description"])) tasks["due_next_week"].append(task) else: logger.debug("This task is due sometime in the future") logger.debug(" {}: {}".format(task["due"], task["description"])) tasks["future"].append(task) labels = { "no_deadline": "Without deadline", "due_today": "Due today", "due_tomorrow": "Due tomorrow", "due_this_week": "Due this week", "due_next_week": "Due next week", "future": "In future", } show_date = { "no_deadline": False, "due_today": False, "due_tomorrow": False, "due_this_week": True, "due_next_week": True, "future": True, } for key, label in labels.items(): if len(tasks[key]) > 0: print("## {}\n".format(label), file=buffer) for task in sorted(tasks[key], key=itemgetter("urgency"), reverse=True): print("- {}".format(task["description"]), file=buffer, end="") if show_date[key]: print(", due on ", file=buffer, end="") if task["due"].year == today.year: print(task["due"].strftime("%A %-d %B"), file=buffer, end="") else: print(task["due"].strftime("%A %-d %B %Y"), file=buffer, end="") print("", file=buffer) print("", file=buffer) return buffer.getvalue()
def __init__(self, factory, db=None, **kwargs): self._db = db or taskw.TaskWarrior(config_filename=kwargs['config']) self._factory = factory