2 # Copyright 2009-2010 Joshua Roesslein
3 # See LICENSE for details.
5 from tweepy.error import TweepError
6 from tweepy.utils import parse_datetime, parse_html_value, parse_a_href
10 """A list like object that holds results from a Twitter API query."""
11 def __init__(self, max_id=None, since_id=None):
12 super(ResultSet, self).__init__()
14 self._since_id = since_id
21 return max(ids) if ids else None
28 return min(ids) if ids else None
31 return [item.id for item in self if hasattr(item, 'id')]
35 def __init__(self, api=None):
38 def __getstate__(self):
40 pickle = dict(self.__dict__)
42 del pickle['_api'] # do not pickle the API reference
48 def parse(cls, api, json):
49 """Parse a JSON object into a model instance."""
50 raise NotImplementedError
53 def parse_list(cls, api, json_list):
54 """Parse a list of JSON objects into a result set of model instances."""
58 results.append(cls.parse(api, obj))
62 state = ['%s=%s' % (k, repr(v)) for (k,v) in vars(self).items()]
63 return '%s(%s)' % (self.__class__.__name__, ', '.join(state))
69 def parse(cls, api, json):
71 for k, v in json.items():
73 user_model = getattr(api.parser.model_factory, 'user') if api else User
74 user = user_model.parse(api, v)
75 setattr(status, 'author', user)
76 setattr(status, 'user', user) # DEPRECIATED
77 elif k == 'created_at':
78 setattr(status, k, parse_datetime(v))
81 setattr(status, k, parse_html_value(v))
82 setattr(status, 'source_url', parse_a_href(v))
85 setattr(status, 'source_url', None)
86 elif k == 'retweeted_status':
87 setattr(status, k, Status.parse(api, v))
90 setattr(status, k, Place.parse(api, v))
92 setattr(status, k, None)
98 return self._api.destroy_status(self.id)
101 return self._api.retweet(self.id)
104 return self._api.retweets(self.id)
107 return self._api.create_favorite(self.id)
113 def parse(cls, api, json):
115 for k, v in json.items():
116 if k == 'created_at':
117 setattr(user, k, parse_datetime(v))
119 setattr(user, k, Status.parse(api, v))
120 elif k == 'following':
121 # twitter sets this to null if it is false
123 setattr(user, k, True)
125 setattr(user, k, False)
131 def parse_list(cls, api, json_list):
132 if isinstance(json_list, list):
133 item_list = json_list
135 item_list = json_list['users']
137 results = ResultSet()
138 for obj in item_list:
139 results.append(cls.parse(api, obj))
142 def timeline(self, **kargs):
143 return self._api.user_timeline(user_id=self.id, **kargs)
145 def friends(self, **kargs):
146 return self._api.friends(user_id=self.id, **kargs)
148 def followers(self, **kargs):
149 return self._api.followers(user_id=self.id, **kargs)
152 self._api.create_friendship(user_id=self.id)
153 self.following = True
156 self._api.destroy_friendship(user_id=self.id)
157 self.following = False
159 def lists_memberships(self, *args, **kargs):
160 return self._api.lists_memberships(user=self.screen_name, *args, **kargs)
162 def lists_subscriptions(self, *args, **kargs):
163 return self._api.lists_subscriptions(user=self.screen_name, *args, **kargs)
165 def lists(self, *args, **kargs):
166 return self._api.lists_all(user=self.screen_name, *args, **kargs)
168 def followers_ids(self, *args, **kargs):
169 return self._api.followers_ids(user_id=self.id, *args, **kargs)
172 class DirectMessage(Model):
175 def parse(cls, api, json):
177 for k, v in json.items():
178 if k == 'sender' or k == 'recipient':
179 setattr(dm, k, User.parse(api, v))
180 elif k == 'created_at':
181 setattr(dm, k, parse_datetime(v))
187 return self._api.destroy_direct_message(self.id)
190 class Friendship(Model):
193 def parse(cls, api, json):
194 relationship = json['relationship']
198 for k, v in relationship['source'].items():
199 setattr(source, k, v)
203 for k, v in relationship['target'].items():
204 setattr(target, k, v)
206 return source, target
209 class Category(Model):
212 def parse(cls, api, json):
214 for k, v in json.items():
215 setattr(category, k, v)
219 class SavedSearch(Model):
222 def parse(cls, api, json):
224 for k, v in json.items():
225 if k == 'created_at':
226 setattr(ss, k, parse_datetime(v))
232 return self._api.destroy_saved_search(self.id)
235 class SearchResults(ResultSet):
238 def parse(cls, api, json):
239 metadata = json['search_metadata']
240 results = SearchResults(metadata.get('max_id'), metadata.get('since_id'))
241 results.refresh_url = metadata.get('refresh_url')
242 results.completed_in = metadata.get('completed_in')
243 results.query = metadata.get('query')
244 results.count = metadata.get('count')
245 results.next_results = metadata.get('next_results')
247 for status in json['statuses']:
248 results.append(Status.parse(api, status))
255 def parse(cls, api, json):
257 for k,v in json.items():
259 setattr(lst, k, User.parse(api, v))
260 elif k == 'created_at':
261 setattr(lst, k, parse_datetime(v))
267 def parse_list(cls, api, json_list, result_set=None):
268 results = ResultSet()
269 if isinstance(json_list, dict):
270 json_list = json_list['lists']
271 for obj in json_list:
272 results.append(cls.parse(api, obj))
275 def update(self, **kargs):
276 return self._api.update_list(self.slug, **kargs)
279 return self._api.destroy_list(self.slug)
281 def timeline(self, **kargs):
282 return self._api.list_timeline(self.user.screen_name, self.slug, **kargs)
284 def add_member(self, id):
285 return self._api.add_list_member(self.slug, id)
287 def remove_member(self, id):
288 return self._api.remove_list_member(self.slug, id)
290 def members(self, **kargs):
291 return self._api.list_members(self.user.screen_name, self.slug, **kargs)
293 def is_member(self, id):
294 return self._api.is_list_member(self.user.screen_name, self.slug, id)
297 return self._api.subscribe_list(self.user.screen_name, self.slug)
299 def unsubscribe(self):
300 return self._api.unsubscribe_list(self.user.screen_name, self.slug)
302 def subscribers(self, **kargs):
303 return self._api.list_subscribers(self.user.screen_name, self.slug, **kargs)
305 def is_subscribed(self, id):
306 return self._api.is_subscribed_list(self.user.screen_name, self.slug, id)
308 class Relation(Model):
310 def parse(cls, api, json):
312 for k,v in json.items():
313 if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
314 setattr(result, k, Status.parse(api, v))
316 setattr(result, k, Relation.parse_list(api, v))
318 setattr(result, k, v)
321 class Relationship(Model):
323 def parse(cls, api, json):
325 for k,v in json.items():
326 if k == 'connections':
327 setattr(result, 'is_following', 'following' in v)
328 setattr(result, 'is_followed_by', 'followed_by' in v)
330 setattr(result, k, v)
333 class JSONModel(Model):
336 def parse(cls, api, json):
340 class IDModel(Model):
343 def parse(cls, api, json):
344 if isinstance(json, list):
350 class BoundingBox(Model):
353 def parse(cls, api, json):
356 for k, v in json.items():
357 setattr(result, k, v)
362 Return longitude, latitude of southwest (bottom, left) corner of
363 bounding box, as a tuple.
365 This assumes that bounding box is always a rectangle, which
366 appears to be the case at present.
368 return tuple(self.coordinates[0][0])
372 Return longitude, latitude of northeast (top, right) corner of
373 bounding box, as a tuple.
375 This assumes that bounding box is always a rectangle, which
376 appears to be the case at present.
378 return tuple(self.coordinates[0][2])
384 def parse(cls, api, json):
386 for k, v in json.items():
387 if k == 'bounding_box':
388 # bounding_box value may be null (None.)
389 # Example: "United States" (id=96683cc9126741d1)
391 t = BoundingBox.parse(api, v)
395 elif k == 'contained_within':
396 # contained_within is a list of Places.
397 setattr(place, k, Place.parse_list(api, v))
403 def parse_list(cls, api, json_list):
404 if isinstance(json_list, list):
405 item_list = json_list
407 item_list = json_list['result']['places']
409 results = ResultSet()
410 for obj in item_list:
411 results.append(cls.parse(api, obj))
414 class ModelFactory(object):
416 Used by parsers for creating instances
417 of models. You may subclass this factory
418 to add your own extended models.
423 direct_message = DirectMessage
424 friendship = Friendship
425 saved_search = SavedSearch
426 search_results = SearchResults
430 relationship = Relationship
435 bounding_box = BoundingBox