+ def __str__(self):
+ s = six.text_type(self.__unicode__())
+ if not six.PY3:
+ s = s.encode('utf-8')
+ return s
+
+ def __repr__(self):
+ return str(self)
+
+
+class TaskAnnotation(TaskResource):
+ read_only_fields = ['entry', 'description']
+
+ def __init__(self, task, data={}):
+ self.task = task
+ self._load_data(data)
+
+ def deserialize_entry(self, data):
+ return datetime.datetime.strptime(data, DATE_FORMAT) if data else None
+
+ def serialize_entry(self, date):
+ return date.strftime(DATE_FORMAT) if date else ''
+
+ def remove(self):
+ self.task.remove_annotation(self)
+
+ def __unicode__(self):
+ return self['description']
+
+ __repr__ = __unicode__
+
+
+class Task(TaskResource):
+ read_only_fields = ['id', 'entry', 'urgency', 'uuid']
+
+ class DoesNotExist(Exception):
+ pass
+
+ class CompletedTask(Exception):
+ """
+ Raised when the operation cannot be performed on the completed task.
+ """
+ pass
+
+ class DeletedTask(Exception):
+ """
+ Raised when the operation cannot be performed on the deleted task.
+ """
+ pass
+
+ class NotSaved(Exception):
+ """
+ Raised when the operation cannot be performed on the task, because
+ it has not been saved to TaskWarrior yet.
+ """
+ pass
+
+ def __init__(self, warrior, data={}, **kwargs):
+ self.warrior = warrior
+
+ # We keep data for backwards compatibility
+ kwargs.update(data)
+
+ self._load_data(kwargs)
+ self._modified_fields = set()
+
+ def __unicode__(self):
+ return self['description']
+
+ @property
+ def completed(self):
+ return self['status'] == six.text_type('completed')
+
+ @property
+ def deleted(self):
+ return self['status'] == six.text_type('deleted')
+
+ @property
+ def waiting(self):
+ return self['status'] == six.text_type('waiting')
+
+ @property
+ def pending(self):
+ return self['status'] == six.text_type('pending')
+
+ @property
+ def saved(self):
+ return self['uuid'] is not None or self['id'] is not None
+