Fixed key error in some tweets
[twitter-api-cdsw-solutions] / tweepy / models.py
index 9b70070887bbb6fa48ea03d15f161cac4f513c3e..0db677ea140c6fe49a70ed0a464368c0eb4e4122 100644 (file)
@@ -2,7 +2,8 @@
 # Copyright 2009-2010 Joshua Roesslein
 # See LICENSE for details.
 
 # Copyright 2009-2010 Joshua Roesslein
 # See LICENSE for details.
 
-from tweepy.error import TweepError
+from __future__ import absolute_import, print_function
+
 from tweepy.utils import parse_datetime, parse_html_value, parse_a_href
 
 
 from tweepy.utils import parse_datetime, parse_html_value, parse_a_href
 
 
@@ -18,18 +19,21 @@ class ResultSet(list):
         if self._max_id:
             return self._max_id
         ids = self.ids()
         if self._max_id:
             return self._max_id
         ids = self.ids()
-        return max(ids) if ids else None
+        # Max_id is always set to the *smallest* id, minus one, in the set
+        return (min(ids) - 1) if ids else None
 
     @property
     def since_id(self):
         if self._since_id:
             return self._since_id
         ids = self.ids()
 
     @property
     def since_id(self):
         if self._since_id:
             return self._since_id
         ids = self.ids()
-        return min(ids) if ids else None
+        # Since_id is always set to the *greatest* id in the set
+        return max(ids) if ids else None
 
     def ids(self):
         return [item.id for item in self if hasattr(item, 'id')]
 
 
     def ids(self):
         return [item.id for item in self if hasattr(item, 'id')]
 
+
 class Model(object):
 
     def __init__(self, api=None):
 class Model(object):
 
     def __init__(self, api=None):
@@ -51,7 +55,10 @@ class Model(object):
 
     @classmethod
     def parse_list(cls, api, json_list):
 
     @classmethod
     def parse_list(cls, api, json_list):
-        """Parse a list of JSON objects into a result set of model instances."""
+        """
+            Parse a list of JSON objects into
+            a result set of model instances.
+        """
         results = ResultSet()
         for obj in json_list:
             if obj:
         results = ResultSet()
         for obj in json_list:
             if obj:
@@ -59,7 +66,7 @@ class Model(object):
         return results
 
     def __repr__(self):
         return results
 
     def __repr__(self):
-        state = ['%s=%s' % (k, repr(v)) for (k,v) in vars(self).items()]
+        state = ['%s=%s' % (k, repr(v)) for (k, v) in vars(self).items()]
         return '%s(%s)' % (self.__class__.__name__, ', '.join(state))
 
 
         return '%s(%s)' % (self.__class__.__name__, ', '.join(state))
 
 
@@ -68,12 +75,14 @@ class Status(Model):
     @classmethod
     def parse(cls, api, json):
         status = cls(api)
     @classmethod
     def parse(cls, api, json):
         status = cls(api)
-        for k, v in json.items():
-            
-            # Hack by guyrt to fix unicode issues, which we do *not* want to teach.
-            if isinstance(v, basestring):
-                v = v.encode('ascii', errors='ignore')
 
 
+        # I'm not proud. Blame billg.
+        json['text'] = str(json['text'].encode('ascii', 'ignore'))[2:-1]
+        if 'user' in json:
+            json['user']['screen_name'] = str(json['user']['screen_name'].encode('ascii', 'ignore'))[2:-1]
+
+        setattr(status, '_json', json)
+        for k, v in json.items():
             if k == 'user':
                 user_model = getattr(api.parser.model_factory, 'user') if api else User
                 user = user_model.parse(api, v)
             if k == 'user':
                 user_model = getattr(api.parser.model_factory, 'user') if api else User
                 user = user_model.parse(api, v)
@@ -111,12 +120,27 @@ class Status(Model):
     def favorite(self):
         return self._api.create_favorite(self.id)
 
     def favorite(self):
         return self._api.create_favorite(self.id)
 
