First stab at implementing threads... seems to work okay, then suddenly segfaults

This commit is contained in:
Anna 2010-04-22 14:57:27 -04:00
parent 4eaf2549c2
commit 45b374f24f
3 changed files with 141 additions and 87 deletions

110
apithreads.py Normal file
View File

@ -0,0 +1,110 @@
# Python module that handles calls to the twitter API as a separate thread
import re
from threading import Thread
class GetTweets(Thread):
def __init__(self, api, list_name, pane, num_entries, username):
Thread.__init__(self)
self.api = api
self.list_name = list_name
self.pane = pane
self.num_entries = num_entries
self.username = username
def run(self):
print 'debug: GetTweets.run(): start'
# username/Home entries need to load the appropriate Home feed
if self.list_name == self.username + '/Home':
statuses = self.api.GetHomeTimeline(count=self.num_entries)
# For @username, check if it is one of our usernames, or
# just needs to be searched on
elif self.list_name == '@' + self.username:
statuses = self.api.GetMentions(count=self.num_entries)
elif re.match('@', self.list_name):
statuses = results_to_statuses(self.api.Search(self.list_name, rpp=self.num_entries))
# Direct Messages should match like /Home, above
elif self.list_name == self.username + '/Direct Messages':
statuses = dms_to_statuses(self.api.GetDirectMessages())
# User lookups go straight to the user
elif re.match(r'user: ', self.list_name):
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', self.list_name), count=self.num_entries)
# Lists load the appropriate list from the appropriate account
elif re.match(r'list: ', self.list_name):
real_list = re.sub(r'list: .*/(.*)', r'\1', self.list_name)
statuses = self.api.GetListStatuses(real_list, per_page=self.num_entries)
# Everything else is a straight search
else:
statuses = results_to_statuses(self.api.Search(self.list_name, rpp=self.num_entries))
self.pane.update_window(statuses)
print 'debug: GetTweets.run(): finished'
### End class GetTweets
# We use these classes to emulate a Status object when we need
# one to be built out of something else.
class Status():
def __init__(self):
self.user = User()
self.id = None
self.created_at = None
self.in_reply_to_screen_name = None
self.in_reply_to_status_id = None
class User():
def __init__(self):
self.screen_name = None
self.name = None
# To keep things simple elsewhere and improve code reuse
# we'll build a list of home-cooked Status objects out of results.
# Why is this even necessary?
# Why can't we have more consistency out of the Twitter API?
def results_to_statuses(results):
statuses = []
for result in results.results:
status = Status()
status.id = result.id
status.user = User()
status.user.screen_name = result.from_user
status.user.name = ""
status.in_reply_to_screen_name = result.to_user
# The Twitter Search API has different timestamps than the
# REST API... balls
# fixme:
# Gotta be a cleaner way to do this, but I can't think of it
# right now
created_at = re.sub(',', '', result.created_at)
created_split = re.split(' ', created_at)
status.created_at = created_split[0] + ' ' + created_split[2] + ' ' + created_split[1] + ' ' + created_split[4] + ' ' + created_split[5] + ' ' + created_split[3]
status.text = result.text
statuses.append(status)
return statuses
def dms_to_statuses(direct_messages):
statuses = []
for dm in direct_messages:
status = Status()
status.id = dm.id
status.user = User()
status.user.screen_name = dm.sender_screen_name
status.user.name = dm.sender.name
status.created_at = dm.created_at
status.text = dm.text
statuses.append(status)
return statuses

View File

