コード例 #1
0
def update_task(task_id, attribute, value):
    # TODO Create Docstring

    logger_obj.info(task_id)
    logger_obj.info("attribute = " + attribute)
    logger_obj.info(value)
    tw = TaskWarrior()
    task_id, task = tw.get_task(id=task_id)
    logger_obj.info(task)

    for attempt in range(9):
        try:
            if attribute not in task or task[attribute] != value:
                task[attribute] = value
                logger_obj.debug("Setting " + attribute + " to " + str(value))
                tw.task_update(task)
        except:
            logger_obj.exception('Retry update - ' + str(attempt))
        else:
            break
    else:
        logger_obj.debug('Failed to Update task')

    # try:
    #     if task[attribute] != value:
    #         task[attribute] = value
    #         logger_obj.debug("Setting " + attribute + " to " + value)
    #         tw.task_update(task)
    # except KeyError:
    #     logger_obj.info("Attribute has not been set so we are adding it")
    #     task[attribute] = value
    #     tw.task_update(task)

    logger_obj.info(task)
コード例 #2
0
def main(task_id, action):
    w = TaskWarrior()
    # First, make sure that the task id is valid.

    if action == 'start':
        task = w.get_task(id=task_id)
        if task[0] is None:
            print "Invalid task ID."
            return
        task = task[1]
        print task

        name = task['description'].replace(",","") # get rid of commas 
        name = "%s %s" % (task_id, name) # store task_id in the name so we can find it again later when we want to mark a task as 'done'...
        category = ""
        if 'tags' in task: # preserve tags from TaskWarrior
            name = "%s, %s " % (name, " ".join(task['tags']))

        if 'project' in task: # if there is a project assigned in TW, make it a Project Hamster category
            name = "%s@%s" % (name, task['project'])

        subprocess.check_output(['hamster', action, name])

        return

    if action == 'done':
        if task_id == 0:
            cur_hamster = subprocess.check_output(['hamster', 'current']).strip().split()
            task_id = int(cur_hamster[2])

        subprocess.check_output(['hamster', 'stop'])
        w.task_done(id=task_id)
        return
コード例 #3
0
def update_task(tw: TaskWarrior, task: Dict[str, Any]) -> None:
    logger.debug('Maybe updating task %s', task['webdesk_key'])
    id_, twt = tw.get_task(webdesk_key=task['webdesk_key'])
    _push_properties(task, twt)
    r = twt.update(task)
    if True in r.values():
        tw.task_update(twt)
        logger.log(logging.INFO + 5, 'Updated task %d (%s)', id_,
                   ', '.join(k for k, v in r.items() if v is True))
コード例 #4
0
ファイル: db.py プロジェクト: ale-rt/bugwarrior
def synchronize(issues):
    tw = TaskWarrior()

    # Load info about the task database
    tasks = tw.load_tasks()
    is_bugwarrior_task = lambda task: task.get('description', '').startswith(MARKUP)

    # Prune down to only tasks managed by bugwarrior
    for key in tasks.keys():
        tasks[key] = filter(is_bugwarrior_task, tasks[key])

    # Build a list of only the descriptions of those local bugwarrior tasks
    local_descs = [t['description'] for t in sum(tasks.values(), []) \
        if t['status'] not in ('deleted')]

    # Now for the remote data.
    # Build a list of only the descriptions of those remote issues
    remote_descs = [i['description'] for i in issues]

    # Build the list of tasks that need to be added
    is_new = lambda issue: issue['description'] not in local_descs
    new_issues = filter(is_new, issues)
    old_issues = filter(lambda i: not is_new(i), issues)

    # Build the list of local tasks that need to be completed
    is_done = lambda task: task['description'] not in remote_descs
    done_tasks = filter(is_done, tasks['pending'])

    log.struct(new=len(new_issues), completed=len(done_tasks))

    # Add new issues
    for issue in new_issues:
        log.info("Adding task {0}", issue['description'].encode("utf-8"))
        tw.task_add(**issue)

    # Update any issues that may have had new properties added.  These are
    # usually annotations that come from comments in the issue thread.
    pending_descriptions = [t['description'] for t in tasks['pending']]
    for upstream_issue in old_issues:
        if upstream_issue['description'] not in pending_descriptions:
            continue

        id, task = tw.get_task(description=upstream_issue['description'])
        for key in upstream_issue:
            if key not in task:
                log.info("Updating {0} on {1}",
                         key, upstream_issue['description'].encode("utf-8"))
                task[key] = upstream_issue[key]
                id, task = tw.task_update(task)

    # Delete old issues
    for task in done_tasks:
        log.info("Completing task {0}", task['description'].encode("utf-8"))
        tw.task_done(uuid=task['uuid'])
コード例 #5
0
def main(args):
    w = TaskWarrior()
    task_id = 0
    try:
        create_or_connect()
        pomodoro_counter = args.pomodoro_counter
        task_id, task_body = w.get_task(id=args.taskw_id)
        print("Starting our pomodoro break period: %d on task: %s" %
              (pomodoro_counter, task_body['description']))
        task_uuid = task_body['uuid']
        while True:
            do_task_work(task_uuid, task_id=task_id)
            pomodoro_counter += 1
            do_task_break(pomodoro_counter, task_uuid, task_id=task_id)
    except KeyboardInterrupt:
        pass
    finally:
        exit_gracefully()
        subprocess.call(["task", str(task_id), "stop"])
コード例 #6
0
class TaskWarriorSide(GenericSide):
    """Handles interaction with the TaskWarrior client."""
    def __init__(self, **kargs):
        super(TaskWarriorSide, self).__init__()

        # Tags are used to filter the tasks for both *push* and *pull*.
        self.config = {
            "tags": [],
            "config_filename": "~/.taskrc",
            "enable_caching": True
        }
        self.config.update(**kargs)
        assert isinstance(self.config["tags"], list), "Expected a list of tags"

        # TaskWarrior instance as a class memeber - initialize only once
        self.tw = TaskWarrior(marshal=True,
                              config_filename=self.config["config_filename"])
        # All TW tasks
        self.items: Dict[str, List[dict]] = []
        # Whether to refresh the cached list of items
        self.reload_items = True

    def _load_all_items(self):
        """Load all tasks to memory.

        May return already loaded list of items, depending on the validity of
        the cache.
        """

        if not self.config["enable_caching"]:
            self.items = self.tw.load_tasks()
            return

        if self.reload_items:
            self.items = self.tw.load_tasks()
            self.reload_items = False

    @overrides
    def get_all_items(self, **kargs):
        """Fetch the tasks off the local taskw db.

        :param kargs: Extra options for the call.
            * Use the `order_by` arg to specify the order by which to return the
              items.
            * Use the `use_ascending_order` boolean flag to specify ascending/descending
              order
            * `include_completed` to also include completed tasks [Default: True]
        :return: list of tasks that exist locally
        :raises: ValueError in case the order_by key is invalid

        """
        self._load_all_items()
        tasks = []
        if kargs.get("include_completed", True):
            tasks.extend(self.items["completed"])
        tasks.extend(self.items["pending"])

        tags = set(self.config["tags"])
        tasks = [t for t in tasks if tags.issubset(t.get("tags", []))]

        if "order_by" in kargs and kargs["order_by"] is not None:
            if "use_ascending_order" in kargs:
                assert isinstance(kargs["use_ascending_order"], bool)
                use_ascending_order = kargs["use_ascending_order"]
            else:
                use_ascending_order = True
            assert (kargs["order_by"] in [
                "description", "end", "entry", "id", "modified", "status",
                "urgency"
            ] and "Invalid 'order_by' value")
            tasks.sort(key=lambda t: t[kargs["order_by"]],
                       reverse=not use_ascending_order)

        return tasks

    @overrides
    def get_single_item(self, item_id: str) -> Union[dict, None]:
        t = self.tw.get_task(id=item_id)[-1] or None
        assert "status" in t.keys()  # type: ignore
        return t if t["status"] != "deleted" else None  # type: ignore

    @overrides
    def update_item(self, item_id: str, **changes):
        """Update an already added item.

        :raises ValaueError: In case the item is not present in the db
        """
        changes.pop("id", False)
        t = self.tw.get_task(uuid=UUID(item_id))[-1]

        # task CLI doesn't allow `imask`
        unwanted_keys = ["imask", "recur", "rtype", "parent"]
        for i in unwanted_keys:
            t.pop(i, False)

        # taskwarrior doesn't let you explicitly set the update time.
        # even if you set it it will revert to the time  that you call
        # `tw.task_update`
        d = dict(t)
        d.update(changes)
        self.tw.task_update(d)

    @overrides
    def add_item(self, item) -> dict:
        """Add a new Item as a TW task.

        :param item:  This should contain only keys that exist in standard TW
                      tasks (e.g., proj, tag, due). It is mandatory that it
                      contains the 'description' key for the task title
        """
        assert "description" in item.keys(), "Item doesn't have a description."
        assert ("uuid" not in item.keys(
        )), "Item already has a UUID, try updating it instead of adding it"

        curr_status = item.get("status", None)
        if curr_status not in ["pending", "done"]:
            self.logger.info(
                'Invalid status of task: "%s", setting it to pending',
                item["status"])
            item["status"] = "pending"

        item.setdefault("tags", [])
        item["tags"] += self.config["tags"]

        description = item.pop("description")
        new_item = self.tw.task_add(description=description, **item)
        len_print = min(20, len(description))
        self.logger.info('Task "{}" created - "{}"...'.format(
            new_item["id"], description[0:len_print]))

        return new_item

    @overrides
    def delete_single_item(self, item_id) -> None:
        self.tw.task_delete(uuid=item_id)

    @staticmethod
    def items_are_identical(item1, item2, ignore_keys=[]) -> bool:

        keys = [
            k for k in [
                "annotations", "description", "due", "modified", "status",
                "uuid"
            ] if k not in ignore_keys
        ]

        # special care for the annotations key
        if "annotations" in item1 and "annotations" in item2:
            if item1["annotations"] != item2["annotations"]:
                return False
            item1.pop("annotations")
            item2.pop("annotations")
        # one may contain empty list
        elif "annotations" in item1 and "annotations" not in item2:
            if item1["annotations"] != []:
                return False
            item1.pop("annotations")
        # one may contain empty list
        elif "annotations" in item2 and "annotations" not in item1:
            if item2["annotations"] != []:
                return False
            item2.pop("annotations")
        else:
            pass

        return GenericSide._items_are_identical(item1, item2, keys)

    @staticmethod
    def get_task_id(item: dict) -> str:
        """Get the ID of a task in string form"""
        return str(item["uuid"])
