File size: 3,990 Bytes
d1ceb73 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
from collections import OrderedDict
from decimal import Decimal, InvalidOperation
import arrow # type: ignore
from isoduration.parser.exceptions import (
IncorrectDesignator,
NoTime,
OutOfDesignators,
UnknownToken,
UnparseableValue,
)
from isoduration.parser.util import (
is_letter,
is_number,
is_time,
is_week,
parse_designator,
)
from isoduration.types import DateDuration, Duration, TimeDuration
def parse_datetime_duration(duration_str: str, sign: int) -> Duration:
try:
duration: arrow.Arrow = arrow.get(duration_str)
except (arrow.ParserError, ValueError):
raise UnparseableValue(f"Value could not be parsed as datetime: {duration_str}")
return Duration(
DateDuration(
years=sign * duration.year,
months=sign * duration.month,
days=sign * duration.day,
),
TimeDuration(
hours=sign * duration.hour,
minutes=sign * duration.minute,
seconds=sign * duration.second,
),
)
def parse_date_duration(date_str: str, sign: int) -> Duration:
date_designators = OrderedDict(
(("Y", "years"), ("M", "months"), ("D", "days"), ("W", "weeks"))
)
duration = DateDuration()
tmp_value = ""
for idx, ch in enumerate(date_str):
if is_time(ch):
if tmp_value != "" and tmp_value == date_str[:idx]:
# PYYYY-MM-DDThh:mm:ss
# PYYYYMMDDThhmmss
return parse_datetime_duration(date_str, sign)
time_idx = idx + 1
time_str = date_str[time_idx:]
if time_str == "":
raise NoTime("Wanted time, no time provided")
return Duration(duration, parse_time_duration(time_str, sign))
if is_letter(ch):
try:
key = parse_designator(date_designators, ch)
value = sign * Decimal(tmp_value)
except OutOfDesignators as exc:
raise IncorrectDesignator(
f"Wrong date designator, or designator in the wrong order: {ch}"
) from exc
except InvalidOperation as exc:
raise UnparseableValue(
f"Value could not be parsed as decimal: {tmp_value}"
) from exc
if is_week(ch) and duration != DateDuration():
raise IncorrectDesignator(
"Week is incompatible with any other date designator"
)
setattr(duration, key, value)
tmp_value = ""
continue
if is_number(ch):
if ch == ",":
tmp_value += "."
else:
tmp_value += ch
continue
raise UnknownToken(f"Token not recognizable: {ch}")
return Duration(duration, TimeDuration())
def parse_time_duration(time_str: str, sign: int) -> TimeDuration:
time_designators = OrderedDict((("H", "hours"), ("M", "minutes"), ("S", "seconds")))
duration = TimeDuration()
tmp_value = ""
for ch in time_str:
if is_letter(ch):
try:
key = parse_designator(time_designators, ch)
value = sign * Decimal(tmp_value)
except OutOfDesignators as exc:
raise IncorrectDesignator(
f"Wrong time designator, or designator in the wrong order: {ch}"
) from exc
except InvalidOperation as exc:
raise UnparseableValue(
f"Value could not be parsed as decimal: {tmp_value}"
) from exc
setattr(duration, key, value)
tmp_value = ""
continue
if is_number(ch):
if ch == ",":
tmp_value += "."
else:
tmp_value += ch
continue
raise UnknownToken(f"Token not recognizable: {ch}")
return duration
|