Added locking and moved work around / reduced repeat work at startup. Should clear up segfaults and improve startup time
This commit is contained in:
parent
7cce83c0f3
commit
6044fa27d2
6
TODO
6
TODO
|
@ -14,6 +14,6 @@ features:
|
||||||
bugs:
|
bugs:
|
||||||
|
|
||||||
* Direct Messages have no names, only screen names (may not be fixable without
|
* Direct Messages have no names, only screen names (may not be fixable without
|
||||||
considerable tweets to python-twitter)
|
considerable tweaks to python-twitter)
|
||||||
* Can't always kill tabs
|
* Can't always kill tabs - open tab list not always correctly populated?
|
||||||
* New segfault at start that can't be reproduced with gdb. Must be a timing issue... adding locked access to some data in TweetPane didn't help... need locks to go with api objects.
|
* Can't always kill application
|
||||||
|
|
|
@ -2,7 +2,19 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import gtk
|
import gtk
|
||||||
from threading import Thread
|
from threading import Thread,RLock
|
||||||
|
from twitter import Api
|
||||||
|
|
||||||
|
class SafeApi(Api):
|
||||||
|
''' This is just a Twitter API with an RLock for multi-threaded access '''
|
||||||
|
|
||||||
|
def __init__(self, username, password):
|
||||||
|
Api.__init__(self, username, password)
|
||||||
|
self.lock = RLock()
|
||||||
|
|
||||||
|
# End class SafeApi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GetTweets(Thread):
|
class GetTweets(Thread):
|
||||||
def __init__(self, api, list_name, pane, num_entries, username):
|
def __init__(self, api, list_name, pane, num_entries, username):
|
||||||
|
@ -15,33 +27,35 @@ class GetTweets(Thread):
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# username/Home entries need to load the appropriate Home feed
|
with self.api.lock:
|
||||||
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
|
# username/Home entries need to load the appropriate Home feed
|
||||||
# just needs to be searched on
|
if self.list_name == self.username + '/Home':
|
||||||
elif self.list_name == '@' + self.username:
|
statuses = self.api.GetHomeTimeline(count=self.num_entries)
|
||||||
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
|
# For @username, check if it is one of our usernames, or
|
||||||
elif self.list_name == self.username + '/Direct Messages':
|
# just needs to be searched on
|
||||||
statuses = dms_to_statuses(self.api.GetDirectMessages())
|
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))
|
||||||
|
|
||||||
# User lookups go straight to the user
|
# Direct Messages should match like /Home, above
|
||||||
elif re.match(r'user: ', self.list_name):
|
elif self.list_name == self.username + '/Direct Messages':
|
||||||
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', self.list_name), count=self.num_entries)
|
statuses = dms_to_statuses(self.api.GetDirectMessages())
|
||||||
|
|
||||||
# Lists load the appropriate list from the appropriate account
|
# User lookups go straight to the user
|
||||||
elif re.match(r'list: ', self.list_name):
|
elif re.match(r'user: ', self.list_name):
|
||||||
real_list = re.sub(r'list: .*/(.*)', r'\1', self.list_name)
|
statuses = self.api.GetUserTimeline(re.sub(r'^user: ', r'', self.list_name), count=self.num_entries)
|
||||||
statuses = self.api.GetListStatuses(real_list, per_page=self.num_entries)
|
|
||||||
|
|
||||||
# Everything else is a straight search
|
# Lists load the appropriate list from the appropriate account
|
||||||
else:
|
elif re.match(r'list: ', self.list_name):
|
||||||
statuses = results_to_statuses(self.api.Search(self.list_name, rpp=self.num_entries))
|
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))
|
||||||
|
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
try:
|
try:
|
||||||
|
@ -64,7 +78,8 @@ class GetSingleTweet(Thread):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
statuses = []
|
statuses = []
|
||||||
statuses.append(self.api.GetStatus(self.single_tweet))
|
with self.api.lock:
|
||||||
|
statuses.append(self.api.GetStatus(self.single_tweet))
|
||||||
|
|
||||||
gtk.gdk.threads_enter()
|
gtk.gdk.threads_enter()
|
||||||
try:
|
try:
|
||||||
|
@ -89,7 +104,8 @@ class GetFollowing(Thread):
|
||||||
screen_name = re.sub('user: ', '', self.user)
|
screen_name = re.sub('user: ', '', self.user)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
relationship = self.api.ShowFriendships(target_screen_name=screen_name)
|
with self.api.lock:
|
||||||
|
relationship = self.api.ShowFriendships(target_screen_name=screen_name)
|
||||||
following = relationship.source.following
|
following = relationship.source.following
|
||||||
except HTTPError:
|
except HTTPError:
|
||||||
following = false
|
following = false
|
||||||
|
@ -112,7 +128,8 @@ class GetVerified(Thread):
|
||||||
screen_name = re.sub('user: ', '', self.user)
|
screen_name = re.sub('user: ', '', self.user)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = self.api.GetUser(screen_name)
|
with self.api.lock:
|
||||||
|
user = self.api.GetUser(screen_name)
|
||||||
verified = user.verified
|
verified = user.verified
|
||||||
except HTTPError:
|
except HTTPError:
|
||||||
verified = false
|
verified = false
|
||||||
|
|
25
mytwitter.py
25
mytwitter.py
|
@ -3,7 +3,6 @@
|
||||||
# Custom twitter client... mostly for learning Python
|
# Custom twitter client... mostly for learning Python
|
||||||
|
|
||||||
import sys, ConfigParser, os, re, optparse, shelve
|
import sys, ConfigParser, os, re, optparse, shelve
|
||||||
import twitter
|
|
||||||
import gtk, gtk.glade, gobject
|
import gtk, gtk.glade, gobject
|
||||||
from urllib2 import HTTPError
|
from urllib2 import HTTPError
|
||||||
from twitterwidgets import TweetPane
|
from twitterwidgets import TweetPane
|
||||||
|
@ -47,7 +46,7 @@ class MyTwitter():
|
||||||
for item in config.sections():
|
for item in config.sections():
|
||||||
if (re.match(r'account', item)):
|
if (re.match(r'account', item)):
|
||||||
username = config.get(item, 'username')
|
username = config.get(item, 'username')
|
||||||
self.accounts[username] = twitter.Api(username=username, password=config.get(item, 'password'))
|
self.accounts[username] = apithreads.SafeApi(username=username, password=config.get(item, 'password'))
|
||||||
|
|
||||||
self.username = self.accounts.keys()[0]
|
self.username = self.accounts.keys()[0]
|
||||||
self.api = self.accounts[self.username]
|
self.api = self.accounts[self.username]
|
||||||
|
@ -106,8 +105,9 @@ class MyTwitter():
|
||||||
# Add the tabs from last session to the notebook
|
# Add the tabs from last session to the notebook
|
||||||
page_num = self.db['active_page']
|
page_num = self.db['active_page']
|
||||||
for tab, single_tweet in self.db['open_tabs']:
|
for tab, single_tweet in self.db['open_tabs']:
|
||||||
self.add_to_notebook(tab, single_tweet)
|
self.add_to_notebook(tab, single_tweet, update=False)
|
||||||
self.tweet_notebook.set_current_page(page_num)
|
self.tweet_notebook.set_current_page(page_num)
|
||||||
|
self.update_windows()
|
||||||
|
|
||||||
# Put Home, @user, Direct Messages, and lists in the View menu for
|
# Put Home, @user, Direct Messages, and lists in the View menu for
|
||||||
# each user
|
# each user
|
||||||
|
@ -188,7 +188,8 @@ class MyTwitter():
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
text = self.update_entry.get_text()
|
text = self.update_entry.get_text()
|
||||||
self.update_entry.set_text("")
|
self.update_entry.set_text("")
|
||||||
self.api.PostUpdate(text, in_reply_to_status_id=self.reply_id)
|
with self.api.lock:
|
||||||
|
self.api.PostUpdate(text, in_reply_to_status_id=self.reply_id)
|
||||||
self.reply_id = None
|
self.reply_id = None
|
||||||
self.update_status_bar('Tweet Posted')
|
self.update_status_bar('Tweet Posted')
|
||||||
|
|
||||||
|
@ -224,7 +225,8 @@ class MyTwitter():
|
||||||
|
|
||||||
|
|
||||||
def on_retweet(self, widget, data):
|
def on_retweet(self, widget, data):
|
||||||
self.api.PostRetweet(data['id'])
|
with self.api.lock:
|
||||||
|
self.api.PostRetweet(data['id'])
|
||||||
|
|
||||||
|
|
||||||
def on_reply_to(self, widget, data):
|
def on_reply_to(self, widget, data):
|
||||||
|
@ -262,7 +264,7 @@ class MyTwitter():
|
||||||
self.remove_view(name, single_tweet)
|
self.remove_view(name, single_tweet)
|
||||||
|
|
||||||
|
|
||||||
def add_to_notebook(self, name, single_tweet=None):
|
def add_to_notebook(self, name, single_tweet=None, update=True):
|
||||||
# If it already exists, don't add it, just switch to it
|
# If it already exists, don't add it, just switch to it
|
||||||
for i in range(self.tweet_notebook.get_n_pages()):
|
for i in range(self.tweet_notebook.get_n_pages()):
|
||||||
pane = self.tweet_notebook.get_nth_page(i)
|
pane = self.tweet_notebook.get_nth_page(i)
|
||||||
|
@ -308,8 +310,9 @@ class MyTwitter():
|
||||||
pane=new_pane,
|
pane=new_pane,
|
||||||
single_tweet=single_tweet).start()
|
single_tweet=single_tweet).start()
|
||||||
|
|
||||||
self.update_windows()
|
if update:
|
||||||
self.tweet_notebook.set_current_page(-1) # switch to the new pane
|
self.update_windows()
|
||||||
|
self.tweet_notebook.set_current_page(-1) # switch to the new pane
|
||||||
|
|
||||||
|
|
||||||
def on_tab_change(self, event, page, page_num):
|
def on_tab_change(self, event, page, page_num):
|
||||||
|
@ -356,10 +359,12 @@ class MyTwitter():
|
||||||
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
||||||
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
||||||
if current_pane.get_following():
|
if current_pane.get_following():
|
||||||
self.api.DestroyFriendship(user_name)
|
with self.api.lock:
|
||||||
|
self.api.DestroyFriendship(user_name)
|
||||||
current_pane.set_following(False)
|
current_pane.set_following(False)
|
||||||
else:
|
else:
|
||||||
self.api.CreateFriendship(user_name)
|
with self.api.lock:
|
||||||
|
self.api.CreateFriendship(user_name)
|
||||||
current_pane.set_following(True)
|
current_pane.set_following(True)
|
||||||
|
|
||||||
self.update_follow_button(current_pane)
|
self.update_follow_button(current_pane)
|
||||||
|
|
Reference in New Issue
Block a user