+    def __eq__(self, other):
+        if isinstance(other, Status):
+            return self.id == other.id
+
+        return NotImplemented
+
+    def __ne__(self, other):
+        result = self == other
+
+        if result is NotImplemented:
+            return result
+
+        return not result
+
 
 class User(Model):
 
     @classmethod
     def parse(cls, api, json):
         user = cls(api)
 
 class User(Model):
 
     @classmethod
     def parse(cls, api, json):
         user = cls(api)
+        setattr(user, '_json', json)
         for k, v in json.items():
             if k == 'created_at':
                 setattr(user, k, parse_datetime(v))
         for k, v in json.items():
             if k == 'created_at':
                 setattr(user, k, parse_datetime(v))
@@ -162,16 +186,24 @@ class User(Model):
         self.following = False
 
     def lists_memberships(self, *args, **kargs):
         self.following = False
 
     def lists_memberships(self, *args, **kargs):
-        return self._api.lists_memberships(user=self.screen_name, *args, **kargs)
+        return self._api.lists_memberships(user=self.screen_name,
+                                           *args,
+                                           **kargs)
 
     def lists_subscriptions(self, *args, **kargs):
 
     def lists_subscriptions(self, *args, **kargs):
-        return self._api.lists_subscriptions(user=self.screen_name, *args, **kargs)
+        return self._api.lists_subscriptions(user=self.screen_name,
+                                             *args,
+                                             **kargs)
 
     def lists(self, *args, **kargs):
 
     def lists(self, *args, **kargs):
-        return self._api.lists_all(user=self.screen_name, *args, **kargs)
+        return self._api.lists_all(user=self.screen_name,
+                                   *args,
+                                   **kargs)
 
     def followers_ids(self, *args, **kargs):
 
     def followers_ids(self, *args, **kargs):
-        return self._api.followers_ids(user_id=self.id, *args, **kargs)
+        return self._api.followers_ids(user_id=self.id,
+                                       *args,
+                                       **kargs)
 
 
 class DirectMessage(Model):
 
 
 class DirectMessage(Model):
@@ -242,15 +274,17 @@ class SearchResults(ResultSet):
     @classmethod
     def parse(cls, api, json):
         metadata = json['search_metadata']
     @classmethod
     def parse(cls, api, json):
         metadata = json['search_metadata']
-        results = SearchResults(metadata.get('max_id'), metadata.get('since_id'))
+        results = SearchResults()
         results.refresh_url = metadata.get('refresh_url')
         results.completed_in = metadata.get('completed_in')
         results.query = metadata.get('query')
         results.count = metadata.get('count')
         results.next_results = metadata.get('next_results')
 
         results.refresh_url = metadata.get('refresh_url')
         results.completed_in = metadata.get('completed_in')
         results.query = metadata.get('query')
         results.count = metadata.get('count')
         results.next_results = metadata.get('next_results')
 
+        status_model = getattr(api.parser.model_factory, 'status') if api else Status
+
         for status in json['statuses']:
         for status in json['statuses']:
-            results.append(Status.parse(api, status))
+            results.append(status_model.parse(api, status))
         return results
 
 
         return results
 
 
@@ -259,7 +293,7 @@ class List(Model):
     @classmethod
     def parse(cls, api, json):
         lst = List(api)
     @classmethod
     def parse(cls, api, json):
         lst = List(api)
-        for k,v in json.items():
+        for k, v in json.items():
             if k == 'user':
                 setattr(lst, k, User.parse(api, v))
             elif k == 'created_at':
             if k == 'user':
                 setattr(lst, k, User.parse(api, v))
             elif k == 'created_at':
@@ -284,7 +318,9 @@ class List(Model):
         return self._api.destroy_list(self.slug)
 
     def timeline(self, **kargs):
         return self._api.destroy_list(self.slug)
 
     def timeline(self, **kargs):
-        return self._api.list_timeline(self.user.screen_name, self.slug, **kargs)
+        return self._api.list_timeline(self.user.screen_name,
+                                       self.slug,
+                                       **kargs)
 
     def add_member(self, id):
         return self._api.add_list_member(self.slug, id)
 
     def add_member(self, id):
         return self._api.add_list_member(self.slug, id)
