aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Evrard <nicoe@openhex.org>2019-02-03 11:11:46 +0100
committerPaul Ganssle <paul@ganssle.io>2019-02-04 09:19:26 -0500
commitc17ea80dd267e1dbfc5da1fa620a6dc5a71df5ba (patch)
treeb8417fa0b0f004b35b334dc54a2d884f37e45d37
parent844f43ba2847999f32eb32818563fe225972d04d (diff)
downloaddateutil-c17ea80dd267e1dbfc5da1fa620a6dc5a71df5ba.tar.gz
Factor rrule datetime value parsing into a method
The logic for DTSTART, EXDATE and RDATE is substantially similar, so it makes sense to factor this out into a separate method.
-rw-r--r--dateutil/rrule.py150
1 files changed, 65 insertions, 85 deletions
diff --git a/dateutil/rrule.py b/dateutil/rrule.py
index 3fe5e21..20a0c4a 100644
--- a/dateutil/rrule.py
+++ b/dateutil/rrule.py
@@ -1412,6 +1412,8 @@ class rruleset(rrulebase):
self._len = total
+
+
class _rrulestr(object):
""" Parses a string representation of a recurrence rule or set of
recurrence rules.
@@ -1557,6 +1559,58 @@ class _rrulestr(object):
raise ValueError("invalid '%s': %s" % (name, value))
return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
+ def _parse_date_value(self, date_value, parms, rule_tzids,
+ ignoretz, tzids, tzinfos):
+ global parser
+ if not parser:
+ from dateutil import parser
+
+ datevals = []
+ value_found = False
+ TZID = None
+
+ for parm in parms:
+ if parm.startswith("TZID="):
+ try:
+ tzkey = rule_tzids[parm.split('TZID=')[-1]]
+ except KeyError:
+ continue
+ if tzids is None:
+ from . import tz
+ tzlookup = tz.gettz
+ elif callable(tzids):
+ tzlookup = tzids
+ else:
+ tzlookup = getattr(tzids, 'get', None)
+ if tzlookup is None:
+ msg = ('tzids must be a callable, mapping, or None, '
+ 'not %s' % tzids)
+ raise ValueError(msg)
+
+ TZID = tzlookup(tzkey)
+ continue
+
+ # RFC 5445 3.8.2.4: The VALUE parameter is optional, but may be found
+ # only once.
+ if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
+ raise ValueError("unsupported parm: " + parm)
+ else:
+ if value_found:
+ msg = ("Duplicate value parameter found in: " + parm)
+ raise ValueError(msg)
+ value_found = True
+
+ for datestr in date_value.split(','):
+ date = parser.parse(datestr, ignoretz=ignoretz, tzinfos=tzinfos)
+ if TZID is not None:
+ if date.tzinfo is None:
+ date = date.replace(tzinfo=TZID)
+ else:
+ raise ValueError('DTSTART/EXDATE specifies multiple timezone')
+ datevals.append(date)
+
+ return datevals
+
def _parse_rfc(self, s,
dtstart=None,
cache=False,
@@ -1629,92 +1683,18 @@ class _rrulestr(object):
raise ValueError("unsupported EXRULE parm: "+parm)
exrulevals.append(value)
elif name == "EXDATE":
- value_found = False
- TZID = None
- for parm in parms:
- if parm.startswith("TZID="):
- try:
- tzkey = TZID_NAMES[parm.split('TZID=')[-1]]
- except KeyError:
- continue
- if tzids is None:
- from . import tz
- tzlookup = tz.gettz
- elif callable(tzids):
- tzlookup = tzids
- else:
- tzlookup = getattr(tzids, 'get', None)
- if tzlookup is None:
- msg = ('tzids must be a callable, ' +
- 'mapping, or None, ' +
- 'not %s' % tzids)
- raise ValueError(msg)
-
- TZID = tzlookup(tzkey)
- continue
- if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
- raise ValueError("unsupported EXDATE parm: "
- + parm)
- else:
- if value_found:
- msg = ("Duplicate value parameter found in "
- "EXDATE: " + parm)
- raise ValueError(msg)
- value_found = True
- for datestr in value.split(','):
- exdate = parser.parse(datestr, ignoretz=ignoretz,
- tzinfos=tzinfos)
- if TZID is not None:
- if exdate.tzinfo is None:
- exdate = exdate.replace(tzinfo=TZID)
- else:
- raise ValueError(
- 'EXDATE specifies multiple timezone')
- exdatevals.append(exdate)
+ exdatevals.extend(
+ self._parse_date_value(value, parms,
+ TZID_NAMES, ignoretz,
+ tzids, tzinfos)
+ )
elif name == "DTSTART":
- # RFC 5445 3.8.2.4: The VALUE parameter is optional, but
- # may be found only once.
- value_found = False
- TZID = None
- valid_values = {"VALUE=DATE-TIME", "VALUE=DATE"}
- for parm in parms:
- if parm.startswith("TZID="):
- try:
- tzkey = TZID_NAMES[parm.split('TZID=')[-1]]
- except KeyError:
- continue
- if tzids is None:
- from . import tz
- tzlookup = tz.gettz
- elif callable(tzids):
- tzlookup = tzids
- else:
- tzlookup = getattr(tzids, 'get', None)
- if tzlookup is None:
- msg = ('tzids must be a callable, ' +
- 'mapping, or None, ' +
- 'not %s' % tzids)
- raise ValueError(msg)
-
- TZID = tzlookup(tzkey)
- continue
- if parm not in valid_values:
- raise ValueError("unsupported DTSTART parm: "+parm)
- else:
- if value_found:
- msg = ("Duplicate value parameter found in " +
- "DTSTART: " + parm)
- raise ValueError(msg)
- value_found = True
- if not parser:
- from dateutil import parser
- dtstart = parser.parse(value, ignoretz=ignoretz,
- tzinfos=tzinfos)
- if TZID is not None:
- if dtstart.tzinfo is None:
- dtstart = dtstart.replace(tzinfo=TZID)
- else:
- raise ValueError('DTSTART specifies multiple timezones')
+ dtvals = self._parse_date_value(value, parms, TZID_NAMES,
+ ignoretz, tzids, tzinfos)
+ if len(dtvals) != 1:
+ raise ValueError("Multiple DTSTART values specified:" +
+ value)
+ dtstart = dtvals[0]
else:
raise ValueError("unsupported property: "+name)
if (forceset or len(rrulevals) > 1 or rdatevals