diff options
author | Nicolas Evrard <nicoe@openhex.org> | 2019-02-03 11:11:46 +0100 |
---|---|---|
committer | Paul Ganssle <paul@ganssle.io> | 2019-02-04 09:19:26 -0500 |
commit | c17ea80dd267e1dbfc5da1fa620a6dc5a71df5ba (patch) | |
tree | b8417fa0b0f004b35b334dc54a2d884f37e45d37 | |
parent | 844f43ba2847999f32eb32818563fe225972d04d (diff) | |
download | dateutil-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.py | 150 |
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 |