this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add simple todoist sync

+133 -11
+1
.gitignore
··· 11 11 12 12 # Project specific 13 13 *.pickle 14 + local.ini
+28 -10
main.py
··· 1 1 import typer 2 - from dataclasses import dataclass 2 + 3 3 from rich import print 4 4 import pickle 5 + from shared import Task 6 + from todoist import fetch_tasks 5 7 6 - @dataclass 7 - class Task: 8 - name: str 9 - 10 - tasks = [] 11 - 12 - with open("data.pickle", "rb") as f: 13 - tasks = pickle.load(f) 8 + try: 9 + with open("data.pickle", "rb") as f: 10 + tasks = pickle.load(f) 11 + except FileNotFoundError: 12 + tasks = [] 14 13 15 14 app = typer.Typer() 16 15 17 16 @app.command() 18 17 def main(): 19 - print("hello world!") 20 18 print(tasks) 21 19 22 20 @app.command() 23 21 def add_task(name: str): 24 22 tasks.append(Task(name=name)) 23 + save_tasks() 24 + 25 + 26 + @app.command() 27 + def sync_todoist(): 28 + todoist_tasks = fetch_tasks() 29 + 30 + new_tasks = [] 31 + for task in todoist_tasks: 32 + for existing_task in tasks: 33 + if existing_task.source == 'todoist' and existing_task.source_id == task.source_id: 34 + break 35 + else: 36 + new_tasks.append(task) 37 + 38 + tasks.extend(new_tasks) 39 + save_tasks() 40 + 41 + 42 + def save_tasks(): 25 43 with open("data.pickle", "wb") as f: 26 44 pickle.dump(tasks, f) 27 45
+1
pyproject.toml
··· 5 5 readme = "README.md" 6 6 requires-python = ">=3.13" 7 7 dependencies = [ 8 + "httpx>=0.28.1", 8 9 "typer>=0.24.1", 9 10 ]
+8
shared.py
··· 1 + from dataclasses import dataclass 2 + 3 + @dataclass 4 + class Task: 5 + name: str 6 + 7 + source: str 8 + source_id: str
+23
todoist.py
··· 1 + from shared import Task 2 + from rich import print 3 + import httpx 4 + import configparser 5 + 6 + 7 + 8 + def fetch_tasks() -> list[Task]: 9 + config = configparser.ConfigParser() 10 + config.read('local.ini') 11 + 12 + todoist_key = config['todoist']['key'] 13 + project_id = config['todoist']['default_project'] 14 + 15 + headers = {"Authorization":f"Bearer {todoist_key}"} 16 + params = {"project_id": project_id} 17 + r = httpx.get(f'https://api.todoist.com/api/v1/tasks', params=params, headers=headers) 18 + 19 + return [Task(name=task["content"], source="todoist", source_id=[task["id"]]) for task in r.json()['results']] 20 + 21 + if __name__ == "__main__": 22 + t = fetch_tasks() 23 + print(t)
+72 -1
uv.lock
··· 12 12 ] 13 13 14 14 [[package]] 15 + name = "anyio" 16 + version = "4.12.1" 17 + source = { registry = "https://pypi.org/simple" } 18 + dependencies = [ 19 + { name = "idna" }, 20 + ] 21 + sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } 22 + wheels = [ 23 + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, 24 + ] 25 + 26 + [[package]] 27 + name = "certifi" 28 + version = "2026.2.25" 29 + source = { registry = "https://pypi.org/simple" } 30 + sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } 31 + wheels = [ 32 + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, 33 + ] 34 + 35 + [[package]] 15 36 name = "click" 16 37 version = "8.3.1" 17 38 source = { registry = "https://pypi.org/simple" } ··· 33 54 ] 34 55 35 56 [[package]] 57 + name = "h11" 58 + version = "0.16.0" 59 + source = { registry = "https://pypi.org/simple" } 60 + sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } 61 + wheels = [ 62 + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, 63 + ] 64 + 65 + [[package]] 66 + name = "httpcore" 67 + version = "1.0.9" 68 + source = { registry = "https://pypi.org/simple" } 69 + dependencies = [ 70 + { name = "certifi" }, 71 + { name = "h11" }, 72 + ] 73 + sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } 74 + wheels = [ 75 + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, 76 + ] 77 + 78 + [[package]] 79 + name = "httpx" 80 + version = "0.28.1" 81 + source = { registry = "https://pypi.org/simple" } 82 + dependencies = [ 83 + { name = "anyio" }, 84 + { name = "certifi" }, 85 + { name = "httpcore" }, 86 + { name = "idna" }, 87 + ] 88 + sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } 89 + wheels = [ 90 + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, 91 + ] 92 + 93 + [[package]] 94 + name = "idna" 95 + version = "3.11" 96 + source = { registry = "https://pypi.org/simple" } 97 + sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } 98 + wheels = [ 99 + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, 100 + ] 101 + 102 + [[package]] 36 103 name = "markdown-it-py" 37 104 version = "4.0.0" 38 105 source = { registry = "https://pypi.org/simple" } ··· 58 125 version = "0.1.0" 59 126 source = { virtual = "." } 60 127 dependencies = [ 128 + { name = "httpx" }, 61 129 { name = "typer" }, 62 130 ] 63 131 64 132 [package.metadata] 65 - requires-dist = [{ name = "typer", specifier = ">=0.24.1" }] 133 + requires-dist = [ 134 + { name = "httpx", specifier = ">=0.28.1" }, 135 + { name = "typer", specifier = ">=0.24.1" }, 136 + ] 66 137 67 138 [[package]] 68 139 name = "pygments"