Merge lp:~aaronp/software-center/enhance-usefulness into lp:software-center

Proposed by Aaron Peachey
Status: Merged
Merged at revision: 1760
Proposed branch: lp:~aaronp/software-center/enhance-usefulness
Merge into: lp:software-center
Diff against target: 208 lines (+125/-8)
6 files modified
softwarecenter/app.py (+3/-1)
softwarecenter/db/reviews.py (+58/-2)
softwarecenter/paths.py (+1/-0)
softwarecenter/utils.py (+10/-5)
utils/get_useful_votes_helper.py (+45/-0)
utils/submit_review.py (+8/-0)
To merge this branch: bzr merge lp:~aaronp/software-center/enhance-usefulness
Reviewer Review Type Date Requested Status
software-store-developers Pending
Review via email: mp+59610@code.launchpad.net

Commit message

enhance usefulness functionality to add support for getting user's votes from the server at startup and anytime we get the username of the user

Description of the change

- fix bug that causes crash when submitting usefulness because unused usefulness UI doesn't contain all elements that need to be updated since adding the error details expander (r1755)
- add support for getting user's votes from server by first loading them from local cache and then spawning a retrieval process in the background to populate them from the server once a response is received. Load from cache whenever UsefulnessCache object is created except upon startup (app.py) when we try to get them from the server (r1756-1758)
- don't update username into local config if the one we have is the same as the one we want to update. (r1759)
- if we DO update a new username into local config, try to update the UsefulnessCache from the server using the new username (as it's likely we didn't get it from the server at startup) (r1759)

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added symlink 'data/get_useful_votes_helper.py'
=== target is u'../utils/get_useful_votes_helper.py'
=== modified file 'softwarecenter/app.py'
--- softwarecenter/app.py 2011-04-29 14:38:29 +0000
+++ softwarecenter/app.py 2011-05-01 07:52:26 +0000
@@ -61,7 +61,7 @@
61from paths import SOFTWARE_CENTER_ICON_CACHE_DIR61from paths import SOFTWARE_CENTER_ICON_CACHE_DIR
6262
63from plugin import PluginManager63from plugin import PluginManager
64from db.reviews import get_review_loader64from db.reviews import get_review_loader, UsefulnessCache
65from distro import get_distro65from distro import get_distro
66from apt.aptcache import AptCache66from apt.aptcache import AptCache
67from gettext import gettext as _67from gettext import gettext as _
@@ -169,6 +169,8 @@
169 self.review_loader = get_review_loader(self.cache, self.db)169 self.review_loader = get_review_loader(self.cache, self.db)
170 # FIXME: add some kind of throttle, I-M-S here170 # FIXME: add some kind of throttle, I-M-S here
171 self.review_loader.refresh_review_stats(self.on_review_stats_loaded)171 self.review_loader.refresh_review_stats(self.on_review_stats_loaded)
172 #load usefulness votes from server when app starts
173 self.useful_cache = UsefulnessCache(True)
172 174
173 # additional icons come from app-install-data175 # additional icons come from app-install-data
174 self.icons = gtk.icon_theme_get_default()176 self.icons = gtk.icon_theme_get_default()
175177
=== modified file 'softwarecenter/db/reviews.py'
--- softwarecenter/db/reviews.py 2011-04-29 14:28:01 +0000
+++ softwarecenter/db/reviews.py 2011-05-01 07:52:26 +0000
@@ -59,16 +59,72 @@
5959
60 USEFULNESS_CACHE = {}60 USEFULNESS_CACHE = {}
61 61
62 def __init__(self):62 def __init__(self, try_server=False):
63 self.rnrclient = RatingsAndReviewsAPI()
63 fname = "usefulness.p"64 fname = "usefulness.p"
64 self.USEFULNESS_CACHE_FILE = os.path.join(SOFTWARE_CENTER_CACHE_DIR,65 self.USEFULNESS_CACHE_FILE = os.path.join(SOFTWARE_CENTER_CACHE_DIR,
65 fname)66 fname)
67
68 self._retrieve_votes_from_cache()
69 #Only try to get votes from the server if required, otherwise just use cache
70 if try_server:
71 self._retrieve_votes_from_server()
72
73 def _retrieve_votes_from_cache(self):
66 if os.path.exists(self.USEFULNESS_CACHE_FILE):74 if os.path.exists(self.USEFULNESS_CACHE_FILE):
67 try:75 try:
68 self.USEFULNESS_CACHE = cPickle.load(open(self.USEFULNESS_CACHE_FILE))76 self.USEFULNESS_CACHE = cPickle.load(open(self.USEFULNESS_CACHE_FILE))
69 except:77 except:
70 LOG.exception("usefulness cache load failure")78 LOG.exception("usefulness cache load fallback failure")
71 os.rename(self.USEFULNESS_CACHE_FILE, self.USEFULNESS_CACHE_FILE+".fail")79 os.rename(self.USEFULNESS_CACHE_FILE, self.USEFULNESS_CACHE_FILE+".fail")
80 return
81
82 def _retrieve_votes_from_server(self):
83 LOG.debug("_retrieve_votes_from_server started")
84 user = get_person_from_config()
85
86 if not user:
87 LOG.warn("Could not get usefulness from server, no username in config file")
88 return False
89
90 # run the command and add watcher
91 cmd = [os.path.join(softwarecenter.paths.datadir, GET_USEFUL_VOTES_HELPER),
92 "--username", user,
93 ]
94 try:
95 (pid, stdin, stdout, stderr) = glib.spawn_async(
96 cmd, flags = glib.SPAWN_DO_NOT_REAP_CHILD,
97 standard_output=True, standard_error=True)
98 glib.child_watch_add(pid, self._usefulness_loaded, data=(stdout, stderr))
99 return True
100 except Exception as e:
101 LOG.warn("failed to launch: '%s' (error: '%s')" % (cmd, e))
102 return False
103
104 def _usefulness_loaded(self, pid, status, (stdout, stderr)):
105 '''called if usefulness retrieved from server'''
106 LOG.debug("_usefulness_loaded started")
107 # get status code
108 res = os.WEXITSTATUS(status)
109 # check stderr
110 err = os.read(stderr, 4*1024)
111 if err:
112 LOG.warn("got error from helper: '%s'" % err)
113 os.close(stderr)
114 # read the raw data
115 data = ""
116 while True:
117 s = os.read(stdout, 1024)
118 if not s: break
119 data += s
120 os.close(stdout)
121
122 results = cPickle.loads(data)
123 self.USEFULNESS_CACHE.clear()
124 for result in results:
125 self.USEFULNESS_CACHE[str(result['review_id'])] = result['useful']
126 if not self.save_usefulness_cache_file():
127 LOG.warn("Read usefulness results from server but failed to write to cache")
72 128
73 def save_usefulness_cache_file(self):129 def save_usefulness_cache_file(self):
74 """write the dict out to cache file"""130 """write the dict out to cache file"""
75131
=== modified file 'softwarecenter/paths.py'
--- softwarecenter/paths.py 2011-04-19 18:21:55 +0000
+++ softwarecenter/paths.py 2011-05-01 07:52:26 +0000
@@ -58,6 +58,7 @@
58SUBMIT_USEFULNESS_APP = "submit_usefulness.py"58SUBMIT_USEFULNESS_APP = "submit_usefulness.py"
59GET_REVIEWS_HELPER = "get_reviews_helper.py"59GET_REVIEWS_HELPER = "get_reviews_helper.py"
60GET_REVIEW_STATS_HELPER = "get_review_stats_helper.py"60GET_REVIEW_STATS_HELPER = "get_review_stats_helper.py"
61GET_USEFUL_VOTES_HELPER = "get_useful_votes_helper.py"
6162
62# there was a bug in maverick 3.0.3 (#652151) that could lead to a empty63# there was a bug in maverick 3.0.3 (#652151) that could lead to a empty
63# root owned directory in ~/.cache/software-center - we remove it here64# root owned directory in ~/.cache/software-center - we remove it here
6465
=== modified file 'softwarecenter/utils.py'
--- softwarecenter/utils.py 2011-04-28 12:32:58 +0000
+++ softwarecenter/utils.py 2011-05-01 07:52:26 +0000
@@ -379,11 +379,16 @@
379 """379 """
380 # FIXME: ideally this would be stored in ubuntu-sso-client380 # FIXME: ideally this would be stored in ubuntu-sso-client
381 # but it dosn't so we store it here381 # but it dosn't so we store it here
382 config = get_config()382 curr_name = get_person_from_config()
383 if not config.has_section("reviews"):383 if curr_name != username:
384 config.add_section("reviews")384 config = get_config()
385 config.set("reviews", "username", username)385 if not config.has_section("reviews"):
386 config.write()386 config.add_section("reviews")
387 config.set("reviews", "username", username)
388 config.write()
389 from db.reviews import UsefulnessCache
390 usefulness = UsefulnessCache(True)
391 return
387 392
388def get_person_from_config():393def get_person_from_config():
389 """ get the username value for Ubuntu SSO from the config file394 """ get the username value for Ubuntu SSO from the config file
390395
=== added file 'utils/get_useful_votes_helper.py'
--- utils/get_useful_votes_helper.py 1970-01-01 00:00:00 +0000
+++ utils/get_useful_votes_helper.py 2011-05-01 07:52:26 +0000
@@ -0,0 +1,45 @@
1#!/usr/bin/python
2
3import pickle
4import simplejson
5import logging
6
7from optparse import OptionParser
8from softwarecenter.backend.rnrclient import RatingsAndReviewsAPI
9from piston_mini_client import APIError
10
11LOG = logging.getLogger(__name__)
12
13if __name__ == "__main__":
14 logging.basicConfig()
15
16 # common options for optparse go here
17 parser = OptionParser()
18
19 # check options
20 parser.add_option("--username", default=None)
21 (options, args) = parser.parse_args()
22
23 rnrclient = RatingsAndReviewsAPI()
24
25 useful_votes = []
26
27 if options.username:
28 try:
29 useful_votes = rnrclient.get_usefulness(username=options.username)
30 except simplejson.decoder.JSONDecodeError, e:
31 LOG.error("failed to parse '%s'" % e.doc)
32 except APIError, e:
33 LOG.warn("_get_useful_votes_helper: no usefulness able to be retrieved for username: %s" % (options.username))
34 LOG.debug("_get_reviews_threaded: no reviews able to be retrieved: %s" % e)
35 except:
36 LOG.exception("_get_useful_votes_helper")
37
38 # print to stdout where its consumed by the parent
39 try:
40 print pickle.dumps(useful_votes)
41 except IOError:
42 # this can happen if the parent gets killed, no need to trigger
43 # apport for this
44 pass
45
046
=== modified file 'utils/submit_review.py'
--- utils/submit_review.py 2011-04-29 15:00:11 +0000
+++ utils/submit_review.py 2011-05-01 07:52:26 +0000
@@ -1105,6 +1105,14 @@
1105 def run(self):1105 def run(self):
1106 self.login()1106 self.login()
1107 1107
1108 # override UI update methods from BaseApp to prevent them
1109 # causing errors if called when UI is hidden
1110 def _clear_status_imagery(self):
1111 pass
1112
1113 def _change_status(self, type, message):
1114 pass
1115
11081116
1109if __name__ == "__main__":1117if __name__ == "__main__":
11101118

Subscribers

People subscribed via source and target branches