Esempio n. 1
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
Esempio n. 2
0
    def get_activities(self, query = None):
        if not self.source:
            return []

        if self.source == "evo":
            return [activity for activity in get_eds_tasks()
                         if query is None or activity['name'].startswith(query)]

        elif self.source == "gtg":
            conn = self.__get_gtg_connection()
            if not conn:
                return []

            activities = []

            tasks = []
            try:
                tasks = conn.GetTasks()
            except dbus.exceptions.DBusException:  #TODO too lame to figure out how to connect to the disconnect signal
                self.__gtg_connection = None
                return self.get_activities(query) # reconnect


            for task in tasks:
                if query is None or task['title'].lower().startswith(query):
                    name = task['title']
                    if len(task['tags']):
                        name = "%s, %s" % (name, " ".join([tag.replace("@", "#") for tag in task['tags']]))

                    activities.append({"name": name,
                                       "category": ""})

            return activities

        elif self.source == "task":
            conn = TaskWarrior ()
            if not conn:
                return []

            activities = []
            tasks = []

            task_filter = {'status':'pending'}
            tasks = conn.filter_tasks(task_filter)

            for task in tasks:
                name = task['description'].replace(",","")  # replace comma
                category = ""
                if 'tags' in task:
                    name = "%s, %s " % (name, " ".join(task['tags']))

                if 'project' in task:
                    category = task['project']

                activities.append({"name":name,"category":category})

            return activities
Esempio n. 3
0
    def __init__(self):
        locale.setlocale(locale.LC_CTYPE, "")
        self.window = curses.initscr()
        curses.noecho()
        curses.cbreak()
        self.window.keypad(1)
        self.window.clear()
        self.window.border()

        self.lines, self.cols = self.window.getmaxyx()
        self.day_width = self.cols // 7
        self.day_height = (self.lines - 2) // 6

        self.task_warrior = TaskWarrior(marshal=True)
        pending_tasks = self.task_warrior.load_tasks()['pending']
        self.tasks = {}
        now = datetime.now()
        timezone = LocalTimezone()
        self.offset = timezone.utcoffset(now)
        for task in pending_tasks:
            if 'due' not in task:
                continue
            due = task['due'] + self.offset
            current_date = date(due.year, due.month, due.day)
            if current_date not in self.tasks:
                self.tasks[current_date] = list()
            self.tasks[current_date].append(task)
Esempio n. 4
0
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'])
Esempio n. 5
0
def synchronize(issues):
    tw = TaskWarrior()

    # Load info about the task database
    tasks = tw.load_tasks()
    is_bugwarrior_task = lambda task: task['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(), [])]

    # 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)

    # 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))

    for issue in new_issues:
        log.info("Adding task {0}", issue['description'])
        tw.task_add(**issue)

    for task in done_tasks:
        log.info("Completing task {0}", task['description'])
        tw.task_done(id=None, uuid=task['uuid'])
Esempio n. 6
0
    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)
Esempio n. 7
0
def add_taskwarrior_task(current_balance, tags, priority='M'):
    ''' Add or update the taskwarrior task. If a task with the description given
        in TASK_DESC and the given tags already exists. The task description will be
        updated to the value of the current_balance if changed. Otherwise a new
        task will be added.
    '''

    task_filter = {'tags': tags,
                   'description': TASK_DESC}
    desc = " ".join([TASK_DESC, str(current_balance)])
    tw = TaskWarrior()

    task = tw.filter_tasks(task_filter)
    if task:
        old_desc = task['description']
        old_balance = float(old_desc.split()[-1])
        if current_balance < old_balance:
            task.update({'description': desc,
                         'priority': priority})
            tw.task_update(task)
    else:
        tw.task_add(desc, tags=tags, priority=priority)
Esempio n. 8
0
#! /usr/bin/python3
from taskw import TaskWarrior
from myschool_student import *
import re

if __name__ == "__main__":
    tw = TaskWarrior()
    assignment_list = get_assignment_list()
    tasks = tw.load_tasks()["pending"]
    for asg in assignment_list:
        if asg.handin:
            continue
        courseid = asg.courseid[6:]
        taskdescr = "{}: {}".format(courseid, asg.name)
        if not any([taskdescr in t.values() for t in tasks]):
            tw.task_add(taskdescr, project="homework:" + courseid, due=asg.due_datetime)
            print("Task due: {}".format(int(asg.due_datetime.timestamp())))
            print('taskw: Adding task "{}"'.format(taskdescr))
        elif asg.handin:
            print('taskw: Moving task "{}" completed.'.format(taskdescr))
            tw.task_done(task)
Esempio n. 9
0
def complete_task(tw: TaskWarrior, task: Dict[str, Any]) -> None:
    r = tw.task_done(webdesk_key=task['webdesk_key'])
    logger.log(logging.INFO + 5, 'Completed task: %s', r['description'])
Esempio n. 10
0
from taskw import TaskWarrior

w = TaskWarrior()
tasks = w.load_tasks()

# replace_tags = {
#     'trello_prio:_high': 'trello_high_priority',
#     'trello_prio:_med': 'trello_medium_priority',
#     'trello_prio:_low': 'trello_low_priority',
#     'github_awaiting____': 'github_awaiting',
# }

done_trello_lists = [
    "PR Sent",
    "Merged in Develop",
    "Merged in Candidate",
    "Merged in Master",
    "Merged in Release",
    "Done",
]

replace_projects = {
    "Project Cinnamon": "cinnamon",
    "Development: Backend Services": "services",
    "Merchant Widget": "widget",
    "Development: Adgo App": "monolith",
}

priority_map = {
    "trello_high_priority": "H",
    "trello_medium_priority": "M",
Esempio n. 11
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"])
def find_taskwarrior_from_azure_devops_id(work_item_id, task_list):
    return [t for t in task_list if t['description'].startswith(str(work_item_id))]


def format_description(desc, tag_list):
    for keyword, tag in keyword_tag_replace_map.items():
        desc, count = re.subn(r'[/\s[]*\b' + keyword + r'\b[]/\s]*', '', desc, flags=re.IGNORECASE)
        if count and tag:
            tag_list.append(tag)

    return desc if len(desc) <= max_description_length else f"{desc[:max_description_length]}..."


# Task Warrior tasks load.
task_warrior = TaskWarrior()

print(f'Loading "{project}" Task warriors pending tasks ...')
tw_tasks = get_taskwarrior_tasks(project.lower())
print(f'Found {len(tw_tasks)} tasks.')

# Azure Devops current sprint's tasks load.
print(f'Loading "{project}" Azure Devops work items ...')
work_items = get_azure_devops_work_items(project, current_sprint, assignee)
print(f'Found {len(work_items)} work items.')

for work_item in work_items:
    # Checks if there is already a time warrior task for this Azure Devops item.
    existing_tw = find_taskwarrior_from_azure_devops_id(work_item['id'], tw_tasks)

    if existing_tw:
Esempio n. 13
0
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)
Esempio n. 14
0
def get_taskwarrior_instance():
    return TaskWarrior(marshal=True)
            task.get("urgency"),
            task.get("entry").date(),
            task.get("due").date() if task.get("due") else "",
            task.get("end").date() if task.get("end") else "",
            task.get("project", " ").strip(),
            ",".join(task.get("tags", [])),
            task.get("description").strip(),
            task.get("jira", ""),
        ])

    print(table)


