more type support

This commit is contained in:
Patrick Nisble 2026-01-12 08:38:03 +01:00
parent 91fcb96619
commit 14e757dd77
1 changed files with 78 additions and 20 deletions

View File

@ -6,10 +6,20 @@ from typing import Any, Callable, Self, TypedDict
from urllib.error import HTTPError from urllib.error import HTTPError
from .hints import JSONDataMap from .hints import JSONDataMap
from .requests import get, put from .requests import delete, get, put, post
from .env import EnvVar from .env import EnvVar
class TaskRespCheckItemDict(TypedDict):
name: str
resolved: int
class TaskRespCheckDict(TypedDict):
name: str
items: list[TaskRespCheckItemDict]
class TaskRespDict(TypedDict): class TaskRespDict(TypedDict):
name: str name: str
markdown_description: str markdown_description: str
@ -20,7 +30,7 @@ class TaskRespDict(TypedDict):
tags: list[dict[str, str]] tags: list[dict[str, str]]
parent: str | None parent: str | None
locations: list[dict[str, str]] locations: list[dict[str, str]]
checklists: dict[str, bool] checklists: list[TaskRespCheckDict]
list: dict[str, str] list: dict[str, str]
@ -29,24 +39,25 @@ class ClickupTask:
"""fields marked with ``repr=False`` will not be pushed for updates""" """fields marked with ``repr=False`` will not be pushed for updates"""
name: str name: str
markdown_description: str
status: str status: str
id: str = field(repr=False) id: str | None = field(default=None, repr=False)
assignees: list[str] = field(repr=False) assignees: list[str] | None = field(default=None, repr=False)
tags: list[str] = field(repr=False) tags: list[str] | None = field(default=None, repr=False)
parent_list: str = field(repr=False) parent_list: str = field(repr=False)
locations: list[str] = field(repr=False) locations: list[str] | None = field(default=None, repr=False)
checklists: dict[str, bool] = field(repr=False) checklists: dict[str, dict[str, bool]] | None = field(default=None, repr=False)
parent: str | None = field(default=None, repr=False) parent: str | None = field(default=None, repr=False)
markdown_content: str
@classmethod @classmethod
def from_resp_data(cls, resp_data_raw: dict[str, Any]) -> Self: def from_resp_data(cls, resp_data_raw: dict[str, Any]) -> Self:
resp_data = TaskRespDict(**resp_data_raw) resp_data = TaskRespDict(**resp_data_raw)
return cls( return cls(
name=resp_data["name"], name=resp_data["name"],
markdown_description=resp_data["markdown_description"], markdown_content=resp_data["markdown_description"],
status=resp_data["status"]["status"], status=resp_data["status"]["status"],
id=resp_data["id"], id=resp_data["id"],
assignees=cls.convert_assignees(resp_data["assignees"]), assignees=cls.convert_assignees(resp_data["assignees"]),
@ -54,7 +65,10 @@ class ClickupTask:
parent=resp_data.get("parent"), parent=resp_data.get("parent"),
parent_list=resp_data["list"]["id"], parent_list=resp_data["list"]["id"],
locations=cls.convert_simple_list_with_names(resp_data["locations"]), locations=cls.convert_simple_list_with_names(resp_data["locations"]),
checklists=resp_data["checklists"], checklists={
tlist["name"]: {t["name"]: bool(t["resolved"]) for t in tlist["items"]}
for tlist in resp_data["checklists"]
},
) )
@classmethod @classmethod
@ -78,16 +92,14 @@ class ClickupTask:
@property @property
def updateables(self) -> dict[str, Any]: def updateables(self) -> dict[str, Any]:
return { return {f.name: getattr(self, f.name, None) for f in fields(type(self)) if f.repr}
f.name: getattr(self, f.name, None) for f in fields(type(self)) if f.repr
}
@property @property
def showables(self) -> dict[str, Any]: def showables(self) -> dict[str, Any]:
return { return {
f.name: getattr(self, f.name, None) dcf.name: getattr(self, dcf.name, ...)
for f in fields(type(self)) for dcf in fields(self)
if f.name != "markdown_description" if getattr(self, dcf.name, ...) is not None
} }
@property @property
@ -97,7 +109,12 @@ class ClickupTask:
if self.parent: if self.parent:
ret += " \033[32m 󰙅 " ret += " \033[32m 󰙅 "
ret += f"{self.name} (#{self.id})" ret += self.name
if self.tags:
ret += "".join(f" #{t}" for t in self.tags)
ret += f" (#{self.id})"
return ret return ret
@ -151,9 +168,38 @@ class ClickupSession:
) )
return loads(raw_data) return loads(raw_data)
def get_tasks(self) -> list[ClickupTask]: def _post(self, endpoint: str, **body_params: str) -> JSONDataMap:
raw_data = post(
self.base_url + endpoint,
body_params,
headers={
"accept": "application/json",
"content-type": "application/json",
"Authorization": self.auth_key,
},
)
return loads(raw_data)
def _delete(self, endpoint: str) -> JSONDataMap:
raw_data = delete(
self.base_url + endpoint,
headers={
"accept": "application/json",
"content-type": "application/json",
"Authorization": self.auth_key,
},
)
return loads(raw_data)
def get_tasks(self, **filters: str) -> list[ClickupTask]:
data = self._get( data = self._get(
f"/team/{self.workspace_id}/task?subtasks=true&include_markdown_description=true&assignees[]={self.user_id}" f"/team/{self.workspace_id}/task",
**{
"subtask": "true",
"include_markdown_description": "true",
"assignees[]": self.user_id,
}
| filters,
).get("tasks", []) ).get("tasks", [])
if isinstance(data, list): if isinstance(data, list):
return [ClickupTask.from_resp_data(t) for t in data if isinstance(t, dict)] return [ClickupTask.from_resp_data(t) for t in data if isinstance(t, dict)]
@ -169,4 +215,16 @@ class ClickupSession:
) )
def update(self, data: ClickupTask) -> None: def update(self, data: ClickupTask) -> None:
_ = self._put(f"/task/{data.id}", **data.updateables) ret_task = self._put(f"/task/{data.id}", **data.updateables)
current_tags: set[str] = set(ret_task["tags"])
new_tags = set(data.tags)
for del_tag in current_tags - new_tags:
self._delete(f"/task/{data.id}/tag/{del_tag}")
for add_tag in new_tags - current_tags:
self._post(f"/task/{data.id}/tag/{add_tag}")
def create(self, data: ClickupTask) -> str:
ret_task = self._post(f"/list/{data.parent_list}/task", **data.updateables)
return str(ret_task["id"])