From: Rob Golding Date: Fri, 20 Jan 2017 21:13:55 +0000 (+0000) Subject: Merge branch 'release/1.1.0' X-Git-Url: https://git.madduck.net/etc/taskwarrior.git/commitdiff_plain/2fd5546d721efa71544cbf028af6fb99d382426b?hp=7f87b5702df2d0dd3b0d1d1c546ba5db490c3860 Merge branch 'release/1.1.0' --- diff --git a/.travis.yml b/.travis.yml index 721c530..c7e0834 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,12 +10,14 @@ env: - TASK_VERSION=v2.4.3 - TASK_VERSION=v2.4.4 - TASK_VERSION=v2.5.0 - - TASK_VERSION=2.5.1 + - TASK_VERSION=v2.5.1 + - TASK_VERSION=2.6.0 python: - "2.7" - "3.3" - "3.4" - "3.5" + - "3.6" install: - pip install -e . - pip install coveralls @@ -23,12 +25,14 @@ install: - sudo apt-get update -qq - sudo apt-get install -qq build-essential cmake uuid-dev g++-4.8 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50 - - git clone https://git.tasktools.org/scm/tm/task.git + - git clone --recursive https://git.tasktools.org/scm/tm/task.git - cd task - git checkout $TASK_VERSION - git clean -dfx - - cmake . - - make + - git submodule init + - git submodule update + - cmake -DCMAKE_BUILD_TYPE=release . + - make -j2 - sudo make install - task --version before_script: diff --git a/LICENSE b/LICENSE index 87b8f3e..72fd2d9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013, Rob Golding. All rights reserved. +Copyright (c) 2013-2017, Rob Golding. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/docs/conf.py b/docs/conf.py index 2da9bac..596f56b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ copyright = u'2014, Rob Golding' # built documents. # # The short X.Y version. -version = '1.0.0' +version = '1.1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.0' +release = '1.1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 2b09f1b..360504e 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages install_requirements = ['six>=1.4', 'pytz', 'tzlocal'] -version = '1.0.0' +version = '1.1.0' try: import importlib diff --git a/tasklib/backends.py b/tasklib/backends.py index 6e7d918..1e1b8c4 100644 --- a/tasklib/backends.py +++ b/tasklib/backends.py @@ -132,7 +132,10 @@ class TaskWarrior(Backend): overrides.update(config_override or dict()) for item in overrides.items(): command_args.append('rc.{0}={1}'.format(*item)) - command_args.extend(map(six.text_type, args)) + command_args.extend([ + x.decode('utf-8') if isinstance(x, six.binary_type) + else six.text_type(x) for x in args + ]) return command_args def _get_version(self): @@ -171,11 +174,17 @@ class TaskWarrior(Backend): if task.saved: for field in task._modified_fields: add_field(field) + # For new tasks, pass all fields that make sense else: for field in task._data.keys(): + # We cannot set stuff that's read only (ID, UUID, ..) if field in task.read_only_fields: continue + # We do not want to do field deletion for new tasks + if task._data[field] is None: + continue + # Otherwise we're fine add_field(field) return args @@ -242,7 +251,7 @@ class TaskWarrior(Backend): ) config = dict() - config_regex = re.compile(r'^(?P[^\s]+)\s+(?P[^\s].+$)') + config_regex = re.compile(r'^(?P[^\s]+)\s+(?P[^\s].*$)') for line in raw_output: match = config_regex.match(line) @@ -258,7 +267,8 @@ class TaskWarrior(Backend): return_all=False): command_args = self._get_command_args( args, config_override=config_override) - logger.debug(' '.join(command_args)) + logger.debug(u' '.join(command_args)) + p = subprocess.Popen(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = [x.decode('utf-8') for x in p.communicate()] @@ -267,6 +277,7 @@ class TaskWarrior(Backend): error_msg = stderr.strip() else: error_msg = stdout.strip() + error_msg += u'\nCommand used: ' + u' '.join(command_args) raise TaskWarriorException(error_msg) # Return all whole triplet only if explicitly asked for diff --git a/tasklib/lazy.py b/tasklib/lazy.py index a1b63ef..f9e0c0a 100644 --- a/tasklib/lazy.py +++ b/tasklib/lazy.py @@ -36,6 +36,9 @@ class LazyUUIDTask(object): # For saved Tasks, just define equality by equality of uuids return self['uuid'] == other['uuid'] + def __ne__(self, other): + return not self.__eq__(other) + def __hash__(self): return self['uuid'].__hash__() diff --git a/tasklib/task.py b/tasklib/task.py index 5eabc65..c7c9e6d 100644 --- a/tasklib/task.py +++ b/tasklib/task.py @@ -13,6 +13,9 @@ DATE_FORMAT = '%Y%m%dT%H%M%SZ' REPR_OUTPUT_SIZE = 10 PENDING = 'pending' COMPLETED = 'completed' +DELETED = 'deleted' +WAITING = 'waiting' +RECURRING = 'recurring' logger = logging.getLogger(__name__) @@ -165,6 +168,9 @@ class TaskAnnotation(TaskResource): # their data dics are the same return self.task == other.task and self._data == other._data + def __ne__(self, other): + return not self.__eq__(other) + __repr__ = __unicode__ @@ -277,6 +283,9 @@ class Task(TaskResource): # If the tasks are not saved, compare the actual instances return id(self) == id(other) + def __ne__(self, other): + return not self.__eq__(other) + def __hash__(self): if self['uuid']: # For saved Tasks, just define equality by equality of uuids @@ -301,6 +310,10 @@ class Task(TaskResource): def pending(self): return self['status'] == six.text_type('pending') + @property + def recurring(self): + return self['status'] == six.text_type('recurring') + @property def active(self): return self['start'] is not None @@ -504,6 +517,15 @@ class TaskQuerySet(object): def completed(self): return self.filter(status=COMPLETED) + def deleted(self): + return self.filter(status=DELETED) + + def waiting(self): + return self.filter(status=WAITING) + + def recurring(self): + return self.filter(status=RECURRING) + def filter(self, *args, **kwargs): """ Returns a new TaskQuerySet with the given filters added. diff --git a/tasklib/tests.py b/tasklib/tests.py index be54504..3e60ac0 100644 --- a/tasklib/tests.py +++ b/tasklib/tests.py @@ -81,6 +81,39 @@ class TaskFilterTest(TasklibTest): self.tw.tasks.all()[0].done() self.assertEqual(len(self.tw.tasks.completed()), 1) + def test_deleted_empty(self): + Task(self.tw, description="test task").save() + self.assertEqual(len(self.tw.tasks.deleted()), 0) + + def test_deleted_non_empty(self): + Task(self.tw, description="test task").save() + self.assertEqual(len(self.tw.tasks.deleted()), 0) + self.tw.tasks.all()[0].delete() + self.assertEqual(len(self.tw.tasks.deleted()), 1) + + def test_waiting_empty(self): + Task(self.tw, description="test task").save() + self.assertEqual(len(self.tw.tasks.waiting()), 0) + + def test_waiting_non_empty(self): + Task(self.tw, description="test task").save() + self.assertEqual(len(self.tw.tasks.waiting()), 0) + + t = self.tw.tasks.all()[0] + t['wait'] = datetime.datetime.now() + datetime.timedelta(days=1) + t.save() + + self.assertEqual(len(self.tw.tasks.waiting()), 1) + + def test_recurring_empty(self): + Task(self.tw, description="test task").save() + self.assertEqual(len(self.tw.tasks.recurring()), 0) + + def test_recurring_non_empty(self): + Task(self.tw, description="test task", recur="daily", + due=datetime.datetime.now()).save() + self.assertEqual(len(self.tw.tasks.recurring()), 1) + def test_filtering_by_attribute(self): Task(self.tw, description="no priority task").save() Task(self.tw, priority="H", description="high priority task").save() @@ -581,6 +614,23 @@ class TaskTest(TasklibTest): t2 = self.tw.tasks.get(uuid=t1['uuid']) self.assertEqual(t1.__hash__(), t2.__hash__()) + def test_hash_unequal_unsaved_tasks(self): + # Compare the hash of the task using two different objects + t1 = Task(self.tw, description="test task 1") + t2 = Task(self.tw, description="test task 2") + + self.assertNotEqual(t1.__hash__(), t2.__hash__()) + + def test_hash_unequal_saved_tasks(self): + # Compare the hash of the task using two different objects + t1 = Task(self.tw, description="test task 1") + t2 = Task(self.tw, description="test task 2") + + t1.save() + t2.save() + + self.assertNotEqual(t1.__hash__(), t2.__hash__()) + def test_adding_task_with_priority(self): t = Task(self.tw, description="test task", priority="M") t.save() @@ -1165,6 +1215,7 @@ class LazyUUIDTaskTest(TasklibTest): def test_normal_to_lazy_equality(self): assert self.stored == self.lazy + assert not self.stored != self.lazy assert type(self.lazy) is LazyUUIDTask def test_lazy_to_lazy_equality(self): @@ -1172,6 +1223,31 @@ class LazyUUIDTaskTest(TasklibTest): lazy2 = LazyUUIDTask(self.tw, self.stored['uuid']) assert lazy1 == lazy2 + assert not lazy1 != lazy2 + assert type(lazy1) is LazyUUIDTask + assert type(lazy2) is LazyUUIDTask + + def test_normal_to_lazy_inequality(self): + # Create a different UUID by changing the last letter + wrong_uuid = self.stored['uuid'] + wrong_uuid = wrong_uuid[:-1] + ('a' if wrong_uuid[-1] != 'a' else 'b') + + wrong_lazy = LazyUUIDTask(self.tw, wrong_uuid) + + assert not self.stored == wrong_lazy + assert self.stored != wrong_lazy + assert type(wrong_lazy) is LazyUUIDTask + + def test_lazy_to_lazy_inequality(self): + # Create a different UUID by changing the last letter + wrong_uuid = self.stored['uuid'] + wrong_uuid = wrong_uuid[:-1] + ('a' if wrong_uuid[-1] != 'a' else 'b') + + lazy1 = LazyUUIDTask(self.tw, self.stored['uuid']) + lazy2 = LazyUUIDTask(self.tw, wrong_uuid) + + assert not lazy1 == lazy2 + assert lazy1 != lazy2 assert type(lazy1) is LazyUUIDTask assert type(lazy2) is LazyUUIDTask @@ -1300,4 +1376,5 @@ class TaskWarriorBackendTest(TasklibTest): def test_config(self): assert self.tw.config['nag'] == "You have more urgent tasks." - assert self.tw.config['debug'] == "no" + assert self.tw.config['default.command'] == "next" + assert self.tw.config['dependency.indicator'] == "D"