Coverage for jutil/parse.py: 83%

# Coverage for jutil/parse.py : 83%

## 51 statements

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

1 import logging

2 from datetime import datetime, time, date

3 from typing import Optional, Any

4 from django.core.exceptions import ValidationError

5 from django.utils.translation import gettext as _

6 import pytz

7 from django.utils.dateparse import parse_datetime as django_parse_datetime

8 from django.utils.dateparse import parse_date as django_parse_date

9

10 logger = logging.getLogger(__name__)

11

12 TRUE_VALUES = (

13 "true",

14 "1",

15 "yes",

16)

17

18 FALSE_VALUES = (

19 "none",

20 "null",

21 "false",

22 "0",

23 "no",

24)

25

26

27 def 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})

39

40

41 def 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 )

70

71

72 def 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

84

85

86 def 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