In order to check the existence of a key in a TodoistAPI
class I use the "in" keyword. However, it causes a KeyError
.
I isolated the code fragments to check what exactly causes the KeyError
and which inputs are provided.
api = TodoistAPI(token)
api.sync()
print("id" in api.state["items"][0])
api.state["items"][0]
contains:
Item({'assigned_by_uid': None,
'checked': 0,
'child_order': 0,
'collapsed': 0,
'content': 'example task',
'date_added': '0',
'date_completed': None,
'day_order': 0,
'due': {'date': '0',
'is_recurring': True,
'lang': 'de',
'string': 'every day',
'timezone': None},
'has_more_notes': False,
'id': 0,
'in_history': 0,
'is_deleted': 0,
'labels': [0, 0],
'parent_id': None,
'priority': 1,
'project_id': 0,
'responsible_uid': None,
'section_id': None,
'sync_id': None,
'user_id': 0})
I expect the output of print(...)
to be True
or False
, but the actual output is as follows
Traceback (most recent call last):
File "/Users/path/to/file.py", line 11, in
print("id" in applicationInterface.state["items"][0])
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/todoist/models.py", line 16, in __getitem__
return self.data[key]
KeyError: 0
Process finished with exit code 1
I also created an issue in the Todoist Github-Repository: https://github.com/Doist/todoist-python/issues/64
Ultimately, this is a bug in the Todoist
library.
First, lets imagine an additional line like this:
item = api.state["items"][0]
print("id" in item)
This means that when you write "id" in item
, Python checks for a __contains__
method in the class. The Item
class does not define __contains__
, but does define __getitem__
(through its base Model
).
According to the Python language reference, __getitem__
will be called to evaluate the in
, using a fallback to a sequence protocol.
I think the logic used to evaluate "id" in item
is equivalent to this:
## Implicit logic used to evaluate `"id" in item`
for i in itertools.count():
try:
result = item[i]
except IndexError:
return False
if result is "id" or result == "id":
return True
return False
Within the evaluation of Model.__getitem__
, a KeyError is raised. At a fundamental level, if Model
is a mapping type, I think it should implement __contains__
as well as __getitem__
. The Python data model says this:
It is recommended that both mappings and sequences implement the
__contains__()
method to allow efficient use of thein
operator; for mappings,in
should search the mapping’s keys