From: Rob Golding-Day Date: Mon, 13 May 2019 14:45:43 +0000 (+0100) Subject: Merge branch 'develop' X-Git-Url: https://git.madduck.net/etc/taskwarrior.git/commitdiff_plain/dcf6974cde7c3c425522bd5e8a582f7a9aa6c8ac?hp=2fd5546d721efa71544cbf028af6fb99d382426b Merge branch 'develop' --- diff --git a/.gitignore b/.gitignore index 06b20e5..0b10a68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ +.cache *.pyc *~ tasklib.egg-info /dist /build docs/_build +.project +.coverage diff --git a/.travis.yml b/.travis.yml index c7e0834..cfa6d5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ env: - TASK_VERSION=v2.4.4 - TASK_VERSION=v2.5.0 - TASK_VERSION=v2.5.1 - - TASK_VERSION=2.6.0 python: - "2.7" - "3.3" @@ -25,8 +24,8 @@ 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 --recursive https://git.tasktools.org/scm/tm/task.git - - cd task + - git clone --recursive https://github.com/GothenburgBitFactory/taskwarrior + - cd taskwarrior - git checkout $TASK_VERSION - git clean -dfx - git submodule init diff --git a/README.rst b/README.rst index b3dce21..731241c 100644 --- a/README.rst +++ b/README.rst @@ -30,7 +30,7 @@ Usage tasklib has a similar API to that of Django's ORM:: - >>> from tasklib.task import TaskWarrior + >>> from tasklib import TaskWarrior >>> tw = TaskWarrior('/home/rob/.task') >>> tasks = tw.tasks.pending() @@ -40,7 +40,7 @@ tasklib has a similar API to that of Django's ORM:: ['Tidy the house'] >>> type(tasks[0]) - >>> task[0].done() + >>> tasks[0].done() >>> tasks = tw.tasks.pending() >>> tasks ['Learn German'] diff --git a/docs/conf.py b/docs/conf.py index 596f56b..9c7dbed 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.1.0' +version = '1.2.0' # The full version, including alpha/beta/rc tags. -release = '1.1.0' +release = '1.2.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 360504e..510136e 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.1.0' +version = '1.2.0' try: import importlib diff --git a/tasklib/backends.py b/tasklib/backends.py index 1e1b8c4..38f6c59 100644 --- a/tasklib/backends.py +++ b/tasklib/backends.py @@ -94,16 +94,22 @@ class TaskWarrior(Backend): VERSION_2_4_4 = six.u('2.4.4') VERSION_2_4_5 = six.u('2.4.5') - def __init__(self, data_location=None, create=True, taskrc_location='~/.taskrc'): - self.taskrc_location = os.path.expanduser(taskrc_location) + def __init__(self, data_location=None, create=True, + taskrc_location=None, task_command='task', + version_override=None): + self.taskrc_location = None + if taskrc_location: + self.taskrc_location = os.path.expanduser(taskrc_location) - # If taskrc does not exist, pass / to use defaults and avoid creating - # dummy .taskrc file by TaskWarrior - if not os.path.exists(self.taskrc_location): - self.taskrc_location = '/' + # If taskrc does not exist, pass / to use defaults and avoid creating + # dummy .taskrc file by TaskWarrior + if not os.path.exists(self.taskrc_location): + self.taskrc_location = '/' + + self.task_command = task_command self._config = None - self.version = self._get_version() + self.version = version_override or self._get_version() self.overrides = { 'confirmation': 'no', 'dependency.confirmation': 'no', # See TW-1483 or taskrc man page @@ -126,8 +132,11 @@ class TaskWarrior(Backend): self.tasks = TaskQuerySet(self) + def _get_task_command(self): + return self.task_command.split() + def _get_command_args(self, args, config_override=None): - command_args = ['task', 'rc:{0}'.format(self.taskrc_location)] + command_args = self._get_task_command() overrides = self.overrides.copy() overrides.update(config_override or dict()) for item in overrides.items(): @@ -140,7 +149,7 @@ class TaskWarrior(Backend): def _get_version(self): p = subprocess.Popen( - ['task', '--version'], + self._get_task_command() + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = [x.decode('utf-8') for x in p.communicate()] @@ -214,21 +223,25 @@ class TaskWarrior(Backend): if self.version < self.VERSION_2_4_0: return task._data['description'] else: - return six.u("description:'{0}'").format(task._data['description'] or '') + return six.u("description:'{0}'").format( + task._data['description'] or '', + ) def convert_datetime_string(self, value): if self.version >= self.VERSION_2_4_0: - # For strings, use 'task calc' to evaluate the string to datetime + # For strings, use 'calc' to evaluate the string to datetime # available since TW 2.4.0 args = value.split() result = self.execute_command(['calc'] + args) naive = datetime.datetime.strptime(result[0], DATE_FORMAT_CALC) localized = local_zone.localize(naive) else: - raise ValueError("Provided value could not be converted to " - "datetime, its type is not supported: {}" - .format(type(value))) + raise ValueError( + 'Provided value could not be converted to ' + 'datetime, its type is not supported: {}' + .format(type(value)), + ) return localized @@ -269,8 +282,11 @@ class TaskWarrior(Backend): args, config_override=config_override) logger.debug(u' '.join(command_args)) + env = os.environ.copy() + if self.taskrc_location: + env['TASKRC'] = self.taskrc_location p = subprocess.Popen(command_args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, env=env) stdout, stderr = [x.decode('utf-8') for x in p.communicate()] if p.returncode and allow_failure: if stderr.strip(): @@ -338,8 +354,10 @@ class TaskWarrior(Backend): # Expected output: Created task 1. # Created task 1 (recurrence template). if len(id_lines) != 1 or len(id_lines[0].split(' ')) not in (3, 5): - raise TaskWarriorException("Unexpected output when creating " - "task: %s" % '\n'.join(id_lines)) + raise TaskWarriorException( + 'Unexpected output when creating ' + 'task: %s' % '\n'.join(id_lines), + ) # Circumvent the ID storage, since ID is considered read-only identifier = id_lines[0].split(' ')[2].rstrip('.') @@ -411,8 +429,8 @@ class TaskWarrior(Backend): # If more than 1 task has been matched still, raise an exception if not valid(output): raise TaskWarriorException( - "Unique identifiers {0} with description: {1} matches " - "multiple tasks: {2}".format( + 'Unique identifiers {0} with description: {1} matches ' + 'multiple tasks: {2}'.format( task['uuid'] or task['id'], task['description'], output) ) diff --git a/tasklib/lazy.py b/tasklib/lazy.py index f9e0c0a..cb268f3 100644 --- a/tasklib/lazy.py +++ b/tasklib/lazy.py @@ -43,7 +43,7 @@ class LazyUUIDTask(object): return self['uuid'].__hash__() def __repr__(self): - return "LazyUUIDTask: {0}".format(self._uuid) + return 'LazyUUIDTask: {0}'.format(self._uuid) def __copy__(self): return LazyUUIDTask(self._tw, self._uuid) @@ -103,7 +103,7 @@ class LazyUUIDTaskSet(object): return getattr(self, name) def __repr__(self): - return "LazyUUIDTaskSet([{0}])".format(', '.join(self._uuids)) + return 'LazyUUIDTaskSet([{0}])'.format(', '.join(self._uuids)) def __eq__(self, other): return set(t['uuid'] for t in other) == self._uuids @@ -128,8 +128,10 @@ class LazyUUIDTaskSet(object): return self.difference_update(other) def __rsub__(self, other): - return LazyUUIDTaskSet(self._tw, - set(t['uuid'] for t in other) - self._uuids) + return LazyUUIDTaskSet( + self._tw, + set(t['uuid'] for t in other) - self._uuids, + ) def __or__(self, other): return self.union(other) @@ -171,20 +173,28 @@ class LazyUUIDTaskSet(object): return all([task in self for task in other]) def union(self, other): - return LazyUUIDTaskSet(self._tw, - self._uuids | set(t['uuid'] for t in other)) + return LazyUUIDTaskSet( + self._tw, + self._uuids | set(t['uuid'] for t in other), + ) def intersection(self, other): - return LazyUUIDTaskSet(self._tw, - self._uuids & set(t['uuid'] for t in other)) + return LazyUUIDTaskSet( + self._tw, + self._uuids & set(t['uuid'] for t in other), + ) def difference(self, other): - return LazyUUIDTaskSet(self._tw, - self._uuids - set(t['uuid'] for t in other)) + return LazyUUIDTaskSet( + self._tw, + self._uuids - set(t['uuid'] for t in other), + ) def symmetric_difference(self, other): - return LazyUUIDTaskSet(self._tw, - self._uuids ^ set(t['uuid'] for t in other)) + return LazyUUIDTaskSet( + self._tw, + self._uuids ^ set(t['uuid'] for t in other), + ) def update(self, other): self._uuids |= set(t['uuid'] for t in other) diff --git a/tasklib/task.py b/tasklib/task.py index c7c9e6d..20bff1f 100644 --- a/tasklib/task.py +++ b/tasklib/task.py @@ -326,20 +326,24 @@ class Task(TaskResource): # Check that all the tasks are saved for task in (cur_dependencies or set()): if not task.saved: - raise Task.NotSaved('Task \'%s\' needs to be saved before ' - 'it can be set as dependency.' % task) + raise Task.NotSaved( + 'Task \'%s\' needs to be saved before ' + 'it can be set as dependency.' % task, + ) return super(Task, self).serialize_depends(cur_dependencies) def delete(self): if not self.saved: - raise Task.NotSaved("Task needs to be saved before it can be deleted") + raise Task.NotSaved( + 'Task needs to be saved before it can be deleted', + ) # Refresh the status, and raise exception if the task is deleted self.refresh(only_fields=['status']) if self.deleted: - raise Task.DeletedTask("Task was already deleted") + raise Task.DeletedTask('Task was already deleted') self.backend.delete_task(self) @@ -348,17 +352,19 @@ class Task(TaskResource): def start(self): if not self.saved: - raise Task.NotSaved("Task needs to be saved before it can be started") + raise Task.NotSaved( + 'Task needs to be saved before it can be started', + ) # Refresh, and raise exception if task is already completed/deleted self.refresh(only_fields=['status']) if self.completed: - raise Task.CompletedTask("Cannot start a completed task") + raise Task.CompletedTask('Cannot start a completed task') elif self.deleted: - raise Task.DeletedTask("Deleted task cannot be started") + raise Task.DeletedTask('Deleted task cannot be started') elif self.active: - raise Task.ActiveTask("Task is already active") + raise Task.ActiveTask('Task is already active') self.backend.start_task(self) @@ -367,13 +373,15 @@ class Task(TaskResource): def stop(self): if not self.saved: - raise Task.NotSaved("Task needs to be saved before it can be stopped") + raise Task.NotSaved( + 'Task needs to be saved before it can be stopped', + ) # Refresh, and raise exception if task is already completed/deleted self.refresh(only_fields=['status']) if not self.active: - raise Task.InactiveTask("Cannot stop an inactive task") + raise Task.InactiveTask('Cannot stop an inactive task') self.backend.stop_task(self) @@ -382,15 +390,17 @@ class Task(TaskResource): def done(self): if not self.saved: - raise Task.NotSaved("Task needs to be saved before it can be completed") + raise Task.NotSaved( + 'Task needs to be saved before it can be completed', + ) # Refresh, and raise exception if task is already completed/deleted self.refresh(only_fields=['status']) if self.completed: - raise Task.CompletedTask("Cannot complete a completed task") + raise Task.CompletedTask('Cannot complete a completed task') elif self.deleted: - raise Task.DeletedTask("Deleted task cannot be completed") + raise Task.DeletedTask('Deleted task cannot be completed') self.backend.complete_task(self) @@ -406,14 +416,14 @@ class Task(TaskResource): def add_annotation(self, annotation): if not self.saved: - raise Task.NotSaved("Task needs to be saved to add annotation") + raise Task.NotSaved('Task needs to be saved to add annotation') self.backend.annotate_task(self, annotation) self.refresh(only_fields=['annotations']) def remove_annotation(self, annotation): if not self.saved: - raise Task.NotSaved("Task needs to be saved to remove annotation") + raise Task.NotSaved('Task needs to be saved to remove annotation') if isinstance(annotation, TaskAnnotation): annotation = annotation['description'] @@ -424,13 +434,14 @@ class Task(TaskResource): def refresh(self, only_fields=None, after_save=False): # Raise error when trying to refresh a task that has not been saved if not self.saved: - raise Task.NotSaved("Task needs to be saved to be refreshed") + raise Task.NotSaved('Task needs to be saved to be refreshed') new_data = self.backend.refresh_task(self, after_save=after_save) if only_fields: to_update = dict( - [(k, new_data.get(k)) for k in only_fields]) + [(k, new_data.get(k)) for k in only_fields], + ) self._update_data(to_update, update_original=True) else: self._load_data(new_data) @@ -461,7 +472,7 @@ class TaskQuerySet(object): def __repr__(self): data = list(self[:REPR_OUTPUT_SIZE + 1]) if len(data) > REPR_OUTPUT_SIZE: - data[-1] = "...(remaining elements truncated)..." + data[-1] = '...(remaining elements truncated)...' return repr(data) def __len__(self): @@ -549,7 +560,9 @@ class TaskQuerySet(object): if not num: raise Task.DoesNotExist( 'Task matching query does not exist. ' - 'Lookup parameters were {0}'.format(kwargs)) + 'Lookup parameters were {0}'.format(kwargs), + ) raise ValueError( 'get() returned more than one Task -- it returned {0}! ' - 'Lookup parameters were {1}'.format(num, kwargs)) + 'Lookup parameters were {1}'.format(num, kwargs), + ) diff --git a/tasklib/tests.py b/tasklib/tests.py index 3e60ac0..1fd449c 100644 --- a/tasklib/tests.py +++ b/tasklib/tests.py @@ -4,6 +4,7 @@ import copy import datetime import itertools import json +import os import pytz import six import shutil @@ -12,7 +13,7 @@ import tempfile import unittest from .backends import TaskWarrior -from .task import Task, ReadOnlyDictView, TaskQuerySet +from .task import Task, ReadOnlyDictView from .lazy import LazyUUIDTask, LazyUUIDTaskSet from .serializing import DATE_FORMAT, local_zone @@ -40,63 +41,88 @@ TASK_STANDARD_ATTRS = ( 'annotations', ) -total_seconds_2_6 = lambda x: x.microseconds / 1e6 + x.seconds + x.days * 24 * 3600 + +def total_seconds_2_6(x): + return x.microseconds / 1e6 + x.seconds + x.days * 24 * 3600 class TasklibTest(unittest.TestCase): + def get_taskwarrior(self, **kwargs): + tw_kwargs = dict( + data_location=self.tmp, + taskrc_location='/', + ) + tw_kwargs.update(kwargs) + return TaskWarrior(**tw_kwargs) + def setUp(self): self.tmp = tempfile.mkdtemp(dir='.') - self.tw = TaskWarrior(data_location=self.tmp, taskrc_location='/') + self.tw = self.get_taskwarrior() def tearDown(self): shutil.rmtree(self.tmp) +class TaskWarriorTest(TasklibTest): + + def test_custom_command(self): + # ensure that a custom command which contains multiple parts + # is properly split up + tw = self.get_taskwarrior( + task_command='wsl task', + # prevent `_get_version` from running as `wsl` may not exist + version_override=os.getenv('TASK_VERSION'), + ) + self.assertEqual(tw._get_task_command(), ['wsl', 'task']) + + class TaskFilterTest(TasklibTest): def test_all_empty(self): self.assertEqual(len(self.tw.tasks.all()), 0) def test_all_non_empty(self): - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() self.assertEqual(len(self.tw.tasks.all()), 1) self.assertEqual(self.tw.tasks.all()[0]['description'], 'test task') self.assertEqual(self.tw.tasks.all()[0]['status'], 'pending') def test_pending_non_empty(self): - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() self.assertEqual(len(self.tw.tasks.pending()), 1) - self.assertEqual(self.tw.tasks.pending()[0]['description'], - 'test task') + self.assertEqual( + self.tw.tasks.pending()[0]['description'], + 'test task', + ) self.assertEqual(self.tw.tasks.pending()[0]['status'], 'pending') def test_completed_empty(self): - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() self.assertEqual(len(self.tw.tasks.completed()), 0) def test_completed_non_empty(self): - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() self.assertEqual(len(self.tw.tasks.completed()), 0) 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() + 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() + 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() + 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() + Task(self.tw, description='test task').save() self.assertEqual(len(self.tw.tasks.waiting()), 0) t = self.tw.tasks.all()[0] @@ -106,29 +132,36 @@ class TaskFilterTest(TasklibTest): self.assertEqual(len(self.tw.tasks.waiting()), 1) def test_recurring_empty(self): - Task(self.tw, description="test task").save() + 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() + 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() + Task(self.tw, description='no priority task').save() + Task(self.tw, priority='H', description='high priority task').save() self.assertEqual(len(self.tw.tasks.all()), 2) # Assert that the correct number of tasks is returned - self.assertEqual(len(self.tw.tasks.filter(priority="H")), 1) + self.assertEqual(len(self.tw.tasks.filter(priority='H')), 1) # Assert that the correct tasks are returned - high_priority_task = self.tw.tasks.get(priority="H") - self.assertEqual(high_priority_task['description'], "high priority task") + high_priority_task = self.tw.tasks.get(priority='H') + self.assertEqual( + high_priority_task['description'], + 'high priority task', + ) def test_filtering_by_empty_attribute(self): - Task(self.tw, description="no priority task").save() - Task(self.tw, priority="H", description="high priority task").save() + Task(self.tw, description='no priority task').save() + Task(self.tw, priority='H', description='high priority task').save() self.assertEqual(len(self.tw.tasks.all()), 2) # Assert that the correct number of tasks is returned @@ -136,69 +169,69 @@ class TaskFilterTest(TasklibTest): # Assert that the correct tasks are returned no_priority_task = self.tw.tasks.get(priority=None) - self.assertEqual(no_priority_task['description'], "no priority task") + self.assertEqual(no_priority_task['description'], 'no priority task') def test_filter_for_task_with_space_in_descripition(self): - task = Task(self.tw, description="test task") + task = Task(self.tw, description='test task') task.save() - filtered_task = self.tw.tasks.get(description="test task") - self.assertEqual(filtered_task['description'], "test task") + filtered_task = self.tw.tasks.get(description='test task') + self.assertEqual(filtered_task['description'], 'test task') def test_filter_for_task_without_space_in_descripition(self): - task = Task(self.tw, description="test") + task = Task(self.tw, description='test') task.save() - filtered_task = self.tw.tasks.get(description="test") - self.assertEqual(filtered_task['description'], "test") + filtered_task = self.tw.tasks.get(description='test') + self.assertEqual(filtered_task['description'], 'test') def test_filter_for_task_with_space_in_project(self): - task = Task(self.tw, description="test", project="random project") + task = Task(self.tw, description='test', project='random project') task.save() - filtered_task = self.tw.tasks.get(project="random project") - self.assertEqual(filtered_task['project'], "random project") + filtered_task = self.tw.tasks.get(project='random project') + self.assertEqual(filtered_task['project'], 'random project') def test_filter_for_task_without_space_in_project(self): - task = Task(self.tw, description="test", project="random") + task = Task(self.tw, description='test', project='random') task.save() - filtered_task = self.tw.tasks.get(project="random") - self.assertEqual(filtered_task['project'], "random") + filtered_task = self.tw.tasks.get(project='random') + self.assertEqual(filtered_task['project'], 'random') def test_filter_with_empty_uuid(self): self.assertRaises(ValueError, lambda: self.tw.tasks.get(uuid='')) def test_filter_dummy_by_status(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(status=t['status']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_uuid(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(uuid=t['uuid']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_entry(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(entry=t['entry']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_description(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(description=t['description']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_start(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() t.start() @@ -206,7 +239,7 @@ class TaskFilterTest(TasklibTest): self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_end(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() t.done() @@ -214,14 +247,14 @@ class TaskFilterTest(TasklibTest): self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_due(self): - t = Task(self.tw, description="test", due=datetime.datetime.now()) + t = Task(self.tw, description='test', due=datetime.datetime.now()) t.save() tasks = self.tw.tasks.filter(due=t['due']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_until(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(until=t['until']) @@ -238,35 +271,35 @@ class TaskFilterTest(TasklibTest): else: return - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(modified=t['modified']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_scheduled(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() tasks = self.tw.tasks.filter(scheduled=t['scheduled']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_tags(self): - t = Task(self.tw, description="test", tags=["home"]) + t = Task(self.tw, description='test', tags=['home']) t.save() tasks = self.tw.tasks.filter(tags=t['tags']) self.assertEqual(list(tasks), [t]) def test_filter_dummy_by_projects(self): - t = Task(self.tw, description="test", project="random") + t = Task(self.tw, description='test', project='random') t.save() tasks = self.tw.tasks.filter(project=t['project']) self.assertEqual(list(tasks), [t]) def test_filter_by_priority(self): - t = Task(self.tw, description="test", priority="H") + t = Task(self.tw, description='test', priority='H') t.save() tasks = self.tw.tasks.filter(priority=t['priority']) @@ -277,71 +310,83 @@ class TaskTest(TasklibTest): def test_create_unsaved_task(self): # Make sure a new task is not saved unless explicitly called for - t = Task(self.tw, description="test task") + Task(self.tw, description='test task') self.assertEqual(len(self.tw.tasks.all()), 0) - # TODO: once python 2.6 compatiblity is over, use context managers here + # TODO: once python 2.6 compatibility is over, use context managers here # and in all subsequent tests for assertRaises def test_delete_unsaved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertRaises(Task.NotSaved, t.delete) def test_complete_unsaved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertRaises(Task.NotSaved, t.done) def test_refresh_unsaved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertRaises(Task.NotSaved, t.refresh) def test_start_unsaved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertRaises(Task.NotSaved, t.start) def test_delete_deleted_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.delete() self.assertRaises(Task.DeletedTask, t.delete) def test_complete_completed_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.done() self.assertRaises(Task.CompletedTask, t.done) def test_start_completed_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.done() self.assertRaises(Task.CompletedTask, t.start) def test_add_completed_task(self): - t = Task(self.tw, description="test", status="completed", - end=datetime.datetime.now()) + t = Task( + self.tw, + description='test', + status='completed', + end=datetime.datetime.now(), + ) t.save() def test_add_multiple_completed_tasks(self): - t1 = Task(self.tw, description="test1", status="completed", - end=datetime.datetime.now()) - t2 = Task(self.tw, description="test2", status="completed", - end=datetime.datetime.now()) + t1 = Task( + self.tw, + description='test1', + status='completed', + end=datetime.datetime.now(), + ) + t2 = Task( + self.tw, + description='test2', + status='completed', + end=datetime.datetime.now(), + ) t1.save() t2.save() def test_complete_deleted_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.delete() self.assertRaises(Task.DeletedTask, t.done) def test_starting_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') now = t.datetime_normalizer(datetime.datetime.now()) t.save() t.start() @@ -350,7 +395,7 @@ class TaskTest(TasklibTest): self.assertEqual(t['status'], 'pending') def test_completing_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') now = t.datetime_normalizer(datetime.datetime.now()) t.save() t.done() @@ -359,7 +404,7 @@ class TaskTest(TasklibTest): self.assertEqual(t['status'], 'completed') def test_deleting_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') now = t.datetime_normalizer(datetime.datetime.now()) t.save() t.delete() @@ -368,51 +413,51 @@ class TaskTest(TasklibTest): self.assertEqual(t['status'], 'deleted') def test_started_task_active(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.start() self.assertTrue(t.active) def test_unstarted_task_inactive(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertFalse(t.active) t.save() self.assertFalse(t.active) def test_start_active_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.start() self.assertRaises(Task.ActiveTask, t.start) def test_stop_completed_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.start() t.done() self.assertRaises(Task.InactiveTask, t.stop) - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.done() self.assertRaises(Task.InactiveTask, t.stop) def test_stop_deleted_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.start() t.delete() t.stop() def test_stop_inactive_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() self.assertRaises(Task.InactiveTask, t.stop) - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.start() t.stop() @@ -420,8 +465,8 @@ class TaskTest(TasklibTest): self.assertRaises(Task.InactiveTask, t.stop) def test_stopping_task(self): - t = Task(self.tw, description="test task") - now = t.datetime_normalizer(datetime.datetime.now()) + t = Task(self.tw, description='test task') + t.datetime_normalizer(datetime.datetime.now()) t.save() t.start() t.stop() @@ -431,41 +476,41 @@ class TaskTest(TasklibTest): self.assertFalse(t.active) def test_modify_simple_attribute_without_space(self): - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() - self.assertEquals(t['description'], "test") + self.assertEqual(t['description'], 'test') - t['description'] = "test-modified" + t['description'] = 'test-modified' t.save() - self.assertEquals(t['description'], "test-modified") + self.assertEqual(t['description'], 'test-modified') def test_modify_simple_attribute_with_space(self): # Space can pose problems with parsing - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() - self.assertEquals(t['description'], "test task") + self.assertEqual(t['description'], 'test task') - t['description'] = "test task modified" + t['description'] = 'test task modified' t.save() - self.assertEquals(t['description'], "test task modified") + self.assertEqual(t['description'], 'test task modified') def test_empty_dependency_set_of_unsaved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') self.assertEqual(t['depends'], set()) def test_empty_dependency_set_of_saved_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() self.assertEqual(t['depends'], set()) def test_set_unsaved_task_as_dependency(self): # Adds only one dependency to task with no dependencies - t = Task(self.tw, description="test task") - dependency = Task(self.tw, description="needs to be done first") + t = Task(self.tw, description='test task') + dependency = Task(self.tw, description='needs to be done first') # We only save the parent task, dependency task is unsaved t.save() @@ -475,8 +520,8 @@ class TaskTest(TasklibTest): def test_set_simple_dependency_set(self): # Adds only one dependency to task with no dependencies - t = Task(self.tw, description="test task") - dependency = Task(self.tw, description="needs to be done first") + t = Task(self.tw, description='test task') + dependency = Task(self.tw, description='needs to be done first') t.save() dependency.save() @@ -487,9 +532,9 @@ class TaskTest(TasklibTest): def test_set_complex_dependency_set(self): # Adds two dependencies to task with no dependencies - t = Task(self.tw, description="test task") - dependency1 = Task(self.tw, description="needs to be done first") - dependency2 = Task(self.tw, description="needs to be done second") + t = Task(self.tw, description='test task') + dependency1 = Task(self.tw, description='needs to be done first') + dependency2 = Task(self.tw, description='needs to be done second') t.save() dependency1.save() @@ -501,9 +546,9 @@ class TaskTest(TasklibTest): def test_remove_from_dependency_set(self): # Removes dependency from task with two dependencies - t = Task(self.tw, description="test task") - dependency1 = Task(self.tw, description="needs to be done first") - dependency2 = Task(self.tw, description="needs to be done second") + t = Task(self.tw, description='test task') + dependency1 = Task(self.tw, description='needs to be done first') + dependency2 = Task(self.tw, description='needs to be done second') dependency1.save() dependency2.save() @@ -518,9 +563,9 @@ class TaskTest(TasklibTest): def test_add_to_dependency_set(self): # Adds dependency to task with one dependencies - t = Task(self.tw, description="test task") - dependency1 = Task(self.tw, description="needs to be done first") - dependency2 = Task(self.tw, description="needs to be done second") + t = Task(self.tw, description='test task') + dependency1 = Task(self.tw, description='needs to be done first') + dependency2 = Task(self.tw, description='needs to be done second') dependency1.save() dependency2.save() @@ -535,8 +580,8 @@ class TaskTest(TasklibTest): def test_add_to_empty_dependency_set(self): # Adds dependency to task with one dependencies - t = Task(self.tw, description="test task") - dependency = Task(self.tw, description="needs to be done first") + t = Task(self.tw, description='test task') + dependency = Task(self.tw, description='needs to be done first') dependency.save() @@ -547,30 +592,30 @@ class TaskTest(TasklibTest): def test_simple_dependency_set_save_repeatedly(self): # Adds only one dependency to task with no dependencies - t = Task(self.tw, description="test task") - dependency = Task(self.tw, description="needs to be done first") + t = Task(self.tw, description='test task') + dependency = Task(self.tw, description='needs to be done first') dependency.save() t['depends'] = set([dependency]) t.save() # We taint the task, but keep depends intact - t['description'] = "test task modified" + t['description'] = 'test task modified' t.save() self.assertEqual(t['depends'], set([dependency])) # We taint the task, but assign the same set to the depends t['depends'] = set([dependency]) - t['description'] = "test task modified again" + t['description'] = 'test task modified again' t.save() self.assertEqual(t['depends'], set([dependency])) def test_compare_different_tasks(self): # Negative: compare two different tasks - t1 = Task(self.tw, description="test task") - t2 = Task(self.tw, description="test task") + t1 = Task(self.tw, description='test task') + t2 = Task(self.tw, description='test task') t1.save() t2.save() @@ -579,14 +624,14 @@ class TaskTest(TasklibTest): def test_compare_same_task_object(self): # Compare Task object wit itself - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() self.assertEqual(t == t, True) def test_compare_same_task(self): # Compare the same task using two different objects - t1 = Task(self.tw, description="test task") + t1 = Task(self.tw, description='test task') t1.save() t2 = self.tw.tasks.get(uuid=t1['uuid']) @@ -595,20 +640,20 @@ class TaskTest(TasklibTest): def test_compare_unsaved_tasks(self): # t1 and t2 are unsaved tasks, considered to be unequal # despite the content of data - t1 = Task(self.tw, description="test task") - t2 = Task(self.tw, description="test task") + t1 = Task(self.tw, description='test task') + t2 = Task(self.tw, description='test task') self.assertEqual(t1 == t2, False) def test_hash_unsaved_tasks(self): # Considered equal, it's the same object - t1 = Task(self.tw, description="test task") + t1 = Task(self.tw, description='test task') t2 = t1 self.assertEqual(hash(t1) == hash(t2), True) def test_hash_same_task(self): # Compare the hash of the task using two different objects - t1 = Task(self.tw, description="test task") + t1 = Task(self.tw, description='test task') t1.save() t2 = self.tw.tasks.get(uuid=t1['uuid']) @@ -616,15 +661,15 @@ class TaskTest(TasklibTest): 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") + 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 = Task(self.tw, description='test task 1') + t2 = Task(self.tw, description='test task 2') t1.save() t2.save() @@ -632,11 +677,11 @@ class TaskTest(TasklibTest): self.assertNotEqual(t1.__hash__(), t2.__hash__()) def test_adding_task_with_priority(self): - t = Task(self.tw, description="test task", priority="M") + t = Task(self.tw, description='test task', priority='M') t.save() def test_removing_priority_with_none(self): - t = Task(self.tw, description="test task", priority="L") + t = Task(self.tw, description='test task', priority='L') t.save() # Remove the priority mark @@ -647,11 +692,11 @@ class TaskTest(TasklibTest): self.assertEqual(t['priority'], None) def test_adding_task_with_due_time(self): - t = Task(self.tw, description="test task", due=datetime.datetime.now()) + t = Task(self.tw, description='test task', due=datetime.datetime.now()) t.save() def test_removing_due_time_with_none(self): - t = Task(self.tw, description="test task", due=datetime.datetime.now()) + t = Task(self.tw, description='test task', due=datetime.datetime.now()) t.save() # Remove the due timestamp @@ -668,15 +713,17 @@ class TaskTest(TasklibTest): self.assertEqual(set(t._modified_fields), set()) # Modify the task - t['description'] = "test task" + t['description'] = 'test task' self.assertEqual(set(t._modified_fields), set(['description'])) t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14) # <3 self.assertEqual(set(t._modified_fields), set(['description', 'due'])) - t['project'] = "test project" - self.assertEqual(set(t._modified_fields), - set(['description', 'due', 'project'])) + t['project'] = 'test project' + self.assertEqual( + set(t._modified_fields), + set(['description', 'due', 'project']), + ) # List of modified fields should clear out when saved t.save() @@ -684,20 +731,20 @@ class TaskTest(TasklibTest): # Reassigning the fields with the same values now should not produce # modified fields - t['description'] = "test task" + t['description'] = 'test task' t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14) # <3 - t['project'] = "test project" + t['project'] = 'test project' self.assertEqual(set(t._modified_fields), set()) def test_modified_fields_loaded_task(self): t = Task(self.tw) # Modify the task - t['description'] = "test task" + t['description'] = 'test task' t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14) # <3 - t['project'] = "test project" + t['project'] = 'test project' - dependency = Task(self.tw, description="dependency") + dependency = Task(self.tw, description='dependency') dependency.save() t['depends'] = set([dependency]) @@ -706,13 +753,13 @@ class TaskTest(TasklibTest): self.assertEqual(set(t._modified_fields), set()) # Get the task by using a filter by UUID - t2 = self.tw.tasks.get(uuid=t['uuid']) + self.tw.tasks.get(uuid=t['uuid']) # Reassigning the fields with the same values now should not produce # modified fields - t['description'] = "test task" + t['description'] = 'test task' t['due'] = datetime.datetime(2014, 2, 14, 14, 14, 14) # <3 - t['project'] = "test project" + t['project'] = 'test project' t['depends'] = set([dependency]) self.assertEqual(set(t._modified_fields), set()) @@ -720,7 +767,7 @@ class TaskTest(TasklibTest): t = Task(self.tw) for field in TASK_STANDARD_ATTRS: - value = t[field] + t[field] self.assertEqual(set(t._modified_fields), set()) @@ -728,30 +775,34 @@ class TaskTest(TasklibTest): # Test that we are unable to set readonly attrs through __init__ for readonly_key in Task.read_only_fields: kwargs = {'description': 'test task', readonly_key: 'value'} - self.assertRaises(RuntimeError, - lambda: Task(self.tw, **kwargs)) + self.assertRaises( + RuntimeError, + lambda: Task(self.tw, **kwargs), + ) def test_setting_read_only_attrs_through_setitem(self): # Test that we are unable to set readonly attrs through __init__ for readonly_key in Task.read_only_fields: t = Task(self.tw, description='test task') - self.assertRaises(RuntimeError, - lambda: t.__setitem__(readonly_key, 'value')) + self.assertRaises( + RuntimeError, + lambda: t.__setitem__(readonly_key, 'value'), + ) def test_saving_unmodified_task(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t.save() def test_adding_tag_by_appending(self): - t = Task(self.tw, description="test task", tags=['test1']) + t = Task(self.tw, description='test task', tags=['test1']) t.save() t['tags'].add('test2') t.save() self.assertEqual(t['tags'], set(['test1', 'test2'])) def test_adding_tag_twice(self): - t = Task(self.tw, description="test task", tags=['test1']) + t = Task(self.tw, description='test task', tags=['test1']) t.save() t['tags'].add('test2') t['tags'].add('test2') @@ -759,7 +810,7 @@ class TaskTest(TasklibTest): self.assertEqual(t['tags'], set(['test1', 'test2'])) def test_adding_tag_by_appending_empty(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t.save() t['tags'].add('test') t.save() @@ -768,16 +819,26 @@ class TaskTest(TasklibTest): def test_serializers_returning_empty_string_for_none(self): # Test that any serializer returns '' when passed None t = Task(self.tw) - serializers = [getattr(t, serializer_name) for serializer_name in - filter(lambda x: x.startswith('serialize_'), dir(t))] + serializers = [ + getattr(t, serializer_name) + for serializer_name in filter( + lambda x: x.startswith('serialize_'), + dir(t), + ) + ] for serializer in serializers: self.assertEqual(serializer(None), '') def test_deserializer_returning_empty_value_for_empty_string(self): # Test that any deserializer returns empty value when passed '' t = Task(self.tw) - deserializers = [getattr(t, deserializer_name) for deserializer_name in - filter(lambda x: x.startswith('deserialize_'), dir(t))] + deserializers = [ + getattr(t, deserializer_name) + for deserializer_name in filter( + lambda x: x.startswith('deserialize_'), + dir(t), + ) + ] for deserializer in deserializers: self.assertTrue(deserializer('') in (None, [], set())) @@ -790,15 +851,23 @@ class TaskTest(TasklibTest): def test_recurrent_task_generation(self): today = datetime.date.today() - t = Task(self.tw, description="brush teeth", - due=today, recur="daily") + t = Task( + self.tw, + description='brush teeth', + due=today, + recur='daily', + ) t.save() self.assertEqual(len(self.tw.tasks.pending()), 2) def test_spawned_task_parent(self): today = datetime.date.today() - t = Task(self.tw, description="brush teeth", - due=today, recur="daily") + t = Task( + self.tw, + description='brush teeth', + due=today, + recur='daily', + ) t.save() spawned = self.tw.tasks.pending().get(due=today) @@ -806,19 +875,22 @@ class TaskTest(TasklibTest): def test_modify_number_of_tasks_at_once(self): for i in range(1, 100): - Task(self.tw, description="test task %d" % i, tags=['test']).save() + Task(self.tw, description='test task %d' % i, tags=['test']).save() self.tw.execute_command(['+test', 'mod', 'unified', 'description']) def test_return_all_from_executed_command(self): - Task(self.tw, description="test task", tags=['test']).save() + Task(self.tw, description='test task', tags=['test']).save() out, err, rc = self.tw.execute_command(['count'], return_all=True) self.assertEqual(rc, 0) def test_return_all_from_failed_executed_command(self): - Task(self.tw, description="test task", tags=['test']).save() - out, err, rc = self.tw.execute_command(['countinvalid'], - return_all=True, allow_failure=False) + Task(self.tw, description='test task', tags=['test']).save() + out, err, rc = self.tw.execute_command( + ['countinvalid'], + return_all=True, + allow_failure=False, + ) self.assertNotEqual(rc, 0) @@ -829,7 +901,8 @@ class TaskFromHookTest(TasklibTest): '"entry":"20141118T050231Z",' '"status":"pending",' '"start":"20141119T152233Z",' - '"uuid":"a360fc44-315c-4366-b70c-ea7e7520b749"}') + '"uuid":"a360fc44-315c-4366-b70c-ea7e7520b749"}', + ) input_add_data_recurring = six.StringIO( '{"description":"Mow the lawn",' @@ -837,46 +910,65 @@ class TaskFromHookTest(TasklibTest): '"parent":"62da6227-519c-42c2-915d-dccada926ad7",' '"recur":"weekly",' '"status":"pending",' - '"uuid":"81305335-0237-49ff-8e87-b3cdc2369cec"}') - - input_modify_data = six.StringIO(input_add_data.getvalue() + '\n' + - '{"description":"Buy some milk finally",' - '"entry":"20141118T050231Z",' - '"status":"completed",' - '"uuid":"a360fc44-315c-4366-b70c-ea7e7520b749"}') + '"uuid":"81305335-0237-49ff-8e87-b3cdc2369cec"}', + ) + + input_modify_data = six.StringIO( + '\n'.join([ + input_add_data.getvalue(), + ( + '{"description":"Buy some milk finally",' + '"entry":"20141118T050231Z",' + '"status":"completed",' + '"uuid":"a360fc44-315c-4366-b70c-ea7e7520b749"}' + ), + ]), + ) exported_raw_data = ( '{"project":"Home",' - '"due":"20150101T232323Z",' - '"description":"test task"}') + '"due":"20150101T232323Z",' + '"description":"test task"}' + ) def test_setting_up_from_add_hook_input(self): t = Task.from_input(input_file=self.input_add_data, backend=self.tw) - self.assertEqual(t['description'], "Buy some milk") + self.assertEqual(t['description'], 'Buy some milk') self.assertEqual(t.pending, True) def test_setting_up_from_add_hook_input_recurring(self): - t = Task.from_input(input_file=self.input_add_data_recurring, - backend=self.tw) - self.assertEqual(t['description'], "Mow the lawn") + t = Task.from_input( + input_file=self.input_add_data_recurring, + backend=self.tw, + ) + self.assertEqual(t['description'], 'Mow the lawn') self.assertEqual(t.pending, True) def test_setting_up_from_modified_hook_input(self): - t = Task.from_input(input_file=self.input_modify_data, modify=True, - backend=self.tw) - self.assertEqual(t['description'], "Buy some milk finally") + t = Task.from_input( + input_file=self.input_modify_data, + modify=True, + backend=self.tw, + ) + self.assertEqual(t['description'], 'Buy some milk finally') self.assertEqual(t.pending, False) self.assertEqual(t.completed, True) - self.assertEqual(t._original_data['status'], "pending") - self.assertEqual(t._original_data['description'], "Buy some milk") - self.assertEqual(set(t._modified_fields), - set(['status', 'description', 'start'])) + self.assertEqual(t._original_data['status'], 'pending') + self.assertEqual(t._original_data['description'], 'Buy some milk') + self.assertEqual( + set(t._modified_fields), + set(['status', 'description', 'start']), + ) def test_export_data(self): - t = Task(self.tw, description="test task", - project="Home", - due=pytz.utc.localize(datetime.datetime(2015,1,1,23,23,23))) + t = Task( + self.tw, + description='test task', + project='Home', + due=pytz.utc.localize( + datetime.datetime(2015, 1, 1, 23, 23, 23)), + ) # Check that the output is a permutation of: # {"project":"Home","description":"test task","due":"20150101232323Z"} @@ -886,78 +978,88 @@ class TaskFromHookTest(TasklibTest): for segments in itertools.permutations(allowed_segments) ] - self.assertTrue(any(t.export_data() == expected - for expected in allowed_output)) + self.assertTrue( + any(t.export_data() == expected + for expected in allowed_output), + ) + class TimezoneAwareDatetimeTest(TasklibTest): def setUp(self): super(TimezoneAwareDatetimeTest, self).setUp() self.zone = local_zone - self.localdate_naive = datetime.datetime(2015,2,2) - self.localtime_naive = datetime.datetime(2015,2,2,0,0,0) + self.localdate_naive = datetime.datetime(2015, 2, 2) + self.localtime_naive = datetime.datetime(2015, 2, 2, 0, 0, 0) self.localtime_aware = self.zone.localize(self.localtime_naive) self.utctime_aware = self.localtime_aware.astimezone(pytz.utc) def test_timezone_naive_datetime_setitem(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t['due'] = self.localtime_naive self.assertEqual(t['due'], self.localtime_aware) def test_timezone_naive_datetime_using_init(self): - t = Task(self.tw, description="test task", due=self.localtime_naive) + t = Task(self.tw, description='test task', due=self.localtime_naive) self.assertEqual(t['due'], self.localtime_aware) def test_filter_by_naive_datetime(self): - t = Task(self.tw, description="task1", due=self.localtime_naive) + t = Task(self.tw, description='task1', due=self.localtime_naive) t.save() matching_tasks = self.tw.tasks.filter(due=self.localtime_naive) self.assertEqual(len(matching_tasks), 1) def test_serialize_naive_datetime(self): - t = Task(self.tw, description="task1", due=self.localtime_naive) - self.assertEqual(json.loads(t.export_data())['due'], - self.utctime_aware.strftime(DATE_FORMAT)) + t = Task(self.tw, description='task1', due=self.localtime_naive) + self.assertEqual( + json.loads(t.export_data())['due'], + self.utctime_aware.strftime(DATE_FORMAT), + ) def test_timezone_naive_date_setitem(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t['due'] = self.localdate_naive self.assertEqual(t['due'], self.localtime_aware) def test_timezone_naive_date_using_init(self): - t = Task(self.tw, description="test task", due=self.localdate_naive) + t = Task(self.tw, description='test task', due=self.localdate_naive) self.assertEqual(t['due'], self.localtime_aware) def test_filter_by_naive_date(self): - t = Task(self.tw, description="task1", due=self.localdate_naive) + t = Task(self.tw, description='task1', due=self.localdate_naive) t.save() matching_tasks = self.tw.tasks.filter(due=self.localdate_naive) self.assertEqual(len(matching_tasks), 1) def test_serialize_naive_date(self): - t = Task(self.tw, description="task1", due=self.localdate_naive) - self.assertEqual(json.loads(t.export_data())['due'], - self.utctime_aware.strftime(DATE_FORMAT)) + t = Task(self.tw, description='task1', due=self.localdate_naive) + self.assertEqual( + json.loads(t.export_data())['due'], + self.utctime_aware.strftime(DATE_FORMAT), + ) def test_timezone_aware_datetime_setitem(self): - t = Task(self.tw, description="test task") + t = Task(self.tw, description='test task') t['due'] = self.localtime_aware self.assertEqual(t['due'], self.localtime_aware) def test_timezone_aware_datetime_using_init(self): - t = Task(self.tw, description="test task", due=self.localtime_aware) + t = Task(self.tw, description='test task', due=self.localtime_aware) self.assertEqual(t['due'], self.localtime_aware) def test_filter_by_aware_datetime(self): - t = Task(self.tw, description="task1", due=self.localtime_aware) + t = Task(self.tw, description='task1', due=self.localtime_aware) t.save() matching_tasks = self.tw.tasks.filter(due=self.localtime_aware) self.assertEqual(len(matching_tasks), 1) def test_serialize_aware_datetime(self): - t = Task(self.tw, description="task1", due=self.localtime_aware) - self.assertEqual(json.loads(t.export_data())['due'], - self.utctime_aware.strftime(DATE_FORMAT)) + t = Task(self.tw, description='task1', due=self.localtime_aware) + self.assertEqual( + json.loads(t.export_data())['due'], + self.utctime_aware.strftime(DATE_FORMAT), + ) + class DatetimeStringTest(TasklibTest): @@ -970,11 +1072,11 @@ class DatetimeStringTest(TasklibTest): else: return - t = Task(self.tw, description="test task", due="now") + t = Task(self.tw, description='test task', due='now') now = local_zone.localize(datetime.datetime.now()) # Assert that both times are not more than 5 seconds apart - if sys.version_info < (2,7): + if sys.version_info < (2, 7): self.assertTrue(total_seconds_2_6(now - t['due']) < 5) self.assertTrue(total_seconds_2_6(t['due'] - now) < 5) else: @@ -990,7 +1092,7 @@ class DatetimeStringTest(TasklibTest): else: return - t = Task(self.tw, description="test task", due="eoy") + t = Task(self.tw, description='test task', due='eoy') now = local_zone.localize(datetime.datetime.now()) eoy = local_zone.localize(datetime.datetime( year=now.year, @@ -998,7 +1100,7 @@ class DatetimeStringTest(TasklibTest): day=31, hour=23, minute=59, - second=59 + second=59, )) self.assertEqual(eoy, t['due']) @@ -1011,16 +1113,18 @@ class DatetimeStringTest(TasklibTest): else: return - t = Task(self.tw, description="test task", due="eoy - 4 months") + t = Task(self.tw, description='test task', due='eoy - 4 months') now = local_zone.localize(datetime.datetime.now()) - due_date = local_zone.localize(datetime.datetime( - year=now.year, - month=12, - day=31, - hour=23, - minute=59, - second=59 - )) - datetime.timedelta(0,4 * 30 * 86400) + due_date = local_zone.localize( + datetime.datetime( + year=now.year, + month=12, + day=31, + hour=23, + minute=59, + second=59, + ) + ) - datetime.timedelta(0, 4 * 30 * 86400) self.assertEqual(due_date, t['due']) def test_filtering_with_string_datetime(self): @@ -1032,16 +1136,20 @@ class DatetimeStringTest(TasklibTest): else: return - t = Task(self.tw, description="test task", - due=datetime.datetime.now() - datetime.timedelta(0,2)) + t = Task( + self.tw, + description='test task', + due=datetime.datetime.now() - datetime.timedelta(0, 2), + ) t.save() - self.assertEqual(len(self.tw.tasks.filter(due__before="now")), 1) + self.assertEqual(len(self.tw.tasks.filter(due__before='now')), 1) + class AnnotationTest(TasklibTest): def setUp(self): super(AnnotationTest, self).setUp() - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() def test_adding_annotation(self): task = self.tw.tasks.get() @@ -1071,20 +1179,20 @@ class AnnotationTest(TasklibTest): self.assertEqual(len(task['annotations']), 0) def test_annotation_after_modification(self): - task = self.tw.tasks.get() - task['project'] = 'test' - task.add_annotation('I should really do this task') - self.assertEqual(task['project'], 'test') - task.save() - self.assertEqual(task['project'], 'test') + task = self.tw.tasks.get() + task['project'] = 'test' + task.add_annotation('I should really do this task') + self.assertEqual(task['project'], 'test') + task.save() + self.assertEqual(task['project'], 'test') def test_serialize_annotations(self): # Test that serializing annotations is possible - t = Task(self.tw, description="test") + t = Task(self.tw, description='test') t.save() - t.add_annotation("annotation1") - t.add_annotation("annotation2") + t.add_annotation('annotation1') + t.add_annotation('annotation2') data = t._serialize('annotations', t._data['annotations']) @@ -1092,59 +1200,66 @@ class AnnotationTest(TasklibTest): self.assertEqual(type(data[0]), dict) self.assertEqual(type(data[1]), dict) - self.assertEqual(data[0]['description'], "annotation1") - self.assertEqual(data[1]['description'], "annotation2") + self.assertEqual(data[0]['description'], 'annotation1') + self.assertEqual(data[1]['description'], 'annotation2') class UnicodeTest(TasklibTest): def test_unicode_task(self): - Task(self.tw, description=six.u("†åßk")).save() + Task(self.tw, description=six.u('†åßk')).save() self.tw.tasks.get() def test_filter_by_unicode_task(self): - Task(self.tw, description=six.u("†åßk")).save() - tasks = self.tw.tasks.filter(description=six.u("†åßk")) + Task(self.tw, description=six.u('†åßk')).save() + tasks = self.tw.tasks.filter(description=six.u('†åßk')) self.assertEqual(len(tasks), 1) def test_non_unicode_task(self): - Task(self.tw, description="test task").save() + Task(self.tw, description='test task').save() self.tw.tasks.get() + class ReadOnlyDictViewTest(unittest.TestCase): def setUp(self): - self.sample = dict(l=[1,2,3], d={'k':'v'}) + self.sample = dict(sample_list=[1, 2, 3], sample_dict={'key': 'value'}) self.original_sample = copy.deepcopy(self.sample) self.view = ReadOnlyDictView(self.sample) def test_readonlydictview_getitem(self): - l = self.view['l'] - self.assertEqual(l, self.sample['l']) + sample_list = self.view['sample_list'] + self.assertEqual(sample_list, self.sample['sample_list']) # Assert that modification changed only copied value - l.append(4) - self.assertNotEqual(l, self.sample['l']) + sample_list.append(4) + self.assertNotEqual(sample_list, self.sample['sample_list']) # Assert that viewed dict is not changed self.assertEqual(self.sample, self.original_sample) def test_readonlydictview_contains(self): - self.assertEqual('l' in self.view, 'l' in self.sample) - self.assertEqual('d' in self.view, 'd' in self.sample) - self.assertEqual('k' in self.view, 'k' in self.sample) + self.assertEqual('sample_list' in self.view, + 'sample_list' in self.sample) + self.assertEqual('sample_dict' in self.view, + 'sample_dict' in self.sample) + self.assertEqual('key' in self.view, 'key' in self.sample) # Assert that viewed dict is not changed self.assertEqual(self.sample, self.original_sample) def test_readonlydictview_iter(self): - self.assertEqual(list(k for k in self.view), - list(k for k in self.sample)) + self.assertEqual( + list(key for key in self.view), + list(key for key in self.sample), + ) # Assert the view is correct after modification self.sample['new'] = 'value' - self.assertEqual(list(k for k in self.view), - list(k for k in self.sample)) + self.assertEqual( + list(key for key in self.view), + list(key for key in self.sample), + ) def test_readonlydictview_len(self): self.assertEqual(len(self.view), len(self.sample)) @@ -1154,12 +1269,12 @@ class ReadOnlyDictViewTest(unittest.TestCase): self.assertEqual(len(self.view), len(self.sample)) def test_readonlydictview_get(self): - l = self.view.get('l') - self.assertEqual(l, self.sample.get('l')) + sample_list = self.view.get('sample_list') + self.assertEqual(sample_list, self.sample.get('sample_list')) # Assert that modification changed only copied value - l.append(4) - self.assertNotEqual(l, self.sample.get('l')) + sample_list.append(4) + self.assertNotEqual(sample_list, self.sample.get('sample_list')) # Assert that viewed dict is not changed self.assertEqual(self.sample, self.original_sample) @@ -1190,7 +1305,7 @@ class LazyUUIDTaskTest(TasklibTest): def setUp(self): super(LazyUUIDTaskTest, self).setUp() - self.stored = Task(self.tw, description="this is test task") + self.stored = Task(self.tw, description='this is test task') self.stored.save() self.lazy = LazyUUIDTask(self.tw, self.stored['uuid']) @@ -1272,9 +1387,9 @@ class LazyUUIDTaskSetTest(TasklibTest): def setUp(self): super(LazyUUIDTaskSetTest, self).setUp() - self.task1 = Task(self.tw, description="task 1") - self.task2 = Task(self.tw, description="task 2") - self.task3 = Task(self.tw, description="task 3") + self.task1 = Task(self.tw, description='task 1') + self.task2 = Task(self.tw, description='task 2') + self.task3 = Task(self.tw, description='task 3') self.task1.save() self.task2.save() @@ -1283,7 +1398,7 @@ class LazyUUIDTaskSetTest(TasklibTest): self.uuids = ( self.task1['uuid'], self.task2['uuid'], - self.task3['uuid'] + self.task3['uuid'], ) self.lazy = LazyUUIDTaskSet(self.tw, self.uuids) @@ -1315,7 +1430,7 @@ class LazyUUIDTaskSetTest(TasklibTest): taskset = set([self.task1]) lazyset = LazyUUIDTaskSet( self.tw, - (self.task2['uuid'], self.task3['uuid']) + (self.task2['uuid'], self.task3['uuid']), ) assert taskset | lazyset == self.lazy @@ -1330,7 +1445,7 @@ class LazyUUIDTaskSetTest(TasklibTest): taskset = set([self.task1, self.task2]) lazyset = LazyUUIDTaskSet( self.tw, - (self.task2['uuid'], self.task3['uuid']) + (self.task2['uuid'], self.task3['uuid']), ) assert taskset - lazyset == set([self.task1]) @@ -1345,13 +1460,19 @@ class LazyUUIDTaskSetTest(TasklibTest): taskset = set([self.task1, self.task2]) lazyset = LazyUUIDTaskSet( self.tw, - (self.task2['uuid'], self.task3['uuid']) + (self.task2['uuid'], self.task3['uuid']), ) assert taskset ^ lazyset == set([self.task1, self.task3]) assert lazyset ^ taskset == set([self.task1, self.task3]) - assert taskset.symmetric_difference(lazyset) == set([self.task1, self.task3]) - assert lazyset.symmetric_difference(taskset) == set([self.task1, self.task3]) + self.assertEqual( + taskset.symmetric_difference(lazyset), + set([self.task1, self.task3]), + ) + self.assertEqual( + lazyset.symmetric_difference(taskset), + set([self.task1, self.task3]), + ) lazyset ^= taskset assert lazyset == set([self.task1, self.task3]) @@ -1360,7 +1481,7 @@ class LazyUUIDTaskSetTest(TasklibTest): taskset = set([self.task1, self.task2]) lazyset = LazyUUIDTaskSet( self.tw, - (self.task2['uuid'], self.task3['uuid']) + (self.task2['uuid'], self.task3['uuid']), ) assert taskset & lazyset == set([self.task2]) @@ -1375,6 +1496,6 @@ class LazyUUIDTaskSetTest(TasklibTest): class TaskWarriorBackendTest(TasklibTest): def test_config(self): - assert self.tw.config['nag'] == "You have more urgent tasks." - assert self.tw.config['default.command'] == "next" - assert self.tw.config['dependency.indicator'] == "D" + assert self.tw.config['nag'] == 'You have more urgent tasks.' + assert self.tw.config['default.command'] == 'next' + assert self.tw.config['dependency.indicator'] == 'D'