2 # Copyright 2009-2010 Joshua Roesslein
3 # See LICENSE for details.
5 from __future__ import absolute_import, print_function
7 from tweepy.utils import parse_datetime, parse_html_value, parse_a_href
10 class ResultSet(list):
11 """A list like object that holds results from a Twitter API query."""
12 def __init__(self, max_id=None, since_id=None):
13 super(ResultSet, self).__init__()
15 self._since_id = since_id
22 # Max_id is always set to the *smallest* id, minus one, in the set
23 return (min(ids) - 1) if ids else None
30 # Since_id is always set to the *greatest* id in the set
31 return max(ids) if ids else None
34 return [item.id for item in self if hasattr(item, 'id')]
39 def __init__(self, api=None):
42 def __getstate__(self):
44 pickle = dict(self.__dict__)
46 del pickle['_api'] # do not pickle the API reference
52 def parse(cls, api, json):
53 """Parse a JSON object into a model instance."""
54 raise NotImplementedError
57 def parse_list(cls, api, json_list):
59 Parse a list of JSON objects into
60 a result set of model instances.
65 results.append(cls.parse(api, obj))
69 state = ['%s=%s' % (k, repr(v)) for (k, v) in vars(self).items()]
70 return '%s(%s)' % (self.__class__.__name__, ', '.join(state))
76 def parse(cls, api, json):
79 # I'm not proud. Blame billg.
80 json['text'] = str(json['text'].encode('ascii', 'ignore'))[2:-1]
82 json['user']['screen_name'] = str(json['user']['screen_name'].encode('ascii', 'ignore'))[2:-1]
84 setattr(status, '_json', json)
85 for k, v in json.items():
87 user_model = getattr(api.parser.model_factory, 'user') if api else User
88 user = user_model.parse(api, v)
89 setattr(status, 'author', user)
90 setattr(status, 'user', user) # DEPRECIATED
91 elif k == 'created_at':
92 setattr(status, k, parse_datetime(v))
95 setattr(status, k, parse_html_value(v))
96 setattr(status, 'source_url', parse_a_href(v))
99 setattr(status, 'source_url', None)
100 elif k == 'retweeted_status':
101 setattr(status, k, Status.parse(api, v))
104 setattr(status, k, Place.parse(api, v))
106 setattr(status, k, None)
108 setattr(status, k, v)
112 return self._api.destroy_status(self.id)
115 return self._api.retweet(self.id)
118 return self._api.retweets(self.id)
121 return self._api.create_favorite(self.id)
123 def __eq__(self, other):
124 if isinstance(other, Status):
125 return self.id == other.id
127 return NotImplemented
129 def __ne__(self, other):
130 result = self == other
132 if result is NotImplemented:
141 def parse(cls, api, json):
143 setattr(user, '_json', json)
144 for k, v in json.items():
145 if k == 'created_at':
146 setattr(user, k, parse_datetime(v))
148 setattr(user, k, Status.parse(api, v))
149 elif k == 'following':
150 # twitter sets this to null if it is false
152 setattr(user, k, True)
154 setattr(user, k, False)
160 def parse_list(cls, api, json_list):
161 if isinstance(json_list, list):
162 item_list = json_list
164 item_list = json_list['users']
166 results = ResultSet()
167 for obj in item_list:
168 results.append(cls.parse(api, obj))
171 def timeline(self, **kargs):
172 return self._api.user_timeline(user_id=self.id, **kargs)
174 def friends(self, **kargs):
175 return self._api.friends(user_id=self.id, **kargs)
177 def followers(self, **kargs):
178 return self._api.followers(user_id=self.id, **kargs)
181 self._api.create_friendship(user_id=self.id)
182 self.following = True
185 self._api.destroy_friendship(user_id=self.id)
186 self.following = False
188 def lists_memberships(self, *args, **kargs):
189 return self._api.lists_memberships(user=self.screen_name,
193 def lists_subscriptions(self, *args, **kargs):
194 return self._api.lists_subscriptions(user=self.screen_name,
198 def lists(self, *args, **kargs):
199 return self._api.lists_all(user=self.screen_name,
203 def followers_ids(self, *args, **kargs):
204 return self._api.followers_ids(user_id=self.id,
209 class DirectMessage(Model):
212 def parse(cls, api, json):
214 for k, v in json.items():
215 if k == 'sender' or k == 'recipient':
216 setattr(dm, k, User.parse(api, v))
217 elif k == 'created_at':
218 setattr(dm, k, parse_datetime(v))
224 return self._api.destroy_direct_message(self.id)
227 class Friendship(Model):
230 def parse(cls, api, json):
231 relationship = json['relationship']
235 for k, v in relationship['source'].items():
236 setattr(source, k, v)
240 for k, v in relationship['target'].items():
241 setattr(target, k, v)
243 return source, target
246 class Category(Model):
249 def parse(cls, api, json):
251 for k, v in json.items():
252 setattr(category, k, v)
256 class SavedSearch(Model):
259 def parse(cls, api, json):
261 for k, v in json.items():
262 if k == 'created_at':
263 setattr(ss, k, parse_datetime(v))
269 return self._api.destroy_saved_search(self.id)
272 class SearchResults(ResultSet):
275 def parse(cls, api, json):
276 metadata = json['search_metadata']
277 results = SearchResults()
278 results.refresh_url = metadata.get('refresh_url')
279 results.completed_in = metadata.get('completed_in')
280 results.query = metadata.get('query')
281 results.count = metadata.get('count')
282 results.next_results = metadata.get('next_results')
284 status_model = getattr(api.parser.model_factory, 'status') if api else Status
286 for status in json['statuses']:
287 results.append(status_model.parse(api, status))
294 def parse(cls, api, json):
296 for k, v in json.items():
298 setattr(lst, k, User.parse(api, v))
299 elif k == 'created_at':
300 setattr(lst, k, parse_datetime(v))
306 def parse_list(cls, api, json_list, result_set=None):
307 results = ResultSet()
308 if isinstance(json_list, dict):
309 json_list = json_list['lists']
310 for obj in json_list:
311 results.append(cls.parse(api, obj))
314 def update(self, **kargs):
315 return self._api.update_list(self.slug, **kargs)
318 return self._api.destroy_list(self.slug)
320 def timeline(self, **kargs):
321 return self._api.list_timeline(self.user.screen_name,
325 def add_member(self, id):
326 return self._api.add_list_member(self.slug, id)
328 def remove_member(self, id):
329 return self._api.remove_list_member(self.slug, id)
331 def members(self, **kargs):
332 return self._api.list_members(self.user.screen_name,
336 def is_member(self, id):
337 return self._api.is_list_member(self.user.screen_name,
342 return self._api.subscribe_list(self.user.screen_name, self.slug)
344 def unsubscribe(self):
345 return self._api.unsubscribe_list(self.user.screen_name, self.slug)
347 def subscribers(self, **kargs):
348 return self._api.list_subscribers(self.user.screen_name,
352 def is_subscribed(self, id):
353 return self._api.is_subscribed_list(self.user.screen_name,
358 class Relation(Model):
360 def parse(cls, api, json):
362 for k, v in json.items():
363 if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
364 setattr(result, k, Status.parse(api, v))
366 setattr(result, k, Relation.parse_list(api, v))
368 setattr(result, k, v)
372 class Relationship(Model):
374 def parse(cls, api, json):
376 for k, v in json.items():
377 if k == 'connections':
378 setattr(result, 'is_following', 'following' in v)
379 setattr(result, 'is_followed_by', 'followed_by' in v)
381 setattr(result, k, v)
385 class JSONModel(Model):
388 def parse(cls, api, json):
392 class IDModel(Model):
395 def parse(cls, api, json):
396 if isinstance(json, list):
402 class BoundingBox(Model):
405 def parse(cls, api, json):
408 for k, v in json.items():
409 setattr(result, k, v)
414 Return longitude, latitude of southwest (bottom, left) corner of
415 bounding box, as a tuple.
417 This assumes that bounding box is always a rectangle, which
418 appears to be the case at present.
420 return tuple(self.coordinates[0][0])
424 Return longitude, latitude of northeast (top, right) corner of
425 bounding box, as a tuple.
427 This assumes that bounding box is always a rectangle, which
428 appears to be the case at present.
430 return tuple(self.coordinates[0][2])
436 def parse(cls, api, json):
438 for k, v in json.items():
439 if k == 'bounding_box':
440 # bounding_box value may be null (None.)
441 # Example: "United States" (id=96683cc9126741d1)
443 t = BoundingBox.parse(api, v)
447 elif k == 'contained_within':
448 # contained_within is a list of Places.
449 setattr(place, k, Place.parse_list(api, v))
455 def parse_list(cls, api, json_list):
456 if isinstance(json_list, list):
457 item_list = json_list
459 item_list = json_list['result']['places']
461 results = ResultSet()
462 for obj in item_list:
463 results.append(cls.parse(api, obj))
470 def parse(cls, api, json):
472 for k, v in json.items():
477 class ModelFactory(object):
479 Used by parsers for creating instances
480 of models. You may subclass this factory
481 to add your own extended models.
486 direct_message = DirectMessage
487 friendship = Friendship
488 saved_search = SavedSearch
489 search_results = SearchResults
493 relationship = Relationship
499 bounding_box = BoundingBox