class_docstr: Parses a string representation of a recurrence rule or set of
  recurrence rules.
  
  :param s:
      Required, a string defining one or more recurrence rules.
  
  :param dtstart:
      If given, used as the default recurrence start if not specified in the
      rule string.
  
  :param cache:
      If set ``True`` caching of results will be enabled, improving
      performance of multiple queries considerably.
  
  :param unfold:
      If set ``True`` indicates that a rule string is split over more
      than one line and should be joined before processing.
  
  :param forceset:
      If set ``True`` forces a :class:`dateutil.rrule.rruleset` to
      be returned.
  
  :param compatible:
      If set ``True`` forces ``unfold`` and ``forceset`` to be ``True``.
  
  :param ignoretz:
      If set ``True``, time zones in parsed strings are ignored and a naive
      :class:`datetime.datetime` object is returned.
  
  :param tzids:
      If given, a callable or mapping used to retrieve a
      :class:`datetime.tzinfo` from a string representation.
      Defaults to :func:`dateutil.tz.gettz`.
  
  :param tzinfos:
      Additional time zone names / aliases which may be present in a string
      representation.  See :func:`dateutil.parser.parse` for more
      information.
  
  :return:
      Returns a :class:`dateutil.rrule.rruleset` or
      :class:`dateutil.rrule.rrule`
class_docstr_tok: ["Parses","a","string","representation","of","a","recurrence","rule","or","set","of","recurrence","rules",".",":","param","s",":","Required",",","a","string","defining","one","or","more","recurrence","rules",".",":","param","dtstart",":","If","given",",","used","as","the","default","recurrence","start","if","not","specified","in","the","rule","string",".",":","param","cache",":","If","set","``","True","``","caching","of","results","will","be","enabled",",","improving","performance","of","multiple","queries","considerably",".",":","param","unfold",":","If","set","``","True","``","indicates","that","a","rule","string","is","split","over","more","than","one","line","and","should","be","joined","before","processing",".",":","param","forceset",":","If","set","``","True","``","forces","a",":","class",":","`","dateutil.rrule.rruleset","`","to","be","returned",".",":","param","compatible",":","If","set","``","True","``","forces","``","unfold","``","and","``","forceset","``","to","be","``","True","``",".",":","param","ignoretz",":","If","set","``","True","``",",","time","zones","in","parsed","strings","are","ignored","and","a","naive",":","class",":","`","datetime.datetime","`","object","is","returned",".",":","param","tzids",":","If","given",",","a","callable","or","mapping","used","to","retrieve","a",":","class",":","`","datetime.tzinfo","`","from","a","string","representation",".","Defaults","to",":","func",":","`","dateutil.tz.gettz","`",".",":","param","tzinfos",":","Additional","time","zone","names","\/","aliases","which","may","be","present","in","a","string","representation",".","See",":","func",":","`","dateutil.parser.parse","`","for","more","information",".",":","return",":","Returns","a",":","class",":","`","dateutil.rrule.rruleset","`","or",":","class",":","`","dateutil.rrule.rrule","`"]
code: def _parse_rfc(
      self,
      s,
      dtstart=None,
      cache=False,
      unfold=False,
      forceset=False,
      compatible=False,
      ignoretz=False,
      tzids=None,
      tzinfos=None,
  ):
      global parser
      if compatible:
          forceset = True
          unfold = True
  
      TZID_NAMES = dict(
          map(
              lambda x: (x.upper(), x),
              re.findall("TZID=(?P<name>[^:]+):", s),
          )
      )
      s = s.upper()
      if not s.strip():
          raise ValueError("empty string")
      if unfold:
          lines = s.splitlines()
          i = 0
          while i < len(lines):
              line = lines[i].rstrip()
              if not line:
                  del lines[i]
              elif i > 0 and line[0] == " ":
                  lines[i - 1] += line[1:]
                  del lines[i]
              else:
                  i += 1
      else:
          lines = s.split()
      if (
          not forceset
          and len(lines) == 1
          and (s.find(":") == -1 or s.startswith("RRULE:"))
      ):
          return self._parse_rfc_rrule(
              lines[0],
              cache=cache,
              dtstart=dtstart,
              ignoretz=ignoretz,
              tzinfos=tzinfos,
          )
      else:
          rrulevals = []
          rdatevals = []
          exrulevals = []
          exdatevals = []
          for line in lines:
              if not line:
                  continue
              if line.find(":") == -1:
                  name = "RRULE"
                  value = line
              else:
                  name, value = line.split(":", 1)
              parms = name.split(";")
              if not parms:
                  raise ValueError("empty property name")
              name = parms[0]
              parms = parms[1:]
              if name == "RRULE":
                  for parm in parms:
                      raise ValueError(
                          "unsupported RRULE parm: " + parm
                      )
                  rrulevals.append(value)
              elif name == "RDATE":
                  for parm in parms:
                      if parm != "VALUE=DATE-TIME":
                          raise ValueError(
                              "unsupported RDATE parm: " + parm
                          )
                  rdatevals.append(value)
              elif name == "EXRULE":
                  for parm in parms:
                      raise ValueError(
                          "unsupported EXRULE parm: " + parm
                      )
                  exrulevals.append(value)
              elif name == "EXDATE":
                  exdatevals.extend(
                      self._parse_date_value(
                          value,
                          parms,
                          TZID_NAMES,
                          ignoretz,
                          tzids,
                          tzinfos,
                      )
                  )
              elif name == "DTSTART":
                  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
              or exrulevals
              or exdatevals
          ):
              if not parser and (rdatevals or exdatevals):
                  from dateutil import parser
              rset = rruleset(cache=cache)
              for value in rrulevals:
                  rset.rrule(
                      self._parse_rfc_rrule(
                          value,
                          dtstart=dtstart,
                          ignoretz=ignoretz,
                          tzinfos=tzinfos,
                      )
                  )
              for value in rdatevals:
                  for datestr in value.split(","):
                      rset.rdate(
                          parser.parse(
                              datestr,
                              ignoretz=ignoretz,
                              tzinfos=tzinfos,
                          )
                      )
              for value in exrulevals:
                  rset.exrule(
                      self._parse_rfc_rrule(
                          value,
                          dtstart=dtstart,
                          ignoretz=ignoretz,
                          tzinfos=tzinfos,
                      )
                  )
              for value in exdatevals:
                  rset.exdate(value)
              if compatible and dtstart:
                  rset.rdate(dtstart)
              return rset
          else:
              return self._parse_rfc_rrule(
                  rrulevals[0],
                  dtstart=dtstart,
                  cache=cache,
                  ignoretz=ignoretz,
                  tzinfos=tzinfos,
              )
  
imports: import calendar
  import datetime
  import heapq
  import itertools
  import re
  import sys
  from functools import wraps
  from warnings import warn
  from six import advance_iterator, integer_types
  from six.moves import _thread, range
  from ._common import weekday
label_desc: Use image node_id 9 for calling the _rrulestr obj's underlying member method code with example usage: obj._parse_rfc(s, dtstart, cache, unfold, forceset, compatible, ignoretz, tzids, tzinfos) and returns: self, rset, self