Merge lp:~terrycojones/tickery/update-to-latest-txrdq-806699 into lp:tickery

Proposed by Terry Jones
Status: Merged
Approved by: Jamu Kakar
Approved revision: 18
Merged at revision: 16
Proposed branch: lp:~terrycojones/tickery/update-to-latest-txrdq-806699
Merge into: lp:tickery
Diff against target: 232 lines (+51/-58)
4 files modified
requirements-local.txt (+2/-0)
tickery/adder.py (+21/-41)
tickery/cache.py (+2/-2)
tickery/service.py (+26/-15)
To merge this branch: bzr merge lp:~terrycojones/tickery/update-to-latest-txrdq-806699
Reviewer Review Type Date Requested Status
Jamu Kakar Approve
Esteve Fernandez Approve
Review via email: mp+67472@code.launchpad.net

Description of the change

A bunch of small changes to make Tickery work with the latest txRDQ.

In running this I found (and fixed) a couple of other problems that
make no sense to me. The JSONRPC service receives str screennames (not
unicode) and passes them to the Tickery Twitter methods (which use
txFluidDB) which complain that the screennames are not unicode. So I
converted them. I don't know how the old code was managing to run,
but presumably something was different. I don't know why the JSONRPC
lib isn't giving us unicode screennames. Weird.

I also added a requirements-local.txt which I'd like you to ignore for
now. It's just a record of things we will need to install locally
when we move to having a Fluidinfo Tickery development/deploy project
as well as a neutral (non-Fluidinfo specific) Tickery release.

To post a comment you must log in.
Revision history for this message
Jamu Kakar (jkakar) wrote :

[1]

I've reviewed the changes and I think I vaguely understand them (but
definitely not deeply). Anyway, before learning more I can't even
build Tickery:

$ make
fab build_pyjs
[localhost] run: cd tickery/www && ../../pyjamas/bin/pyjsbuild index.py

Fatal error: local() encountered an error (return code 127) while executing 'cd tickery/www && ../../pyjamas/bin/pyjsbuild index.py'

Aborting.
make: *** [all] Error 1

Do you know what's going on here?

review: Needs Information
Revision history for this message
Eric Seidel (gridaphobe) wrote :

> $ make
> fab build_pyjs
> [localhost] run: cd tickery/www && ../../pyjamas/bin/pyjsbuild index.py
>
> Fatal error: local() encountered an error (return code 127) while executing
> 'cd tickery/www && ../../pyjamas/bin/pyjsbuild index.py'
>
> Aborting.
> make: *** [all] Error 1
>
> Do you know what's going on here?

You need to run `fab install_pyjs` to install pyjamas before building
the app. This should be documented or just included in the default target.
Also, there's a silly typo in the Makefile, unless debub is an actual word :P

Revision history for this message
Terry Jones (terrycojones) wrote :

Hi Jamu (and thanks Eric!)

The setup is a bit better in the fix-fab-deploy-798485 branch (see the
Makefile in there). We need to separate the Tickery code from the
Fluidinfo project to build and deploy our own running instance. I'm
waiting to do that until more of the merge proposals are accepted
(mainly 798485). I don't want to document a deploy procedure in the
public branch that is only relevant to us. There is a doc dir, which
is docs for the public (probably not 100%) accurate.

Anyway, as Eric says, if you do fab install_pyjs (which will be done
via make when 798485 lands), you'll have a top-level pyjamas dir. You
should then

$ virtualenv env
$ . env/bin/activate
$ pip install --update -r requirements.txt

and at that point if you run just twistd, you should see tickery
listed as a plugin. So,

$ twistd tickery

then visit http://localhost:6969

Let me know if you have a problem. Thanks!

Revision history for this message
Esteve Fernandez (esteve) wrote :

+1 LGTM!

review: Approve
Revision history for this message
Jamu Kakar (jkakar) wrote :

> Anyway, as Eric says, if you do fab install_pyjs (which will be done
> via make when 798485 lands), you'll have a top-level pyjamas dir. You
> should then
>
> $ virtualenv env
> $ . env/bin/activate
> $ pip install --update -r requirements.txt

