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]
81 json['user']['screen_name'] = str(json['user']['screen_name'].encode('ascii', 'ignore'))[2:-1]
83 setattr(status, '_json', json)
84 for k, v in json.items():
86 user_model = getattr(api.parser.model_factory, 'user') if api else User
87 user = user_model.parse(api, v)
88 setattr(status, 'author', user)
89 setattr(status, 'user', user) # DEPRECIATED
90 elif k == 'created_at':
91 setattr(status, k, parse_datetime(v))
94 setattr(status, k, parse_html_value(v))
95 setattr(status, 'source_url', parse_a_href(v))
98 setattr(status, 'source_url', None)
99 elif k == 'retweeted_status':
100 setattr(status, k, Status.parse(api, v))
103 setattr(status, k, Place.parse(api, v))
105 setattr(status, k, None)
107 setattr(status, k, v)
111 return self._api.destroy_status(self.id)
114 return self._api.retweet(self.id)
117 return self._api.retweets(self.id)
120 return self._api.create_favorite(self.id)
122 def __eq__(self, other):
123 if isinstance(other, Status):
124 return self.id == other.id
126 return NotImplemented
128 def __ne__(self, other):
129 result = self == other
131 if result is NotImplemented:
140 def parse(cls, api, json):
142 setattr(user, '_json', json)
143 for k, v in json.items():
144 if k == 'created_at':
145 setattr(user, k, parse_datetime(v))
147 setattr(user, k, Status.parse(api, v))
148 elif k == 'following':
149 # twitter sets this to null if it is false
151 setattr(user, k, True)
153 setattr(user, k, False)
159 def parse_list(cls, api, json_list):
160 if isinstance(json_list, list):
161 item_list = json_list
163 item_list = json_list['users']
165 results = ResultSet()
166 for obj in item_list:
167 results.append(cls.parse(api, obj))
170 def timeline(self, **kargs):
171 return self._api.user_timeline(user_id=self.id, **kargs)
173 def friends(self, **kargs):
174 return self._api.friends(user_id=self.id, **kargs)
176 def followers(self, **kargs):
177 return self._api.followers(user_id=self.id, **kargs)
180 self._api.create_friendship(user_id=self.id)
181 self.following = True
184 self._api.destroy_friendship(user_id=self.id)
185 self.following = False
187 def lists_memberships(self, *args, **kargs):
188 return self._api.lists_memberships(user=self.screen_name,
192 def lists_subscriptions(self, *args, **kargs):
193 return self._api.lists_subscriptions(user=self.screen_name,
197 def lists(self, *args, **kargs):
198 return self._api.lists_all(user=self.screen_name,
202 def followers_ids(self, *args, **kargs):
203 return self._api.followers_ids(user_id=self.id,
208 class DirectMessage(Model):
211 def parse(cls, api, json):
213 for k, v in json.items():
214 if k == 'sender' or k == 'recipient':
215 setattr(dm, k, User.parse(api, v))
216 elif k == 'created_at':
217 setattr(dm, k, parse_datetime(v))
223 return self._api.destroy_direct_message(self.id)
226 class Friendship(Model):
229 def parse(cls, api, json):
230 relationship = json['relationship']
234 for k, v in relationship['source'].items():
235 setattr(source, k, v)
239 for k, v in relationship['target'].items():
240 setattr(target, k, v)
242 return source, target
245 class Category(Model):
248 def parse(cls, api, json):
250 for k, v in json.items():
251 setattr(category, k, v)
255 class SavedSearch(Model):
258 def parse(cls, api, json):
260 for k, v in json.items():
261 if k == 'created_at':
262 setattr(ss, k, parse_datetime(v))
268 return self._api.destroy_saved_search(self.id)
271 class SearchResults(ResultSet):
274 def parse(cls, api, json):
275 metadata = json['search_metadata']
276 results = SearchResults()
277 results.refresh_url = metadata.get('refresh_url')
278 results.completed_in = metadata.get('completed_in')
279 results.query = metadata.get('query')
280 results.count = metadata.get('count')
281 results.next_results = metadata.get('next_results')
283 status_model = getattr(api.parser.model_factory, 'status') if api else Status
285 for status in json['statuses']:
286 results.append(status_model.parse(api, status))
293 def parse(cls, api, json):
295 for k, v in json.items():
297 setattr(lst, k, User.parse(api, v))
298 elif k == 'created_at':
299 setattr(lst, k, parse_datetime(v))
305 def parse_list(cls, api, json_list, result_set=None):
306 results = ResultSet()
307 if isinstance(json_list, dict):
308 json_list = json_list['lists']
309 for obj in json_list:
310 results.append(cls.parse(api, obj))
313 def update(self, **kargs):
314 return self._api.update_list(self.slug, **kargs)
317 return self._api.destroy_list(self.slug)
319 def timeline(self, **kargs):
320 return self._api.list_timeline(self.user.screen_name,
324 def add_member(self, id):
325 return self._api.add_list_member(self.slug, id)
327 def remove_member(self, id):
328 return self._api.remove_list_member(self.slug, id)
330 def members(self, **kargs):
331 return self._api.list_members(self.user.screen_name,
335 def is_member(self, id):
336 return self._api.is_list_member(self.user.screen_name,
341 return self._api.subscribe_list(self.user.screen_name, self.slug)
343 def unsubscribe(self):
344 return self._api.unsubscribe_list(self.user.screen_name, self.slug)
346 def subscribers(self, **kargs):
347 return self._api.list_subscribers(self.user.screen_name,
351 def is_subscribed(self, id):
352 return self._api.is_subscribed_list(self.user.screen_name,
357 class Relation(Model):
359 def parse(cls, api, json):
361 for k, v in json.items():
362 if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
363 setattr(result, k, Status.parse(api, v))
365 setattr(result, k, Relation.parse_list(api, v))
367 setattr(result, k, v)
371 class Relationship(Model):
373 def parse(cls, api, json):
375 for k, v in json.items():
376 if k == 'connections':
377 setattr(result, 'is_following', 'following' in v)
378 setattr(result, 'is_followed_by', 'followed_by' in v)
380 setattr(result, k, v)
384 class JSONModel(Model):
387 def parse(cls, api, json):
391 class IDModel(Model):
394 def parse(cls, api, json):
395 if isinstance(json, list):
401 class BoundingBox(Model):
404 def parse(cls, api, json):
407 for k, v in json.items():
408 setattr(result, k, v)
413 Return longitude, latitude of southwest (bottom, left) corner of
414 bounding box, as a tuple.
416 This assumes that bounding box is always a rectangle, which
417 appears to be the case at present.
419 return tuple(self.coordinates[0][0])
423 Return longitude, latitude of northeast (top, right) corner of
424 bounding box, as a tuple.
426 This assumes that bounding box is always a rectangle, which
427 appears to be the case at present.
429 return tuple(self.coordinates[0][2])
435 def parse(cls, api, json):
437 for k, v in json.items():
438 if k == 'bounding_box':
439 # bounding_box value may be null (None.)
440 # Example: "United States" (id=96683cc9126741d1)
442 t = BoundingBox.parse(api, v)
446 elif k == 'contained_within':
447 # contained_within is a list of Places.
448 setattr(place, k, Place.parse_list(api, v))
454 def parse_list(cls, api, json_list):
455 if isinstance(json_list, list):
456 item_list = json_list
458 item_list = json_list['result']['places']
460 results = ResultSet()
461 for obj in item_list:
462 results.append(cls.parse(api, obj))
469 def parse(cls, api, json):
471 for k, v in json.items():
476 class ModelFactory(object):
478 Used by parsers for creating instances
479 of models. You may subclass this factory
480 to add your own extended models.
485 direct_message = DirectMessage
486 friendship = Friendship
487 saved_search = SavedSearch
488 search_results = SearchResults
492 relationship = Relationship
498 bounding_box = BoundingBox