コード例 #7
0
ファイル: test_datas.py プロジェクト: techdragon/taskw
class TestDB(object):
    def setup(self):
        # Create some temporary config stuff
        fd, fname = tempfile.mkstemp(prefix='taskw-testsrc')
        dname = tempfile.mkdtemp(prefix='taskw-tests-data')

        with open(fname, 'w') as f:
            f.writelines(['data.location=%s' % dname])

        # Create empty .data files
        for piece in ['completed', 'pending', 'undo']:
            with open(os.path.sep.join([dname, piece + '.data']), 'w'):
                pass

        # Save names for .tearDown()
        self.fname, self.dname = fname, dname

        # Create the taskwarrior db object that each test will use.
        self.tw = TaskWarrior(config_filename=fname)

    def tearDown(self):
        os.remove(self.fname)
        shutil.rmtree(self.dname)

    def test_has_two_categories(self):
        tasks = self.tw.load_tasks()
        eq_(len(tasks), 2)

    def test_empty_db(self):
        tasks = self.tw.load_tasks()
        eq_(len(sum(tasks.values(), [])), 0)

    def test_add(self):
        self.tw.task_add("foobar")
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 1)

    def test_unchanging_load_tasks(self):
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)

    @raises(KeyError)
    def test_completion_raising_unspecified(self):
        self.tw.task_done()

    def test_completing_task_by_id_unspecified(self):
        self.tw.task_add("foobar")
        self.tw.task_done(id=1)
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        eq_(len(tasks['completed']), 1)
        eq_(len(sum(tasks.values(), [])), 1)
        ok_(tasks['completed'][0]['end'] != None)

    def test_completing_task_with_date(self):
        self.tw.task_add("foobar")
        uuid = self.tw.load_tasks()['pending'][0]['uuid']
        self.tw.task_done(uuid=uuid, end="1234567890")
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        eq_(len(tasks['completed']), 1)
        eq_(tasks['completed'][0]['end'], '1234567890')

    def test_completing_task_by_id_specified(self):
        self.tw.task_add("foobar")
        self.tw.task_done(id=1)
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        eq_(len(tasks['completed']), 1)
        eq_(len(sum(tasks.values(), [])), 1)

    def test_completing_task_by_id_retrieved(self):
        task = self.tw.task_add("foobar")
        self.tw.task_done(id=task['id'])
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        eq_(len(tasks['completed']), 1)
        eq_(len(sum(tasks.values(), [])), 1)

    def test_completing_task_by_uuid(self):
        self.tw.task_add("foobar")
        uuid = self.tw.load_tasks()['pending'][0]['uuid']
        self.tw.task_done(uuid=uuid)
        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 0)
        eq_(len(tasks['completed']), 1)
        eq_(len(sum(tasks.values(), [])), 1)

    @raises(KeyError)
    def test_get_task_mismatch(self):
        self.tw.task_add("foobar")
        self.tw.task_add("bazbar")
        uuid = self.tw.load_tasks()['pending'][0]['uuid']
        self.tw.get_task(id=2, uuid=uuid)  # which one?

    def test_updating_task(self):
        self.tw.task_add("foobar")

        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 1)

        task = tasks['pending'][0]
        task["priority"] = "L"
        self.tw.task_update(task)

        tasks = self.tw.load_tasks()
        eq_(len(tasks['pending']), 1)
        eq_(tasks['pending'][0], task)

    @raises(KeyError)
    def test_update_exc(self):
        task = dict(description="lol")
        self.tw.task_update(task)