Merge lp:~robru/gwibber/foursquare into lp:~barry/gwibber/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
Reviewer Review Type Date Requested Status
Barry Warsaw Pending
Review via email: mp+125372@code.launchpad.net

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
=== modified file 'gwibber/gwibber/protocols/foursquare.py'
--- gwibber/gwibber/protocols/foursquare.py 2012-09-19 22:21:39 +0000
+++ gwibber/gwibber/protocols/foursquare.py 2012-09-20 03:15:40 +0000
@@ -19,8 +19,106 @@
19 ]19 ]
2020
2121
22import gettext
23import logging
24import datetime
25
26from gwibber.errors import AuthorizationError
27from gwibber.utils.authentication import Authentication
22from gwibber.utils.base import Base28from gwibber.utils.base import Base
29from gwibber.utils.download import get_json
30from gwibber.utils.results import Results
31
32
33log = logging.getLogger('gwibber.service')
34_ = gettext.lgettext
35
36# The '&v=YYYYMMDD' defines the date that the API was last confirmed
37# to be functional, and is used by foursquare to indicate how old our
38# software is. In the event that they change their API, an old 'v'
39# date will tell them to give us the old, deprecated API behaviors,
40# giving us some time to be notified of API breakage and update
41# accordingly. If you're working on this code and you don't see any
42# bugs with foursquare then feel free to update the date here.
43API_BASE = 'https://api.foursquare.com/v2/'
44TOKEN ='?oauth_token={access_token}&v=20120917'
45SELF_URL = API_BASE + 'users/self' + TOKEN
46CHECKIN_URL = API_BASE + 'checkins/{checkin_id}' + TOKEN
47RECENT_URL = API_BASE + 'checkins/recent' + TOKEN
48
49HTML_PREFIX = 'https://foursquare.com/'
50USER_URL = HTML_PREFIX + 'user/{user_id}'
51VENUE_URL = HTML_PREFIX + 'venue/{venue_id}'
52
53
54def _full_name(user):
55 names = (user.get('firstName'), user.get('lastName'))
56 return ' '.join(name for name in names if name)
2357
2458
25class FourSquare(Base):59class FourSquare(Base):
60<<<<<<< TREE
26 pass61 pass
62=======
63 def _locked_login(self, old_token):
64 log.debug('{} to FourSquare'.format(
65 'Re-authenticating' if old_token else 'Logging in'))
66
67 result = Authentication(self.account, log).login()
68 if result is None:
69 log.error('No FourSquare authentication results received.')
70 return
71
72 token = result.get('AccessToken')
73 if token is not None:
74 data = get_json(SELF_URL.format(access_token=token)) or {}
75 user = data.get('response', {}).get('user', {})
76 names = (user.get('firstName'), user.get('lastName'))
77 uid = user['id']
78
79 self.account.update(username=_full_name(user),
80 access_token=token,
81 user_id=uid)
82 log.debug('FourSquare UID is: ' + uid)
83 else:
84 log.error('No AccessToken in FourSquare session: {!r}', result)
85
86 def receive(self):
87 """Gets a list of each friend's most recent check-ins."""
88 if 'access_token' not in self.account and not self._login():
89 log.error('FourSquare: {}'.format(_('Unable to authenticate.')))
90
91 token = self.account.get('access_token')
92 if token is not None:
93 result = get_json(RECENT_URL.format(access_token=token))
94
95 response_code = result.get('meta', {}).get('code')
96 if response_code != 200:
97 log.error('FourSquare: Error: {}'.format(result))
98 return
99
100 checkins = result.get('response', {}).get('recent', [])
101 for checkin in checkins:
102 user = checkin.get('user', {})
103 avatar = user.get('photo', {})
104 avatar_url = '{prefix}100x100{suffix}'.format(**avatar)
105 checkin_id = checkin.get('id')
106 tz = checkin.get('timeZoneOffset', 0)
107 epoch = checkin.get('createdAt')
108 timestamp = datetime.datetime.fromtimestamp(
109 epoch - (tz * 36)).isoformat()
110
111 self._publish(
112 account_id=self.account['id'],
113 message_id=checkin_id,
114 stream='messages',
115 sender=_full_name(user),
116 from_me=(user.get('relationship') == 'self'),
117 timestamp=timestamp,
118 message=checkin.get('shout', ''),
119 likes=checkin.get('likes', {}).get('count', 0),
120 icon_uri=avatar_url,
121 url=CHECKIN_URL.format(access_token=token,
122 checkin_id=checkin_id),
123 )
124>>>>>>> MERGE-SOURCE
27125
=== added file 'gwibber/gwibber/tests/data/foursquare-full.dat'
--- gwibber/gwibber/tests/data/foursquare-full.dat 1970-01-01 00:00:00 +0000
+++ gwibber/gwibber/tests/data/foursquare-full.dat 2012-09-20 03:15:40 +0000
@@ -0,0 +1,1 @@
1{"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":[]}}]}}
02
=== added file 'gwibber/gwibber/tests/test_foursquare.py'
--- gwibber/gwibber/tests/test_foursquare.py 1970-01-01 00:00:00 +0000
+++ gwibber/gwibber/tests/test_foursquare.py 2012-09-20 03:15:40 +0000
@@ -0,0 +1,108 @@
1# Copyright (C) 2012 Canonical Ltd
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License version 2 as
5# published by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15"""Test the FourSquare plugin."""
16
17__all__ = [
18 'TestFourSquare',
19 ]
20
21
22import unittest
23
24from gi.repository import Dee
25
26from gwibber.errors import AuthorizationError
27from gwibber.testing.helpers import FakeAccount, LogPreserver
28from gwibber.testing.mocks import FakeData
29from gwibber.protocols.foursquare import FourSquare
30from gwibber.utils.model import COLUMN_TYPES
31
32
33try:
34 # Python 3.3
35 from unittest import mock
36except ImportError:
37 import mock
38
39
40# Create a test model that will not interfere with the user's environment.
41# We'll use this object as a mock of the real model.
42TestModel = Dee.SharedModel.new('com.Gwibber.TestSharedModel')
43TestModel.set_schema_full(COLUMN_TYPES)
44
45
46# Disable i18n translations so we only need to test English responses.
47@mock.patch.dict('gwibber.protocols.foursquare.__dict__', {'_': lambda s: s})
48class TestFourSquare(unittest.TestCase):
49 """Test the FourSquare API."""
50
51 @classmethod
52 def setUpClass(cls):
53 cls._log_state = LogPreserver()
54
55 @classmethod
56 def tearDownClass(cls):
57 cls._log_state.restore()
58
59 def setUp(self):
60 self.account = FakeAccount()
61 self.protocol = FourSquare(self.account)
62
63 def test_protocol_info(self):
64 self.assertEqual(self.protocol.__class__.__name__, 'FourSquare')
65
66 @mock.patch('gwibber.utils.authentication.Authentication.login',
67 return_value=None)
68 @mock.patch('gwibber.utils.download.get_json',
69 return_value=None)
70 def test_unsuccessful_authentication(self, *mocks):
71 self.assertFalse(self.protocol._login())
72 self.assertNotIn('username', self.account)
73 self.assertNotIn('user_id', self.account)
74
75 @mock.patch('gwibber.utils.authentication.Authentication.login',
76 return_value=dict(AccessToken='tokeny goodness'))
77 @mock.patch('gwibber.protocols.foursquare.get_json',
78 return_value=dict(
79 response=dict(
80 user=dict(firstName='Bob',
81 lastName='Loblaw',
82 id='1234567'))))
83 def test_successful_authentication(self, *mocks):
84 self.assertTrue(self.protocol._login())
85 self.assertEqual(self.account['username'], 'Bob Loblaw')
86 self.assertEqual(self.account['user_id'], '1234567')
87
88 @mock.patch('gwibber.utils.base.Model', TestModel)
89 @mock.patch('gwibber.utils.download.urlopen',
90 FakeData('gwibber.tests.data', 'foursquare-full.dat'))
91 @mock.patch('gwibber.protocols.foursquare.FourSquare._login',
92 return_value=True)
93 def test_receive(self, *mocks):
94 self.account['access_token'] = 'tokeny goodness'
95 self.assertEqual(0, TestModel.get_n_rows())
96 self.protocol.receive()
97 self.assertEqual(1, TestModel.get_n_rows())
98 expected = [
99 [['foursquare', 'faker/than fake', '50574c9ce4b0a9a6e84433a0']],
100 'messages', 'Jimbob Smith', '', True, '2012-09-17T14:15:24',
101 "Working on gwibber's foursquare plugin.", '',
102 'https://irs0.4sqi.net/img/user/100x100/5IEW3VIX55BBEXAO.jpg',
103 'https://api.foursquare.com/v2/checkins/50574c9ce4b0a9a6e84433a0' +
104 '?oauth_token=tokeny goodness&v=20120917', '', '', '', '', 0.0,
105 False, '', '', '', '', '', '', '', '', '', '', '', '', '', '',
106 '', '', '', '', '', '', '']
107 for i, col in enumerate(TestModel[0]):
108 self.assertEqual(col, expected[i])
0109
=== modified file 'gwibber/gwibber/tests/test_model.py'
--- gwibber/gwibber/tests/test_model.py 2012-09-19 20:05:40 +0000
+++ gwibber/gwibber/tests/test_model.py 2012-09-20 03:15:40 +0000
@@ -34,10 +34,10 @@
3434
35 def test_basic_properties(self):35 def test_basic_properties(self):
36 self.assertIsInstance(Model, Dee.SharedModel)36 self.assertIsInstance(Model, Dee.SharedModel)
37 self.assertEqual(Model.get_n_columns(), 39)37 self.assertEqual(Model.get_n_columns(), 37)
38 self.assertEqual(Model.get_n_rows(), 0)38 self.assertEqual(Model.get_n_rows(), 0)
39 self.assertEqual(Model.get_schema(),39 self.assertEqual(Model.get_schema(),
40 ['aas', 's', 's', 's', 's', 'b', 's', 's', 's', 's',40 ['aas', 's', 's', 's', 'b', 's', 's', 's',
41 's', 's', 's', 's', 's', 's', 'd', 'b', 's', 's',41 's', 's', 's', 's', 's', 's', 'd', 'b', 's', 's',
42 's', 's', 's', 's', 's', 's', 's', 's', 's', 's',42 's', 's', 's', 's', 's', 's', 's', 's', 's', 's',
43 's', 's', 's', 's', 's', 's', 's', 's', 's'])43 's', 's', 's', 's', 's', 's', 's', 's', 's'])
4444
=== modified file 'gwibber/gwibber/tests/test_protocols.py'
--- gwibber/gwibber/tests/test_protocols.py 2012-09-19 22:21:39 +0000
+++ gwibber/gwibber/tests/test_protocols.py 2012-09-20 03:15:40 +0000
@@ -141,12 +141,9 @@
141 self.assertEqual(Model.get_n_rows(), 0)141 self.assertEqual(Model.get_n_rows(), 0)
142 self.assertEqual(TestModel.get_n_rows(), 0)142 self.assertEqual(TestModel.get_n_rows(), 0)
143 base = Base(None)143 base = Base(None)
144 base._publish('a', 'b', 'c', message='a',144 base._publish('a', 'b', message='a')
145 from_me=True, likes=1, liked=True)145 base._publish('a', 'b', message='b')
146 base._publish('a', 'b', 'c', message='b',146 base._publish('a', 'b', message='c')
147 from_me=True, likes=1, liked=True)
148 base._publish('a', 'b', 'c', message='c',
149 from_me=True, likes=1, liked=True)
150 self.assertEqual(Model.get_n_rows(), 0)147 self.assertEqual(Model.get_n_rows(), 0)
151 self.assertEqual(TestModel.get_n_rows(), 3)148 self.assertEqual(TestModel.get_n_rows(), 3)
152149
@@ -155,7 +152,7 @@
155 base = Base(None)152 base = Base(None)
156 self.assertEqual(0, TestModel.get_n_rows())153 self.assertEqual(0, TestModel.get_n_rows())
157 with self.assertRaises(TypeError) as cm:154 with self.assertRaises(TypeError) as cm:
158 base._publish('x', 'y', 'z', invalid_argument='not good')155 base._publish('x', 'y', invalid_argument='not good')
159 self.assertEqual(str(cm.exception),156 self.assertEqual(str(cm.exception),
160 'Unexpected keyword arguments: invalid_argument')157 'Unexpected keyword arguments: invalid_argument')
161158
@@ -165,7 +162,7 @@
165 base = Base(None)162 base = Base(None)
166 self.assertEqual(0, TestModel.get_n_rows())163 self.assertEqual(0, TestModel.get_n_rows())
167 with self.assertRaises(TypeError) as cm:164 with self.assertRaises(TypeError) as cm:
168 base._publish('x', 'y', 'z', bad='no', wrong='yes')165 base._publish('x', 'y', bad='no', wrong='yes')
169 self.assertEqual(str(cm.exception),166 self.assertEqual(str(cm.exception),
170 'Unexpected keyword arguments: bad, wrong')167 'Unexpected keyword arguments: bad, wrong')
171168
@@ -176,17 +173,16 @@
176 base = Base(None)173 base = Base(None)
177 self.assertEqual(0, TestModel.get_n_rows())174 self.assertEqual(0, TestModel.get_n_rows())
178 self.assertTrue(base._publish(175 self.assertTrue(base._publish(
179 service='facebook', account_id='1/facebook',176 account_id='1/facebook', message_id='1234', stream='messages',
180 message_id='1234', stream='messages', sender='fred',177 sender='fred', sender_nick='freddy', from_me=True,
181 sender_nick='freddy', from_me=True, timestamp='today',178 timestamp='today', message='hello, @jimmy', likes=10, liked=True))
182 message='hello, @jimmy', likes=10, liked=True))
183 self.assertEqual(1, TestModel.get_n_rows())179 self.assertEqual(1, TestModel.get_n_rows())
184 row = TestModel.get_row(0)180 row = TestModel.get_row(0)
185 # For convenience.181 # For convenience.
186 def V(column_name):182 def V(column_name):
187 return row[COLUMN_INDICES[column_name]]183 return row[COLUMN_INDICES[column_name]]
188 self.assertEqual(V('message_ids'),184 self.assertEqual(V('message_ids'),
189 [['facebook', '1/facebook', '1234']])185 [['base', '1/facebook', '1234']])
190 self.assertEqual(V('stream'), 'messages')186 self.assertEqual(V('stream'), 'messages')
191 self.assertEqual(V('sender'), 'fred')187 self.assertEqual(V('sender'), 'fred')
192 self.assertEqual(V('sender_nick'), 'freddy')188 self.assertEqual(V('sender_nick'), 'freddy')
@@ -215,18 +211,16 @@
215 # Insert the first message into the table. The key will be the string211 # Insert the first message into the table. The key will be the string
216 # 'fredhellojimmy'212 # 'fredhellojimmy'
217 self.assertTrue(base._publish(213 self.assertTrue(base._publish(
218 service='facebook', account_id='1/facebook',214 account_id='1/facebook', message_id='1234', stream='messages',
219 message_id='1234', stream='messages', sender='fred',215 sender='fred', sender_nick='freddy', from_me=True,
220 sender_nick='freddy', from_me=True, timestamp='today',216 timestamp='today', message='hello, @jimmy', likes=10, liked=True))
221 message='hello, @jimmy', likes=10, liked=True))
222 # Insert the second message into the table. Note that because217 # Insert the second message into the table. Note that because
223 # punctuation was stripped from the above message, this one will also218 # punctuation was stripped from the above message, this one will also
224 # have the key 'fredhellojimmy', thus it will be deemed a duplicate.219 # have the key 'fredhellojimmy', thus it will be deemed a duplicate.
225 self.assertTrue(base._publish(220 self.assertTrue(base._publish(
226 service='twitter', account_id='2/twitter',221 account_id='2/twitter', message_id='5678', stream='messages',
227 message_id='5678', stream='messages', sender='fred',222 sender='fred', sender_nick='freddy', from_me=True,
228 sender_nick='freddy', from_me=True, timestamp='today',223 timestamp='today', message='hello jimmy', likes=10, liked=False))
229 message='hello jimmy', likes=10, liked=False))
230 # See, we get only one row in the table.224 # See, we get only one row in the table.
231 self.assertEqual(1, TestModel.get_n_rows())225 self.assertEqual(1, TestModel.get_n_rows())
232 # The first published message wins.226 # The first published message wins.
@@ -234,8 +228,8 @@
234 self.assertEqual(row[COLUMN_INDICES['message']], 'hello, @jimmy')228 self.assertEqual(row[COLUMN_INDICES['message']], 'hello, @jimmy')
235 # Both message ids will be present, in the order they were published.229 # Both message ids will be present, in the order they were published.
236 self.assertEqual(row[COLUMN_INDICES['message_ids']],230 self.assertEqual(row[COLUMN_INDICES['message_ids']],
237 [['facebook', '1/facebook', '1234'],231 [['base', '1/facebook', '1234'],
238 ['twitter', '2/twitter', '5678']])232 ['base', '2/twitter', '5678']])
239233
240 @mock.patch('gwibber.utils.base.Model', TestModel)234 @mock.patch('gwibber.utils.base.Model', TestModel)
241 @mock.patch('gwibber.utils.base._seen_messages', {})235 @mock.patch('gwibber.utils.base._seen_messages', {})
@@ -247,17 +241,15 @@
247 self.assertEqual(0, TestModel.get_n_rows())241 self.assertEqual(0, TestModel.get_n_rows())
248 # The key for this row is 'fredhellojimmy'242 # The key for this row is 'fredhellojimmy'
249 self.assertTrue(base._publish(243 self.assertTrue(base._publish(
250 service='facebook', account_id='1/facebook',244 account_id='1/facebook', message_id='1234', stream='messages',
251 message_id='1234', stream='messages', sender='fred',245 sender='fred', sender_nick='freddy', from_me=True,
252 sender_nick='freddy', from_me=True, timestamp='today',246 timestamp='today', message='hello, @jimmy', likes=10, liked=True))
253 message='hello, @jimmy', likes=10, liked=True))
254 self.assertEqual(1, TestModel.get_n_rows())247 self.assertEqual(1, TestModel.get_n_rows())
255 # The key for this row is 'tedtholomewhellojimmy'248 # The key for this row is 'tedtholomewhellojimmy'
256 self.assertTrue(base._publish(249 self.assertTrue(base._publish(
257 service='facebook', account_id='1/facebook',250 account_id='1/facebook', message_id='34567', stream='messages',
258 message_id='34567', stream='messages', sender='tedtholomew',251 sender='tedtholomew', sender_nick='teddy', from_me=False,
259 sender_nick='teddy', from_me=False, timestamp='today',252 timestamp='today', message='hello, @jimmy', likes=10, liked=True))
260 message='hello, @jimmy', likes=10, liked=True))
261 # See? Two rows in the table.253 # See? Two rows in the table.
262 self.assertEqual(2, TestModel.get_n_rows())254 self.assertEqual(2, TestModel.get_n_rows())
263 # The first row is the message from fred.255 # The first row is the message from fred.
264256
=== modified file 'gwibber/gwibber/utils/base.py'
--- gwibber/gwibber/utils/base.py 2012-09-19 22:21:39 +0000
+++ gwibber/gwibber/utils/base.py 2012-09-20 03:15:40 +0000
@@ -25,7 +25,7 @@
2525
26from threading import Lock, Thread26from threading import Lock, Thread
2727
28from gwibber.utils.model import COLUMN_INDICES, SCHEMA, Model28from gwibber.utils.model import COLUMN_INDICES, SCHEMA, DEFAULTS, Model
2929
3030
31IGNORED = string.punctuation + string.whitespace31IGNORED = string.punctuation + string.whitespace
@@ -98,7 +98,7 @@
98 thread.daemon = True98 thread.daemon = True
99 thread.start()99 thread.start()
100100
101 def _publish(self, service, account_id, message_id, **kwargs):101 def _publish(self, account_id, message_id, **kwargs):
102 """Publish fresh data into the model, ignoring duplicates.102 """Publish fresh data into the model, ignoring duplicates.
103103
104 :param service: The name of the service this message is published104 :param service: The name of the service this message is published
@@ -125,7 +125,7 @@
125 # The column value is a list of lists (see gwibber/utils/model.py for125 # The column value is a list of lists (see gwibber/utils/model.py for
126 # details), and because the arguments are themselves a list, this gets126 # details), and because the arguments are themselves a list, this gets
127 # initialized as a triply-nested list.127 # initialized as a triply-nested list.
128 args = [[[service, account_id, message_id]]]128 args = [[[self.__class__.__name__.lower(), account_id, message_id]]]
129 # Now iterate through all the column names listed in the SCHEMA,129 # Now iterate through all the column names listed in the SCHEMA,
130 # except for the first, since we just composed its value in the130 # except for the first, since we just composed its value in the
131 # preceding line. Pop matching column values from the kwargs, in the131 # preceding line. Pop matching column values from the kwargs, in the
@@ -135,7 +135,7 @@
135 #135 #
136 # Missing column values default to the empty string.136 # Missing column values default to the empty string.
137 for column_name, column_type in SCHEMA[1:]:137 for column_name, column_type in SCHEMA[1:]:
138 args.append(kwargs.pop(column_name, ''))138 args.append(kwargs.pop(column_name, DEFAULTS[column_type]))
139 if len(kwargs) > 0:139 if len(kwargs) > 0:
140 raise TypeError('Unexpected keyword arguments: {}'.format(140 raise TypeError('Unexpected keyword arguments: {}'.format(
141 COMMA_SPACE.join(sorted(kwargs))))141 COMMA_SPACE.join(sorted(kwargs))))
142142
=== modified file 'gwibber/gwibber/utils/model.py'
--- gwibber/gwibber/utils/model.py 2012-09-19 20:05:40 +0000
+++ gwibber/gwibber/utils/model.py 2012-09-20 03:15:40 +0000
@@ -27,6 +27,7 @@
27 'COLUMN_NAMES',27 'COLUMN_NAMES',
28 'COLUMN_TYPES',28 'COLUMN_TYPES',
29 'COLUMN_INDICES',29 'COLUMN_INDICES',
30 'DEFAULTS',
30 ]31 ]
3132
3233
@@ -54,7 +55,6 @@
54SCHEMA = (55SCHEMA = (
55 ('message_ids', 'aas'),56 ('message_ids', 'aas'),
56 ('stream', 's'),57 ('stream', 's'),
57 ('transient', 's'),
58 ('sender', 's'),58 ('sender', 's'),
59 ('sender_nick', 's'),59 ('sender_nick', 's'),
60 ('from_me', 'b'),60 ('from_me', 'b'),
@@ -64,7 +64,6 @@
64 ('icon_uri', 's'),64 ('icon_uri', 's'),
65 ('url', 's'),65 ('url', 's'),
66 ('source', 's'),66 ('source', 's'),
67 ('timestring', 's'),
68 ('reply_nick', 's'),67 ('reply_nick', 's'),
69 ('reply_name', 's'),68 ('reply_name', 's'),
70 ('reply_url', 's'),69 ('reply_url', 's'),
@@ -103,3 +102,7 @@
103102
104Model = Dee.SharedModel.new('com.Gwibber.Streams')103Model = Dee.SharedModel.new('com.Gwibber.Streams')
105Model.set_schema_full(COLUMN_TYPES)104Model.set_schema_full(COLUMN_TYPES)
105
106
107# This defines default values for the different data types
108DEFAULTS = dict(s='', b=False, d=0)

Subscribers

People subscribed via source and target branches