11from __future__ import annotations
22
33from collections .abc import Callable , Iterator
4+ from datetime import UTC
45from typing import TYPE_CHECKING , Annotated , Any , Literal , Self , TypeVar
56from weakref import finalize
67
3334)
3435
3536if TYPE_CHECKING :
37+ from datetime import date , datetime
3638 from types import TracebackType
3739
38- DateFormat = Annotated [str , Predicate (lambda x : len (x ) == 10 and x .count ("-" ) == 2 )] # noqa: PLR2004
39- DateTimeFormat = Annotated [
40- str , Predicate (lambda x : len (x ) >= 20 and "T" in x and ":" in x ) # noqa: PLR2004
41- ]
40+
4241LanguageCode = Annotated [str , Predicate (lambda x : len (x ) == 2 )] # noqa: PLR2004
4342ColorString = Annotated [
4443 str ,
@@ -230,16 +229,16 @@ def add_task( # noqa: PLR0912
230229 labels : list [Annotated [str , MaxLen (100 )]] | None = None ,
231230 priority : Annotated [int , Ge (1 ), Le (4 )] | None = None ,
232231 due_string : Annotated [str , MaxLen (150 )] | None = None ,
233- due_date : DateFormat | None = None ,
234- due_datetime : DateTimeFormat | None = None ,
235232 due_lang : LanguageCode | None = None ,
233+ due_date : date | None = None ,
234+ due_datetime : datetime | None = None ,
236235 assignee_id : str | None = None ,
237236 order : int | None = None ,
238237 auto_reminder : bool | None = None ,
239238 auto_parse_labels : bool | None = None ,
240239 duration : Annotated [int , Ge (1 )] | None = None ,
241240 duration_unit : Literal ["minute" , "day" ] | None = None ,
242- deadline_date : DateFormat | None = None ,
241+ deadline_date : date | None = None ,
243242 deadline_lang : LanguageCode | None = None ,
244243 ) -> Task :
245244 """
@@ -252,17 +251,17 @@ def add_task( # noqa: PLR0912
252251 :param labels: The task's labels (a list of names).
253252 :param priority: The priority of the task (4 for very urgent).
254253 :param due_string: The due date in natural language format.
255- :param due_date: The due date in YYYY-MM-DD format.
256- :param due_datetime: The due date and time in RFC 3339 format.
257254 :param due_lang: Language for parsing the due date (e.g., 'en').
255+ :param due_date: The due date as a date object.
256+ :param due_datetime: The due date and time as a datetime object.
258257 :param assignee_id: User ID to whom the task is assigned.
259258 :param description: Description for the task.
260259 :param order: The order of task in the project or section.
261260 :param auto_reminder: Whether to add default reminder if date with time is set.
262261 :param auto_parse_labels: Whether to parse labels from task content.
263262 :param duration: The amount of time the task will take.
264263 :param duration_unit: The unit of time for duration.
265- :param deadline_date: The deadline date in YYYY-MM-DD format .
264+ :param deadline_date: The deadline date as a date object .
266265 :param deadline_lang: Language for parsing the deadline date.
267266 :return: The newly created task.
268267 :raises requests.exceptions.HTTPError: If the API request fails.
@@ -285,12 +284,12 @@ def add_task( # noqa: PLR0912
285284 data ["priority" ] = priority
286285 if due_string is not None :
287286 data ["due_string" ] = due_string
288- if due_date is not None :
289- data ["due_date" ] = due_date
290- if due_datetime is not None :
291- data ["due_datetime" ] = due_datetime
292287 if due_lang is not None :
293288 data ["due_lang" ] = due_lang
289+ if due_date is not None :
290+ data ["due_date" ] = _format_date (due_date )
291+ if due_datetime is not None :
292+ data ["due_datetime" ] = _format_datetime (due_datetime )
294293 if assignee_id is not None :
295294 data ["assignee_id" ] = assignee_id
296295 if order is not None :
@@ -304,7 +303,7 @@ def add_task( # noqa: PLR0912
304303 if duration_unit is not None :
305304 data ["duration_unit" ] = duration_unit
306305 if deadline_date is not None :
307- data ["deadline_date" ] = deadline_date
306+ data ["deadline_date" ] = _format_date ( deadline_date )
308307 if deadline_lang is not None :
309308 data ["deadline_lang" ] = deadline_lang
310309
@@ -362,15 +361,15 @@ def update_task( # noqa: PLR0912
362361 labels : list [Annotated [str , MaxLen (60 )]] | None = None ,
363362 priority : Annotated [int , Ge (1 ), Le (4 )] | None = None ,
364363 due_string : Annotated [str , MaxLen (150 )] | None = None ,
365- due_date : DateFormat | None = None ,
366- due_datetime : DateTimeFormat | None = None ,
367364 due_lang : LanguageCode | None = None ,
365+ due_date : date | None = None ,
366+ due_datetime : datetime | None = None ,
368367 assignee_id : str | None = None ,
369368 day_order : int | None = None ,
370369 collapsed : bool | None = None ,
371370 duration : Annotated [int , Ge (1 )] | None = None ,
372371 duration_unit : Literal ["minute" , "day" ] | None = None ,
373- deadline_date : DateFormat | None = None ,
372+ deadline_date : date | None = None ,
374373 deadline_lang : LanguageCode | None = None ,
375374 ) -> Task :
376375 """
@@ -384,15 +383,15 @@ def update_task( # noqa: PLR0912
384383 :param labels: The task's labels (a list of names).
385384 :param priority: The priority of the task (4 for very urgent).
386385 :param due_string: The due date in natural language format.
387- :param due_date: The due date in YYYY-MM-DD format.
388- :param due_datetime: The due date and time in RFC 3339 format.
389386 :param due_lang: Language for parsing the due date (e.g., 'en').
387+ :param due_date: The due date as a date object.
388+ :param due_datetime: The due date and time as a datetime object.
390389 :param assignee_id: User ID to whom the task is assigned.
391390 :param day_order: The order of the task inside Today or Next 7 days view.
392391 :param collapsed: Whether the task's sub-tasks are collapsed.
393392 :param duration: The amount of time the task will take.
394393 :param duration_unit: The unit of time for duration.
395- :param deadline_date: The deadline date in YYYY-MM-DD format .
394+ :param deadline_date: The deadline date as a date object .
396395 :param deadline_lang: Language for parsing the deadline date.
397396 :return: the updated Task.
398397 :raises requests.exceptions.HTTPError: If the API request fails.
@@ -410,12 +409,12 @@ def update_task( # noqa: PLR0912
410409 data ["priority" ] = priority
411410 if due_string is not None :
412411 data ["due_string" ] = due_string
413- if due_date is not None :
414- data ["due_date" ] = due_date
415- if due_datetime is not None :
416- data ["due_datetime" ] = due_datetime
417412 if due_lang is not None :
418413 data ["due_lang" ] = due_lang
414+ if due_date is not None :
415+ data ["due_date" ] = _format_date (due_date )
416+ if due_datetime is not None :
417+ data ["due_datetime" ] = _format_datetime (due_datetime )
419418 if assignee_id is not None :
420419 data ["assignee_id" ] = assignee_id
421420 if day_order is not None :
@@ -427,7 +426,7 @@ def update_task( # noqa: PLR0912
427426 if duration_unit is not None :
428427 data ["duration_unit" ] = duration_unit
429428 if deadline_date is not None :
430- data ["deadline_date" ] = deadline_date
429+ data ["deadline_date" ] = _format_date ( deadline_date )
431430 if deadline_lang is not None :
432431 data ["deadline_lang" ] = deadline_lang
433432
@@ -1152,3 +1151,19 @@ def __next__(self) -> list[T]:
11521151
11531152 results : list [Any ] = data .get (self ._results_field , [])
11541153 return [self ._results_inst (result ) for result in results ]
1154+
1155+
1156+ def _format_date (d : date ) -> str :
1157+ """Format a date object as YYYY-MM-DD."""
1158+ return d .isoformat ()
1159+
1160+
1161+ def _format_datetime (dt : datetime ) -> str :
1162+ """
1163+ Format a datetime object.
1164+
1165+ YYYY-MM-DDTHH:MM:SS for naive datetimes; YYYY-MM-DDTHH:MM:SSZ for aware datetimes.
1166+ """
1167+ if dt .tzinfo is None :
1168+ return dt .isoformat ()
1169+ return dt .astimezone (UTC ).isoformat ().replace ("+00:00" , "Z" )
0 commit comments