Thanks, this worked. I had to remove '--update' from the command-line
options. I guess this is a difference in the version of PIP on Ubuntu
11.04.

> and at that point if you run just twistd, you should see tickery
> listed as a plugin. So,
>
> $ twistd tickery
>
> then visit http://localhost:6969
>
> Let me know if you have a problem. Thanks!

It still doesn't work, I guess I need a Twitter API key (or
something):

$ twistd tickery
Unhandled Error
Traceback (most recent call last):
  File "/home/jkakar/src/projects/twisted/trunk/twisted/application/app.py", line 595, in parseOptions
    usage.Options.parseOptions(self, options)
  File "/home/jkakar/src/projects/twisted/trunk/twisted/python/usage.py", line 226, in parseOptions
    for (cmd, short, parser, doc) in self.subCommands:
  File "/home/jkakar/src/projects/twisted/trunk/twisted/application/app.py", line 607, in subCommands
    for plug in plugins:
  File "/home/jkakar/src/projects/twisted/trunk/twisted/plugin.py", line 209, in getPlugins
    allDropins = getCache(package)
--- <exception caught here> ---
  File "/home/jkakar/src/projects/twisted/trunk/twisted/plugin.py", line 167, in getCache
    provider = pluginModule.load()
  File "/home/jkakar/src/projects/twisted/trunk/twisted/python/modules.py", line 383, in load
    return self.pathEntry.pythonPath.moduleLoader(self.name)
  File "/home/jkakar/src/projects/twisted/trunk/twisted/python/reflect.py", line 464, in namedAny
    topLevelPackage = _importAndCheckStack(trialname)
  File "/home/jkakar/src/projects/twisted/trunk/twisted/python/reflect.py", line 400, in _importAndCheckStack
    return __import__(importName)
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/twisted/plugins/tickery_service.py", line 25, in <module>
    from tickery.cache import TickeryCache
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/tickery/cache.py", line 23, in <module>
    from tickery.usercache import TwitterUserCache
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/tickery/usercache.py", line 18, in <module>
    from tickery import twitter
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/tickery/twitter.py", line 27, in <module>
    from tickery import oauth, consumer, signature, version, error as terror
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/tickery/consumer.py", line 36, in <module>
    consumer = TickeryConsumer().consumer
  File "/home/jkakar/src/fluidinfo/tickery/reviews/update-to-latest-txrdq-806699/tickery/consumer.py", line 28, in __init__
    TICKERY_CONSUMER_KEY_ENV_VAR)
exceptions.Exception: Please set 'TICKERY_CONSUMER_KEY' in your environment.

Anyway, the changes in the branch look good to me, +1!

review: Approve
Revision history for this message
Esteve Fernandez (esteve) wrote :

> > $ virtualenv env
> > $ . env/bin/activate
> > $ pip install --update -r requirements.txt
>
> Thanks, this worked. I had to remove '--update' from the command-line
> options. I guess this is a difference in the version of PIP on Ubuntu
> 11.04.

