How to uncheck a subtree of tasks?
dluxhu opened this issue · comments
Is it possible to query completed subtasks of active tasks somehow? I couldn't figure it out how:
api.items
does not seem to return them.api.completed.get_all()
returns them, but they don't return the full property list (parent_id
is missing for example) and it is not possible to filter forparent_id
either.
What I'd like to do is to uncheck a whole subtree of tasks given a root task id.
I have written a script that does this. You need to loop through all children one at a time, and uncomplete them.
Any update on this by any chance?
Hey @dluxhu perhaps I can help you out here. As I said, I have already written this functionality using this Todoist Python library. I will paste the function here that does it.
def get_sub_items(self, parent_id):
sub_items = []
for tds_item in self.api.state['items']:
if tds_item['parent_id'] == parent_id:
sub_items.append(self._tds_item_to_item(tds_item))
return sub_items
def uncomplete_item(self, item, *, recursively=True):
# Get the raw item, and complete it
tds_item = item.tds_item
# Only perform the uncomplete action IF the item is checked
if tds_item['checked']:
tds_item.uncomplete()
# If the user wants it, uncomplete the children and attributes as well
if recursively:
# Uncomplete all sub-items (if they exist and have been requested above)
for sub_item in self.get_sub_items(tds_item['id']):
self.uncomplete_item(sub_item, recursively=True)
return True
My code has some helper functions that translate data, etc., but this should give you an idea.
Lloyd
Hi @dluxhu , you'll notice that I am searching every item to find the sub-items. This means looping over every single Todoist item in my account. Thankfully, Python is fast and I only have perhaps 1000 Todoist items at one time. Even if you have many thousands of Todoist items (what are you doing in Todoist..?), it would still be a quick operation.
As for your questions about caching and stale data. Perhaps I do not understand your use case. You can request a sync of your data 50 times a minute, which is an absurdly high and useful limit for most people. Here is the code I call before I do an operation:
api = TodoistAPI(user_api_token)
api.sync()
After this, all data is synced and correct.
Are you in need of something in addition to that?
Lloyd
I have a Heroku-based Python client that allows me to do special things with Todoist. One of them allows me to uncheck all children of a repeating task, when I complete the repeating task. I have been using this system for around 6 months, and it has not failed me yet. However, out of curiosity, I ran a test to try and replicate your issue.
Test 1
- Create a repeating task
- Add a subtask
- Mark repeating task (parent) complete. This of course does not actually mark the parent as complete, since it is repeating.
- (server automatically notices change and runs code)
- Child is uncompleted: Success!
Test 2
- Create a repeating task
- Add a subtask
- Restart my Heroku servers (dynos)
- Mark repeating task complete
- (server automatically notices change and runs code)
- Child is left completed: Failure...
- Add a new child and complete it
- Mark repeating task as complete again
- New child is uncompleted (Success!), old child is still left completed (Failure...)
It appears you have identified a bug in my code, and a limitation of the Todoist SyncAPI I was not aware of until right now. It is both frustrating that sync does not include completed tasks (for this exact reason) and a really good thing (for performance reasons).
I may not work on this code for another couple of months, so unfortunately I cannot immediately try to resolve both of our issues here. Have you looked into this to see if there is a way to force-sync completed tasks? I think there is a way based on some documentation I read awhile ago, but I cannot remember it right now.
Lloyd
Hi Lloyd,
What I found in the API is in the first comment of this bug, but it is not adequate.
Balázs