if __name__ == "__main__":
    # TODO: Wrap this in a main() method.
    task_client = TaskWarrior(marshal=True)
    today = date.today()
    yesterday = date.today() + relativedelta(days=-1)

    print(f"Daily Standup Report for {today}")
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print("")
    print("Yesterday's Completed Tasks")
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print("")
    completed_tasks = get_completed_tasks(task_client=task_client,
                                          start_date=yesterday,
                                          end_date=today)
    print_task_table(completed_tasks)

    overdue_tasks = filter_tasks(
Esempio n. 16
0
class TW_Loader:

    symbol = "*"

    def __init__(self, config=None):
        if config is not None:
            self.w = TaskWarrior(config_filename=config)
        else:
            self.w = TaskWarrior()
        self.refresh_tasks()

    def refresh_tasks(self):
        self.tasks = self.w.load_tasks()
        pending = self.tasks['pending']
        # newlist = sorted(pending, key=itemgetter('project', 'urgency'), reverse=True) #reverse=True sorts descending
        self.tasks = {}
        self.task_tables = {}
        for task in pending:
            pr = 'unassigned'
            if 'project' in task:
                pr = task['project']
            if pr in self.tasks:
                self.tasks[pr].append(task)
            else:
                self.tasks[pr] = []
                self.tasks[pr].append(task)
        #create tables from sorted tasks
        for project in self.tasks.keys():
            table = TaskTable(self.tasks[project])
            self.task_tables[project] = table

    def get_tasks(self, project=None):
        if project is None:
            return self.tasks
        elif project in self.tasks:
            return self.tasks[project]
        else:
            return None

    def add_task(self, text):
        #positive lookbehind to match and extract terms
        #task MUST come before project
        task = re.search("(?<=task:)(?:(?!project:).)*", text)
        project = re.search("(?<=project:)\w+", text)
        tags = re.findall("\+(\S+)", text)
        urgency = re.search("(?<=urgency:)\w+", text)
        due = re.search("(?<=due:).*?(?=\s)", text)
        parsed_task = {}
        if project is not None:
            project = project.group().strip()
        if urgency is not None:
            urgency = urgency.group().strip().upper()
        if task is not None:
            task = task.group().strip()
        if due is not None:
            due = due.group().strip()
            #TODO convert to epoch
        print(urgency)
        self.w.task_add(task, project=project, tags=tags, priority=urgency)
        self.refresh_tasks()
        parsed_task['task'] = task
        parsed_task['project'] = project
        parsed_task['urgency'] = urgency
        parsed_task['tags'] = tags
        return parsed_task

    def print_tasks(self):
        for project in self.tasks.keys():
            proj = "* {0} *".format(project)
            print(proj)
            print("*" * len(proj))
            print(
                tabulate(self.tasks[project], headers="keys", tablefmt="pipe"))
            print()

    def get_tables(self, project=None):
        if project is None:
            return self.task_tables
        elif project in self.tasks:
            table = TaskTable(self.tasks[project])
            return table
        else:
            return None
class ProjectManager:
    def __init__(self):
        self.home_dir = str(Path.home())
        self.EDITOR = os.environ.get('EDITOR', 'vim')
        PERSONAL_FOLDER = os.environ.get('PERSONAL_DIRECTORY', 'personal')
        self.w = TaskWarrior()
        self.tasks = self.w.load_tasks()
        self.personal_dir = '{}/core/{}'.format(self.home_dir, PERSONAL_FOLDER)

    def project_min(self):
        filedir = '{}/project_notes'.format(self.personal_dir)
        filename = 'MINIMUM'

        self.modify_file(
            filename,
            filedir,
        )

    def project_note(
        self,
        project,
        description,
    ):
        base_dir = '{personal_dir}/project_notes'.format(
            personal_dir=self.personal_dir)

        filedir = self.get_full_dir_path(base_dir, project)
        filename = description
        if not filename:
            files = (_file for _file in os.listdir(filedir)
                     if os.path.isfile(os.path.join(filedir, _file)))
            print("Notes for this project:\n")
            for _file in files:
                print(_file)
        else:
            self.modify_file(
                filename,
                filedir,
                filename,
            )

    def project_dev_setup(
        self,
        project,
    ):
        base_dir = '{personal_dir}/projects'.format(
            personal_dir=self.personal_dir)

        filedir = self.get_full_dir_path(base_dir, project)

        readme = '{filedir}/README'.format(filedir=filedir)
        data = '{filedir}/data'.format(filedir=filedir)
        data_readme = '{filedir}/data/README'.format(filedir=filedir)
        poc = '{filedir}/poc'.format(filedir=filedir)
        prod = '{filedir}/prod'.format(filedir=filedir)
        utils = '{filedir}/utils'.format(filedir=filedir)
        utils_readme = '{filedir}/utils/README'.format(filedir=filedir)

        call(['mkdir', data])
        call(['touch', data_readme])
        call(['mkdir', poc])
        call(['mkdir', prod])
        call(['touch', readme])
        call(['mkdir', utils])
        call(['touch', utils_readme])

    def get_task_id(
        self,
        project,
    ):
        project_id = jsonpath(
            self.tasks,
            "$..[?(@.description=='{project}')].id".format(project=project))
        return project_id[0]

    def get_full_dir_path(
        self,
        base_dir,
        project,
        final_dir=None,
    ):
        if final_dir:
            full_dir_path = '{project}/{final_dir}'.format(
                project=project,
                final_dir=final_dir,
            )
        else:
            full_dir_path = project

        project_id = jsonpath(
            self.tasks,
            "$..[?(@.description=='{project}')].uuid".format(project=project))
        current_id = jsonpath(
            self.tasks, "$..[?('{}' in @.depends)].uuid".format(project_id[0]))
        while current_id:
            parent_project = jsonpath(
                self.tasks,
                "$..[?(@.uuid=='{}')].description".format(current_id[0]))
            full_dir_path = '{project}/{path}'.format(
                project=parent_project[0], path=full_dir_path)
            current_id = jsonpath(
                self.tasks,
                "$..[?('{}' in @.depends)].uuid".format(current_id[0]))

        full_dir_path = '{base_dir}/{path}'.format(base_dir=base_dir,
                                                   path=full_dir_path)
        call(['mkdir', '-p', full_dir_path])
        return full_dir_path

    def create_file(
        self,
        filename,
        filedir,
        defaulttext='',
    ):

        filepath = '{0}/{1}'.format(
            filedir,
            filename,
        )
        with open(filepath, 'w') as _in:
            _in.write(defaulttext)
            _in.flush()
            call([self.EDITOR, _in.name])

    def modify_file(
        self,
        filename,
        filedir,
        defaulttext='',
    ):
        filepath = '{0}/{1}'.format(
            filedir,
            filename,
        )
        if filename in os.listdir(filedir):
            with open(filepath, 'r') as _in:
                call([self.EDITOR, _in.name])
        else:
            self.create_file(
                filename,
                filedir,
                defaulttext,
            )
Esempio n. 18
0
from taskw import TaskWarrior
import time

logfile = "/home/noon/Dropbox/Public/taskwarrior.txt"

def write_log (active):
    with open(logfile, "w") as f:
        if not active or len(active) == 0:
            print("unknown", file=f)
            return

        # otherwise, print everything
        for (p, d) in active:
            print("%s, %s" % (p, d), file=f)

if __name__ == "__main__":
    w = TaskWarrior()
    tasks = w.load_tasks()['pending']

    def display_time (epoch):
        return time.strftime("%a %d %b %Y, %I:%M:%S %p", time.localtime(float(epoch)))

    def maybe_proj (t):
        if 'project' in t:
            return t['project']
        else:
            return 'something'

    active = [ (maybe_proj(t), display_time(t['start'])) for t in tasks if 'start' in t ]
    write_log(active)
import copy
from taskw import TaskWarrior

URL = 'https://habitica.com/api/v3'

if len(sys.argv) == 1:
    print "The Habitica hook does not work with TaskWarrior API v1, please upgrade to Taskwarrior 2.4.3 or higher"
    sys.exit(0)

if not sys.argv[1] == "api:2":
    print "The Habitica hook only supports TaskWarrior API v2 at this time"
    sys.exit(0)

configarg = sys.argv[4]
configfile = configarg[3:]
w = TaskWarrior(config_filename=configfile)
config = w.load_config()
API_KEY = config['habitica']['api_key']
API_USER = config['habitica']['api_user']

headers = {
    'Content-Type': 'application/json',
    'x-api-user': API_USER,
    'x-api-key': API_KEY
}


def main():
    jsonTaskOriginal = json.loads(sys.stdin.readline())
    jsonTask = json.loads(sys.stdin.readline())
#!/usr/bin/python
from datetime import time, datetime, timedelta
from taskw import TaskWarrior
from pytz import timezone, utc

CONFIG = TaskWarrior.load_config()
if 'dst' in CONFIG['default']:
    if CONFIG['default']['dst'].lower() in ['true', '1', 'yes']:
        dst = True
    else:
        dst = False

if 'timezone' in CONFIG['default']:
    DEFAULT_ZONE = timezone(CONFIG['default']['timezone'])
else:
    DEFAULT_ZONE = utc

if 'time' in CONFIG["default"]:
    DEFAULT_TIME = datetime.strptime(CONFIG['default']['time'], u'%H:%M').time()
else:
    DEFAULT_TIME = time(0, 0, 0, 0, DEFAULT_ZONE)

def is_local_midnight(timestamp):
    tmp = utc.localize(timestamp).astimezone(DEFAULT_ZONE)
    return tmp.time() == time(0, 0, 0)

def set_default_time(timestamp):
    utcoffset = DEFAULT_ZONE.utcoffset(timestamp, is_dst=dst).days * 24 + DEFAULT_ZONE.utcoffset(timestamp, is_dst=dst).seconds / 3600

    tmp = timestamp.replace(
        hour=DEFAULT_TIME.hour,
Esempio n. 21
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
from taskw import TaskWarrior

label = '◔'
ret = {
    'name': 'taskwarrior',
    'align': 'left',
    'label': label
}
w = TaskWarrior()

context = w.config["context"]

active = w.filter_tasks({'start.isnt': None})
if active:
    ret['short_text'] = str(active[0]['id'])
    ret['full_text'] = str.format("{0}{1[id]}: {1[description]}", label, active[0])
else:
    ret['short_text'] = ""
    ret['full_text'] = "none"

#if context == 'work':
#  print(json.dumps(ret))

print(json.dumps(ret, ensure_ascii=False))
Esempio n. 22
0
        return utils.parse_recur(due)
    except errors.UnsupportedRecurrence:
        io.error("Unsupported recurrence: '%s'. Please enter a valid value" %
                 due['string'])
        return io.prompt(
            'Set recurrence (todoist style)',
            default='',
            value_proc=validation.validate_recur,
        )


""" Entrypoint """

if __name__ == '__main__':
    is_help_cmd = '-h' in sys.argv or '--help' in sys.argv
    todoist_api_key = os.getenv('TODOIST_API_KEY')
    if todoist_api_key is None and not is_help_cmd:
        io.error(
            'TODOIST_API_KEY environment variable not specified. Exiting.')
        exit(1)

    todoist = TodoistAPI(todoist_api_key, cache=TODOIST_CACHE)

    # Create the TaskWarrior client, overriding config to
    # create a `todoist_id` field which we'll use to
    # prevent duplicates
    taskwarrior = TaskWarrior(config_overrides={
        'uda.todoist_id.type': 'string',
    })
    cli()
Esempio n. 23
0
 def __init__(self, config=None):
     if config is not None:
         self.w = TaskWarrior(config_filename=config)
     else:
         self.w = TaskWarrior()
     self.refresh_tasks()
Esempio n. 24
0
class CursesTask(object):
    def __init__(self):
        locale.setlocale(locale.LC_CTYPE, "")
        self.window = curses.initscr()
        curses.noecho()
        curses.cbreak()
        self.window.keypad(1)
        self.window.clear()
        self.window.border()

        self.lines, self.cols = self.window.getmaxyx()
        self.day_width = self.cols // 7
        self.day_height = (self.lines - 2) // 6

        self.task_warrior = TaskWarrior(marshal=True)
        pending_tasks = self.task_warrior.load_tasks()['pending']
        self.tasks = {}
        now = datetime.now()
        timezone = LocalTimezone()
        self.offset = timezone.utcoffset(now)
        for task in pending_tasks:
            if 'due' not in task:
                continue
            due = task['due'] + self.offset
            current_date = date(due.year, due.month, due.day)
            if current_date not in self.tasks:
                self.tasks[current_date] = list()
            self.tasks[current_date].append(task)

    def run(self, show_date=datetime.now()):
        self.draw_header()
        first_day, last_day = calendar.monthrange(
            show_date.year,
            show_date.month
        )
        number_of_days = first_day + last_day
        number_of_weeks = (number_of_days // 7)
        if (number_of_weeks * 7) < number_of_days:
            number_of_weeks += 1
        self.day_height = (self.lines - 1) // number_of_weeks
        for day in range(1, last_day+1):
            self.draw_day(show_date.year, show_date.month, day)
        self.window.getch()

    def uninit(self):
        curses.nocbreak()
        self.window.keypad(0)
        curses.echo()
        curses.endwin()

    def draw_header(self):
        self.window.addstr(0, 2, datetime.now().strftime('%B %Y'))
        for day in range(7):
            top_x = day * self.day_width + (self.day_width // 2) - 3
            self.window.addstr(1, top_x, calendar.day_name[day])

    def draw_day(self, year, month, day):
        first_day, last_day = calendar.monthrange(year, month)
        current_day = first_day + day - 1
        week = current_day // 7
        top_y = 2 + week * self.day_height
        top_x = (current_day % 7) * self.day_width
        bottom_y = top_y + self.day_height
        bottom_x = top_x + self.day_width
        curses.textpad.rectangle(self.window, top_y, top_x, bottom_y, bottom_x)

        label_top_y = top_y
        label_top_x = top_x + 2
        label = str(day) + '.'
        self.window.addstr(label_top_y, label_top_x, label)

        date_key = date(year, month, day)
        if date_key in self.tasks:
            tasks = self.tasks[date_key]
        else:
            tasks = list()
        self.day_content(top_y, top_x, tasks)

    def day_content(self, top_y, top_x, tasks):
        offset_y = 1
        for task in tasks:
            y = top_y + offset_y
            x = top_x + 1
            due = task['due'] + self.offset
            description = '{} {}'.format(
                due.strftime('%H:%M'),
                task['description'].encode('utf-8')[:self.day_width-7]
            )
            self.window.addstr(y, x, description)
            offset_y += 1
Esempio n. 25
0
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)

    def test_completion_raising_unspecified(self):
        try:
            self.tw.task_done()
            assert False
        except KeyError:
            assert True

    def test_completing_task_by_id_unspecified(self):
        self.tw.task_add("foobar")
        self.tw.task_done(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_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_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)
Esempio n. 26
0
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)

    def test_completion_raising_unspecified(self):
        try:
            self.tw.task_done()
            assert False
        except KeyError:
            assert True

    def test_completing_task_by_id_unspecified(self):
        self.tw.task_add("foobar")
        self.tw.task_done(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_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_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)
Esempio n. 27
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#strings to translate
strListAll = "Zobrazit všechny úkoly"

from taskw import TaskWarrior
w = TaskWarrior()
tasks = w.load_tasks()
tasksPending = (tasks['pending'])
lot = len(tasksPending)


def render_tasks():

    rend = str(lot)
    rend = rend + "|iconName=task-past-due-symbolic-symbolic \n---\n"

    for i in range(len(tasks['pending'])):
        rend = rend + tasks['pending'][i][
            'description'] + " | bash='task " + str(i + 1) + "'" + '\n'
        # str(tasks['pending'][i]['tags']) +"\n"

    rend = rend + "---\n <span weight='bold'>" + strListAll + "</span> | bash='task' iconName=task-past-due-symbolic-symbolic"
    return rend


print(render_tasks())
#!/usr/bin/env python
import datetime
import json
import re
import sys
import subprocess
from taskw import TaskWarrior

TIME_FORMAT = '%Y%m%dT%H%M%SZ'
UDA_KEY = 'totalactivetime'

w = TaskWarrior()
config = w.load_config()
if ('max_active_tasks' in config):
    MAX_ACTIVE = int(config['max_active_tasks'])
else:
    MAX_ACTIVE = 1

ISO8601DURATION = re.compile(
    "P((\d*)Y)?((\d*)M)?((\d*)D)?T((\d*)H)?((\d*)M)?((\d*)S)?")

# Convert duration string into a timedelta object.
# Valid formats for duration_str include
# - int (in seconds)
# - string ending in seconds e.g "123seconds"
# - ISO-8601: e.g. "PT1H10M31S"
def duration_str_to_time_delta(duration_str):
    if (duration_str.startswith("P")):
        match = ISO8601DURATION.match(duration_str)
        if (match):
            year = match.group(2)
#!/usr/bin/env python
import datetime
import json
import sys
import subprocess
from taskw import TaskWarrior

TIME_FORMAT = '%Y%m%dT%H%M%SZ'
UDA_KEY = 'totalactivetime'

w = TaskWarrior()
config = w.load_config()
if ('max_active_tasks' in config):
    MAX_ACTIVE = int(config['max_active_tasks'])
else:
    MAX_ACTIVE = 1


def main():
    original = json.loads(sys.stdin.readline())
    modified = json.loads(sys.stdin.readline())

    # An inactive task has just been started.
    if 'start' in modified and 'start' not in original:
        # Check if `task +ACTIVE count` is greater than MAX_ACTIVE. If so
        # prevent this task from starting.
        p = subprocess.Popen(
            ['task', '+ACTIVE', 'status:pending', 'count', 'rc.verbose:off'],
            stdout=subprocess.PIPE)
        out, err = p.communicate()
        count = int(out.rstrip())