11import datetime
22import logging
3- from typing import Optional , TypedDict
3+ from typing import Any , Optional , TypedDict
44from urllib .parse import ParseResult , urlparse
55
6- from pydantic import BaseModel , TypeAdapter
6+ from pydantic import (
7+ AwareDatetime ,
8+ BaseModel ,
9+ TypeAdapter ,
10+ ValidationError ,
11+ ValidationInfo ,
12+ ValidatorFunctionWrapHandler ,
13+ )
14+ from pydantic .functional_validators import WrapValidator
15+ from typing_extensions import Annotated
716
817logger = logging .getLogger (__name__ )
918JIRA_HOSTNAMES = ("jira" , "atlassian" )
1019
1120BugId = TypedDict ("BugId" , {"id" : Optional [int ]})
1221
1322
23+ def maybe_add_timezone (
24+ v : Any , handler : ValidatorFunctionWrapHandler , info : ValidationInfo
25+ ):
26+ if isinstance (v , str ):
27+ try :
28+ return handler (v )
29+ except ValidationError :
30+ return handler (v + "+00:00" )
31+ assert isinstance (v , datetime .datetime ), "must be a datetime here"
32+ v = v .replace (tzinfo = datetime .timezone .utc )
33+ return v
34+
35+
36+ SmartAwareDatetime = Annotated [AwareDatetime , WrapValidator (maybe_add_timezone )]
37+
38+
1439class WebhookUser (BaseModel , frozen = True ):
1540 """Bugzilla User Object"""
1641
@@ -31,7 +56,7 @@ class WebhookEvent(BaseModel, frozen=True):
3156 """Bugzilla Event Object"""
3257
3358 action : str
34- time : datetime . datetime
59+ time : SmartAwareDatetime
3560 user : Optional [WebhookUser ] = None
3661 changes : Optional [list [WebhookEventChange ]] = None
3762 target : Optional [str ] = None
@@ -50,7 +75,7 @@ class WebhookComment(BaseModel, frozen=True):
5075 id : Optional [int ] = None
5176 number : Optional [int ] = None
5277 is_private : Optional [bool ] = None
53- creation_time : Optional [datetime . datetime ] = None
78+ creation_time : Optional [SmartAwareDatetime ] = None
5479
5580
5681class Bug (BaseModel , frozen = True ):
0 commit comments