Skip to content

Commit c32ba0e

Browse files
Save work.
1 parent 9357c4c commit c32ba0e

File tree

4 files changed

+206
-10
lines changed

4 files changed

+206
-10
lines changed

source/one_way_sync.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,9 @@ def sync_todoist_to_habitica():
6767
todoist_tasks, todo_api = get_tasks(todo_token) # todoist_tasks used to be tod_tasks
6868

6969
tod_tasks = []
70-
tzone = None
7170
for task in todoist_tasks:
7271
tod_tasks.append(TodTask(task))
7372

74-
if tzone is None:
75-
# assumption is that timezone from Todoist
76-
# is the same as local timezone
77-
tzone = pytz.timezone(str(get_localzone()))
78-
79-
for task in tod_tasks:
80-
if task.due != '':
81-
task.task_dict['due'] = task.due.astimezone(tzone)
82-
8373
# TODO: add back to filter out repeating older than a certain amount?
8474
# date stuff
8575
# today = datetime.now()

source/todo_task.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from builtins import *
1111
from datetime import datetime
1212
from tzlocal import get_localzone
13+
import pytz
1314

1415

1516
#from .dates import parse_date_utc
@@ -38,6 +39,9 @@ def __init__(self, task=None):
3839

3940
self.__task_dict = task_dict
4041

