4
\$\begingroup\$

I want to use Tweets sent out by a twitter account as a command to shut down Ubuntu. For this, I've written a Python script using tweepy, a Python library for Twitter. I scheduled the script to run half past the hour every hour (for eg at 5:30, 6:30, and so on) using crontab.

Here's the script:

import tweepy
import os
from datetime import datetime
p=None

api= tweepy.API()

for status in api.user_timeline('tweetneag4'):         
    while p==None:    #so that it checks only the first tweet
        if status.text.count(str((datetime.now().hour)+1))< 2 and str((datetime.time.now().hour)+1)==10:
            p=1
            pass
        elif str((datetime.now().hour)+1) in status.text:
            print "System shut down in 20 mins."
            os.system('shutdown -h +20')  
            p=1 

Here is a sample tweet:

#loadshedding schedule in 10mins: 15:00-21:00 #group4 #nea

The twitter account (@tweetneag4) tweets an alert 30 mins and 10 mins before the power outage begins (here, the account tweets if and only if there's a power outage next hour). What I've tried to do is check at 5:30 whether it posts a tweet regarding 6 o'clock. I've done this by seeing if the tweet contains the string "6"(when checking at 5). When checking for ten o'clock, an additional complication arises because it may contain "10" in two scenarios- first as in 10 o'clock and second as in 10mins later. (I'm sure there's a better way of doing this)

If you see the twitter feed, things should be clearer. How could I improve so that the code become more elegant?

\$\endgroup\$
6
\$\begingroup\$
import tweepy
import os
from datetime import datetime
p=None

Use of single letter variable names is confusing, I have no idea what p is for.

api= tweepy.API()

Put spaces around your =

for status in api.user_timeline('tweetneag4'):         
    while p==None:    #so that it checks only the first tweet

What are you thinking here? If p doesn't get set to a true value, you'll loop over the next block repeatedly in an infinite loop. If you only want the first tweet pass count = 1 to user_timeline

        if status.text.count(str((datetime.now().hour)+1))< 2 and str((datetime.time.now().hour)+1)==10:

            p=1

Setting flags is ugly. If you must set boolean flags use True and False not None and 1.

            pass
        elif str((datetime.now().hour)+1) in status.text:
            print "System shut down in 20 mins."
            os.system('shutdown -h +20')  
            p=1 

It seems to me that a much more straightforward way of doing this is to look at the time at which the status was posted. It seems to be available as status.created_at. Based on that you know that outage is either 30 or 10 minutes after that. So if it has been more then 30 minutes since that message, it must have already happened and we aren't concerned.

Something like this:

import tweepy
import os
from datetime import datetime, timedelta

api= tweepy.API()

status = api.user_timeline('tweetneag4', count=1)[0]
age = datetime.now() - status.created_at
if age < timedelta(minutes = 45):
    print "System shut down in 20 mins."
    os.system('shutdown -h +20')  

NOTE: I get negative ages when I run this, I'm assuming that's time zones. Its also possible my logic is screwy.

If you really do need to get the actual time from the text, your current strategy of searching for numbers in the text is fragile. Instead you could do something like this:

# split the message up by whitespace, this makes it easy to grab the outage time
outage_time = status.split()[4]
# find everything up to the colon
hour_text, junk = outage_time.split(':')
# parse the actual hour
hour = int(hour_text)

Finally, for more complex examples using regular expressions to parse the text would be a good idea.

\$\endgroup\$
  • \$\begingroup\$ @Winston- Thanks for the critique. I'll try to improve some of my programming habits!! I was really searching for something like status.created_at and I'll definitely try out your solution- the logic is much neater. \$\endgroup\$ – infoquad Mar 30 '11 at 4:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.