Improve order in models.py
authorHarmon <Harmon758@gmail.com>
Tue, 27 Apr 2021 16:50:07 +0000 (11:50 -0500)
committerHarmon <Harmon758@gmail.com>
Tue, 27 Apr 2021 16:53:00 +0000 (11:53 -0500)
tweepy/models.py

index 7222da633b5b6d6931e7a496c8a84e5653e4ff00..a7ab0e760e89fdeda1c15771a62f903becac47be 100644 (file)
@@ -7,34 +7,6 @@ from email.utils import parsedate_to_datetime
 from tweepy.mixins import HashableID
 
 
-class ResultSet(list):
-    """A list like object that holds results from a Twitter API query."""
-
-    def __init__(self, max_id=None, since_id=None):
-        super().__init__()
-        self._max_id = max_id
-        self._since_id = since_id
-
-    @property
-    def max_id(self):
-        if self._max_id:
-            return self._max_id
-        ids = self.ids()
-        # 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()
-        # 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')]
-
-
 class Model:
 
     def __init__(self, api=None):
@@ -85,123 +57,63 @@ class Model:
         return f'{self.__class__.__name__}({", ".join(state)})'
 
 
-class Status(Model, HashableID):
-
-    @classmethod
-    def parse(cls, api, json):
-        status = cls(api)
-        setattr(status, '_json', json)
-        for k, v in json.items():
-            if k == 'user':
-                try:
-                    user = api.parser.model_factory.user.parse(api, v)
-                except AttributeError:
-                    user = User.parse(api, v)
-                setattr(status, 'author', user)
-                setattr(status, 'user', user)  # DEPRECIATED
-            elif k == 'created_at':
-                setattr(status, k, parsedate_to_datetime(v))
-            elif k == 'source':
-                if '<' in v:
-                    # At this point, v should be of the format:
-                    # <a href="{source_url}" rel="nofollow">{source}</a>
-                    setattr(status, k, v[v.find('>') + 1:v.rfind('<')])
-                    start = v.find('"') + 1
-                    end = v.find('"', start)
-                    setattr(status, 'source_url', v[start:end])
-                else:
-                    setattr(status, k, v)
-                    setattr(status, 'source_url', None)
-            elif k == 'retweeted_status':
-                setattr(status, k, Status.parse(api, v))
-            elif k == 'quoted_status':
-                setattr(status, k, Status.parse(api, v))
-            elif k == 'place':
-                if v is not None:
-                    setattr(status, k, Place.parse(api, v))
-                else:
-                    setattr(status, k, None)
-            else:
-                setattr(status, k, v)
-        return status
+class ResultSet(list):
+    """A list like object that holds results from a Twitter API query."""
 
-    def destroy(self):
-        return self._api.destroy_status(self.id)
+    def __init__(self, max_id=None, since_id=None):
+        super().__init__()
+        self._max_id = max_id
+        self._since_id = since_id
 
-    def retweet(self):
-        return self._api.retweet(self.id)
+    @property
+    def max_id(self):
+        if self._max_id:
+            return self._max_id
+        ids = self.ids()
+        # Max_id is always set to the *smallest* id, minus one, in the set
+        return (min(ids) - 1) if ids else None
 
-    def retweets(self):
-        return self._api.retweets(self.id)
+    @property
+    def since_id(self):
+        if self._since_id:
+            return self._since_id
+        ids = self.ids()
+        # Since_id is always set to the *greatest* id in the set
+        return max(ids) if ids else None
 
-    def favorite(self):
-        return self._api.create_favorite(self.id)
+    def ids(self):
+        return [item.id for item in self if hasattr(item, 'id')]
 
 
-class User(Model, HashableID):
+class BoundingBox(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, parsedate_to_datetime(v))
-            elif k == 'status':
-                setattr(user, k, Status.parse(api, v))
-            elif k == 'following':
-                # twitter sets this to null if it is false
-                if v is True:
-                    setattr(user, k, True)
-                else:
-                    setattr(user, k, False)
-            else:
-                setattr(user, k, v)
-        return user
-
-    @classmethod
-    def parse_list(cls, api, json_list):
-        if isinstance(json_list, list):
-            item_list = json_list
-        else:
-            item_list = json_list['users']
-
-        results = ResultSet()
-        for obj in item_list:
-            results.append(cls.parse(api, obj))
-        return results
-
-    def timeline(self, **kwargs):
-        return self._api.user_timeline(user_id=self.id, **kwargs)
-
-    def friends(self, **kwargs):
-        return self._api.friends(user_id=self.id, **kwargs)
-
-    def followers(self, **kwargs):
-        return self._api.followers(user_id=self.id, **kwargs)
-
-    def follow(self):
-        self._api.create_friendship(user_id=self.id)
-        self.following = True
-
-    def unfollow(self):
-        self._api.destroy_friendship(user_id=self.id)
-        self.following = False
-
-    def lists_memberships(self, *args, **kwargs):
-        return self._api.lists_memberships(user_id=self.id, *args, **kwargs)
+        result = cls(api)
+        if json is not None:
+            for k, v in json.items():
+                setattr(result, k, v)
+        return result
 