42+
tzone = pytz.timezone(str(get_localzone()))
43+
self.__task_dict['due']['date'] = self.due.astimezone(tzone)
44+
4145
@property
4246
#Get the task dictionary as is
4347
def task_dict(self):
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# pylint: disable=missing-function-docstring, missing-module-docstring, invalid-name, import-error
2+
# integration test for one_way_sync.py
3+
import pickle
4+
from datetime import datetime
5+
from dateutil.tz import tzoffset
6+
import pytest
7+
import requests
8+
import vcr
9+
from mockito import when, mock, when2, verify, captor, ANY, arg_that
10+
from one_way_sync import sync_todoist_to_habitica
11+
from todoist_api_python import models
12+
from common_fixtures import empty_pickle, fake_config_file, mock_web_calls # pylint: disable=unused-import
13+
# pylint: enable=invalid-name
14+
15+
16+
def case1():
17+
hab_val = {"data": []}
18+
19+
due_dict = {'date': '2024-12-27',
20+
'datetime': None,
21+
'is_recurring': True,
22+
'string': 'every day',
23+
'timezone': None}
24+
duedate = models.Due.from_dict(due_dict)
25+
created_at = '2025-01-04T00:00:00.0Z'
26+
27+
todoist_task = models.Task(None, # assignee id
28+
None, # assigner id
29+
0, # comment count
30+
False, # is_completed
31+
'Test task 1', # content
32+
created_at, # created_at
33+
'59292300', # creater_id
34+
'', # description
35+
duedate, # due
36+
'8296278113', # id
37+
[], # labels
38+
0, # order
39+
None, # parent id
40+
1, # priority
41+
'9187482462', # project id
42+
'19099659', # section id
43+
None, # url
44+
'' # duration
45+
)
46+
todo_tasks = [todoist_task]
47+
completed_todos = []
48+
49+
inputs = {'hab_task': hab_val,
50+
'completed_habs': hab_val,
51+
'todo_tasks': todo_tasks,
52+
'done_tasks': completed_todos}
53+
54+
return inputs
55+
56+
57+
'''def check_headers(headers):
58+
assert headers['url'] == 'https://habitica.com'
59+
assert headers['x-api-user'] == 'cd18fc9f-b649-4384-932a-f3bda6fe8102'
60+
assert headers['x-api-key'] == '18f22441-2c87-6d8e-fb2a-3fa670837b5a'
61+
'''
62+
63+
64+
def verify_post_request(data):
65+
if data['text'] == 'Test task 1':
66+
assert data['type'] == 'todo'
67+
assert data['text'] == 'Test task 1'
68+
assert data['date'] == '12/27/2024, 00:00:00'
69+
assert data['alias'] == '8296278113'
70+
assert data['priority'] == '2'
71+
assert data['attribute'] == 'str'
72+
return True
73+
return False
74+
75+
'''
76+
def verify_put_request(the_url, the_data):
77+
assert the_url.value == 'https://habitica.com/api/v3/tasks/96935939'
78+
data = the_data.value
79+
assert data['alias'] == '96935939'
80+
assert data['text'] == 'Some test task'
81+
assert data['priority'] == 1
82+
'''
83+
84+
85+
def verify_pickle_dump(dump_dict):
86+
data = dump_dict.value
87+
# check 'simple' values
88+
assert '8296278113' in data.keys()
89+
data = data['8296278113']
90+
assert data['recurs'] == 'No'
91+
assert data['duelast'] == 'NA'
92+
# Get objects to verify
93+
assert 'tod' in data.keys()
94+
tod_task = data['tod']
95+
assert 'hab' in data.keys()
96+
hab_task = data['hab']
97+
# Check tod_task
98+
tod_data = tod_task.task_dict
99+
assert tod_data['content'] == 'Test task 1'
100+
assert tod_data['id'] == '8296278113'
101+
assert tod_data['created_at'] == '2025-01-04T00:00:00.0Z'
102+
assert tod_data['priority'] == 1
103+
# Check hab_task
104+
hab_data = hab_task.task_dict
105+
assert hab_data['type'] == 'daily'
106+
assert hab_data['alias'] == '96935939'
107+
assert hab_data['text'] == 'Some test task'
108+
assert hab_data['priority'] == 1
109+
expected_due = datetime(2024, 12, 27, tzinfo=tzoffset(None, -25200))
110+
due = hab_task.due
111+
assert due == expected_due
112+
113+
114+
# pylint: disable=missing-class-docstring
115+
class TestDailies:
116+
test_vcr = vcr.VCR(
117+
serializer='yaml',
118+
cassette_library_dir="/tmp/throwaway",
119+
record_mode='none'
120+
)
121+
122+
# pylint: disable=redefined-outer-name, unused-argument, too-many-locals, too-few-public-methods
123+
@pytest.mark.parametrize("mock_web_calls", [case1()], indirect=True)
124+
@pytest.mark.parametrize("pickle_in", [empty_pickle()], indirect=True)
125+
def test(self,
126+
fake_config_file,
127+
mock_web_calls):
128+
# pylint: enable=redefined-outer-name, unused-argument
129+
130+
# set default response
131+
response = mock({'status': 200, 'ok': True}, spec=requests.Response)
132+
133+
# mock out post to Habitica
134+
when(requests).post(...).thenReturn(response)
135+
136+
# mock out put to Habitica
137+
when(requests).put(...).thenReturn(response)
138+
139+
# mock out web call to get id
140+
hab_task = {'text': 'Some test task', 'priority': '', 'attribute': '',
141+
'type': 'todo', '_id': 'a94e8f46-5c14-f14a-f189-e669e239730a',
142+
'completed': False, 'alias': '96935939', 'date': '12/27/2024, 00:00:00'}
143+
hab_val2 = {"data": hab_task}
144+
145+
response2 = mock({'status': 200, 'ok': True}, spec=requests.Response)
146+
task_url = 'https://habitica.com/api/v3/tasks/8296278113'
147+
when(requests).get(headers={'url': 'https://habitica.com',
148+
'x-api-user': 'cd18fc9f-b649-4384-932a-f3bda6fe8102',
149+
'x-api-key': '18f22441-2c87-6d8e-fb2a-3fa670837b5a'},
150+
url=task_url).thenReturn(response2)
151+
when(response2).json().thenReturn(hab_val2)
152+
153+
# mock dump of pickle file
154+
pkl_out = mock()
155+
pkl_file = mock()
156+
when2(open, ...).thenCallOriginalImplementation()
157+
when2(open, 'oneWay_matchDict.pkl', 'wb').thenReturn(pkl_file)
158+
when(pickle).Pickler(...).thenReturn(pkl_out)
159+
when(pkl_out).dump(...)
160+
161+
# using get_all_habtasks() which contains requests.get(), uses the monkeypatch
162+
with self.test_vcr.use_cassette("null.yaml"):
163+
sync_todoist_to_habitica()
164+
165+
# verify post request
166+
'''the_url = captor(ANY(str))
167+
the_data = captor(ANY(dict))
168+
the_headers = captor(ANY(dict))
169+
verify(requests, times=1).post(url='https://habitica.com/api/v3/tasks/user/',
170+
data=arg_that(verify_post_request),
171+
headers=the_headers)
172+
# check_headers(the_headers.value)'''
173+
174+
# verify put request
175+
'''the_url = captor(ANY(str))
176+
verify(requests, times=1).put(headers=the_headers, url=the_url, data=the_data)'''
177+
# check_headers(the_headers.value)
178+
# verify_put_request(the_url, the_data)
179+
180+
# verify pickle dump
181+
dump_dict = captor(ANY(dict))
182+
verify(pkl_out, times=1).dump(dump_dict)
183+
verify_pickle_dump(dump_dict)

test/integration/oneWaySyncTests/end_to_end_integration_test.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,25 @@ def test_end_to_end(self,
157157
save_pickle_for_test(data)
158158
assert len(data.keys()) == expected_vals.keys
159159

160+
num_todos = 0
161+
num_habits = 0
162+
num_dailies = 0
163+
num_other = 0
164+
for value in data.values():
165+
hab_type = value['hab'].category
166+
if hab_type == 'todo':
167+
num_todos += 1
168+
elif hab_type == 'habit':
169+
num_habits += 1
170+
elif hab_type == 'daily':
171+
num_dailies += 1
172+
else:
173+
num_other += 1
174+
assert num_todos == 77
175+
assert num_habits == 0
176+
assert num_dailies < 0
177+
assert num_other == 0
178+
160179
# check put
161180
if expected_vals.iters != 0:
162181
the_url = captor(ANY(str))

0 commit comments

Comments
 (0)