Finished porting my street cleaning reminder program to Python for AppEngine, where it seems to be working fine. One unfortunate thing about moving the original desktop C# 3.5 code to ASP.NET 2.0 was that I had to replace all my nice Linq queries with regular loops, so being able to make use of Python features like tuples and list comprehensions was enjoyable.
Here is the code, with my personal identification information removed, and which I hereby release into the public domain:
import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import gdata.service
import gdata.calendar
import gdata.calendar.service
import atom.service
import gdata.alt.appengine
import string
import time
class Cleanendar(webapp.RequestHandler):
def __init__(self):
manager = CalendarManager()
self.commands = { 'n': manager.north, 's': manager.south, '': manager.clear }
def post(self):
if self.request.get('event') == 'MO':
if self.request.get('uid') == MY_ZEEP_UID:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write(self.process_command(self.request.get('body').lower()))
return
self.response.clear()
self.response.set_status(400)
def process_command(self, body):
if body in self.commands:
self.commands[body]()
return ''
else:
return 'Bad command [' + body + ']'
class CalendarManager:
def __init__(self):
self.service = self.get_service()
(self.calendar, hcalendar) = self.get_calendars(self.service)
self.id = self.calendar.id.text.split('/')[-1]
self.holidays = self.get_events(hcalendar.id.text.split('/')[-1])
self.prefix = 'Cleanendar: '
self.begin = time.strptime(time.strftime('%Y%m%d', time.localtime()) + '1230', '%Y%m%d%H%M')
self.end = time.strptime(time.strftime('%Y%m%d', time.localtime()) + '1400', '%Y%m%d%H%M')
self.daynames = ['Mo','Tu','We','Th','Fr','Sa','Su']
def get_service(self):
service = gdata.calendar.service.CalendarService(MY_GOOGLE_ID, MY_GOOGLE_PW, MY_APP_ID)
service.ProgrammaticLogin()
return service
def get_calendars(self, service):
feed = service.GetAllCalendarsFeed()
calendar = None
holidays = None
for i, c in enumerate(feed.entry):
if c.title.text == "Cleanendar":
calendar = c
elif c.title.text == "2009 NYC Alternate Side Parking":
holidays = c
return (calendar, holidays)
def north(self):
self.set_days([0,3])
def south(self):
self.set_days([1,4])
def clear(self):
events = self.get_events(self.id)
for i, e in enumerate(events.entry):
if e.title.text.startswith(self.prefix):
self.service.DeleteEvent(e.GetEditLink().href)
def set_days(self, days):
self.clear()
self.add_event(self.make_event(self.begin, "Move car", days))
self.add_event(self.make_event(self.end, "Move back", days))
def get_events(self, id):
return self.service.GetCalendarEventFeed('/calendar/feeds/' + id + '/private/full')
def make_event(self, t, desc, days):
event = gdata.calendar.CalendarEventEntry()
event.title = atom.Title(text=self.prefix + 'Street cleaning')
event.content = atom.Content(text=desc)
event.recurrence = self.make_recurrence(t, days)
event.reminder = self.make_reminder()
return event
def add_event(self, event):
return self.service.InsertEvent(event, '/calendar/feeds/' + self.id + '/private/full')
def make_recurrence(self, t, days):
data = ('DTSTART;TZID=UTC;VALUE=DATE-TIME:' + time.strftime('%Y%m%dT%H%M%S', t) + '\r\n' +
'DURATION:PT5M\r\n' +
'RRULE:FREQ=WEEKLY;BYDAY=' + string.join([self.daynames[d] for d in days], ',') + ';' +
'UNTIL=' + time.strftime('%Y', t) + '1231\r\n' +
'EXDATE:' + string.join([time.strftime('%Y%m%d', d) + time.strftime('T%H%M%S', t) for d in self.make_exclusions(days)], ',') + '\r\n')
return gdata.calendar.Recurrence(text=data)
def make_exclusions(self, days):
e = []
for i, h in enumerate(self.holidays.entry):
for t in [time.strptime(w.start_time, '%Y-%m-%d') for w in h.when]:
if t.tm_wday in [0,3]:
e.append(t)
return e
def make_reminder(self):
return gdata.calendar.Reminder(minutes=10, method='sms')
application = webapp.WSGIApplication([('/', Cleanendar)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Friday, September 4, 2009
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment