Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly handles custom priorities #304

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion taskwiki/regexp.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
DUE = r'(?P<due>{0})'.format(DUE_UNNAMED)
TEXT = r'(?P<text>.+?)'
COMPLETION_MARK = r'(?P<completed>.)'
PRIORITY = r'(?P<priority>!{1,3})'
PRIORITY = r'(?P<priority>!+|¡+)'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan of the reversed exclamation mark - while it really does look cool, it is not straightforward to type on the keyboard. I'm wondering if there is not a different symbol we could use that would naturally convey the meaning of lower priority.


GENERIC_TASK = re.compile(''.join([
'^',
Expand Down
24 changes: 23 additions & 1 deletion taskwiki/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,32 @@ def __init__(self, default_rc, default_data, extra_warrior_defs):
current_kwargs.update(extra_warrior_defs[key])
self.warriors[key] = TaskWarrior(**current_kwargs)

# Make sure context is not respected in any TaskWarrior
for tw in self.warriors.values():
# Make sure context is not respected in any TaskWarrior
tw.overrides.update({'context':''})

# Read urgency levels once instead of at every task processing.
_urgency_levels = tw.config.get("uda.priority.values") or "H,M,L,"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue urgency_levels is not a fortunate name here, as urgency already has a meaning in TW ecosystem which is distinct from priority.

tw._config = None # unset the config cache
_urgency_levels = _urgency_levels.split(",")
_urgency_levels.reverse()

# The empty urgency (priority:) is considered the zero point.
# Priorities left of it in taskwarrior's conf are considered values
# of insignificance, i.e. they have a negative weight.
zero_point = _urgency_levels.index('')
keys = [i - zero_point for i in range(0, len(_urgency_levels))]

urgency_levels = {k:_urgency_levels[i] for i, k in enumerate(keys)}
urgency_levels[0] = None
# urgency_levels[None] = None
# For the default urgency levels, this will be:
# {0: None, 1: 'L', 2: 'M', 3: 'H'}

# Urgency levels need to be stored in the respective TaskWarrior
# instance as they are specific to it.
tw.urgency_levels = urgency_levels

def __getitem__(self, key):
try:
return self.warriors[key]
Expand Down
32 changes: 18 additions & 14 deletions taskwiki/vwtask.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@
from taskwiki.short import ShortUUID


def convert_priority_from_tw_format(priority):
return {None: None, 'L': 1, 'M': 2, 'H': 3}[priority]


def convert_priority_to_tw_format(priority):
return {0: None, 1: 'L', 2: 'M', 3: 'H'}[priority]


class VimwikiTask(object):
# Lists all data keys that are reflected in Vim representation
buffer_keys = ('indent', 'description', 'uuid', 'completed_mark',
Expand Down Expand Up @@ -106,9 +98,11 @@ def from_line(cls, cache, number):
else:
self.task['description'] = match.group('text')

self.task['priority'] = convert_priority_to_tw_format(
len(match.group('priority') or [])) # This is either 0,1,2 or 3

self.task['priority'] = tw.urgency_levels.get(
0 if match.group('priority') is None
else len(match.group('priority')) if '!' in match.group('priority')
else -len(match.group('priority')) # if '¡' in match.group('priority')
)
# Also make sure changes in the progress field are reflected
if self['completed_mark'] == 'X':
self.task['status'] = 'completed'
Expand Down Expand Up @@ -241,11 +235,13 @@ def task(self, task):

@property
def priority_from_tw_format(self):
return convert_priority_from_tw_format(self.task['priority'])
return list(self.tw.urgency_levels.keys())[
list(self.tw.urgency_levels.values()).index(self.task["priority"])
]

@property
def priority_to_tw_format(self):
return convert_priority_to_tw_format(self['priority'])
return self.tw.urgency_levels[self['priority']]

def save_to_tw(self):
# This method persumes all the dependencies have been created at the
Expand Down Expand Up @@ -328,14 +324,22 @@ def __str__(self):
self['due'].strftime(regexp.DATE_FORMAT)
) if self['due'] else ''

priority_str = (
" " + "!" * self.priority_from_tw_format
if self["priority"] and self.priority_from_tw_format > 0
else " " + "¡" * self.priority_from_tw_format
if self["priority"] and self.priority_from_tw_format < 0
else ""
)

return ''.join([
self['indent'],
'* [',
self['completed_mark'],
'] ',
(self['description'].encode('utf-8') if six.PY2 else self['description'])
if self['description'] else 'TEXT MISSING?',
' ' + '!' * self.priority_from_tw_format if self['priority'] else '',
priority_str,
due_str,
' #' + self.uuid.vim_representation(self.cache) if self.uuid else '',
])
Expand Down
29 changes: 29 additions & 0 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,32 @@ def reset(self):
self.warriors.clear()
self.warriors.update({'default': 'default'})
self.buffer_has_authority = True

class MockCacheWithPriorities(object):
default_urgency_levels = {0: None, 1: 'L', 2: 'M', 3: 'H'}

# Create a warrior object on the fly
warriors = {"default": type("", (object,), {"urgency_levels": {}},)()}

buffer_has_authority = True

def __init__(self, urgency_levels=None):
from taskwiki import store
self.urgency_levels = urgency_levels
self.warriors['default'].urgency_levels = urgency_levels or self.default_urgency_levels
self.buffer = MockBuffer()
self.line = store.LineStore(self)
self.vwtask = dict()
self.task = dict()
self.viewport = dict()

def reset(self):
self.warriors.clear()
self.warriors.update(
{
"default": type(
"", (object,), {"urgency_levels": self.urgency_levels}
)()
}
)
self.buffer_has_authority = True
82 changes: 77 additions & 5 deletions tests/test_vwtask_parsing.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from tests.base import MockVim, MockCache
from tests.base import MockVim, MockCacheWithPriorities
import sys

from tasklib import local_zone

class TestParsingVimwikiTask(object):
def setup(self):
self.mockvim = MockVim()
self.cache = MockCache()
self.cache = MockCacheWithPriorities()
sys.modules['vim'] = self.mockvim
from taskwiki.vwtask import VimwikiTask
self.VimwikiTask = VimwikiTask
Expand Down Expand Up @@ -56,23 +56,23 @@ def test_due_short(self):
assert vwtask['priority'] == None
assert vwtask['indent'] == ''

def test_priority_low(self):
def test_default_priority_low(self):
self.cache.buffer[0] = "* [ ] Semi-Important task !"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Semi-Important task"
assert vwtask['priority'] == 'L'
assert vwtask['uuid'] == None

def test_priority_medium(self):
def test_default_priority_medium(self):
self.cache.buffer[0] = "* [ ] Important task !!"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Important task"
assert vwtask['priority'] == 'M'
assert vwtask['uuid'] == None

def test_priority_high(self):
def test_default_priority_high(self):
self.cache.buffer[0] = "* [ ] Very important task !!!"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

Expand All @@ -81,6 +81,78 @@ def test_priority_high(self):
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_0(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task ¡¡"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == 0
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_L(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task ¡"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == 'L'
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_none(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == None
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_M(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task !"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == 'M'
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_H(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task !!"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == 'H'
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_custom_priority_no_three_exclamations(self):
self.cache = MockCacheWithPriorities({
-2: 0, -1: 'L', 0: None, 1: 'M', 2: 'H'
})
self.cache.buffer[0] = "* [ ] Very important task !!!"
vwtask = self.VimwikiTask.from_line(self.cache, 0)

assert vwtask['description'] == u"Very important task"
assert vwtask['priority'] == None
assert vwtask['uuid'] == None
assert vwtask['due'] == None

def test_priority_and_due(self):
self.cache.buffer[0] = "* [ ] Due today !!! (2015-08-08)"
vwtask = self.VimwikiTask.from_line(self.cache, 0)
Expand Down