From 408ff32c9e616ba1e03ff31be40c0dca891cd13b Mon Sep 17 00:00:00 2001 From: Harmon Date: Tue, 27 Apr 2021 11:50:07 -0500 Subject: [PATCH] Improve order in models.py --- tweepy/models.py | 454 +++++++++++++++++++++++------------------------ 1 file changed, 227 insertions(+), 227 deletions(-) diff --git a/tweepy/models.py b/tweepy/models.py index 7222da6..a7ab0e7 100644 --- a/tweepy/models.py +++ b/tweepy/models.py @@ -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: - # {source} - 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: + # {source} + 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 -- 2.25.1