Merge lp:~robru/gwibber/foursquare into lp:~barry/gwibber/py3
- foursquare
- Merge into py3
Proposed by
Robert Bruce Park
Status: | Merged |
---|---|
Merged at revision: | 1435 |
Proposed branch: | lp:~robru/gwibber/foursquare |
Merge into: | lp:~barry/gwibber/py3 |
Diff against target: |
442 lines (+241/-39) (has conflicts) 7 files modified
gwibber/gwibber/protocols/foursquare.py (+98/-0) gwibber/gwibber/tests/data/foursquare-full.dat (+1/-0) gwibber/gwibber/tests/test_foursquare.py (+108/-0) gwibber/gwibber/tests/test_model.py (+2/-2) gwibber/gwibber/tests/test_protocols.py (+23/-31) gwibber/gwibber/utils/base.py (+4/-4) gwibber/gwibber/utils/model.py (+5/-2) Text conflict in gwibber/gwibber/protocols/foursquare.py |
To merge this branch: | bzr merge lp:~robru/gwibber/foursquare |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Barry Warsaw | Pending | ||
Review via email: mp+125372@code.launchpad.net |
Commit message
Description of the change
BLAM.
To post a comment you must log in.
lp:~robru/gwibber/foursquare
updated
- 1435. By Robert Bruce Park
-
Add likes count and avatar URL to FourSquare.receive method.
Also committing foursquare-
full.dat, which is a real live json data
dump of a real live foursquare checkin, that we use for testing. It
was supposed to be part of the previous commit, but I forgot to add it. - 1436. By Robert Bruce Park
-
Modify Base._publish to calculate the service name on it's own.
This alleviates the need for every single protocol having to specify
'self.__class_ _.__name_ _.lower( )' every single time that it wants to
call Base._publish. Instead, Base._publish simply calls that ugliness
just once, in one place.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'gwibber/gwibber/protocols/foursquare.py' |
2 | --- gwibber/gwibber/protocols/foursquare.py 2012-09-19 22:21:39 +0000 |
3 | +++ gwibber/gwibber/protocols/foursquare.py 2012-09-20 03:15:40 +0000 |
4 | @@ -19,8 +19,106 @@ |
5 | ] |
6 | |
7 | |
8 | +import gettext |
9 | +import logging |
10 | +import datetime |
11 | + |
12 | +from gwibber.errors import AuthorizationError |
13 | +from gwibber.utils.authentication import Authentication |
14 | from gwibber.utils.base import Base |
15 | +from gwibber.utils.download import get_json |
16 | +from gwibber.utils.results import Results |
17 | + |
18 | + |
19 | +log = logging.getLogger('gwibber.service') |
20 | +_ = gettext.lgettext |
21 | + |
22 | +# The '&v=YYYYMMDD' defines the date that the API was last confirmed |
23 | +# to be functional, and is used by foursquare to indicate how old our |
24 | +# software is. In the event that they change their API, an old 'v' |
25 | +# date will tell them to give us the old, deprecated API behaviors, |
26 | +# giving us some time to be notified of API breakage and update |
27 | +# accordingly. If you're working on this code and you don't see any |
28 | +# bugs with foursquare then feel free to update the date here. |
29 | +API_BASE = 'https://api.foursquare.com/v2/' |
30 | +TOKEN ='?oauth_token={access_token}&v=20120917' |
31 | +SELF_URL = API_BASE + 'users/self' + TOKEN |
32 | +CHECKIN_URL = API_BASE + 'checkins/{checkin_id}' + TOKEN |
33 | +RECENT_URL = API_BASE + 'checkins/recent' + TOKEN |
34 | + |
35 | +HTML_PREFIX = 'https://foursquare.com/' |
36 | +USER_URL = HTML_PREFIX + 'user/{user_id}' |
37 | +VENUE_URL = HTML_PREFIX + 'venue/{venue_id}' |
38 | + |
39 | + |
40 | +def _full_name(user): |
41 | + names = (user.get('firstName'), user.get('lastName')) |
42 | + return ' '.join(name for name in names if name) |
43 | |
44 | |
45 | class FourSquare(Base): |
46 | +<<<<<<< TREE |
47 | pass |
48 | +======= |
49 | + def _locked_login(self, old_token): |
50 | + log.debug('{} to FourSquare'.format( |
51 | + 'Re-authenticating' if old_token else 'Logging in')) |
52 | + |
53 | + result = Authentication(self.account, log).login() |
54 | + if result is None: |
55 | + log.error('No FourSquare authentication results received.') |
56 | + return |
57 | + |
58 | + token = result.get('AccessToken') |
59 | + if token is not None: |
60 | + data = get_json(SELF_URL.format(access_token=token)) or {} |
61 | + user = data.get('response', {}).get('user', {}) |
62 | + names = (user.get('firstName'), user.get('lastName')) |
63 | + uid = user['id'] |
64 | + |
65 | + self.account.update(username=_full_name(user), |
66 | + access_token=token, |
67 | + user_id=uid) |
68 | + log.debug('FourSquare UID is: ' + uid) |
69 | + else: |
70 | + log.error('No AccessToken in FourSquare session: {!r}', result) |
71 | + |
72 | + def receive(self): |
73 | + """Gets a list of each friend's most recent check-ins.""" |
74 | + if 'access_token' not in self.account and not self._login(): |
75 | + log.error('FourSquare: {}'.format(_('Unable to authenticate.'))) |
76 | + |
77 | + token = self.account.get('access_token') |
78 | + if token is not None: |
79 | + result = get_json(RECENT_URL.format(access_token=token)) |
80 | + |
81 | + response_code = result.get('meta', {}).get('code') |
82 | + if response_code != 200: |
83 | + log.error('FourSquare: Error: {}'.format(result)) |
84 | + return |
85 | + |
86 | + checkins = result.get('response', {}).get('recent', []) |
87 | + for checkin in checkins: |
88 | + user = checkin.get('user', {}) |
89 | + avatar = user.get('photo', {}) |
90 | + avatar_url = '{prefix}100x100{suffix}'.format(**avatar) |
91 | + checkin_id = checkin.get('id') |
92 | + tz = checkin.get('timeZoneOffset', 0) |
93 | + epoch = checkin.get('createdAt') |
94 | + timestamp = datetime.datetime.fromtimestamp( |
95 | + epoch - (tz * 36)).isoformat() |
96 | + |
97 | + self._publish( |
98 | + account_id=self.account['id'], |
99 | + message_id=checkin_id, |
100 | + stream='messages', |
101 | + sender=_full_name(user), |
102 | + from_me=(user.get('relationship') == 'self'), |
103 | + timestamp=timestamp, |
104 | + message=checkin.get('shout', ''), |
105 | + likes=checkin.get('likes', {}).get('count', 0), |
106 | + icon_uri=avatar_url, |
107 | + url=CHECKIN_URL.format(access_token=token, |
108 | + checkin_id=checkin_id), |
109 | + ) |
110 | +>>>>>>> MERGE-SOURCE |
111 | |
112 | === added file 'gwibber/gwibber/tests/data/foursquare-full.dat' |
113 | --- gwibber/gwibber/tests/data/foursquare-full.dat 1970-01-01 00:00:00 +0000 |
114 | +++ gwibber/gwibber/tests/data/foursquare-full.dat 2012-09-20 03:15:40 +0000 |
115 | @@ -0,0 +1,1 @@ |
116 | +{"meta":{"code":200},"notifications":[{"type":"notificationTray","item":{"unreadCount":0}}],"response":{"recent":[{"id":"50574c9ce4b0a9a6e84433a0","createdAt":1347898524,"type":"checkin","shout":"Working on gwibber's foursquare plugin.","timeZoneOffset":-300,"user":{"id":"37199983","firstName":"Jimbob","lastName":"Smith","relationship":"self","photo":{"prefix":"https:\/\/irs0.4sqi.net\/img\/user\/","suffix":"\/5IEW3VIX55BBEXAO.jpg"}},"venue":{"id":"4e73f722fa76059700582a27","name":"Pop Soda's Coffee House & Gallery","contact":{"phone":"2044157666","formattedPhone":"(204) 415-7666","twitter":"PopSodasWpg"},"location":{"address":"625 Portage Ave.","crossStreet":"Furby St.","lat":49.88873164336725,"lng":-97.158043384552,"postalCode":"R3B 2G4","city":"Winnipeg","state":"MB","country":"Canada","cc":"CA"},"categories":[{"id":"4bf58dd8d48988d16d941735","name":"Café","pluralName":"Cafés","shortName":"Café","icon":{"prefix":"https:\/\/foursquare.com\/img\/categories_v2\/food\/cafe_","suffix":".png"},"primary":true}],"verified":false,"stats":{"checkinsCount":216,"usersCount":84,"tipCount":8},"url":"http:\/\/www.popsodascoffeehouse.com","likes":{"count":0,"groups":[]},"friendVisits":{"count":0,"summary":"You've been here","items":[{"visitedCount":1,"liked":false,"user":{"id":"37199983","firstName":"Jimbob","lastName":"Smith","relationship":"self","photo":{"prefix":"https:\/\/irs0.4sqi.net\/img\/user\/","suffix":"\/5IEW3VIX55BBEXAO.jpg"}}}]},"beenHere":{"count":1,"marked":true},"specials":{"count":0}},"source":{"name":"foursquare for Android","url":"https:\/\/foursquare.com\/download\/#\/android"},"photos":{"count":0,"items":[]}}]}} |
117 | |
118 | === added file 'gwibber/gwibber/tests/test_foursquare.py' |
119 | --- gwibber/gwibber/tests/test_foursquare.py 1970-01-01 00:00:00 +0000 |
120 | +++ gwibber/gwibber/tests/test_foursquare.py 2012-09-20 03:15:40 +0000 |
121 | @@ -0,0 +1,108 @@ |
122 | +# Copyright (C) 2012 Canonical Ltd |
123 | +# |
124 | +# This program is free software: you can redistribute it and/or modify |
125 | +# it under the terms of the GNU General Public License version 2 as |
126 | +# published by the Free Software Foundation. |
127 | +# |
128 | +# This program is distributed in the hope that it will be useful, |
129 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
130 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
131 | +# GNU General Public License for more details. |
132 | +# |
133 | +# You should have received a copy of the GNU General Public License |
134 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
135 | + |
136 | +"""Test the FourSquare plugin.""" |
137 | + |
138 | +__all__ = [ |
139 | + 'TestFourSquare', |
140 | + ] |
141 | + |
142 | + |
143 | +import unittest |
144 | + |
145 | +from gi.repository import Dee |
146 | + |
147 | +from gwibber.errors import AuthorizationError |
148 | +from gwibber.testing.helpers import FakeAccount, LogPreserver |
149 | +from gwibber.testing.mocks import FakeData |
150 | +from gwibber.protocols.foursquare import FourSquare |
151 | +from gwibber.utils.model import COLUMN_TYPES |
152 | + |
153 | + |
154 | +try: |
155 | + # Python 3.3 |
156 | + from unittest import mock |
157 | +except ImportError: |
158 | + import mock |
159 | + |
160 | + |
161 | +# Create a test model that will not interfere with the user's environment. |
162 | +# We'll use this object as a mock of the real model. |
163 | +TestModel = Dee.SharedModel.new('com.Gwibber.TestSharedModel') |
164 | +TestModel.set_schema_full(COLUMN_TYPES) |
165 | + |
166 | + |
167 | +# Disable i18n translations so we only need to test English responses. |
168 | +@mock.patch.dict('gwibber.protocols.foursquare.__dict__', {'_': lambda s: s}) |
169 | +class TestFourSquare(unittest.TestCase): |
170 | + """Test the FourSquare API.""" |
171 | + |
172 | + @classmethod |
173 | + def setUpClass(cls): |
174 | + cls._log_state = LogPreserver() |
175 | + |
176 | + @classmethod |
177 | + def tearDownClass(cls): |
178 | + cls._log_state.restore() |
179 | + |
180 | + def setUp(self): |
181 | + self.account = FakeAccount() |
182 | + self.protocol = FourSquare(self.account) |
183 | + |
184 | + def test_protocol_info(self): |
185 | + self.assertEqual(self.protocol.__class__.__name__, 'FourSquare') |
186 | + |
187 | + @mock.patch('gwibber.utils.authentication.Authentication.login', |
188 | + return_value=None) |
189 | + @mock.patch('gwibber.utils.download.get_json', |
190 | + return_value=None) |
191 | + def test_unsuccessful_authentication(self, *mocks): |
192 | + self.assertFalse(self.protocol._login()) |
193 | + self.assertNotIn('username', self.account) |
194 | + self.assertNotIn('user_id', self.account) |
195 | + |
196 | + @mock.patch('gwibber.utils.authentication.Authentication.login', |
197 | + return_value=dict(AccessToken='tokeny goodness')) |
198 | + @mock.patch('gwibber.protocols.foursquare.get_json', |
199 | + return_value=dict( |
200 | + response=dict( |
201 | + user=dict(firstName='Bob', |
202 | + lastName='Loblaw', |
203 | + id='1234567')))) |
204 | + def test_successful_authentication(self, *mocks): |
205 | + self.assertTrue(self.protocol._login()) |
206 | + self.assertEqual(self.account['username'], 'Bob Loblaw') |
207 | + self.assertEqual(self.account['user_id'], '1234567') |
208 | + |
209 | + @mock.patch('gwibber.utils.base.Model', TestModel) |
210 | + @mock.patch('gwibber.utils.download.urlopen', |
211 | + FakeData('gwibber.tests.data', 'foursquare-full.dat')) |
212 | + @mock.patch('gwibber.protocols.foursquare.FourSquare._login', |
213 | + return_value=True) |
214 | + def test_receive(self, *mocks): |
215 | + self.account['access_token'] = 'tokeny goodness' |
216 | + self.assertEqual(0, TestModel.get_n_rows()) |
217 | + self.protocol.receive() |
218 | + self.assertEqual(1, TestModel.get_n_rows()) |
219 | + expected = [ |
220 | + [['foursquare', 'faker/than fake', '50574c9ce4b0a9a6e84433a0']], |
221 | + 'messages', 'Jimbob Smith', '', True, '2012-09-17T14:15:24', |
222 | + "Working on gwibber's foursquare plugin.", '', |
223 | + 'https://irs0.4sqi.net/img/user/100x100/5IEW3VIX55BBEXAO.jpg', |
224 | + 'https://api.foursquare.com/v2/checkins/50574c9ce4b0a9a6e84433a0' + |
225 | + '?oauth_token=tokeny goodness&v=20120917', '', '', '', '', 0.0, |
226 | + False, '', '', '', '', '', '', '', '', '', '', '', '', '', '', |
227 | + '', '', '', '', '', '', ''] |
228 | + for i, col in enumerate(TestModel[0]): |
229 | + self.assertEqual(col, expected[i]) |
230 | |
231 | === modified file 'gwibber/gwibber/tests/test_model.py' |
232 | --- gwibber/gwibber/tests/test_model.py 2012-09-19 20:05:40 +0000 |
233 | +++ gwibber/gwibber/tests/test_model.py 2012-09-20 03:15:40 +0000 |
234 | @@ -34,10 +34,10 @@ |
235 | |
236 | def test_basic_properties(self): |
237 | self.assertIsInstance(Model, Dee.SharedModel) |
238 | - self.assertEqual(Model.get_n_columns(), 39) |
239 | + self.assertEqual(Model.get_n_columns(), 37) |
240 | self.assertEqual(Model.get_n_rows(), 0) |
241 | self.assertEqual(Model.get_schema(), |
242 | - ['aas', 's', 's', 's', 's', 'b', 's', 's', 's', 's', |
243 | + ['aas', 's', 's', 's', 'b', 's', 's', 's', |
244 | 's', 's', 's', 's', 's', 's', 'd', 'b', 's', 's', |
245 | 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', |
246 | 's', 's', 's', 's', 's', 's', 's', 's', 's']) |
247 | |
248 | === modified file 'gwibber/gwibber/tests/test_protocols.py' |
249 | --- gwibber/gwibber/tests/test_protocols.py 2012-09-19 22:21:39 +0000 |
250 | +++ gwibber/gwibber/tests/test_protocols.py 2012-09-20 03:15:40 +0000 |
251 | @@ -141,12 +141,9 @@ |
252 | self.assertEqual(Model.get_n_rows(), 0) |
253 | self.assertEqual(TestModel.get_n_rows(), 0) |
254 | base = Base(None) |
255 | - base._publish('a', 'b', 'c', message='a', |
256 | - from_me=True, likes=1, liked=True) |
257 | - base._publish('a', 'b', 'c', message='b', |
258 | - from_me=True, likes=1, liked=True) |
259 | - base._publish('a', 'b', 'c', message='c', |
260 | - from_me=True, likes=1, liked=True) |
261 | + base._publish('a', 'b', message='a') |
262 | + base._publish('a', 'b', message='b') |
263 | + base._publish('a', 'b', message='c') |
264 | self.assertEqual(Model.get_n_rows(), 0) |
265 | self.assertEqual(TestModel.get_n_rows(), 3) |
266 | |
267 | @@ -155,7 +152,7 @@ |
268 | base = Base(None) |
269 | self.assertEqual(0, TestModel.get_n_rows()) |
270 | with self.assertRaises(TypeError) as cm: |
271 | - base._publish('x', 'y', 'z', invalid_argument='not good') |
272 | + base._publish('x', 'y', invalid_argument='not good') |
273 | self.assertEqual(str(cm.exception), |
274 | 'Unexpected keyword arguments: invalid_argument') |
275 | |
276 | @@ -165,7 +162,7 @@ |
277 | base = Base(None) |
278 | self.assertEqual(0, TestModel.get_n_rows()) |
279 | with self.assertRaises(TypeError) as cm: |
280 | - base._publish('x', 'y', 'z', bad='no', wrong='yes') |
281 | + base._publish('x', 'y', bad='no', wrong='yes') |
282 | self.assertEqual(str(cm.exception), |
283 | 'Unexpected keyword arguments: bad, wrong') |
284 | |
285 | @@ -176,17 +173,16 @@ |
286 | base = Base(None) |
287 | self.assertEqual(0, TestModel.get_n_rows()) |
288 | self.assertTrue(base._publish( |
289 | - service='facebook', account_id='1/facebook', |
290 | - message_id='1234', stream='messages', sender='fred', |
291 | - sender_nick='freddy', from_me=True, timestamp='today', |
292 | - message='hello, @jimmy', likes=10, liked=True)) |
293 | + account_id='1/facebook', message_id='1234', stream='messages', |
294 | + sender='fred', sender_nick='freddy', from_me=True, |
295 | + timestamp='today', message='hello, @jimmy', likes=10, liked=True)) |
296 | self.assertEqual(1, TestModel.get_n_rows()) |
297 | row = TestModel.get_row(0) |
298 | # For convenience. |
299 | def V(column_name): |
300 | return row[COLUMN_INDICES[column_name]] |
301 | self.assertEqual(V('message_ids'), |
302 | - [['facebook', '1/facebook', '1234']]) |
303 | + [['base', '1/facebook', '1234']]) |
304 | self.assertEqual(V('stream'), 'messages') |
305 | self.assertEqual(V('sender'), 'fred') |
306 | self.assertEqual(V('sender_nick'), 'freddy') |
307 | @@ -215,18 +211,16 @@ |
308 | # Insert the first message into the table. The key will be the string |
309 | # 'fredhellojimmy' |
310 | self.assertTrue(base._publish( |
311 | - service='facebook', account_id='1/facebook', |
312 | - message_id='1234', stream='messages', sender='fred', |
313 | - sender_nick='freddy', from_me=True, timestamp='today', |
314 | - message='hello, @jimmy', likes=10, liked=True)) |
315 | + account_id='1/facebook', message_id='1234', stream='messages', |
316 | + sender='fred', sender_nick='freddy', from_me=True, |
317 | + timestamp='today', message='hello, @jimmy', likes=10, liked=True)) |
318 | # Insert the second message into the table. Note that because |
319 | # punctuation was stripped from the above message, this one will also |
320 | # have the key 'fredhellojimmy', thus it will be deemed a duplicate. |
321 | self.assertTrue(base._publish( |
322 | - service='twitter', account_id='2/twitter', |
323 | - message_id='5678', stream='messages', sender='fred', |
324 | - sender_nick='freddy', from_me=True, timestamp='today', |
325 | - message='hello jimmy', likes=10, liked=False)) |
326 | + account_id='2/twitter', message_id='5678', stream='messages', |
327 | + sender='fred', sender_nick='freddy', from_me=True, |
328 | + timestamp='today', message='hello jimmy', likes=10, liked=False)) |
329 | # See, we get only one row in the table. |
330 | self.assertEqual(1, TestModel.get_n_rows()) |
331 | # The first published message wins. |
332 | @@ -234,8 +228,8 @@ |
333 | self.assertEqual(row[COLUMN_INDICES['message']], 'hello, @jimmy') |
334 | # Both message ids will be present, in the order they were published. |
335 | self.assertEqual(row[COLUMN_INDICES['message_ids']], |
336 | - [['facebook', '1/facebook', '1234'], |
337 | - ['twitter', '2/twitter', '5678']]) |
338 | + [['base', '1/facebook', '1234'], |
339 | + ['base', '2/twitter', '5678']]) |
340 | |
341 | @mock.patch('gwibber.utils.base.Model', TestModel) |
342 | @mock.patch('gwibber.utils.base._seen_messages', {}) |
343 | @@ -247,17 +241,15 @@ |
344 | self.assertEqual(0, TestModel.get_n_rows()) |
345 | # The key for this row is 'fredhellojimmy' |
346 | self.assertTrue(base._publish( |
347 | - service='facebook', account_id='1/facebook', |
348 | - message_id='1234', stream='messages', sender='fred', |
349 | - sender_nick='freddy', from_me=True, timestamp='today', |
350 | - message='hello, @jimmy', likes=10, liked=True)) |
351 | + account_id='1/facebook', message_id='1234', stream='messages', |
352 | + sender='fred', sender_nick='freddy', from_me=True, |
353 | + timestamp='today', message='hello, @jimmy', likes=10, liked=True)) |
354 | self.assertEqual(1, TestModel.get_n_rows()) |
355 | # The key for this row is 'tedtholomewhellojimmy' |
356 | self.assertTrue(base._publish( |
357 | - service='facebook', account_id='1/facebook', |
358 | - message_id='34567', stream='messages', sender='tedtholomew', |
359 | - sender_nick='teddy', from_me=False, timestamp='today', |
360 | - message='hello, @jimmy', likes=10, liked=True)) |
361 | + account_id='1/facebook', message_id='34567', stream='messages', |
362 | + sender='tedtholomew', sender_nick='teddy', from_me=False, |
363 | + timestamp='today', message='hello, @jimmy', likes=10, liked=True)) |
364 | # See? Two rows in the table. |
365 | self.assertEqual(2, TestModel.get_n_rows()) |
366 | # The first row is the message from fred. |
367 | |
368 | === modified file 'gwibber/gwibber/utils/base.py' |
369 | --- gwibber/gwibber/utils/base.py 2012-09-19 22:21:39 +0000 |
370 | +++ gwibber/gwibber/utils/base.py 2012-09-20 03:15:40 +0000 |
371 | @@ -25,7 +25,7 @@ |
372 | |
373 | from threading import Lock, Thread |
374 | |
375 | -from gwibber.utils.model import COLUMN_INDICES, SCHEMA, Model |
376 | +from gwibber.utils.model import COLUMN_INDICES, SCHEMA, DEFAULTS, Model |
377 | |
378 | |
379 | IGNORED = string.punctuation + string.whitespace |
380 | @@ -98,7 +98,7 @@ |
381 | thread.daemon = True |
382 | thread.start() |
383 | |
384 | - def _publish(self, service, account_id, message_id, **kwargs): |
385 | + def _publish(self, account_id, message_id, **kwargs): |
386 | """Publish fresh data into the model, ignoring duplicates. |
387 | |
388 | :param service: The name of the service this message is published |
389 | @@ -125,7 +125,7 @@ |
390 | # The column value is a list of lists (see gwibber/utils/model.py for |
391 | # details), and because the arguments are themselves a list, this gets |
392 | # initialized as a triply-nested list. |
393 | - args = [[[service, account_id, message_id]]] |
394 | + args = [[[self.__class__.__name__.lower(), account_id, message_id]]] |
395 | # Now iterate through all the column names listed in the SCHEMA, |
396 | # except for the first, since we just composed its value in the |
397 | # preceding line. Pop matching column values from the kwargs, in the |
398 | @@ -135,7 +135,7 @@ |
399 | # |
400 | # Missing column values default to the empty string. |
401 | for column_name, column_type in SCHEMA[1:]: |
402 | - args.append(kwargs.pop(column_name, '')) |
403 | + args.append(kwargs.pop(column_name, DEFAULTS[column_type])) |
404 | if len(kwargs) > 0: |
405 | raise TypeError('Unexpected keyword arguments: {}'.format( |
406 | COMMA_SPACE.join(sorted(kwargs)))) |
407 | |
408 | === modified file 'gwibber/gwibber/utils/model.py' |
409 | --- gwibber/gwibber/utils/model.py 2012-09-19 20:05:40 +0000 |
410 | +++ gwibber/gwibber/utils/model.py 2012-09-20 03:15:40 +0000 |
411 | @@ -27,6 +27,7 @@ |
412 | 'COLUMN_NAMES', |
413 | 'COLUMN_TYPES', |
414 | 'COLUMN_INDICES', |
415 | + 'DEFAULTS', |
416 | ] |
417 | |
418 | |
419 | @@ -54,7 +55,6 @@ |
420 | SCHEMA = ( |
421 | ('message_ids', 'aas'), |
422 | ('stream', 's'), |
423 | - ('transient', 's'), |
424 | ('sender', 's'), |
425 | ('sender_nick', 's'), |
426 | ('from_me', 'b'), |
427 | @@ -64,7 +64,6 @@ |
428 | ('icon_uri', 's'), |
429 | ('url', 's'), |
430 | ('source', 's'), |
431 | - ('timestring', 's'), |
432 | ('reply_nick', 's'), |
433 | ('reply_name', 's'), |
434 | ('reply_url', 's'), |
435 | @@ -103,3 +102,7 @@ |
436 | |
437 | Model = Dee.SharedModel.new('com.Gwibber.Streams') |
438 | Model.set_schema_full(COLUMN_TYPES) |
439 | + |
440 | + |
441 | +# This defines default values for the different data types |
442 | +DEFAULTS = dict(s='', b=False, d=0) |