Coverage for jutil/parse.py : 83%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import logging
2from datetime import datetime, time, date
3from typing import Optional, Any
4from django.core.exceptions import ValidationError
5from django.utils.translation import gettext as _
6import pytz
7from django.utils.dateparse import parse_datetime as django_parse_datetime
8from django.utils.dateparse import parse_date as django_parse_date
10logger = logging.getLogger(__name__)
12TRUE_VALUES = (
13 "true",
14 "1",
15 "yes",
16)
18FALSE_VALUES = (
19 "none",
20 "null",
21 "false",
22 "0",
23 "no",
24)
27def parse_bool(v: str) -> bool:
28 """
29 Parses boolean value
30 :param v: Input string
31 :return: bool
32 """
33 s = str(v).lower()
34 if s in TRUE_VALUES:
35 return True
36 if s in FALSE_VALUES:
37 return False
38 raise ValidationError(_("%(value)s is not one of the available choices") % {"value": v})
41def parse_datetime(v: str, tz: Any = None) -> datetime:
42 """
43 Parses ISO date/datetime string to timezone-aware datetime.
44 Supports YYYY-MM-DD date strings where time part is missing.
45 Returns always timezone-aware datetime (assumes UTC if timezone missing).
46 :param v: Input string to parse
47 :param tz: Default pytz timezone or if None then use UTC as default
48 :return: datetime with timezone
49 """
50 try:
51 t = django_parse_datetime(v)
52 if t is None:
53 t_date: Optional[date] = django_parse_date(v)
54 if t_date is None:
55 raise ValidationError(
56 _(
57 "“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."
58 )
59 % {"value": v}
60 )
61 t = datetime.combine(t_date, time())
62 if tz is None: 62 ↛ 64line 62 didn't jump to line 64, because the condition on line 62 was never false
63 tz = pytz.utc
64 return t if t.tzinfo else tz.localize(t)
65 except Exception:
66 raise ValidationError(
67 _("“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.")
68 % {"value": v}
69 )
72def parse_bool_or_none(v: str) -> Optional[bool]:
73 """
74 Parses boolean value, or returns None if parsing fails.
75 :param v: Input string
76 :return: bool or None
77 """
78 s = str(v).lower()
79 if s in TRUE_VALUES:
80 return True
81 if s in FALSE_VALUES:
82 return False
83 return None
86def parse_datetime_or_none(v: str, tz: Any = None) -> Optional[datetime]:
87 """
88 Parses ISO date/datetime string to timezone-aware datetime.
89 Supports YYYY-MM-DD date strings where time part is missing.
90 Returns timezone-aware datetime (assumes UTC if timezone missing) or None if parsing fails.
91 :param v: Input string to parse
92 :param tz: Default pytz timezone or if None then use UTC as default
93 :return: datetime with timezone or None
94 """
95 try:
96 t = django_parse_datetime(v)
97 if t is None:
98 t_date: Optional[date] = django_parse_date(v)
99 if t_date is None:
100 return None
101 t = datetime.combine(t_date, time())
102 if tz is None: 102 ↛ 104line 102 didn't jump to line 104, because the condition on line 102 was never false
103 tz = pytz.utc
104 return t if t.tzinfo else tz.localize(t)
105 except Exception:
106 return None