GothenburgBitFactory / tasklib

A Python library for interacting with taskwarrior databases.
http://tasklib.readthedocs.org/en/latest/
BSD 3-Clause "New" or "Revised" License
147 stars 28 forks source link

Problems saving tag lists #18

Closed niknow closed 9 years ago

niknow commented 9 years ago

Modifications to a tag list of a task might not be saved.

1) Minimum working example: Assuming our Taskwarrior has a task with id=1, the following will correctly add the tags hello and world to the task:

from tasklib.task import TaskWarrior
tw = TaskWarrior(data_location='path_to_my_taskwarrior')
task = tw.tasks.filter('1').get()
task['tags'] = ['hello', 'world']
print task['tags']  #prints ['hello', 'world'] correctly
task.save() #saves the tag list correctly

2) Minimum not working example: Now assume that the task with id=1 already has the tag hello. The following will not append world to the tag list:

from tasklib.task import TaskWarrior
tw = TaskWarrior(data_location='path_to_my_taskwarrior')
task = tw.tasks.filter('1').get()
task['tags'].append('world')
print task['tags']   #prints ['hello', 'world'] correctly
task.save() #does not save the taglist

I think the reason why the first example works and the second does not is line 339 of task.py from the save()-function of Task:

args.extend(self._get_modified_fields_as_args())

In the first example, tags has correctly been added to the _modified_fields of the task, because the = operator actually assigns a new list to task['tags']. This is correctly recognized by the __setitem__ method of the TaskRessource and thus added to the _modified_fields.

However, in the second example, the task['tags'].append('world') does not cause tags to be added to the _modified_fields, because the list pointer is not changed. Only the elements of the list are changed and this cannot be detected by the __setitem__ method (see http://stackoverflow.com/questions/27680343/why-is-setitem-not-invoked-when-changing-list-type-data). Similarly, things like task['tags'][0]='foo' won't work either.

So how can a user add a tag to a task and save it? The only workaround I could come up with so far is to replace task['tags'].append('world') by

taglist = task['tags'] if task['tags'] else []
taglist.append('world')
task['tags'] = taglist

which is a bit cumbersome. :(

tbabej commented 9 years ago

Yes, I am aware of this problem. This is actually true of any mutable type generated by __getitem__ function. Rob pointed out in #17 he's working on a refactor to address this.

tbabej commented 9 years ago

Solved in develop.