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):
78 setattr(status, '_json', json)
79 for k, v in json.items():
81 user_model = getattr(api.parser.model_factory, 'user') if api else User
82 user = user_model.parse(api, v)
83 setattr(status, 'author', user)
84 setattr(status, 'user', user) # DEPRECIATED
85 elif k == 'created_at':
86 setattr(status, k, parse_datetime(v))
89 setattr(status, k, parse_html_value(v))
90 setattr(status, 'source_url', parse_a_href(v))
93 setattr(status, 'source_url', None)
94 elif k == 'retweeted_status':
95 setattr(status, k, Status.parse(api, v))
98 setattr(status, k, Place.parse(api, v))
100 setattr(status, k, None)
102 setattr(status, k, v)
106 return self._api.destroy_status(self.id)
109 return self._api.retweet(self.id)
112 return self._api.retweets(self.id)
115 return self._api.create_favorite(self.id)
117 def __eq__(self, other):
118 if isinstance(other, Status):
119 return self.id == other.id
121 return NotImplemented
123 def __ne__(self, other):
124 result = self == other
126 if result is NotImplemented:
135 def parse(cls, api, json):
137 setattr(user, '_json', json)
138 for k, v in json.items():
139 if k == 'created_at':
140 setattr(user, k, parse_datetime(v))
142 setattr(user, k, Status.parse(api, v))
143 elif k == 'following':
144 # twitter sets this to null if it is false
146 setattr(user, k, True)
148 setattr(user, k, False)
154 def parse_list(cls, api, json_list):
155 if isinstance(json_list, list):
156 item_list = json_list
158 item_list = json_list['users']
160 results = ResultSet()
161 for obj in item_list:
162 results.append(cls.parse(api, obj))
165 def timeline(self, **kargs):
166 return self._api.user_timeline(user_id=self.id, **kargs)
168 def friends(self, **kargs):
169 return self._api.friends(user_id=self.id, **kargs)
171 def followers(self, **kargs):
172 return self._api.followers(user_id=self.id, **kargs)
175 self._api.create_friendship(user_id=self.id)
176 self.following = True
179 self._api.destroy_friendship(user_id=self.id)
180 self.following = False
182 def lists_memberships(self, *args, **kargs):
183 return self._api.lists_memberships(user=self.screen_name,
187 def lists_subscriptions(self, *args, **kargs):
188 return self._api.lists_subscriptions(user=self.screen_name,
192 def lists(self, *args, **kargs):
193 return self._api.lists_all(user=self.screen_name,
197 def followers_ids(self, *args, **kargs):
198 return self._api.followers_ids(user_id=self.id,
203 class DirectMessage(Model):
206 def parse(cls, api, json):
208 for k, v in json.items():
209 if k == 'sender' or k == 'recipient':
210 setattr(dm, k, User.parse(api, v))
211 elif k == 'created_at':
212 setattr(dm, k, parse_datetime(v))
218 return self._api.destroy_direct_message(self.id)
221 class Friendship(Model):
224 def parse(cls, api, json):
225 relationship = json['relationship']
229 for k, v in relationship['source'].items():
230 setattr(source, k, v)
234 for k, v in relationship['target'].items():
235 setattr(target, k, v)
237 return source, target
240 class Category(Model):
243 def parse(cls, api, json):
245 for k, v in json.items():
246 setattr(category, k, v)
250 class SavedSearch(Model):
253 def parse(cls, api, json):
255 for k, v in json.items():
256 if k == 'created_at':
257 setattr(ss, k, parse_datetime(v))
263 return self._api.destroy_saved_search(self.id)
266 class SearchResults(ResultSet):
269 def parse(cls, api, json):
270 metadata = json['search_metadata']
271 results = SearchResults()
272 results.refresh_url = metadata.get('refresh_url')
273 results.completed_in = metadata.get('completed_in')
274 results.query = metadata.get('query')
275 results.count = metadata.get('count')
276 results.next_results = metadata.get('next_results')
278 status_model = getattr(api.parser.model_factory, 'status') if api else Status
280 for status in json['statuses']:
281 results.append(status_model.parse(api, status))
288 def parse(cls, api, json):
290 for k, v in json.items():
292 setattr(lst, k, User.parse(api, v))
293 elif k == 'created_at':
294 setattr(lst, k, parse_datetime(v))
300 def parse_list(cls, api, json_list, result_set=None):
301 results = ResultSet()
302 if isinstance(json_list, dict):
303 json_list = json_list['lists']
304 for obj in json_list:
305 results.append(cls.parse(api, obj))
308 def update(self, **kargs):
309 return self._api.update_list(self.slug, **kargs)
312 return self._api.destroy_list(self.slug)
314 def timeline(self, **kargs):
315 return self._api.list_timeline(self.user.screen_name,
319 def add_member(self, id):
320 return self._api.add_list_member(self.slug, id)
322 def remove_member(self, id):
323 return self._api.remove_list_member(self.slug, id)
325 def members(self, **kargs):
326 return self._api.list_members(self.user.screen_name,
330 def is_member(self, id):
331 return self._api.is_list_member(self.user.screen_name,
336 return self._api.subscribe_list(self.user.screen_name, self.slug)
338 def unsubscribe(self):
339 return self._api.unsubscribe_list(self.user.screen_name, self.slug)
341 def subscribers(self, **kargs):
342 return self._api.list_subscribers(self.user.screen_name,
346 def is_subscribed(self, id):
347 return self._api.is_subscribed_list(self.user.screen_name,
352 class Relation(Model):
354 def parse(cls, api, json):
356 for k, v in json.items():
357 if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
358 setattr(result, k, Status.parse(api, v))
360 setattr(result, k, Relation.parse_list(api, v))
362 setattr(result, k, v)
366 class Relationship(Model):
368 def parse(cls, api, json):
370 for k, v in json.items():
371 if k == 'connections':
372 setattr(result, 'is_following', 'following' in v)
373 setattr(result, 'is_followed_by', 'followed_by' in v)
375 setattr(result, k, v)
379 class JSONModel(Model):
382 def parse(cls, api, json):
386 class IDModel(Model):
389 def parse(cls, api, json):
390 if isinstance(json, list):
396 class BoundingBox(Model):
399 def parse(cls, api, json):
402 for k, v in json.items():
403 setattr(result, k, v)
408 Return longitude, latitude of southwest (bottom, left) corner of
409 bounding box, as a tuple.
411 This assumes that bounding box is always a rectangle, which
412 appears to be the case at present.
414 return tuple(self.coordinates[0][0])
418 Return longitude, latitude of northeast (top, right) corner of
419 bounding box, as a tuple.
421 This assumes that bounding box is always a rectangle, which
422 appears to be the case at present.
424 return tuple(self.coordinates[0][2])
430 def parse(cls, api, json):
432 for k, v in json.items():
433 if k == 'bounding_box':
434 # bounding_box value may be null (None.)
435 # Example: "United States" (id=96683cc9126741d1)
437 t = BoundingBox.parse(api, v)
441 elif k == 'contained_within':
442 # contained_within is a list of Places.
443 setattr(place, k, Place.parse_list(api, v))
449 def parse_list(cls, api, json_list):
450 if isinstance(json_list, list):
451 item_list = json_list
453 item_list = json_list['result']['places']
455 results = ResultSet()
456 for obj in item_list:
457 results.append(cls.parse(api, obj))
464 def parse(cls, api, json):
466 for k, v in json.items():
471 class ModelFactory(object):
473 Used by parsers for creating instances
474 of models. You may subclass this factory
475 to add your own extended models.
480 direct_message = DirectMessage
481 friendship = Friendship
482 saved_search = SavedSearch
483 search_results = SearchResults
487 relationship = Relationship
493 bounding_box = BoundingBox