@@ -293,10 +329,14 @@ class List(Model):
         return self._api.remove_list_member(self.slug, id)
 
     def members(self, **kargs):
         return self._api.remove_list_member(self.slug, id)
 
     def members(self, **kargs):
-        return self._api.list_members(self.user.screen_name, self.slug, **kargs)
+        return self._api.list_members(self.user.screen_name,
+                                      self.slug,
+                                      **kargs)
 
     def is_member(self, id):
 
     def is_member(self, id):
-        return self._api.is_list_member(self.user.screen_name, self.slug, id)
+        return self._api.is_list_member(self.user.screen_name,
+                                        self.slug,
+                                        id)
 
     def subscribe(self):
         return self._api.subscribe_list(self.user.screen_name, self.slug)
 
     def subscribe(self):
         return self._api.subscribe_list(self.user.screen_name, self.slug)
@@ -305,16 +345,21 @@ class List(Model):
         return self._api.unsubscribe_list(self.user.screen_name, self.slug)
 
     def subscribers(self, **kargs):
         return self._api.unsubscribe_list(self.user.screen_name, self.slug)
 
     def subscribers(self, **kargs):
-        return self._api.list_subscribers(self.user.screen_name, self.slug, **kargs)
+        return self._api.list_subscribers(self.user.screen_name,
+                                          self.slug,
+                                          **kargs)
 
     def is_subscribed(self, id):
 
     def is_subscribed(self, id):
-        return self._api.is_subscribed_list(self.user.screen_name, self.slug, id)
+        return self._api.is_subscribed_list(self.user.screen_name,
+                                            self.slug,
+                                            id)
+
 
 class Relation(Model):
     @classmethod
     def parse(cls, api, json):
         result = cls(api)
 
 class Relation(Model):
     @classmethod
     def parse(cls, api, json):
         result = cls(api)
-        for k,v in json.items():
+        for k, v in json.items():
             if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
                 setattr(result, k, Status.parse(api, v))
             elif k == 'results':
             if k == 'value' and json['kind'] in ['Tweet', 'LookedupStatus']:
                 setattr(result, k, Status.parse(api, v))
             elif k == 'results':
@@ -323,11 +368,12 @@ class Relation(Model):
                 setattr(result, k, v)
         return result
 
                 setattr(result, k, v)
         return result
 
+
 class Relationship(Model):
     @classmethod
     def parse(cls, api, json):
         result = cls(api)
 class Relationship(Model):
     @classmethod
     def parse(cls, api, json):
         result = cls(api)
-        for k,v in json.items():
+        for k, v in json.items():
             if k == 'connections':
                 setattr(result, 'is_following', 'following' in v)
                 setattr(result, 'is_followed_by', 'followed_by' in v)
             if k == 'connections':
                 setattr(result, 'is_following', 'following' in v)
                 setattr(result, 'is_followed_by', 'followed_by' in v)
@@ -335,6 +381,7 @@ class Relationship(Model):
                 setattr(result, k, v)
         return result
 
                 setattr(result, k, v)
         return result
 
+
 class JSONModel(Model):
 
     @classmethod
 class JSONModel(Model):
 
     @classmethod
@@ -416,6 +463,17 @@ class Place(Model):
             results.append(cls.parse(api, obj))
         return results
 
             results.append(cls.parse(api, obj))
         return results
 
+
+class Media(Model):
+
+    @classmethod
+    def parse(cls, api, json):
+        media = cls(api)
+        for k, v in json.items():
+            setattr(media, k, v)
+        return media
+
+
 class ModelFactory(object):
     """
     Used by parsers for creating instances
 class ModelFactory(object):
     """
     Used by parsers for creating instances
@@ -433,9 +491,9 @@ class ModelFactory(object):
     list = List
     relation = Relation
     relationship = Relationship
     list = List
     relation = Relation
     relationship = Relationship
+    media = Media
 
     json = JSONModel
     ids = IDModel
     place = Place
     bounding_box = BoundingBox
 
     json = JSONModel
     ids = IDModel
     place = Place
     bounding_box = BoundingBox
-

Benjamin Mako Hill || Want to submit a patch?