Herding the Cats
Todoist にタスクを追加するスクリプトを Python で書いてみた 2020-01-18. 去年から Todoist でタスク管理をしているのですが、調べてみると Todoist でタスクやプロジェクトを扱うための API が用意されていることがわかりました。. Add the Todoist Python Library. The good folks at Doist created a library that makes our job really easy. In order to add it click on requirements.txt and add a new line todoist-python. Write the Codes. Ok now we just need to write the code that will make your shiny new cloud function do cool stuff.
- Python Todoist is a Python wrapper around the Todoist API. It provides a Python interface for the Todoist API.
- Analyzing Todoist data with Python If you use Todoist, you may have already wondered how to put all your task data in a single place and generate meaningful reports on top of it.
- CHAPTER 1 Modules 1.1pytodoist.todoist This module introduces abstractions over Todoist entities such as Users, Tasks and Projects. It’s purpose is to hide the.
I’ve taken a liking to Todoist for tracking my daily tasks, professional goals, and helping my managers organize our major intiatives. However, their reporting is lacking. You can use the print feature, but that’s not terribly flexible. Furthermore, I’d like to be able to have some sort of mechanism to track changes over time.
Todoist Install Python
Fortunately, Todoist provides a couple different APIs to develop against. They also provide support for a Python library that wraps their REST and Sync APIs.
Using the Python API
Todoist Python Online
What I want to do is build a service that provides some additional value for Todoist users, and I want to implement that using serverless technologies atop AWS Lambda. When you get into the serverless environment, you are restricted on things like storing data persistently within the serverless platform.
The Todoist Python library provides two modes of operation:
- Cache results locally to files
- No caching whatsoever
Neither of these are scalable solutions, particularly if scalablity and not being throttled are requirements.
How to fix?
I am not a Python-ista. I come from a Perl, Java and, more recently, a JavaScript background. Looking at the source for the Python API, I want to immediately re-architect the API code so that storage backends can be arbitrarily changed out depending on the desired backend.
That’s a bit involved for the way the API class is currently written. I’m also not quite comfortable to take an axe to their API and fight that battle (yet).
Without completely rewriting the Todoist Python library, how did I work around this?
One thing I did learn about is monkey patching to dynamically modify classes. With that said, I was able to fairly trivally replace two methods within the TodoistAPI class in order to use Redis as a backing store for the cached Todoist data.
Is this perfect? No! However, it does allow me to continue working on my prototype without getting bogged down in a much larger conversation…
Implementing the solution
To keep it simple, all of this code landed in the prototype script I’ve been using to explore the API and the library. One could abstract this out appropriately (and perhaps that’s yet a better position than attempting to re-architect the Todoist Python library).
Below are two methods I created. The intent was to mimic, as closely as possible, the original API code as to not disturb the original functionality within the library. This was done by replacing two specific internal calls, _read_cache() and _write_cache().
You will note that I am not doing anything fancy with Redis. I had started with delusions of grandeur and started down the path of using HSET and HGET to store hashes directly. I quickly learned that this is not straightforward, especially when dealing with types other than strings. It is possible to do all sorts of contortions to get there, either manually mapping and decoding the data returned from Redis, or using Redis 4 and the ReJSON module. One should note that (at the time of writing) AWS ElastiCache is still on Redis 3, and therefore does not support modules.
With my tail between my legs, I fell back to simply serializing the JSON completely as a string and also the sync token – mimicking exactly the way the original methods work on the file system, except instead writing that data to Redis. It works for now, but I’m waiting for the other shoe to drop as I dig further into the weeds.
Read from the Cache
Write to the Cache
Below is where the magic happens. Using the ability to monkey patch, I insert my newly crafted methods in place of the originals. The code following this proceeds to initialize the API and use it as per the Todoist Python library docs.
Inject Methods into the Todoist API
Rethinking the Python Library
I’m surprised they didn’t do this out of the gate. They did such a good job abstracting out all of the various object types that could come from their web service, but didn’t fully think through the caching issue. I do give them kudos for considering SOME FORM of caching, as that provides immediate relief on their backend. However, the library needs some work in order to provide scaling and protections on the “client’s” side as well. Here’s what I’m thinking:
Abstract the caching piece out of the TodoistAPI class and implement a generic “None” caching class (aka the general interface). This interface would implement empty _read_cache() and _write_cache() methods.
Provide a default file system caching class that would implement the current file system reading / writing that is currently embedded in the current TodoistAPI class.
Allow the TodoistAPI class to pass in a configurable caching class. This would be something like a formal implementation of this Redis monkey patch, or other classes that implement caching with other backing stores. If no caching class is given to the API, it defaults to the file caching class so that it behaves as it does today out of the box.
I have forked the todoist-python library, but I’ve not yet committed the changes I’ve been batting around. I will do that soon.
Wrapping Up
That’s it! Making a couple slight tweaks to the existing Todoist Python library will enable you to write to Redis as a caching store. One could conceive that it would be equally trivial to implement these methods to write to other backends like DynamoDB or other platforms.
I have provided this full snippet as a Gist on Github.
Inspired by the diary app in the Databases in Python course of Kenneth Love, I've made a to-do list app. It lets you add and delete entries, modify them, as well as flag them 'DONE'. There is a handy cleanup feature that gets rid of all completed (DONE) entries that are more than a week old, unless they are flagged 'Protected'.Please feel free to make suggestions and comments!:)
very cool, trying to do the same thing. already created a program that takes links i found interesting on the web and stores them. you can tag by keyword and search for keywords to find links quickly.
one problem i have encountered, let me know how you solved it: when running the program from the terminal (another directory) i have to specify the absolute filepath. is there any solution to not hardcore said path to locate the db?
Todoist Python Api
Posting to the forum is only allowed for members with active accounts.
Please sign in or sign up to post.