1.1 --- a/imipweb/data.py Fri May 15 22:09:02 2015 +0200
1.2 +++ b/imipweb/data.py Sat May 16 01:03:51 2015 +0200
1.3 @@ -35,12 +35,19 @@
1.4 """
1.5
1.6 def __init__(self, start, end, start_attr=None, end_attr=None, form_start=None, form_end=None, origin=None):
1.7 - Period.__init__(self, start, end)
1.8 +
1.9 + """
1.10 + Initialise a period with the given 'start' and 'end' datetimes, together
1.11 + with optional 'start_attr' and 'end_attr' metadata, 'form_start' and
1.12 + 'form_end' values provided as textual input, and with an optional
1.13 + 'origin' indicating the kind of period this object describes.
1.14 + """
1.15 +
1.16 + Period.__init__(self, start, end, origin)
1.17 self.start_attr = start_attr
1.18 self.end_attr = end_attr
1.19 self.form_start = form_start
1.20 self.form_end = form_end
1.21 - self.origin = origin
1.22
1.23 def as_tuple(self):
1.24 return self.start, self.end, self.start_attr, self.end_attr, self.form_start, self.form_end, self.origin
1.25 @@ -62,6 +69,12 @@
1.26 def get_tzid(self):
1.27 return get_tzid(self.start_attr, self.end_attr)
1.28
1.29 + def get_start_item(self):
1.30 + return self.start, self.start_attr
1.31 +
1.32 + def get_end_item(self):
1.33 + return self.end, self.end_attr
1.34 +
1.35 # Form data compatibility methods.
1.36
1.37 def get_form_start(self):
1.38 @@ -110,52 +123,50 @@
1.39 return "FormPeriod(%r, %r, %r, %r, %r)" % self.as_tuple()
1.40
1.41 def _get_start(self):
1.42 - t = self.start.as_datetime_item(self.times_enabled)
1.43 - if t:
1.44 - return t
1.45 - else:
1.46 - return None
1.47 + return self.start.as_datetime(self.times_enabled), self.start.get_attributes(self.times_enabled)
1.48
1.49 def _get_end(self, adjust=False):
1.50
1.51 # Handle specified end datetimes.
1.52
1.53 if self.end_enabled:
1.54 - t = self.end.as_datetime_item(self.times_enabled)
1.55 - if t:
1.56 - dtend, dtend_attr = t
1.57 + dtend = self.end.as_datetime(self.times_enabled)
1.58 + dtend_attr = self.end.get_attributes(self.times_enabled)
1.59 + if dtend:
1.60 dtend = adjust and end_date_to_calendar(dtend) or dtend
1.61 else:
1.62 - return None
1.63 + return None, None
1.64
1.65 # Otherwise, treat the end date as the start date. Datetimes are
1.66 # handled by making the event occupy the rest of the day.
1.67
1.68 else:
1.69 - t = self._get_start()
1.70 - if t:
1.71 - dtstart, dtstart_attr = t
1.72 + dtstart, dtstart_attr = self._get_start()
1.73 + if dtstart:
1.74 dtend = dtstart + timedelta(1)
1.75 dtend_attr = dtstart_attr
1.76
1.77 if isinstance(dtstart, datetime):
1.78 dtend = get_start_of_day(dtend, dtend_attr["TZID"])
1.79 else:
1.80 - return None
1.81 + return None, None
1.82
1.83 return dtend, dtend_attr
1.84
1.85 def as_event_period(self, index=None):
1.86 - t = self._get_start()
1.87 - if t:
1.88 - dtstart, dtstart_attr = t
1.89 - else:
1.90 +
1.91 + """
1.92 + Return a converted version of this object as an event period suitable
1.93 + for iCalendar usage. If 'index' is indicated, include it in any error
1.94 + raised in the conversion process.
1.95 + """
1.96 +
1.97 + dtstart, dtstart_attr = self._get_start()
1.98 + if not dtstart:
1.99 raise PeriodError(*[index is not None and ("dtstart", index) or "dtstart"])
1.100
1.101 - t = self._get_end(adjust=True)
1.102 - if t:
1.103 - dtend, dtend_attr = t
1.104 - else:
1.105 + dtend, dtend_attr = self._get_end(adjust=True)
1.106 + if not dtend:
1.107 raise PeriodError(*[index is not None and ("dtend", index) or "dtend"])
1.108
1.109 if dtstart > dtend:
1.110 @@ -169,20 +180,18 @@
1.111 # Period data methods.
1.112
1.113 def get_start(self):
1.114 - t = self._get_start()
1.115 - if t:
1.116 - dtstart, dtstart_attr = t
1.117 - return dtstart
1.118 - else:
1.119 - return None
1.120 + dtstart, dtstart_attr = self._get_start()
1.121 + return dtstart
1.122
1.123 def get_end(self):
1.124 - t = self._get_end()
1.125 - if t:
1.126 - dtend, dtend_attr = t
1.127 - return dtend
1.128 - else:
1.129 - return None
1.130 + dtend, dtend_attr = self._get_end()
1.131 + return dtend
1.132 +
1.133 + def get_start_item(self):
1.134 + return self._get_start()
1.135 +
1.136 + def get_end_item(self):
1.137 + return self._get_end()
1.138
1.139 # Form data methods.
1.140
1.141 @@ -245,39 +254,50 @@
1.142 def get_tzid(self):
1.143 return self.tzid
1.144
1.145 - def as_datetime_item(self, with_time=True):
1.146 + def as_datetime(self, with_time=True):
1.147
1.148 - """
1.149 - Return a (datetime, attr) tuple for the datetime information provided by
1.150 - this object, or None if the fields cannot be used to construct a
1.151 - datetime object.
1.152 - """
1.153 + "Return a datetime for this object."
1.154
1.155 # Return any original datetime details.
1.156
1.157 if self.dt:
1.158 - return self.dt, self.attr
1.159 + return self.dt
1.160
1.161 - # Otherwise, construct a datetime and attributes.
1.162 + # Otherwise, construct a datetime.
1.163
1.164 - if not self.date:
1.165 - return None
1.166 - elif with_time:
1.167 - attr = {"TZID" : self.get_tzid(), "VALUE" : "DATE-TIME"}
1.168 - dt = get_datetime(self.get_datetime_string(), attr)
1.169 + s, attr = self.as_datetime_item(with_time)
1.170 + if s:
1.171 + return get_datetime(s, attr)
1.172 else:
1.173 - dt = None
1.174 + return None
1.175 +
1.176 + def as_datetime_item(self, with_time=True):
1.177
1.178 - # Interpret incomplete datetimes as dates.
1.179 + """
1.180 + Return a (datetime string, attr) tuple for the datetime information
1.181 + provided by this object, where both tuple elements will be None if no
1.182 + suitable date or datetime information exists.
1.183 + """
1.184
1.185 - if not dt:
1.186 - attr = {"VALUE" : "DATE"}
1.187 - dt = get_datetime(self.get_date_string(), attr)
1.188 + s = None
1.189 + if with_time:
1.190 + s = self.get_datetime_string()
1.191 + attr = self.get_attributes(True)
1.192 + if not s:
1.193 + s = self.get_date_string()
1.194 + attr = self.get_attributes(False)
1.195 + if not s:
1.196 + return None, None
1.197 + return s, attr
1.198
1.199 - if dt:
1.200 - return dt, attr
1.201 + def get_attributes(self, with_time=True):
1.202 +
1.203 + "Return attributes for the date or datetime represented by this object."
1.204
1.205 - return None
1.206 + if with_time:
1.207 + return {"TZID" : self.get_tzid(), "VALUE" : "DATE-TIME"}
1.208 + else:
1.209 + return {"VALUE" : "DATE"}
1.210
1.211 def end_date_to_calendar(dt):
1.212
1.213 @@ -309,7 +329,9 @@
1.214 elif isinstance(period, FormPeriod):
1.215 return period.as_event_period()
1.216 else:
1.217 - return EventPeriod(period.start, period.end, period.start_attr, period.end_attr, origin=period.origin)
1.218 + dtstart, dtstart_attr = period.get_start_item()
1.219 + dtend, dtend_attr = period.get_end_item()
1.220 + return EventPeriod(dtstart, dtend, dtstart_attr, dtend_attr, origin=period.origin)
1.221
1.222 def form_period_from_period(period):
1.223 if isinstance(period, EventPeriod):