How a geek tells his wife he loves her: an exercise in Python programming
I’m away from my better half this weekend, visiting my Mom and brother. I scheduled this a few weeks ago, but shortly after Carmen was granted an entry into the Nike Women’s Half Marathon on the same weekend. Rescheduling the visit with Mom would have been hard, so I decided to go anyway, and missed the opportunity to cheer her on.
But I’m a geek. On Saturday night, I hit upon a brilliant, romantic idea (or what passes for one when you are a geek). I knew I was gonna be busy during her run, so I decided to write a script that would text her ever half an hour with an encouraging message. That way, even if I got busy, she’d know I was thinking about her.
It probably would have helped had I started before 10:00pm on Saturday.
First of all, it’s pretty straightforward to send texts to someone using email. If you send an email to email@example.com, the contents will get routed to the person. And using Python’s smtplib, sending email is pretty easy. Here’s a function that worked for me:
def emailtxt(addr, msg): server = smtplib.SMTP("smtp.gmail.com", 587) server.ehlo() server.starttls() server.ehlo() server.login("firstname.lastname@example.org", "mypassword") server.sendmail("email@example.com", addr, msg) server.close()
I decided to use my gmail account, but you can use whatever SMTP mail server you like.
So, now that I had a function to txt her, how to handle the scheduling? It turns out that Python has an interesting library called
sched which can be used to implement a scheduler. Here’s the interesting bits:
import sched import time scheduler = sched.scheduler(time.time, time.sleep) def timefor(t): tp = time.strptime(t, "%a %b %d %H:%M:%S %Z %Y") return time.mktime(tp) scheduler.enterabs(timefor("Sun Oct 17 04:00:00 PDT 2010"), 1, sendit, (0,)) scheduler.enterabs(timefor("Sun Oct 17 04:30:00 PDT 2010"), 1, sendit, (1,)) scheduler.enterabs(timefor("Sun Oct 17 05:00:00 PDT 2010"), 1, sendit, (2,)) scheduler.enterabs(timefor("Sun Oct 17 05:30:00 PDT 2010"), 1, sendit, (3,)) scheduler.enterabs(timefor("Sun Oct 17 06:00:00 PDT 2010"), 1, sendit, (4,)) scheduler.enterabs(timefor("Sun Oct 17 06:30:00 PDT 2010"), 1, sendit, (5,)) ... scheduler.run()
So, what does this do? It creates a scheduler object, which operates in real time (the time.time and time.delay functions are abstract functions that implement a time and delay function). It then uses the utility function
timefor to figure out the absolute time when I wanted the event to occur, and when that time expires, it will call
sendit, passing it the args in parens (which in my case is a message number in a table of nice things to send her, which I’ve omitted since they are too precious for words). When the
run() method is called, the scheduler will wait until the appropriate time, and then make the calls.
I had it set to start sending messages at 4:00AM, since that is when she was going to wake up. Sadly, I screwed up the code slightly, and she didn’t get her first message until 7:30 or so. But she was successfully encourage every 30 minutes after that.
I’m very proud of her and her half-marathon performance. Neither of us are natural athletes, but she’s a constant inspiration to me, and makes me want to be stronger and better.
It’s too bad I’m such a geek.