-    def lists_ownerships(self, *args, **kwargs):
-        return self._api.lists_ownerships(user_id=self.id, *args, **kwargs)
+    def origin(self):
+        """
+        Return longitude, latitude of southwest (bottom, left) corner of
+        bounding box, as a tuple.
 
-    def lists_subscriptions(self, *args, **kwargs):
-        return self._api.lists_subscriptions(user_id=self.id, *args, **kwargs)
+        This assumes that bounding box is always a rectangle, which
+        appears to be the case at present.
+        """
+        return tuple(self.coordinates[0][0])
 
-    def lists(self, *args, **kwargs):
-        return self._api.lists_all(user_id=self.id, *args, **kwargs)
+    def corner(self):
+        """
+        Return longitude, latitude of northeast (top, right) corner of
+        bounding box, as a tuple.
 
-    def followers_ids(self, *args, **kwargs):
-        return self._api.followers_ids(user_id=self.id, *args, **kwargs)
+        This assumes that bounding box is always a rectangle, which
+        appears to be the case at present.
+        """
+        return tuple(self.coordinates[0][2])
 
 
 class DirectMessage(Model):
@@ -253,44 +165,6 @@ class Friendship(Model):
         return source, target
 
 
-class SavedSearch(Model):
-
-    @classmethod
-    def parse(cls, api, json):
-        ss = cls(api)
-        for k, v in json.items():
-            if k == 'created_at':
-                setattr(ss, k, parsedate_to_datetime(v))
-            else:
-                setattr(ss, k, v)
-        return ss
-
-    def destroy(self):
-        return self._api.destroy_saved_search(self.id)
-
-
-class SearchResults(ResultSet):
-
-    @classmethod
-    def parse(cls, api, json):
-        metadata = json['search_metadata']
-        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')
-
-        try:
-            status_model = api.parser.model_factory.status
-        except AttributeError:
-            status_model = Status
-
-        for status in json['statuses']:
-            results.append(status_model.parse(api, status))
-        return results
-
-
 class List(Model):
 
     @classmethod
@@ -357,6 +231,50 @@ class List(Model):
         )
 
 
+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 Place(Model):
+
+    @classmethod
+    def parse(cls, api, json):
+        place = cls(api)
+        for k, v in json.items():
+            if k == 'bounding_box':
+                # bounding_box value may be null (None.)
+                # Example: "United States" (id=96683cc9126741d1)
+                if v is not None:
+                    t = BoundingBox.parse(api, v)
+                else:
+                    t = v
+                setattr(place, k, t)
+            elif k == 'contained_within':
+                # contained_within is a list of Places.
+                setattr(place, k, Place.parse_list(api, v))
+            else:
+                setattr(place, k, v)
+        return place
+
+    @classmethod
+    def parse_list(cls, api, json_list):
+        if isinstance(json_list, list):
+            item_list = json_list
+        else:
+            item_list = json_list['result']['places']
+
+        results = ResultSet()
+        for obj in item_list:
+            results.append(cls.parse(api, obj))
+        return results
+
+
 class Relationship(Model):
     @classmethod
     def parse(cls, api, json):
@@ -374,96 +292,178 @@ class Relationship(Model):
         return result
 
 
-class JSONModel(Model):
+class SavedSearch(Model):
 
     @classmethod
     def parse(cls, api, json):
-        return json
+        ss = cls(api)
+        for k, v in json.items():
+            if k == 'created_at':
+                setattr(ss, k, parsedate_to_datetime(v))
+            else:
+                setattr(ss, k, v)
+        return ss
+
+    def destroy(self):
+        return self._api.destroy_saved_search(self.id)
 
 
-class IDModel(Model):
+class SearchResults(ResultSet):
 
     @classmethod
     def parse(cls, api, json):
-        if isinstance(json, list):
-            return json
-        else:
-            return json['ids']
+        metadata = json['search_metadata']
+        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')
 
+        try:
+            status_model = api.parser.model_factory.status
+        except AttributeError:
+            status_model = Status
 
-class BoundingBox(Model):
+        for status in json['statuses']:
+            results.append(status_model.parse(api, status))
+        return results
+
+
+class Status(Model, HashableID):
 
     @classmethod
     def parse(cls, api, json):
-        result = cls(api)
-        if json is not None:
-            for k, v in json.items():
-                setattr(result, k, v)
-        return result
+        status = cls(api)
+        setattr(status, '_json', json)
+        for k, v in json.items():
+            if k == 'user':
+                try:
+                    user = api.parser.model_factory.user.parse(api, v)
+                except AttributeError:
+                    user = User.parse(api, v)
+                setattr(status, 'author', user)
+                setattr(status, 'user', user)  # DEPRECIATED
+            elif k == 'created_at':
+                setattr(status, k, parsedate_to_datetime(v))
+            elif k == 'source':
+                if '<' in v:
+                    # At this point, v should be of the format:
+                    # <a href="{source_url}" rel="nofollow">{source}</a>
+                    setattr(status, k, v[v.find('>') + 1:v.rfind('<')])
+                    start = v.find('"') + 1
+                    end = v.find('"', start)
+                    setattr(status, 'source_url', v[start:end])
+                else:
+                    setattr(status, k, v)
+                    setattr(status, 'source_url', None)
+            elif k == 'retweeted_status':
+                setattr(status, k, Status.parse(api, v))
+            elif k == 'quoted_status':
+                setattr(status, k, Status.parse(api, v))
+            elif k == 'place':
+                if v is not None:
+                    setattr(status, k, Place.parse(api, v))
+                else:
+                    setattr(status, k, None)
+            else:
+                setattr(status, k, v)
+        return status
 
-    def origin(self):
-        """
-        Return longitude, latitude of southwest (bottom, left) corner of
-        bounding box, as a tuple.
+    def destroy(self):
+        return self._api.destroy_status(self.id)
 
-        This assumes that bounding box is always a rectangle, which
-        appears to be the case at present.
-        """
-        return tuple(self.coordinates[0][0])
+    def retweet(self):
+        return self._api.retweet(self.id)
 
-    def corner(self):
-        """
-        Return longitude, latitude of northeast (top, right) corner of
-        bounding box, as a tuple.
+    def retweets(self):
+        return self._api.retweets(self.id)
 
-        This assumes that bounding box is always a rectangle, which
-        appears to be the case at present.
-        """
-        return tuple(self.coordinates[0][2])
+    def favorite(self):
+        return self._api.create_favorite(self.id)
 
 
-class Place(Model):
+class User(Model, HashableID):
 
     @classmethod
     def parse(cls, api, json):
-        place = cls(api)
+        user = cls(api)
+        setattr(user, '_json', json)
         for k, v in json.items():
-            if k == 'bounding_box':
-                # bounding_box value may be null (None.)
-                # Example: "United States" (id=96683cc9126741d1)
-                if v is not None:
-                    t = BoundingBox.parse(api, v)
+            if k == 'created_at':
+                setattr(user, k, parsedate_to_datetime(v))
+            elif k == 'status':
+                setattr(user, k, Status.parse(api, v))
+            elif k == 'following':
+                # twitter sets this to null if it is false
+                if v is True:
+                    setattr(user, k, True)
                 else:
-                    t = v
-                setattr(place, k, t)
-            elif k == 'contained_within':
-                # contained_within is a list of Places.
-                setattr(place, k, Place.parse_list(api, v))
+                    setattr(user, k, False)
             else:
-                setattr(place, k, v)
-        return place
+                setattr(user, k, v)
+        return user
 
     @classmethod
     def parse_list(cls, api, json_list):
         if isinstance(json_list, list):
             item_list = json_list
         else:
-            item_list = json_list['result']['places']
+            item_list = json_list['users']
 
         results = ResultSet()
         for obj in item_list:
             results.append(cls.parse(api, obj))
         return results
 
+    def timeline(self, **kwargs):
+        return self._api.user_timeline(user_id=self.id, **kwargs)
+
+    def friends(self, **kwargs):
+        return self._api.friends(user_id=self.id, **kwargs)
 
-class Media(Model):
+    def followers(self, **kwargs):
+        return self._api.followers(user_id=self.id, **kwargs)
+
+    def follow(self):
+        self._api.create_friendship(user_id=self.id)
+        self.following = True
+
+    def unfollow(self):
+        self._api.destroy_friendship(user_id=self.id)
+        self.following = False
+
+    def lists_memberships(self, *args, **kwargs):
+        return self._api.lists_memberships(user_id=self.id, *args, **kwargs)
+
+    def lists_ownerships(self, *args, **kwargs):
+        return self._api.lists_ownerships(user_id=self.id, *args, **kwargs)
+
+    def lists_subscriptions(self, *args, **kwargs):
+        return self._api.lists_subscriptions(user_id=self.id, *args, **kwargs)
+
+    def lists(self, *args, **kwargs):
+        return self._api.lists_all(user_id=self.id, *args, **kwargs)
+
+    def followers_ids(self, *args, **kwargs):
+        return self._api.followers_ids(user_id=self.id, *args, **kwargs)
+
+
+class IDModel(Model):
 
     @classmethod
     def parse(cls, api, json):
-        media = cls(api)
-        for k, v in json.items():
-            setattr(media, k, v)
-        return media
+        if isinstance(json, list):
+            return json
+        else:
+            return json['ids']
+
+
+class JSONModel(Model):
+
+    @classmethod
+    def parse(cls, api, json):
+        return json
 
 
 class ModelFactory:
@@ -473,17 +473,17 @@ class ModelFactory:
     to add your own extended models.
     """
 
-    status = Status
-    user = User
+    bounding_box = BoundingBox
     direct_message = DirectMessage
     friendship = Friendship
-    saved_search = SavedSearch
-    search_results = SearchResults
     list = List
-    relationship = Relationship
     media = Media
+    place = Place
+    relationship = Relationship
+    saved_search = SavedSearch
+    search_results = SearchResults
+    status = Status
+    user = User
 
-    json = JSONModel
     ids = IDModel
-    place = Place
-    bounding_box = BoundingBox
+    json = JSONModel