Skip to content

Commit

Permalink
Fix override attribute and default description
Browse files Browse the repository at this point in the history
Rework constructor of PSEvents so that it always take a date, and
the override attribute is accurate. This allows us to compare two
PSEvents for equality and use .override in templates.

Fixes #8, #15 and #22
  • Loading branch information
marksteward committed Mar 27, 2016
1 parent f83cd26 commit 44c159a
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 21 deletions.
78 changes: 57 additions & 21 deletions ps_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,48 @@
PS_STARTS = datetime.time(18, 0, 0)
PS_ENDS = datetime.time(23, 30, 0)
PS_TIMEZONE = 'Europe/London'
PS_DESCRIPTION = 'We\'ll meet in the upstairs room as usual.'

class PSEvent(object):
def __init__(self, data={}, date=None, override=False):
"""
Represents a meeting on a particular date.
For a scheduled event, construct with a date from the algorithm.
Otherwise override the calendar by passing any date and event_data.
>>> ps_100 = PSEvent(datetime.date(2014, 3, 13))
>>> ps_100
<PSEvent 2014-03-13>
>>> ps_100 == PSEvent('2014-03-13')
True
>>> ps_100_named = PSEvent('2014-03-13', {'name': "PS 100"})
>>> ps_100_named == ps_100
False
>>> ps_100_named
<PSEvent 2014-03-13: 'PS 100'>
"""
def __init__(self, date, event_data=None):
if isinstance(date, basestring):
self.date = datetime.datetime.strptime(date, '%Y-%m-%d').date()
else:
self.date = date

self.starts = PS_STARTS
self.ends = PS_ENDS
self.location = PS_LOCATION
self.address = PS_ADDRESS
self.name = None
self.description = PS_DESCRIPTION
self.cancelled = False
self.override = override # used for merging iters

if date is not None:
data['date'] = date
if event_data is None:
self.override = False

for k, v in data.items():
if k == 'date' and isinstance(v, basestring):
v = datetime.datetime.strptime(v, '%Y-%m-%d')
if k in ('starts', 'ends') and isinstance(v, basestring):
v = datetime.datetime.strptime(v, '%H:%M').time()
setattr(self, k, v)
else:
self.override = True
for k, v in event_data.items():
if k in ('starts', 'ends') and isinstance(v, basestring):
v = datetime.datetime.strptime(v, '%H:%M').time()
setattr(self, k, v)

self.tzinfo = pytz.timezone(PS_TIMEZONE)

Expand All @@ -46,8 +66,19 @@ def __init__(self, data={}, date=None, override=False):
self.start_dt = combine_tz(self.date, self.starts, self.tzinfo)
self.end_dt = combine_tz(self.date, self.ends, self.tzinfo)

def __eq__(self, other):
if self.override or other.override:
return set(self.__dict__.items()) == set(other.__dict__.items())
return self.date == other.date

def __lt__(self, other):
return self.date.date() < other.date.date()
return self.date < other.date

def __repr__(self):
datestr = self.date.strftime('%Y-%m-%d')
if self.override:
return '<PSEvent %s: %r>' % (datestr, self.name)
return '<PSEvent %s>' % datestr

@property
def title(self):
Expand Down Expand Up @@ -92,36 +123,41 @@ def get_ps_event_by_number(number):
date = the_algorithm.ps_date_from_offset(number)
stringdate = date.strftime('%Y-%m-%d')
event_data = load_ps_data().get(stringdate, {})
return PSEvent(event_data, date=date)
if event_data:
return PSEvent(date, event_data)

return PSEvent(date)

def get_ps_event_by_slug(slug):
for stringdate, event in load_ps_data().items():
event = PSEvent(event, date=stringdate)
event = PSEvent(stringdate, event)
if event.slug == slug:
return event

def gen_events(start=None, end=None):
gen = the_algorithm.gen_ps_dates(start)
event = PSEvent(date=gen.next())
# gen_ps_dates actually returns datetimes
event = PSEvent(gen.next().date())
while not end or event.end_dt < end:
yield event
event = PSEvent(date=gen.next())
event = PSEvent(gen.next().date())

def get_manual_ps_events(start=None, end=None):
for stringdate, event in load_ps_data().items():
event = PSEvent(event, date=stringdate, override=True)
event = PSEvent(stringdate, event)
if start and event.end_dt < start:
continue
if not end or event.end_dt < end:
yield event
if end and event.end_dt >= end:
continue
yield event

# heapq.merge is not stable, however the merge guaranteed overrides will be sequential
def merge_event_iters(one, two):
events = heapq.merge(one, two)
previous = None
for event in events:
if previous:
if previous.date.date() == event.date.date():
if previous.date == event.date:
if event.override:
previous = event
continue
Expand Down
2 changes: 2 additions & 0 deletions templates/event.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ <h1>{{event.title}}</h1>
<div class='description'>
{{ event.description|safe }}
</div>
{% elif not event.override and not event.in_the_past %}
We'll meet in the upstairs room as usual.
{% endif %}
{% endif %}
</li>
Expand Down
2 changes: 2 additions & 0 deletions templates/homepage.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ <h3><a href='/event/{{ event.slug }}' class='nav'>{{ event.title }}</a></h3>
</p>
{% if event.description %}
<p class='description'>{{ event.description }}</p>
{% elif not event.override and not event.in_the_past %}
We'll meet in the upstairs room as usual.
{% endif %}
{% endif %}
</li>
Expand Down
6 changes: 6 additions & 0 deletions tests/test_ps_data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
import doctest
import ps_data
from test_util import parse_datestr, is_algorithmic_ps_date, utc_datetime
from datetime import datetime, timedelta
Expand Down Expand Up @@ -216,3 +217,8 @@ def get_prev_evs(start):
check_event_queries_for_starts(begin_dst)
check_event_queries_for_starts(end_dst)

def test_doctests():
results = doctest.testmod(ps_data)
if results.failed:
raise Exception(results)

0 comments on commit 44c159a

Please sign in to comment.