X-Git-Url: https://git.madduck.net/etc/taskwarrior.git/blobdiff_plain/4d6ac9d4196e0abab277706b58e63b56f2fe0ba9..238c0ba7d462d67f8b847bee06233a7fd20893c4:/tasklib/task.py diff --git a/tasklib/task.py b/tasklib/task.py index c821fcc..6ebee4c 100644 --- a/tasklib/task.py +++ b/tasklib/task.py @@ -1,6 +1,5 @@ from __future__ import print_function import copy -import datetime import importlib import json import logging @@ -39,6 +38,11 @@ class ReadOnlyDictView(object): def __len__(self): return len(self.viewed_dict) + def __unicode__(self): + return six.u('ReadOnlyDictView: {0}'.format(repr(self.viewed_dict))) + + __repr__ = __unicode__ + def get(self, key, default=None): return copy.deepcopy(self.viewed_dict.get(key, default)) @@ -76,7 +80,6 @@ class TaskResource(SerializingObject): if update_original: self._original_data = copy.deepcopy(self._data) - def __getitem__(self, key): # This is a workaround to make TaskResource non-iterable # over simple index-based iteration @@ -121,7 +124,7 @@ class TaskResource(SerializingObject): # to pass that to TaskWarrior. data_tuples = filter(lambda t: t[1] is not '', data_tuples) data = dict(data_tuples) - return json.dumps(data, separators=(',',':')) + return json.dumps(data, separators=(',', ':')) @property def _modified_fields(self): @@ -165,6 +168,97 @@ class TaskAnnotation(TaskResource): __repr__ = __unicode__ +class LazyUUIDTask(object): + """ + A lazy wrapper around Task object, referenced by UUID. + + - Supports comparison with LazyUUIDTask or Task objects (equality by UUIDs) + - If any attribute other than 'uuid' requested, a lookup in the + backend will be performed and this object will be replaced by a proper + Task object. + """ + + def __init__(self, tw, uuid): + self._tw = tw + self._uuid = uuid + + def __getitem__(self, key): + # LazyUUIDTask does not provide anything else other than 'uuid' + if key is 'uuid': + return self._uuid + else: + self.replace() + return self[key] + + def __getattr__(self, name): + # Getattr is called only if the attribute could not be found using + # normal means + self.replace() + return self.name + + def __eq__(self, other): + if other['uuid']: + # For saved Tasks, just define equality by equality of uuids + return self['uuid'] == other['uuid'] + + def __hash__(self): + return self['uuid'].__hash__() + + def replace(self): + """ + Performs conversion to the regular Task object, referenced by the + stored UUID. + """ + + replacement = self._tw.tasks.get(uuid=self._uuid) + self.__class__ = replacement.__class__ + self.__dict__ = replacement.__dict__ + + +class LazyUUIDTaskSet(object): + """ + A lazy wrapper around TaskQuerySet object, for tasks referenced by UUID. + + - Supports 'in' operator with LazyUUIDTask or Task objects + - If iteration over the objects in the LazyUUIDTaskSet is requested, the + LazyUUIDTaskSet will be converted to QuerySet and evaluated + """ + + def __init__(self, tw, uuids): + self._tw = tw + self._uuids = set(uuids) + + def __getattr__(self, name): + # Getattr is called only if the attribute could not be found using + # normal means + self.replace() + return self.name + + def __eq__(self, other): + return set(t['uuid'] for t in other) == self._uuids + + def __contains__(self, task): + return task['uuid'] in self._uuids + + def __len__(self): + return len(self._uuids) + + def __iter__(self): + self.replace() + for task in self: + yield task + + def replace(self): + """ + Performs conversion to the regular TaskQuerySet object, referenced by + the stored UUIDs. + """ + + replacement = self._tw.tasks.filter(' '.join(self._uuids)) + self.__class__ = replacement.__class__ + self.__dict__ = replacement.__dict__ + + class Task(TaskResource): read_only_fields = ['id', 'entry', 'urgency', 'uuid', 'modified'] @@ -225,7 +319,7 @@ class Task(TaskResource): # Create the TaskWarrior instance if none passed if backend is None: - backends = importlib.import_module('.backends') + backends = importlib.import_module('tasklib.backends') hook_parent_dir = os.path.dirname(os.path.dirname(sys.argv[0])) backend = backends.TaskWarrior(data_location=hook_parent_dir) @@ -274,7 +368,6 @@ class Task(TaskResource): # If the tasks are not saved, compare the actual instances return id(self) == id(other) - def __hash__(self): if self['uuid']: # For saved Tasks, just define equality by equality of uuids @@ -420,6 +513,7 @@ class Task(TaskResource): else: self._load_data(new_data) + class TaskQuerySet(object): """ Represents a lazy lookup for a task objects.