]> git.madduck.net Git - etc/taskwarrior.git/blobdiff - tasklib/task.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Task: Change export_data() to expect non-serialized values in self._data dict
[etc/taskwarrior.git] / tasklib / task.py
index 1ab63479d96e140873730c2a39a5eea345627a78..fc56a89a33f8d8cdccde96803a1bb2820703f81f 100644 (file)
@@ -5,6 +5,7 @@ import json
 import logging
 import os
 import six
+import sys
 import subprocess
 
 DATE_FORMAT = '%Y%m%dT%H%M%SZ'
@@ -205,6 +206,36 @@ class Task(TaskResource):
         """
         pass
 
+    @classmethod
+    def from_input(cls, input_file=sys.stdin, modify=False):
+        """
+        Creates a Task object, directly from the stdin, by reading one line.
+        If modify=True, two lines are used, first line interpreted as the
+        original state of the Task object, and second line as its new,
+        modified value. This is consistent with the TaskWarrior's hook
+        system.
+
+        Object created by this method should not be saved, deleted
+        or refreshed, as t could create a infinite loop. For this
+        reason, TaskWarrior instance is set to None.
+
+        Input_file argument can be used to specify the input file,
+        but defaults to sys.stdin.
+        """
+
+        # TaskWarrior instance is set to None
+        task = cls(None)
+
+        # Load the data from the input
+        task._load_data(json.loads(input_file.readline().strip()))
+
+        # If this is a on-modify event, we are provided with additional
+        # line of input, which provides updated data
+        if modify:
+            task._update_data(json.loads(input_file.readline().strip()))
+
+        return task
+
     def __init__(self, warrior, **kwargs):
         self.warrior = warrior
 
@@ -249,7 +280,7 @@ class Task(TaskResource):
                 yield key
 
     @property
-    def _is_modified(self):
+    def modified(self):
         return bool(list(self._modified_fields))
 
     @property
@@ -342,7 +373,7 @@ class Task(TaskResource):
         self.refresh(only_fields=['status'])
 
     def save(self):
-        if self.saved and not self._is_modified:
+        if self.saved and not self.modified:
             return
 
         args = [self['uuid'], 'modify'] if self.saved else ['add']
@@ -362,6 +393,9 @@ class Task(TaskResource):
             # Circumvent the ID storage, since ID is considered read-only
             self._data['id'] = int(id_lines[0].split(' ')[2].rstrip('.'))
 
+        # Refreshing is very important here, as not only modification time
+        # is updated, but arbitrary attribute may have changed due hooks
+        # altering the data before saving
         self.refresh()
 
     def add_annotation(self, annotation):
@@ -427,6 +461,15 @@ class Task(TaskResource):
         else:
             self._load_data(new_data)
 
+    def export_data(self):
+        """
+        Exports current data contained in the Task as JSON
+        """
+
+        # We need to remove spaces for TW-1504, use custom separators
+        data = dict((key, self._serialize(key, value))
+                    for key, value in six.iteritems(self._data))
+        return json.dumps(data, separators=(',',':'))
 
 class TaskFilter(SerializingObject):
     """