@ -7,6 +7,7 @@ import twitter
import gtk, gtk.glade, gobject
from urllib2 import HTTPError
from twitterwidgets import TweetPane
import apithreads
class MyTwitter():
@ -135,6 +136,7 @@ class MyTwitter():
gobject.timeout_add(self.refresh_time * 1000, self.update_windows)
# Spawns a thread for each pane, which updates that pane.
def update_windows(self):
for i in range(0, self.tweet_notebook.get_n_pages()):
pane = self.tweet_notebook.get_nth_page(i)
@ -144,41 +146,36 @@ class MyTwitter():
if pane.get_single_tweet() is not None:
continue
# username/Home entries need to load the appropriate Home feed
elif re.search(r'/Home', list_name):
account = self.accounts[re.sub(r'/Home', r'', list_name)]
statuses = account.GetHomeTimeline(count=self.num_entries)
# Determine username and appropriate account to use
found = False
# For @username, we need to check if it is one of our usernames, or
# just needs to be searched on
elif re.match('@', list_name):
if self.accounts.has_key(re.sub('@', '', list_name)):
account = self.accounts[re.sub(r'@', r'', list_name)]
statuses = account.GetMentions(count=self.num_entries)
else:
statuses = self.results_to_statuses(self.api.Search(list_name, rpp=self.num_entries))
# Direct Messages should match like /Home, above
elif re.search(r'/Direct Messages', list_name):
account = self.accounts[re.sub(r'/Direct Messages', r'', list_name)]
statuses = self.dms_to_statuses(account.GetDirectMessages())
# User lookups go straight to the user
elif re.match(r'user: ', list_name):
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', list_name), count=self.num_entries)
# Lists load the appropriate list from the appropriate account
elif re.match(r'list: ', list_name):
username = re.sub(r'list: (.*)/.*', r'\1', list_name)
real_list = re.sub(r'list: .*/(.*)', r'\1', list_name)
username = re.sub('/Home', '', list_name)
if self.accounts.has_key(username):
account = self.accounts[username]
statuses = account.GetListStatuses(real_list, per_page=self.num_entries)
found = True
# Everything else is a straight search
else:
statuses = self.results_to_statuses(self.api.Search(list_name, rpp=self.num_entries))
if not found:
username = re.sub('@', '', list_name)
if self.accounts.has_key(username):
account = self.accounts[username]
found = True
pane.update_window(statuses)
if not found:
username = re.sub('/Direct Messages', '', list_name)
if self.accounts.has_key(username):
account = self.accounts[username]
found = True
if not found:
account = self.api
username = self.username
apithreads.GetTweets(api=account,
list_name=list_name,
pane=pane,
num_entries=self.num_entries,
username=username
).start()
# We have to return true, so the timeout_add event will keep happening
return True
@ -440,69 +437,14 @@ class MyTwitter():
self.username = new_user
self.api = self.accounts[self.username]
# To keep things simple elsewhere and improve code reuse
# we'll build a list of home-cooked Status objects out of results.
# Why is this even necessary?
# Why can't we have more consistency out of the Twitter API?
def results_to_statuses(self, results):
statuses = []
for result in results.results:
status = Status()
status.id = result.id
status.user = User()
status.user.screen_name = result.from_user
status.user.name = ""
status.in_reply_to_screen_name = result.to_user
# The Twitter Search API has different timestamps than the
# REST API... balls
# fixme:
# Gotta be a cleaner way to do this, but I can't think of it
# right now
created_at = re.sub(',', '', result.created_at)
created_split = re.split(' ', created_at)
status.created_at = created_split[0] + ' ' + created_split[2] + ' ' + created_split[1] + ' ' + created_split[4] + ' ' + created_split[5] + ' ' + created_split[3]
status.text = result.text
statuses.append(status)
return statuses
def dms_to_statuses(self, direct_messages):
statuses = []
for dm in direct_messages:
status = Status()
status.id = dm.id
status.user = User()
status.user.screen_name = dm.sender_screen_name
status.user.name = dm.sender.name
status.created_at = dm.created_at
status.text = dm.text
statuses.append(status)
return statuses
### end class MyTwitter
# We use these classes to emulate a Status object when we need
# one to be built out of something else.
class Status():
def __init__(self):
self.user = User()
self.id = None
self.created_at = None
self.in_reply_to_screen_name = None
self.in_reply_to_status_id = None
class User():
def __init__(self):
self.screen_name = None
self.name = None
# main
parser = optparse.OptionParser()
parser.add_option('-c' ,'--config', dest="filename", default="~/.mytwitter.conf")
(options, args) = parser.parse_args()
my_twitter = MyTwitter(options.filename)
gtk.gdk.threads_init()
gtk.main()

View File

@ -70,6 +70,8 @@ class TweetPane(gtk.ScrolledWindow):
def update_window(self, statuses):
print 'debug: TweetPane.update_window(): ' + self.list_name
if self.updated_once is False:
self.updated_once = True