]> 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: Provide automatic hook type detection
[etc/taskwarrior.git] / tasklib / task.py
index 4dab52804502ca076961f15f8ec1d37dd38c70c8..040c15bd274e06353b1b380894ee9ad0e4154c90 100644 (file)
@@ -207,7 +207,7 @@ class Task(TaskResource):
         pass
 
     @classmethod
         pass
 
     @classmethod
-    def from_input(cls, modify=False):
+    def from_input(cls, input_file=sys.stdin, modify=None):
         """
         Creates a Task object, directly from the stdin, by reading one line.
         If modify=True, two lines are used, first line interpreted as the
         """
         Creates a Task object, directly from the stdin, by reading one line.
         If modify=True, two lines are used, first line interpreted as the
@@ -218,18 +218,25 @@ class Task(TaskResource):
         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.
         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)
 
         """
 
         # TaskWarrior instance is set to None
         task = cls(None)
 
+        # Detect the hook type if not given directly
+        name = os.path.basename(sys.argv[0])
+        modify = name.startswith('on-modify') if modify is None else modify
+
         # Load the data from the input
         # Load the data from the input
-        task._load_data(json.loads(sys.stdin.readline().strip()))
+        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:
 
         # 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(sys.stdin.readline().strip()))
+            task._update_data(json.loads(input_file.readline().strip()))
 
         return task
 
 
         return task
 
@@ -277,7 +284,7 @@ class Task(TaskResource):
                 yield key
 
     @property
                 yield key
 
     @property
-    def _is_modified(self):
+    def modified(self):
         return bool(list(self._modified_fields))
 
     @property
         return bool(list(self._modified_fields))
 
     @property
@@ -370,7 +377,7 @@ class Task(TaskResource):
         self.refresh(only_fields=['status'])
 
     def save(self):
         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']
             return
 
         args = [self['uuid'], 'modify'] if self.saved else ['add']
@@ -390,6 +397,9 @@ class Task(TaskResource):
             # Circumvent the ID storage, since ID is considered read-only
             self._data['id'] = int(id_lines[0].split(' ')[2].rstrip('.'))
 
             # 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):
         self.refresh()
 
     def add_annotation(self, annotation):
@@ -461,7 +471,9 @@ class Task(TaskResource):
         """
 
         # We need to remove spaces for TW-1504, use custom separators
         """
 
         # We need to remove spaces for TW-1504, use custom separators
-        return json.dumps(self._data, separators=(',',':'))
+        data = dict((key, self._serialize(key, value))
+                    for key, value in six.iteritems(self._data))
+        return json.dumps(data, separators=(',',':'))
 
 class TaskFilter(SerializingObject):
     """
 
 class TaskFilter(SerializingObject):
     """