Virtualenv installs the latest version of PIP onto the new environment, overriding the system one. However, the correct syntax is --upgrade, not --update. pip install --upgrade (or .-U) -r requirements.txt should work.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'requirements-local.txt'
2--- requirements-local.txt 1970-01-01 00:00:00 +0000
3+++ requirements-local.txt 2011-07-11 00:54:27 +0000
4@@ -0,0 +1,2 @@
5+simplejson
6+ply
7
8=== modified file 'tickery/adder.py'
9--- tickery/adder.py 2011-06-16 16:10:07 +0000
10+++ tickery/adder.py 2011-07-11 00:54:27 +0000
11@@ -12,8 +12,6 @@
12 # implied. See the License for the specific language governing
13 # permissions and limitations under the License.
14
15-import time
16-
17 from operator import attrgetter
18
19 from twisted.internet import defer
20@@ -43,8 +41,6 @@
21
22 def reset(self):
23 self.state = 'queued'
24- self.queuedAt = time.time()
25- self.failureCount = 0
26
27 def setState(self, newState):
28 currentState = self.state
29@@ -58,21 +54,6 @@
30 log.msg('Logic error? %r is already in state %r.' %
31 (screenname, newState))
32 else:
33- if newState == 'queued':
34- self.queuedAt = time.time()
35- elif newState == 'underway':
36- now = time.time()
37- log.msg('User %r was queued for %.2f seconds.' %
38- (screenname, now - self.queuedAt))
39- self.underwayAt = now
40- elif newState == 'added':
41- log.msg('User %r was underway for %.2f seconds.' %
42- (screenname, time.time() - self.underwayAt))
43- elif newState == 'failed':
44- self.failureCount += 1
45- log.msg('%r failed. Failure count = %d' %
46- (screenname, self.failureCount))
47-
48 log.msg('Adder: %r state change: %r -> %r.' %
49 (screenname, currentState, newState))
50 self.state = newState
51@@ -119,7 +100,8 @@
52 log.msg('Restoring %r (previous state %r)' %
53 (user.screenname, user.state))
54 user.reset()
55- self.rdq.put(user)
56+ d = self.rdq.put(user)
57+ d.addErrback(self._reportCancelled, user.screenname)
58 self.clean = False
59 else:
60 log.msg('Not restoring formerly queued names.')
61@@ -147,7 +129,8 @@
62 self.users[screennameLower] = user
63 log.msg('Adding screenname %r to request queue.' % screenname)
64 self.clean = False
65- self.rdq.put(user)
66+ d = self.rdq.put(user)
67+ d.addErrback(self._reportCancelled, screenname)
68
69 def _addUser(self, user):
70 def _added(result):
71@@ -179,28 +162,18 @@
72 except KeyError:
73 raise Exception('Cannot cancel unknown user %r.' % screenname)
74 else:
75- if user.state == 'underway':
76- for item in self.rdq.underway():
77- if item.job.screenname == screenname:
78- log.msg('Cancelling underway %r addition.' %
79- screenname)
80- item.cancel()
81- user.setState('canceled')
82- break
83- else:
84- raise Exception('Could not find %r in underway list.' %
85- screenname)
86- elif user.state == 'queued':
87- queued = self.rdq.pending()
88- for i, u in enumerate(queued):
89+ if user.state == 'underway' or user.state == 'queued':
90+ for job in self.rdq.underway() + self.rdq.pending():
91+ u = job.jobarg
92 if u.screenname == screenname:
93- del queued[i]
94+ log.msg('Cancelling %s %r addition.' %
95+ (user.state, screenname))
96+ job.cancel()
97 user.setState('canceled')
98- log.msg('Canceled queued %r addition.' % screenname)
99 break
100 else:
101- raise Exception('Could not find %r in queued list.' %
102- screenname)
103+ raise Exception('Could not find %r in underway '
104+ 'or pending lists.' % screenname)
105 else:
106 user.setState('canceled')
107
108@@ -217,9 +190,9 @@
109
110 def statusSummary(self, screennames):
111 position = {}
112- for i, user in enumerate(self.rdq.pending()):
113+ for i, user in enumerate(
114+ [job.jobarg for job in self.rdq.pending()]):
115 position[user.screenname.lower()] = i
116- log.msg('position dict is %r' % (position,))
117 queued = []
118 underway = []
119 added = []
120@@ -273,3 +246,10 @@
121 log.msg('Pending user additions canceled: %r' %
122 [p.screenname for p in pending])
123 super(AdderCache, self).close()
124+
125+ def _reportCancelled(self, fail, screenname):
126+ """
127+ A user addition was cancelled. Log it and absorb the failure.
128+ """
129+ fail.trap(defer.CancelledError)
130+ log.msg('Addition of user %r cancelled.' % screenname)
131
132=== modified file 'tickery/cache.py'
133--- tickery/cache.py 2011-06-16 16:10:07 +0000
134+++ tickery/cache.py 2011-07-11 00:54:27 +0000
135@@ -18,7 +18,7 @@
136 from twisted.internet import defer
137 from twisted.application import service
138
139-from txrdq.rdq import DeferredPool
140+from txrdq.pool import DeferredPool
141
142 from tickery.usercache import TwitterUserCache
143 from tickery.querycache import QueryCache
144@@ -67,7 +67,7 @@
145 @defer.inlineCallbacks
146 def stopService(self):
147 yield self.adderCache.close()
148- yield self.extraTwitterTagsPool.deferUntilEmpty()
149+ yield self.extraTwitterTagsPool.notifyWhenEmpty()
150 self.userCache.close()
151 self.oidUidScreennameCache.close()
152 self.queryCache.close()
153
154=== modified file 'tickery/service.py'
155--- tickery/service.py 2011-06-21 23:56:18 +0000
156+++ tickery/service.py 2011-07-11 00:54:27 +0000
157@@ -66,11 +66,20 @@
158 'users': users}}
159
160 def jsonrpc_friendOf(self, screenname1, screenname2):
161- # Return True if screenname1 follows screenname2 (i.e., screenname2
162- # is a friend of screenname1).
163+ """
164+ Does screenname1 follow screenname2?
165+
166+ @param screenname1: A C{str} Twitter screen name.
167+
168+ @param screenname2: A C{str} Twitter screen name.
169+
170+ @return: a C{Deferred} that fires with C{True} if screenname1 follows
171+ screenname2 (i.e., screenname2 is a friend of screenname1) and with
172+ C{False} otherwise.
173+ """
174 log.msg('FriendOf %r and %r.' % (screenname1, screenname2))
175 d = ftwitter.friendOf(self.cache, self.endpoint,
176- screenname1, screenname2)
177+ unicode(screenname1), unicode(screenname2))
178 d.addCallback(lambda result: {'result': result})
179 d.addErrback(log.err)
180 return d
181@@ -331,22 +340,23 @@
182 return {'result': True}
183
184 def jsonrpc_getQueued(self):
185- pending = self.cache.adderCache.rdq.pending()
186- result = [[u.screenname, u.nFriends, time.ctime(u.queuedAt)]
187- for u in pending]
188+ pendingJobs = self.cache.adderCache.rdq.pending()
189+ result = [[pj.jobarg.screenname, pj.jobarg.nFriends,
190+ time.ctime(pj.queuedTime)] for pj in pendingJobs]
191 return {'result': result}
192
193 def jsonrpc_getUnderway(self):
194- underway = self.cache.adderCache.rdq.underway()
195+ underwayJobs = self.cache.adderCache.rdq.underway()
196 result = []
197- for u in underway:
198- pct = 100.0 * float(u.job.workDone) / float(u.job.workToDo)
199+ for job in underwayJobs:
200+ user = job.jobarg
201+ pct = 100.0 * float(user.workDone) / float(user.workToDo)
202 result.append([
203- u.job.screenname,
204- u.job.nFriends,
205+ user.screenname,
206+ user.nFriends,
207 pct,
208- time.ctime(u.job.queuedAt),
209- time.ctime(u.startTime)]
210+ time.ctime(job.queuedTime),
211+ time.ctime(job.startTime)]
212 )
213 return {'result': result}
214
215@@ -395,7 +405,7 @@
216 'result': True,
217 }
218
219- d = ftwitter.directAddUser(self.cache, screenname)
220+ d = ftwitter.directAddUser(self.cache, unicode(screenname))
221 d.addCallbacks(_ok, _err)
222 return d
223
224@@ -412,7 +422,8 @@
225 'result': True,
226 }
227
228- d = ftwitter.bulkAddUsers(self.cache, screennames.split())
229+ d = ftwitter.bulkAddUsers(
230+ self.cache, map(unicode, screennames.split()))
231 d.addCallback(_ret)
232 return d
233

Subscribers

People subscribed via source and target branches

to all changes: