Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework constructor of PSEvent #28

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
16 changes: 9 additions & 7 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 @@ -84,18 +85,14 @@ def test_events_construct(self):
end = max(next_year, manual_events[-1].end_dt)
all_events = list(ps_data.events(end=end))

# As there's no __eq__ for PSEvent yet
manual_start_dts = [e.start_dt for e in manual_events]
all_start_dts = [e.start_dt for e in all_events]
assert set(all_start_dts) > set(manual_start_dts)
manual_dates = [e.date for e in manual_events]
all_dates = [e.date for e in all_events]
assert set(all_dates) > set(manual_dates)

def test_override(self):
ps_100 = ps_data.get_ps_event_by_number(100)
assert 'ONE HUNDREDTH' in ps_100.description

# For now, don't test .date, as it's either date() or datetime(),
# depending on whether the event is from the algorithm or not

def assertStartsAt(self, event, dt):
assert event.start_dt == dt, '%r is wrong start time' % event.start_dt

Expand Down Expand Up @@ -216,3 +213,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)