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.utils.translation import gettext as _

5 from rest_framework.exceptions import ValidationError

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 "“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.") % {

57 'value': v})

58 t = datetime.combine(t_date, time())

59 if tz is None: 59 ↛ 61line 59 didn't jump to line 61, because the condition on line 59 was never false

60 tz = pytz.utc

61 return t if t.tzinfo else tz.localize(t)

62 except Exception:

63 raise ValidationError(_("“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.") % {'value': v})

64

65

66 def parse_bool_or_none(v: str) -> Optional[bool]:

67 """

68 Parses boolean value, or returns None if parsing fails.

69 :param v: Input string

70 :return: bool or None

71 """

72 s = str(v).lower()

73 if s in TRUE_VALUES:

74 return True

75 if s in FALSE_VALUES:

76 return False

77 return None

78

79

80 def parse_datetime_or_none(v: str, tz: Any = None) -> Optional[datetime]:

81 """

82 Parses ISO date/datetime string to timezone-aware datetime.

83 Supports YYYY-MM-DD date strings where time part is missing.

84 Returns timezone-aware datetime (assumes UTC if timezone missing) or None if parsing fails.

85 :param v: Input string to parse

86 :param tz: Default pytz timezone or if None then use UTC as default

87 :return: datetime with timezone or None

88 """

89 try:

90 t = django_parse_datetime(v)

91 if t is None:

92 t_date: Optional[date] = django_parse_date(v)

93 if t_date is None:

94 return None

95 t = datetime.combine(t_date, time())

96 if tz is None: 96 ↛ 98line 96 didn't jump to line 98, because the condition on line 96 was never false

97 tz = pytz.utc

98 return t if t.tzinfo else tz.localize(t)

99 except Exception:

100 return None