From d4fe1f50d92d86ddc7d1cdafbe332a0ce0852078 Mon Sep 17 00:00:00 2001 From: Alex Ch Date: Wed, 21 Oct 2015 00:02:09 +0300 Subject: [PATCH 01/28] beat > the JSON object must be str, not 'bytes' --- instagram/bind.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instagram/bind.py b/instagram/bind.py index cce758bf..e77b3d29 100644 --- a/instagram/bind.py +++ b/instagram/bind.py @@ -125,6 +125,8 @@ def _do_api_request(self, url, method="GET", body=None, headers=None): response, content = OAuth2Request(self.api).make_request(url, method=method, body=body, headers=headers) if response['status'] == '503' or response['status'] == '429': raise InstagramAPIError(response['status'], "Rate limited", "Your client is making too many request per second") + if hasattr(content, "decode"): + content = content.decode() try: content_obj = simplejson.loads(content) except ValueError: From 57a09ad249d9cbe708dfcac39489916d7a7765cb Mon Sep 17 00:00:00 2001 From: Alex Ch Date: Wed, 21 Oct 2015 00:09:02 +0300 Subject: [PATCH 02/28] encoding --- instagram/bind.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instagram/bind.py b/instagram/bind.py index e77b3d29..452cf3a1 100644 --- a/instagram/bind.py +++ b/instagram/bind.py @@ -126,7 +126,7 @@ def _do_api_request(self, url, method="GET", body=None, headers=None): if response['status'] == '503' or response['status'] == '429': raise InstagramAPIError(response['status'], "Rate limited", "Your client is making too many request per second") if hasattr(content, "decode"): - content = content.decode() + content = content.decode('utf-8') try: content_obj = simplejson.loads(content) except ValueError: From 05f18c79581d3f1b2cce1db049680c0badda7b49 Mon Sep 17 00:00:00 2001 From: Krish Munot Date: Sun, 15 Nov 2015 00:02:46 +0530 Subject: [PATCH 03/28] Making the word an alive hyperlink --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 223c0dbf..54b87319 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Our [developer site](http://instagram.com/developer) documents all the Instagram Blog ---------------------------- -The [Developer Blog] features news and important announcements about the Instagram Platform. You will also find tutorials and best practices to help you build great platform integrations. Make sure to subscribe to the RSS feed not to miss out on new posts: [http://developers.instagram.com](http://developers.instagram.com). +The [Developer Blog](http://developers.instagram.com/) features news and important announcements about the Instagram Platform. You will also find tutorials and best practices to help you build great platform integrations. Make sure to subscribe to the RSS feed not to miss out on new posts: [http://developers.instagram.com](http://developers.instagram.com). Community From 8b02858e4257d492d40346a0d19cdf300a8a06c1 Mon Sep 17 00:00:00 2001 From: Konstantin Lebedev Date: Sat, 27 Aug 2016 13:03:20 +0300 Subject: [PATCH 04/28] Update user_media_feed https://www.instagram.com/developer/endpoints/users/#get_users_media_recent_self --- instagram/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instagram/client.py b/instagram/client.py index 624bc0ec..c30c7eef 100644 --- a/instagram/client.py +++ b/instagram/client.py @@ -94,7 +94,7 @@ def __init__(self, *args, **kwargs): root_class=Media) user_media_feed = bind_method( - path="/users/self/feed", + path="/users/self/media/recent", accepts_parameters=MEDIA_ACCEPT_PARAMETERS, root_class=Media, paginates=True) From 17f11a0c8258f3f2b367849861e445b7d2cd816e Mon Sep 17 00:00:00 2001 From: Hossein Amin Date: Tue, 31 Jan 2017 01:25:05 +0300 Subject: [PATCH 05/28] specify urlencoded Content-Type (exchange_for_...) In my situation Instagram was not able to read post content. And reason was content-type. --- instagram/oauth2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instagram/oauth2.py b/instagram/oauth2.py index 053b1be8..002032a4 100644 --- a/instagram/oauth2.py +++ b/instagram/oauth2.py @@ -109,7 +109,8 @@ def exchange_for_access_token(self, code=None, username=None, password=None, sco data = self._data_for_exchange(code, username, password, scope=scope, user_id=user_id) http_object = Http(disable_ssl_certificate_validation=True) url = self.api.access_token_url - response, content = http_object.request(url, method="POST", body=data) + headers={"Content-Type":"application/x-www-form-urlencoded"} + response, content = http_object.request(url, method="POST", body=data, headers=headers) parsed_content = simplejson.loads(content.decode()) if int(response['status']) != 200: raise OAuth2AuthExchangeError(parsed_content.get("error_message", "")) From 0b67a18f659255b084d8d6f80f555debb112dd06 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 10:42:55 +0100 Subject: [PATCH 06/28] Safely fetch comment data, by checking availability before calling --- instagram/models.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/instagram/models.py b/instagram/models.py index d2517ca2..4f04192b 100644 --- a/instagram/models.py +++ b/instagram/models.py @@ -94,10 +94,12 @@ def object_from_dictionary(cls, entry): for like in entry['likes']['data']: new_media.likes.append(User.object_from_dictionary(like)) - new_media.comment_count = entry['comments']['count'] - new_media.comments = [] - for comment in entry['comments']['data']: - new_media.comments.append(Comment.object_from_dictionary(comment)) + new_media.comment_count = entry.get('comments', {}).get('count', 0) + if new_media.comment_count: + new_media.comments = [] + if entry.get('comments', {}).get('data'): + for comment in entry['comments']['data']: + new_media.comments.append(Comment.object_from_dictionary(comment)) new_media.users_in_photo = [] if entry.get('users_in_photo'): From 93ee521802cbb05fd1f3a8c1ee5968af152d1bb9 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 11:47:12 +0100 Subject: [PATCH 07/28] pep8 tests --- .gitignore | 1 - tests.py | 83 +++++++++++++++++++++++++----------------------------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 90f7f583..bf3ba0be 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ .DS_Store *.swp test_settings.py - diff --git a/tests.py b/tests.py index fcf705a7..6b0d43b0 100755 --- a/tests.py +++ b/tests.py @@ -1,7 +1,7 @@ #!/usr/bin/env python - import types import six + try: import simplejson as json except ImportError: @@ -17,15 +17,13 @@ access_token = "DEBUG" redirect_uri = "http://example.com" -class MockHttp(object): +class MockHttp(object): def __init__(self, *args, **kwargs): pass def request(self, url, method="GET", body=None, headers={}): - fail_state = { - 'status':'400' - }, "{}" + fail_state = {'status': '400'}, "{}" parsed = urlparse(url) options = parse_qs(parsed.query) @@ -33,27 +31,28 @@ def request(self, url, method="GET", body=None, headers={}): fn_name = str(active_call) if fn_name == 'get_authorize_login_url': return { - 'status': '200', - 'content-location':'http://example.com/redirect/login' - }, None + 'status': '200', + 'content-location': 'http://example.com/redirect/login' + }, None - if not 'access_token' in options and not 'client_id' in options: + if 'access_token' not in options and 'client_id' not in options: fn_name += '_unauthorized' - if 'self' in url and not 'access_token' in options: + if 'self' in url and 'access_token' not in options: fn_name += '_no_auth_user' fl = open('fixtures/%s.json' % fn_name) content = fl.read() fl.close() + json_content = json.loads(content) status = json_content['meta']['code'] - return { - 'status': status - }, content + return {'status': status}, content -oauth2.Http = MockHttp +oauth2.Http = MockHttp active_call = None + + class TestInstagramAPI(client.InstagramAPI): def __getattribute__(self, attr): global active_call @@ -62,6 +61,7 @@ def __getattribute__(self, attr): active_call = attr return actual_val + class InstagramAuthTests(unittest.TestCase): def setUp(self): self.unauthenticated_api = TestInstagramAPI(client_id=client_id, redirect_uri=redirect_uri, client_secret=client_secret) @@ -69,6 +69,7 @@ def setUp(self): def test_authorize_login_url(self): redirect_uri = self.unauthenticated_api.get_authorize_login_url() assert redirect_uri + print("Please visit and authorize at:\n%s" % redirect_uri) code = raw_input("Paste received code (blank to skip): ").strip() if not code: @@ -83,12 +84,13 @@ def test_xauth_exchange(self): username = raw_input("Enter username for XAuth (blank to skip): ").strip() if not username: return - password = getpass.getpass("Enter password for XAuth (blank to skip): ").strip() + + password = getpass.getpass("Enter password for XAuth (blank to skip): ").strip() access_token = self.unauthenticated_api.exchange_xauth_login_for_access_token(username, password) assert access_token -class InstagramAPITests(unittest.TestCase): +class InstagramAPITests(unittest.TestCase): def setUp(self): super(InstagramAPITests, self).setUp() self.client_only_api = TestInstagramAPI(client_id=client_id) @@ -98,8 +100,8 @@ def test_media_popular(self): self.api.media_popular(count=10) def test_media_search(self): - self.client_only_api.media_search(lat=37.7,lng=-122.22) - self.api.media_search(lat=37.7,lng=-122.22) + self.client_only_api.media_search(lat=37.7, lng=-122.22) + self.api.media_search(lat=37.7, lng=-122.22) def test_media_shortcode(self): self.client_only_api.media_shortcode('os1NQjxtvF') @@ -144,43 +146,39 @@ def test_user_liked_media(self): def test_user_recent_media(self): media, url = self.api.user_recent_media(count=10) - self.assertTrue( all( [hasattr(obj, 'type') for obj in media] ) ) + self.assertTrue(all([hasattr(obj, 'type') for obj in media])) image = media[0] self.assertEqual( - image.get_standard_resolution_url(), - "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_7.jpg") + image.get_standard_resolution_url(), + "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_7.jpg") self.assertEqual( - image.get_low_resolution_url(), - "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_6.jpg") + image.get_low_resolution_url(), + "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_6.jpg") self.assertEqual( - image.get_thumbnail_url(), - "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_5.jpg") + image.get_thumbnail_url(), + "http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_5.jpg") - self.assertEqual( False, hasattr(image, 'videos') ) + self.assertEqual(False, hasattr(image, 'videos')) video = media[1] self.assertEqual( - video.get_standard_resolution_url(), - video.videos['standard_resolution'].url) + video.get_standard_resolution_url(), + video.videos['standard_resolution'].url) self.assertEqual( - video.get_standard_resolution_url(), - "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_101.mp4") + video.get_standard_resolution_url(), + "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_101.mp4") self.assertEqual( - video.get_low_resolution_url(), - "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_102.mp4") + video.get_low_resolution_url(), + "http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_102.mp4") self.assertEqual( - video.get_thumbnail_url(), - "http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_5.jpg") - - - - + video.get_thumbnail_url(), + "http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_5.jpg") def test_user_search(self): self.api.user_search('mikeyk', 10) @@ -204,7 +202,7 @@ def test_location_recent_media(self): self.api.location_recent_media(location_id=1) def test_location_search(self): - self.api.location_search(lat=37.7,lng=-122.22, distance=2500) + self.api.location_search(lat=37.7, lng=-122.22, distance=2500) def test_location(self): self.api.location(1) @@ -225,12 +223,6 @@ def test_tag(self): def test_user_follows(self): self.api.user_follows() - def test_user_followed_by(self): - self.api.user_followed_by() - - def test_user_followed_by(self): - self.api.user_followed_by() - def test_user_requested_by(self): self.api.user_followed_by() @@ -246,6 +238,7 @@ def test_change_relationship(self): def test_geography_recent_media(self): self.api.geography_recent_media(geography_id=1) + if __name__ == '__main__': if not TEST_AUTH: del InstagramAuthTests From cfe9b14251472d3c2bd00d503b1a8cab32948164 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 12:58:48 +0100 Subject: [PATCH 08/28] Add test case for fixed logic --- fixtures/media_search.json | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/fixtures/media_search.json b/fixtures/media_search.json index b03cf157..cf95c2c0 100644 --- a/fixtures/media_search.json +++ b/fixtures/media_search.json @@ -594,6 +594,60 @@ "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_113603_75sq_1287035206.jpg", "id": "113603" } + }, + { + "type": "image", + "tags": [], + "location": { + "latitude": 37.775180799999987, + "id": "68841", + "longitude": -122.2270716, + "name": "El Novillo Taco Truck" + }, + "comments": { + "count": 1 + }, + "caption": { + "created_time": "1287585453", + "text": "Image with broken comment data ", + "from": { + "username": "darodriguez", + "first_name": "David", + "last_name": "Rodriguez", + "type": "user", + "id": "113603" + }, + "id": "495311" + }, + "link": "http://localhost:8000/p/C5Wr/", + "likes": { + "count": 0 + }, + "created_time": "1287585407", + "images": { + "low_resolution": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_6.jpg", + "width": 480, + "height": 480 + }, + "thumbnail": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_5.jpg", + "width": 150, + "height": 150 + }, + "standard_resolution": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_7.jpg", + "width": 612, + "height": 612 + } + }, + "user_has_liked": false, + "id": "759211", + "user": { + "username": "darodriguez", + "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_113603_75sq_1287035206.jpg", + "id": "113603" + } } ] } \ No newline at end of file From f04d1780c4a057f9f6f06ec46bf3a508e36060de Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 13:10:44 +0100 Subject: [PATCH 09/28] pep8 formatting --- instagram/models.py | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/instagram/models.py b/instagram/models.py index 4f04192b..3ee2f7a7 100644 --- a/instagram/models.py +++ b/instagram/models.py @@ -3,21 +3,17 @@ class ApiModel(object): - @classmethod def object_from_dictionary(cls, entry): # make dict keys all strings if entry is None: return "" + entry_str_dict = dict([(str(key), value) for key, value in entry.items()]) return cls(**entry_str_dict) def __repr__(self): return str(self) - # if six.PY2: - # return six.text_type(self).encode('utf8') - # else: - # return self.encode('utf8') def __str__(self): if six.PY3: @@ -27,7 +23,6 @@ def __str__(self): class Image(ApiModel): - def __init__(self, url, width, height): self.url = url self.height = height @@ -38,13 +33,11 @@ def __unicode__(self): class Video(Image): - def __unicode__(self): return "Video: %s" % self.url class Media(ApiModel): - def __init__(self, id=None, **kwargs): self.id = id for key, value in six.iteritems(kwargs): @@ -62,11 +55,9 @@ def get_low_resolution_url(self): else: return self.videos['low_resolution'].url - def get_thumbnail_url(self): return self.images['thumbnail'].url - def __unicode__(self): return "Media: %s" % self.id @@ -74,7 +65,6 @@ def __unicode__(self): def object_from_dictionary(cls, entry): new_media = Media(id=entry['id']) new_media.type = entry['type'] - new_media.user = User.object_from_dictionary(entry['user']) new_media.images = {} @@ -114,21 +104,19 @@ def object_from_dictionary(cls, entry): new_media.caption = None if entry['caption']: new_media.caption = Comment.object_from_dictionary(entry['caption']) - + new_media.tags = [] if entry['tags']: for tag in entry['tags']: new_media.tags.append(Tag.object_from_dictionary({'name': tag})) new_media.link = entry['link'] - new_media.filter = entry.get('filter') return new_media class MediaShortcode(Media): - def __init__(self, shortcode=None, **kwargs): self.shortcode = shortcode for key, value in six.iteritems(kwargs): @@ -181,11 +169,9 @@ def __init__(self, id, *args, **kwargs): def object_from_dictionary(cls, entry): point = None if 'latitude' in entry: - point = Point(entry.get('latitude'), - entry.get('longitude')) - location = Location(entry.get('id', 0), - point=point, - name=entry.get('name', '')) + point = Point(entry.get('latitude'), entry.get('longitude')) + + location = Location(entry.get('id', 0), point=point, name=entry.get('name', '')) return location def __unicode__(self): @@ -193,7 +179,6 @@ def __unicode__(self): class User(ApiModel): - def __init__(self, id, *args, **kwargs): self.id = id for key, value in six.iteritems(kwargs): @@ -204,7 +189,6 @@ def __unicode__(self): class Relationship(ApiModel): - def __init__(self, incoming_status="none", outgoing_status="none", target_user_is_private=False): self.incoming_status = incoming_status self.outgoing_status = outgoing_status From f2e1c3143f134831e222012ec283372c0c8ed049 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 13:19:31 +0100 Subject: [PATCH 10/28] Safely fetch entry data, by checking availability before calling --- instagram/models.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/instagram/models.py b/instagram/models.py index 3ee2f7a7..550305a5 100644 --- a/instagram/models.py +++ b/instagram/models.py @@ -68,25 +68,28 @@ def object_from_dictionary(cls, entry): new_media.user = User.object_from_dictionary(entry['user']) new_media.images = {} - for version, version_info in six.iteritems(entry['images']): - new_media.images[version] = Image.object_from_dictionary(version_info) + if entry.get('images'): + for version, version_info in six.iteritems(entry['images']): + new_media.images[version] = Image.object_from_dictionary(version_info) - if new_media.type == 'video': + if new_media.type == 'video' and entry.get('videos'): new_media.videos = {} for version, version_info in six.iteritems(entry['videos']): new_media.videos[version] = Video.object_from_dictionary(version_info) - if 'user_has_liked' in entry: + if entry.get('user_has_liked'): new_media.user_has_liked = entry['user_has_liked'] - new_media.like_count = entry['likes']['count'] + + new_media.like_count = entry.get('likes', {}).get('count', 0) new_media.likes = [] - if 'data' in entry['likes']: - for like in entry['likes']['data']: - new_media.likes.append(User.object_from_dictionary(like)) + if new_media.like_count: + if entry.get('likes', {}).get('data'): + for like in entry['likes']['data']: + new_media.likes.append(User.object_from_dictionary(like)) new_media.comment_count = entry.get('comments', {}).get('count', 0) + new_media.comments = [] if new_media.comment_count: - new_media.comments = [] if entry.get('comments', {}).get('data'): for comment in entry['comments']['data']: new_media.comments.append(Comment.object_from_dictionary(comment)) @@ -98,15 +101,15 @@ def object_from_dictionary(cls, entry): new_media.created_time = timestamp_to_datetime(entry['created_time']) - if entry['location'] and 'id' in entry: + if entry.get('location') and entry.get('id'): new_media.location = Location.object_from_dictionary(entry['location']) new_media.caption = None - if entry['caption']: + if entry.get('caption'): new_media.caption = Comment.object_from_dictionary(entry['caption']) new_media.tags = [] - if entry['tags']: + if entry.get('tags'): for tag in entry['tags']: new_media.tags.append(Tag.object_from_dictionary({'name': tag})) From e40306cc4200861cca4b2e88831b4aa07a797d7d Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 13:21:31 +0100 Subject: [PATCH 11/28] Add test case for missing field videos --- fixtures/media_search.json | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/fixtures/media_search.json b/fixtures/media_search.json index cf95c2c0..38c1f171 100644 --- a/fixtures/media_search.json +++ b/fixtures/media_search.json @@ -648,6 +648,60 @@ "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_113603_75sq_1287035206.jpg", "id": "113603" } + }, + { + "type": "video", + "tags": [], + "location": { + "latitude": 37.775180799999987, + "id": "68841", + "longitude": -122.2270716, + "name": "El Novillo Taco Truck" + }, + "comments": { + "count": 0 + }, + "caption": { + "created_time": "1287585453", + "text": "Type video without having videos in data", + "from": { + "username": "darodriguez", + "first_name": "David", + "last_name": "Rodriguez", + "type": "user", + "id": "113603" + }, + "id": "495311" + }, + "link": "http://localhost:8000/p/C5Wr/", + "likes": { + "count": 0 + }, + "created_time": "1287585407", + "images": { + "low_resolution": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_6.jpg", + "width": 480, + "height": 480 + }, + "thumbnail": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_5.jpg", + "width": 150, + "height": 150 + }, + "standard_resolution": { + "url": "http://distillery-dev.s3.amazonaws.com/media/2010/10/20/1fde15405b6349ef949c9a8f5498868e_7.jpg", + "width": 612, + "height": 612 + } + }, + "user_has_liked": false, + "id": "759211", + "user": { + "username": "darodriguez", + "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_113603_75sq_1287035206.jpg", + "id": "113603" + } } ] } \ No newline at end of file From bbca28d7a8177d953a3f48213bd7480c5d4a95f6 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 13:34:12 +0100 Subject: [PATCH 12/28] pep8 formatting --- instagram/oauth2.py | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/instagram/oauth2.py b/instagram/oauth2.py index 002032a4..c9ceee0b 100644 --- a/instagram/oauth2.py +++ b/instagram/oauth2.py @@ -54,8 +54,7 @@ def exchange_user_id_for_access_token(self, user_id): def exchange_xauth_login_for_access_token(self, username, password, scope=None): """ scope should be a tuple or list of requested scope access levels """ req = OAuth2AuthExchangeRequest(self) - return req.exchange_for_access_token(username=username, password=password, - scope=scope) + return req.exchange_for_access_token(username=username, password=password, scope=scope) class OAuth2AuthExchangeRequest(object): @@ -68,8 +67,10 @@ def _url_for_authorize(self, scope=None): "response_type": "code", "redirect_uri": self.api.redirect_uri } + if scope: client_params.update(scope=' '.join(scope)) + url_params = urlencode(client_params) return "%s?%s" % (self.api.authorize_url, url_params) @@ -80,6 +81,7 @@ def _data_for_exchange(self, code=None, username=None, password=None, scope=None "redirect_uri": self.api.redirect_uri, "grant_type": "authorization_code" } + if code: client_params.update(code=code) elif username and password: @@ -88,8 +90,10 @@ def _data_for_exchange(self, code=None, username=None, password=None, scope=None grant_type="password") if scope: client_params.update(scope=' '.join(scope)) + elif user_id: client_params.update(user_id=user_id) + return urlencode(client_params) def get_authorize_url(self, scope=None): @@ -102,18 +106,22 @@ def get_authorize_login_url(self, scope=None): response, content = http_object.request(url) if response['status'] != '200': raise OAuth2AuthExchangeError("The server returned a non-200 response for URL %s" % url) - redirected_to = response['content-location'] + + redirected_to = response['Content-Location'] return redirected_to def exchange_for_access_token(self, code=None, username=None, password=None, scope=None, user_id=None): data = self._data_for_exchange(code, username, password, scope=scope, user_id=user_id) http_object = Http(disable_ssl_certificate_validation=True) url = self.api.access_token_url - headers={"Content-Type":"application/x-www-form-urlencoded"} + + headers = {"Content-Type": "application/x-www-form-urlencoded"} response, content = http_object.request(url, method="POST", body=data, headers=headers) parsed_content = simplejson.loads(content.decode()) + if int(response['status']) != 200: raise OAuth2AuthExchangeError(parsed_content.get("error_message", "")) + return parsed_content['access_token'], parsed_content['user'] @@ -137,15 +145,12 @@ def post_request(self, path, **kwargs): return self.make_request(self.prepare_request("POST", path, kwargs)) def _full_url(self, path, include_secret=False, include_signed_request=True): - return "%s://%s%s%s%s%s" % (self.api.protocol, - self.api.host, - self.api.base_path, - path, - self._auth_query(include_secret), - self._signed_request(path, {}, include_signed_request, include_secret)) + return "%s://%s%s%s%s%s" % (self.api.protocol, self.api.host, self.api.base_path, path, + self._auth_query(include_secret), + self._signed_request(path, {}, include_signed_request, include_secret)) def _full_url_with_params(self, path, params, include_secret=False, include_signed_request=True): - return (self._full_url(path, include_secret) + + return (self._full_url(path, include_secret) + self._full_query_with_params(params) + self._signed_request(path, params, include_signed_request, include_secret)) @@ -168,8 +173,10 @@ def _signed_request(self, path, params, include_signed_request, include_secret): params['access_token'] = self.api.access_token elif self.api.client_id: params['client_id'] = self.api.client_id + if include_secret and self.api.client_secret: params['client_secret'] = self.api.client_secret + return "&sig=%s" % self._generate_sig(path, params, self.api.client_secret) else: return '' @@ -200,6 +207,7 @@ def encode_file(field_name): lines.extend(encode_field(field)) for field in files: lines.extend(encode_file(field)) + lines.extend(("--%s--" % (boundary), "")) body = "\r\n".join(lines) @@ -219,7 +227,7 @@ def prepare_request(self, method, path, params, include_secret=False): if not params.get('files'): if method == "POST": body = self._post_body(params) - headers = {'Content-type': 'application/x-www-form-urlencoded'} + headers = {'Content-Type': 'application/x-www-form-urlencoded'} url = self._full_url(path, include_secret) else: url = self._full_url_with_params(path, params, include_secret) @@ -231,9 +239,11 @@ def prepare_request(self, method, path, params, include_secret=False): def make_request(self, url, method="GET", body=None, headers=None): headers = headers or {} - if not 'User-Agent' in headers: + if 'User-Agent' not in headers: headers.update({"User-Agent": "%s Python Client" % self.api.api_name}) + # https://github.com/jcgregorio/httplib2/issues/173 # bug in httplib2 w/ Python 3 and disable_ssl_certificate_validation=True - http_obj = Http() if six.PY3 else Http(disable_ssl_certificate_validation=True) + http_obj = Http() if six.PY3 else Http(disable_ssl_certificate_validation=True) + return http_obj.request(url, method, body=body, headers=headers) From 08096be8e02c20f43c88bd5b2c257aa8f345c0c9 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 13:54:54 +0100 Subject: [PATCH 13/28] Clean up and use six directly --- instagram/models.py | 32 +++++++++++--------------- python_instagram.egg-info/requires.txt | 3 ++- requirements.txt | 1 - 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/instagram/models.py b/instagram/models.py index 550305a5..e1fa888b 100644 --- a/instagram/models.py +++ b/instagram/models.py @@ -68,36 +68,31 @@ def object_from_dictionary(cls, entry): new_media.user = User.object_from_dictionary(entry['user']) new_media.images = {} - if entry.get('images'): - for version, version_info in six.iteritems(entry['images']): - new_media.images[version] = Image.object_from_dictionary(version_info) + for version, version_info in six.iteritems(entry.get('images', {})): + new_media.images[version] = Image.object_from_dictionary(version_info) - if new_media.type == 'video' and entry.get('videos'): + if new_media.type == 'video': new_media.videos = {} - for version, version_info in six.iteritems(entry['videos']): + for version, version_info in six.iteritems(entry.get('videos', {})): new_media.videos[version] = Video.object_from_dictionary(version_info) - if entry.get('user_has_liked'): - new_media.user_has_liked = entry['user_has_liked'] + new_media.user_has_liked = entry.get('user_has_liked', False) new_media.like_count = entry.get('likes', {}).get('count', 0) new_media.likes = [] if new_media.like_count: - if entry.get('likes', {}).get('data'): - for like in entry['likes']['data']: - new_media.likes.append(User.object_from_dictionary(like)) + for like in entry.get('likes', {}).get('data', []): + new_media.likes.append(User.object_from_dictionary(like)) new_media.comment_count = entry.get('comments', {}).get('count', 0) new_media.comments = [] if new_media.comment_count: - if entry.get('comments', {}).get('data'): - for comment in entry['comments']['data']: - new_media.comments.append(Comment.object_from_dictionary(comment)) + for comment in entry.get('comments', {}).get('data', []): + new_media.comments.append(Comment.object_from_dictionary(comment)) new_media.users_in_photo = [] - if entry.get('users_in_photo'): - for user_in_photo in entry['users_in_photo']: - new_media.users_in_photo.append(UserInPhoto.object_from_dictionary(user_in_photo)) + for user_in_photo in entry.get('users_in_photo', []): + new_media.users_in_photo.append(UserInPhoto.object_from_dictionary(user_in_photo)) new_media.created_time = timestamp_to_datetime(entry['created_time']) @@ -109,9 +104,8 @@ def object_from_dictionary(cls, entry): new_media.caption = Comment.object_from_dictionary(entry['caption']) new_media.tags = [] - if entry.get('tags'): - for tag in entry['tags']: - new_media.tags.append(Tag.object_from_dictionary({'name': tag})) + for tag in entry.get('tags', []): + new_media.tags.append(Tag.object_from_dictionary({'name': tag})) new_media.link = entry['link'] new_media.filter = entry.get('filter') diff --git a/python_instagram.egg-info/requires.txt b/python_instagram.egg-info/requires.txt index b85397f3..34b941ea 100644 --- a/python_instagram.egg-info/requires.txt +++ b/python_instagram.egg-info/requires.txt @@ -1,2 +1,3 @@ simplejson -httplib2 \ No newline at end of file +httplib2 +six \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c0eed9ba..a57426b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ bottle==0.12.7 httplib2==0.9 -python-instagram==1.1.3 redis==2.10.3 simplejson==3.6.3 beaker==1.6.4 From daa9854f54ac8ec6f76db86345c882e1f807703d Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 14:12:01 +0100 Subject: [PATCH 14/28] Fix travis build --- .travis.yml | 1 - instagram/models.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cadb27c..ed2b151c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,3 @@ python: install: - "pip install ." script: "python tests.py" - diff --git a/instagram/models.py b/instagram/models.py index e1fa888b..87a73111 100644 --- a/instagram/models.py +++ b/instagram/models.py @@ -91,7 +91,7 @@ def object_from_dictionary(cls, entry): new_media.comments.append(Comment.object_from_dictionary(comment)) new_media.users_in_photo = [] - for user_in_photo in entry.get('users_in_photo', []): + for user_in_photo in entry.get('users_in_photo') or []: new_media.users_in_photo.append(UserInPhoto.object_from_dictionary(user_in_photo)) new_media.created_time = timestamp_to_datetime(entry['created_time']) From 22f062f27ba83869981fa2d0db66bfde1f33fdf4 Mon Sep 17 00:00:00 2001 From: Kaviraj Date: Mon, 17 Aug 2015 20:25:48 +0530 Subject: [PATCH 15/28] Cherry pick 75c32cf1db32650a05236220758df369423e8c58 --- instagram/helper.py | 4 +++- tests.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/instagram/helper.py b/instagram/helper.py index 62bcf5b5..ef96d53a 100644 --- a/instagram/helper.py +++ b/instagram/helper.py @@ -1,9 +1,11 @@ import calendar from datetime import datetime +import pytz def timestamp_to_datetime(ts): - return datetime.utcfromtimestamp(float(ts)) + naive = datetime.utcfromtimestamp(float(ts)) + return naive.replace(tzinfo=pytz.UTC) def datetime_to_timestamp(dt): diff --git a/tests.py b/tests.py index 6b0d43b0..f0715c91 100755 --- a/tests.py +++ b/tests.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import types import six +import pytz try: import simplejson as json @@ -10,6 +11,7 @@ import unittest from six.moves.urllib.parse import urlparse, parse_qs from instagram import client, oauth2, InstagramAPIError +from instagram.helper import timestamp_to_datetime TEST_AUTH = False client_id = "DEBUG" @@ -239,6 +241,16 @@ def test_geography_recent_media(self): self.api.geography_recent_media(geography_id=1) +class InstagramHelperTests(unittest.TestCase): + def setUp(self): + self.timestamp = 1439822186 + + def test_timestamp_to_datetime(self): + date_time = timestamp_to_datetime(float(self.timestamp)) + self.assertIsNotNone(date_time.tzinfo) + self.assertEqual(date_time.tzinfo, pytz.UTC) + + if __name__ == '__main__': if not TEST_AUTH: del InstagramAuthTests From 5bd95e632f959e820571092f5bc670a32c7feb7b Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 14:28:13 +0100 Subject: [PATCH 16/28] Cherry pick a28e4b7493f47913bf2b91876cd28b5c5ffa503f and also add in requires.txt --- python_instagram.egg-info/requires.txt | 3 ++- requirements.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python_instagram.egg-info/requires.txt b/python_instagram.egg-info/requires.txt index 34b941ea..eb906474 100644 --- a/python_instagram.egg-info/requires.txt +++ b/python_instagram.egg-info/requires.txt @@ -1,3 +1,4 @@ simplejson httplib2 -six \ No newline at end of file +six +pytz \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a57426b8..bae04fca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ redis==2.10.3 simplejson==3.6.3 beaker==1.6.4 six==1.8.0 +pytz==2015.4 \ No newline at end of file From 537735d2837c81be929eb3f9f9b60f04abad9ea6 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 14:32:50 +0100 Subject: [PATCH 17/28] Incorrect place to add pytz requirement, needs setup.py --- python_instagram.egg-info/requires.txt | 2 +- requirements.txt | 2 +- setup.py | 29 ++++++++++++++++---------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/python_instagram.egg-info/requires.txt b/python_instagram.egg-info/requires.txt index eb906474..14223b98 100644 --- a/python_instagram.egg-info/requires.txt +++ b/python_instagram.egg-info/requires.txt @@ -1,4 +1,4 @@ simplejson httplib2 six -pytz \ No newline at end of file +pytz diff --git a/requirements.txt b/requirements.txt index bae04fca..0bc7b0e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,4 @@ redis==2.10.3 simplejson==3.6.3 beaker==1.6.4 six==1.8.0 -pytz==2015.4 \ No newline at end of file +pytz==2015.4 diff --git a/setup.py b/setup.py index b0187529..898d620f 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,21 @@ #!/usr/bin/env python from setuptools import setup, find_packages -setup(name="python-instagram", - version="1.3.2", - description="Instagram API client", - license="MIT", - install_requires=["simplejson","httplib2","six"], - author="Instagram, Inc", - author_email="apidevelopers@instagram.com", - url="http://github.com/Instagram/python-instagram", - packages = find_packages(), - keywords= "instagram", - zip_safe = True) +setup( + name="python-instagram", + version="1.3.2", + description="Instagram API client", + license="MIT", + install_requires=[ + "simplejson", + "httplib2", + "six", + "pytz", + ], + author="Instagram, Inc", + author_email="apidevelopers@instagram.com", + url="http://github.com/Instagram/python-instagram", + packages=find_packages(), + keywords="instagram", + zip_safe=True +) From f33638e57b29f6ff1787371fd745bed9c6b24318 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 14:35:38 +0100 Subject: [PATCH 18/28] Support python 2.6 for tests --- tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.py b/tests.py index f0715c91..21629fc8 100755 --- a/tests.py +++ b/tests.py @@ -247,7 +247,7 @@ def setUp(self): def test_timestamp_to_datetime(self): date_time = timestamp_to_datetime(float(self.timestamp)) - self.assertIsNotNone(date_time.tzinfo) + self.assertTrue(date_time.tzinfo is not None) self.assertEqual(date_time.tzinfo, pytz.UTC) From 248f55acfa3f4f9206bfab175cb781efc4e72a3f Mon Sep 17 00:00:00 2001 From: Colin Stolley Date: Mon, 5 Oct 2015 09:38:42 -0500 Subject: [PATCH 19/28] Cherry pick 93cd4fd4fbf0c3b3d1e050fbc950089aba1c23e3 --- README.md | 18 ++++++++++++++++++ instagram/oauth2.py | 12 ++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8802fc1f..03af94dc 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,24 @@ except InstagramAPIError as e: print "\nUser is set to private." ``` +Setting Timeouts +------ +By default there is no timeout for requests to the Instagram API. You can specify a timeout in one of two ways: +``` python +from instagram.client import InstagramAPI + +# set a 30-second timeout for this particular InstagramAPI instance +api = InstagramAPI(access_token=access_token, client_secret=client_secret, timeout=30) +``` +or +``` python +import socket + +# Set the global default timeout, which applies to all sockets in your +# program where a timeout is not otherwise specified. +socket.setdefaulttimeout(30) +``` + Trouble Shooting ------ diff --git a/instagram/oauth2.py b/instagram/oauth2.py index c9ceee0b..8211a06d 100644 --- a/instagram/oauth2.py +++ b/instagram/oauth2.py @@ -27,12 +27,13 @@ class OAuth2API(object): # override with 'Instagram', etc api_name = "Generic API" - def __init__(self, client_id=None, client_secret=None, client_ips=None, access_token=None, redirect_uri=None): + def __init__(self, client_id=None, client_secret=None, client_ips=None, access_token=None, redirect_uri=None, timeout=None): self.client_id = client_id self.client_secret = client_secret self.client_ips = client_ips self.access_token = access_token self.redirect_uri = redirect_uri + self.timeout = timeout def get_authorize_url(self, scope=None): req = OAuth2AuthExchangeRequest(self) @@ -100,7 +101,7 @@ def get_authorize_url(self, scope=None): return self._url_for_authorize(scope=scope) def get_authorize_login_url(self, scope=None): - http_object = Http(disable_ssl_certificate_validation=True) + http_object = Http(timeout=self.api.timeout, disable_ssl_certificate_validation=True) url = self._url_for_authorize(scope=scope) response, content = http_object.request(url) @@ -112,7 +113,7 @@ def get_authorize_login_url(self, scope=None): def exchange_for_access_token(self, code=None, username=None, password=None, scope=None, user_id=None): data = self._data_for_exchange(code, username, password, scope=scope, user_id=user_id) - http_object = Http(disable_ssl_certificate_validation=True) + http_object = Http(timeout=self.api.timeout, disable_ssl_certificate_validation=True) url = self.api.access_token_url headers = {"Content-Type": "application/x-www-form-urlencoded"} @@ -244,6 +245,9 @@ def make_request(self, url, method="GET", body=None, headers=None): # https://github.com/jcgregorio/httplib2/issues/173 # bug in httplib2 w/ Python 3 and disable_ssl_certificate_validation=True - http_obj = Http() if six.PY3 else Http(disable_ssl_certificate_validation=True) + if six.PY3: + http_obj = Http(timeout=self.api.timeout) + else: + http_obj = Http(timeout=self.api.timeout, disable_ssl_certificate_validation=True) return http_obj.request(url, method, body=body, headers=headers) From ef43834d60904bb0a99dbf6c21d54dc30a6564fe Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:13:05 +0100 Subject: [PATCH 20/28] Raise SkipTest instead of del AuthTests and make test pass on case-sensitive systems --- tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests.py b/tests.py index 21629fc8..8ff3cf7d 100755 --- a/tests.py +++ b/tests.py @@ -34,7 +34,7 @@ def request(self, url, method="GET", body=None, headers={}): if fn_name == 'get_authorize_login_url': return { 'status': '200', - 'content-location': 'http://example.com/redirect/login' + 'Content-Location': 'http://example.com/redirect/login' }, None if 'access_token' not in options and 'client_id' not in options: @@ -66,6 +66,9 @@ def __getattribute__(self, attr): class InstagramAuthTests(unittest.TestCase): def setUp(self): + if not TEST_AUTH: + raise unittest.SkipTest() + self.unauthenticated_api = TestInstagramAPI(client_id=client_id, redirect_uri=redirect_uri, client_secret=client_secret) def test_authorize_login_url(self): @@ -252,7 +255,4 @@ def test_timestamp_to_datetime(self): if __name__ == '__main__': - if not TEST_AUTH: - del InstagramAuthTests - unittest.main() From d3bc7d7232dcffec37fd73775584b7fdd62984b9 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:18:47 +0100 Subject: [PATCH 21/28] Cherry pick 2d5768b6f71f4312da0bf4084a6ca1fb7eba7525 --- instagram/oauth2.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/instagram/oauth2.py b/instagram/oauth2.py index 8211a06d..d3fa624e 100644 --- a/instagram/oauth2.py +++ b/instagram/oauth2.py @@ -131,9 +131,12 @@ def __init__(self, api): self.api = api def _generate_sig(self, endpoint, params, secret): - sig = endpoint - for key in sorted(params.keys()): - sig += '|%s=%s' % (key, params[key]) + # handle unicode when signing, urlencode can't handle otherwise. + def enc_if_str(p): + return p.encode('utf-8') if isinstance(p, unicode) else p + + p = ''.join('|{}={}'.format(k, enc_if_str(params[k])) for k in sorted(params.keys())) + sig = '{}{}'.format(endpoint, p) return hmac.new(secret.encode(), sig.encode(), sha256).hexdigest() def url_for_get(self, path, parameters): @@ -229,7 +232,7 @@ def prepare_request(self, method, path, params, include_secret=False): if method == "POST": body = self._post_body(params) headers = {'Content-Type': 'application/x-www-form-urlencoded'} - url = self._full_url(path, include_secret) + url = self._full_url_with_params(path, params, include_secret) else: url = self._full_url_with_params(path, params, include_secret) else: From b283cb955725ff03d75b2f27e6fc1e04c42f1bf9 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:20:13 +0100 Subject: [PATCH 22/28] Remove now obsolete else --- instagram/oauth2.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/instagram/oauth2.py b/instagram/oauth2.py index d3fa624e..b5db0fe9 100644 --- a/instagram/oauth2.py +++ b/instagram/oauth2.py @@ -232,9 +232,8 @@ def prepare_request(self, method, path, params, include_secret=False): if method == "POST": body = self._post_body(params) headers = {'Content-Type': 'application/x-www-form-urlencoded'} - url = self._full_url_with_params(path, params, include_secret) - else: - url = self._full_url_with_params(path, params, include_secret) + + url = self._full_url_with_params(path, params, include_secret) else: body, headers = self._encode_multipart(params, params['files']) url = self._full_url(path) From 6b07bdff1426eb974109e6a1d22dbf18c28ab35e Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:27:41 +0100 Subject: [PATCH 23/28] Skip AuthTests in a python 2.6 friendly way --- tests.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests.py b/tests.py index 8ff3cf7d..f7db3227 100755 --- a/tests.py +++ b/tests.py @@ -64,11 +64,9 @@ def __getattribute__(self, attr): return actual_val +@unittest.skipUnless(TEST_AUTH, 'Skipping InstagramAuthTests') class InstagramAuthTests(unittest.TestCase): def setUp(self): - if not TEST_AUTH: - raise unittest.SkipTest() - self.unauthenticated_api = TestInstagramAPI(client_id=client_id, redirect_uri=redirect_uri, client_secret=client_secret) def test_authorize_login_url(self): From 97af5fb95c1a6139d0009ee3d57dd6193519511c Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:38:14 +0100 Subject: [PATCH 24/28] All forms of skipping are not there, don't want to import unittest2.. try old way --- tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests.py b/tests.py index f7db3227..e88b3e0b 100755 --- a/tests.py +++ b/tests.py @@ -253,4 +253,7 @@ def test_timestamp_to_datetime(self): if __name__ == '__main__': + if not TEST_AUTH: + del InstagramAuthTests + unittest.main() From 9702c7f1194848fefef86ebd8061b3160cac019b Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 15:42:55 +0100 Subject: [PATCH 25/28] Revert previous attempt; try within the class --- tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests.py b/tests.py index e88b3e0b..d18e26fa 100755 --- a/tests.py +++ b/tests.py @@ -64,9 +64,11 @@ def __getattribute__(self, attr): return actual_val -@unittest.skipUnless(TEST_AUTH, 'Skipping InstagramAuthTests') class InstagramAuthTests(unittest.TestCase): def setUp(self): + if not TEST_AUTH: + raise unittest.SkipTest() + self.unauthenticated_api = TestInstagramAPI(client_id=client_id, redirect_uri=redirect_uri, client_secret=client_secret) def test_authorize_login_url(self): From db766d697263c1058768b06645624cab531dd2d4 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 16:03:37 +0100 Subject: [PATCH 26/28] Toss and ignore old folders --- .gitignore | 2 ++ dist/python-instagram-1.0.0.tar.gz | Bin 8017 -> 0 bytes dist/python-instagram-1.0.1.tar.gz | Bin 8165 -> 0 bytes dist/python-instagram-1.1.0.tar.gz | Bin 8164 -> 0 bytes dist/python-instagram-1.1.1.tar.gz | Bin 8227 -> 0 bytes dist/python-instagram-1.1.2.tar.gz | Bin 8240 -> 0 bytes python_instagram.egg-info/PKG-INFO | 11 ----------- python_instagram.egg-info/SOURCES.txt | 15 --------------- python_instagram.egg-info/dependency_links.txt | 1 - python_instagram.egg-info/requires.txt | 4 ---- python_instagram.egg-info/top_level.txt | 1 - python_instagram.egg-info/zip-safe | 1 - 12 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 dist/python-instagram-1.0.0.tar.gz delete mode 100644 dist/python-instagram-1.0.1.tar.gz delete mode 100644 dist/python-instagram-1.1.0.tar.gz delete mode 100644 dist/python-instagram-1.1.1.tar.gz delete mode 100644 dist/python-instagram-1.1.2.tar.gz delete mode 100644 python_instagram.egg-info/PKG-INFO delete mode 100644 python_instagram.egg-info/SOURCES.txt delete mode 100644 python_instagram.egg-info/dependency_links.txt delete mode 100644 python_instagram.egg-info/requires.txt delete mode 100644 python_instagram.egg-info/top_level.txt delete mode 100644 python_instagram.egg-info/zip-safe diff --git a/.gitignore b/.gitignore index bf3ba0be..17611746 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .DS_Store *.swp test_settings.py +dist +*.egg-info diff --git a/dist/python-instagram-1.0.0.tar.gz b/dist/python-instagram-1.0.0.tar.gz deleted file mode 100644 index 10c8c6b4235cf09c44cf98ff6434fbf2920d1bc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8017 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 Q5|lDf$yOKc1`h6j0P~{U@c;k- diff --git a/dist/python-instagram-1.0.1.tar.gz b/dist/python-instagram-1.0.1.tar.gz deleted file mode 100644 index 8d63ba3486fc80db466e183ecbc2b1d65edf0eb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8165 zcma*sb6Xt@1Ay^tTg&#c?Pa&L(=wOcsbwzPwp;FGW7)Pl+2?&e!u#L-74GXt5sidI zG!Ux=12MO8b>sNu?Pl%d$Y$f{>ISfK0XVRIW#?r7%I*emfw~m6b6pome5p3=12BKH zkxOL*ah;1U)^a$L3oB+TWw&qMw&^!3e9KlS4l90NF{-@s+8aP`H|1flywT_nD_c+;HmCU zBkNShVUbmmfD+1Wvn&e67_8y!QW5^=!Fx&9wEf})?Sh~#>6ET&1*Wz2H4W%^y{cNaY55Lt z+m#vPM5htwXcQoB;RqfRIU{Q(Q!vn;Y#OBc2sH}c(6@skApXkH)-Aoy1LjI=F{P$K#zVY4t^%=eA zOWlwW6u3q3i1A~b+W@6KI!$!*?>)f-AT|_*2kqP^*PkZFCjd%d*C!cV$C8O5!3-1+s@zv?9Glq3 zLDwdQ)Y4Ejo0>&N6A3D6+~UWhCY~{x>0ex#QwJ7UE?1b$ub7&#Vek8a!#q! zffmJj^s0>qNv`BX-0)-l9XKI>fC-lKP>LsXv%K{(eBflR(t1NAS=&adu8{<4+tc(D zt<#--zbXJncLR;uxLU9sktR)lyNeB&Z2U@p+<1r+a2IA{k>Xi9J&40rT=02VmC+}j zH@Aop*7Fv7k$3&Z@QrJ7jLAAaJGBad} zm%X$R$us&jsbo56K|_fm4Y0@5c4{*PQRMebmW^6ztZUNzR7@3Q2obJlX6Jm263CEe z+jmIVT#2^k5if~xQdrcQ+iT*^E@Q1sg%+ZA<(ec^kD8o&Tx+64C;%*GZY1%zmrA+> z=RhwgMs188HxZj7Z>mmEo*tjbQ8WJRB3i?MlzG2B^0eTE3pH@XhE)~4=B9;aY#`Gc z;DzwhHFDNT%jPUK)&?uLydsiZ?S>qV6fk5uW!S*#e=^tr##k-5c&tsL#;9C#Mf9U0 z%CTm_H#K@+?Ex}&KG;^_6O_@xcgO$)f4bRDC`SzXB)+OPBEvSCpe2b1GF8k|2OcF~;)JZZ%0 zS50=}vUu*{G(Rktmi{(3ex^l(qF|}nI%?+K1Z%5#SQ)*!O>D4biV2Q! z3)2Go?^CWUr854w+5xW+b6!M|qM3@PR&=g!4qXb|>9PZigHGB6kh0}B!PulnrqJ8hu{9wHZy zQOlj{z-Dw<_a1^J1YD%*O0j%@TO2jXWhCd6hbOmOWNt4E+exeR=$zknJZQ#N2-GC6 zOe$!x!$JiLTnK{F=?gwdJVW!AKIgJrb|olD7pvBBhest%>m*ZY88)8=NnVV)u7fpg$-* z`=9ry$K(5zOC@Or+!VBBp#r0&x1x-!@a(%-8%F9EU>_ohs9|PmSx9imu^)s+r8?IQ zM@>;(-)F^u=em@zVTsUzlA?C?dS6ns>%HK~>GSl`A9RB_7-!Dwdsr{^zBM8V*<8q3 z;SHlp9L;mM`? zntiG6Ge(MiZ;|ZJP?2-kv3GJXXg4gsD4i;m0vFrXN&uW5Ho*Vf9`)|Pakt)Bi!Ua2vhH=qC_wYCTW+&Ov2qFZVd%1*1x z3+K^nE9Wv(5IlI_k~)+V2pM_NLUsDJzdjn$rO}Ga5LoW^-zn>j8O&3me%%X7eZ;aA z{L1rcjTU5YIL@LDE8#9dN@KgHISib?NTdJKLSE>hw5GN;E-e*TNXN@rG7_eV0}CM5xK28zc)g$)I-K*Y5t9Q34Rb)Tu!(SR*Qbc)^v(y8gkTvTs|e95IV}q!%NZXV2<6~>eWc2aKYkI&ZTar>Cl@4kkC`Vb>;v2biNF7P zempri8IU)s=p1m%&3}Sk^^cQ&s(t{U+zd47;jaSws+%Vbsvf}eZ%-o>s&Tn*9C6}Z zq9Rn@B1YA{jl)M;3#AHA<&MypZFUm^QyLqcZJdO#(5-$I&W9qSr+m0at6dlKWokuPj!T_9=>FM-z>2Z37G^89G9}KqAtOeVR=W zF!S%nZh+FSJc2fp3tYu5-W%reH7?ItIzSl%CqMlhK@JcA_tNCXmj`zOqV}~kSRxQz6e#9ik`gf&-){2!9m_D1hI;Ij3hb!Zb8Wnm7BF88MgA zg4Op{ykg8BU&pac0TgNIA|RE3bvx@oeK(h$?4{Es>fz;5yP}vmmUjwl4RBBf%)(PA znVn&thP1N}S3d`Pvd6T*5HPoBn2w$++nn5F{DfKD#0T(!>YbkNcMV`qw3k54MT}&L z+ceQwZ*w`^qF`C$f_*3M`|E<2!PKjzT=@tsTzDY1EI>u1Ub`n!X@EYpy zU{K84!iR=z_ljU9g@hW@XJ(P)VR+SD45<( zrIIPB-DFZ3^E}4Rgy0|ckE;N`Z~521Vo=LjV()PFeZS`z7vHf$EaFJHwZRGGMvfc| z(5T@!&gs7{=@oVzNP0gvlAK=hAhj5T$% zo1uQ|oR0H`v0Wd}=wqdyi9fuqwKzyD?P%&vwimuwcJ<;MHU9OQy(!dEhWVBwKnynS z@N@4@NvY0Exa2`kqGY-I!(D;KkT9-CCN8iCy?SfI~r@TJSWXs zCdb^wetPGA;$V7ND}U8Vbu2}lDDC$oCu>$_rMhPE_TiUpIrPh<*@pkyUms0M)kH=^ z+ofgx^C|?TtXTkM1_a(g$WB1^pB$$C`oomnnopG2V($y_j%>({weDZcuWGuCW86)R z$NBbtwL0+!c)Uv-Be#u-efFs(X}_-)yuFa&bi*W}G7>GTpz~!#f+ucYyu~KX8oT%A zF>GDsQI693{jv+sZ_@^~m$>)KE?65oV+=MZ^A^WPjL;*iUCD(PqxMzS%iJ7m(zlJ#X$5XgUfBG)?-lhwUO)Gxu6n>88=0BLF4){ z2}|A0m3;D_26G!hFA8jh?KT-M8~5v_xWS{vj_jjsgwl(Ak0J|VE1dGdHHl27M$KqP zz4nhR$t8~-b!10nxkN4}BjXl*72zP^SmD{=S4d3J80+}eEX2yrt_)N(0$ks++Y=Wp zhF~fyP=>)0EV0402W6dZOoc-%XMYZg2`dETf$Rv|Nx~yRCsWZ>Qurlngh@P%oZ^`B z15MOjT!#APP~N1z=@vYpPX~ry^Hd5w$`VkYxIas9C7BY z`?_#(Z1&)>L16flOOGRlhC5=*Ce!duJO)zk)LVCSO38knkl)t+`*!##5OV}FtqSy| zI0`s}bgsuh5ThYV?jm9v)$^S<`J&lFP6>3)zkUI!oHEKdO^@}+=15g<*+p-e*p4Xn zcaKK?i^6zH^tP(46aB-cxx7)JOKp=X zw*C`}C&bMvA1M8{?xgeF7z(>&*>v_JfVGR(pJk--eJe>ySv6Q=;ppB3>o%TDvOQ|R zEXGQ0Z?^4U5wWH?;02GwTbVoQ4)9!3BKwRI8O{BYd~O+A7pJX263`1Hd;1FiU3?gj z{8y12zpUh!;+RsKxo;^(`(AuTN~M|j@JSY)ZU9z1_^ss$Z}q%@mP`EM!G zJt?uA$+61xyo|=dV>~O}pR~Dp4#srXt~d#j;nz72=6w2OX?HltJy>zSF-Rn@k#X_w zzboiVmLuWqzub!;??u*J{0S&v~kq-UrLnoT0NqVT77 z!-$$WU_^c(e79-E1`{ZG<3sm7bk3QM3)3J%y4w(>l>($Tc&#EsnC%+&@qSgc3mg>x zO|;OL06+tf9oz$T3-haF-Ho4@(7b|0eovFp0ax0u9|vM%K$nRhH~LI3 z(l6P}YwEu3g?@R%Ezbz8;Ap|HjEv&32){*n)ESuOUDFn{F507=Z9S><=Eq(eacD>H zL{BA|iK7bMln58FDXiW_6P+jY#+%R0Qm|E6aig*pIfKsP!5FIMbbLr1W81$|Ird&( zXqrawQ!24RZHNG(lg_flcYaDB%N=DCCT+U8(wR{12HLPj7cYx5l@mX)r$Z=ag1fac zrafTHpK;)fm^#3JsY(%EMzN)fQ;;S;)ql&DYQ~tyM!za33+lSVm?4L-XyMlA*5Ph{ zBhLa%7ole`bm@rk8mR>{DXpkcE4aB zbf5LH9lj2!aF0#%lO+m63!>Odtk=8AI?gIo8=hhvA6n>zsqW1yvO9Y=eCw#@#Q8Mq zh)*-w9aep*x{6g2!t3rPq6)iqRs;Y-;^;<#urVKQ*bh;;9izR{`po#GEu3dtVf%X{1V`V<4!yc5xALTW1dai$J@>fo&X; zMr1tDoxT={65O`ekjk%`*)y0XA9b+&W4@+er+|wOkkR_w%q;189VLk~4w92%WwB+~wD!gU0OBr_u6`Szl#Cq?6^7$w+3^{R-4)G*N@pK0PYG zb1TX_H&&~#vr3JjGEkJc?)2P^B9rZ<9b#3n#AMy~V>8(5TPpEc;TW6AFuhEN3QK9) zcHu8Z1kq9Hfa73HuN0j-WxN>f2~&t4;yKTXNxsdmtcF)EH7q}^O9apd>si_y@g^uH z@1SNXvEdTwJ~2=AZ;J@C(IXppXX>NF`BdfTYIrxhoE^mKmeRj1+IAGPI%%+=_MPOf zfHj(|^SQkhM3%=MQ+?K>;(M-wyt6{(FfMyKV9^c;|7cW;|P}`!N_&6(Q-@(bjn-6oXvLwrwE9_Ko{KsyuLM&l} zfMTXS6r%=egI>VvO_%{j%J5B4oFRLK+bO)`58N2O@l69)m(=m^3kmQY8^*}$9^o+2 z$PNnjBqgBl$5g;?JHtC|=%xlMQIn!;C~jX&&TQouZD@TSmf&50>L+RSsoSP97-$5k zq-jEY|^ano4!rdn(5d;Z&oB9$3U-dP+n|MHV zQN-c8i>wO8+EqC{3$27oi&sBf?-W%b70l$VjSCtOS*m8X8f^)pytCxWtUrwy2IJ7^ zO<8|EL<3`eP=bj?GM7uN4K3FH*6<5WdvbXu(c8YOXd@J5SgLNRCqg6$jJ3Zwb^?DD z@JaLU^5zekWsH$WHLe}Z!EGtAC5$qA^b%mpZ3N~=I#!k0t%sHj_v$+kh4s~bDXrbi zUaiJ)f%lpQiXVUI9|20_y-&Ko+ZU;mva7CeA1(3!6JHhhY;222z0G+@mV4?F> zB1P4feQxEjbN;0`V%K5z=sf^ijhgsCaBD1zAr309^^RZ7bjG7;@2%#g^SE<$+tj|K z)<+rz#Vo)Tllj3RL|(b>@fS(|#un+6BCygzwRL(_)&<(+tMX#S6dqog84X7xQm}8; zQKp${7Sb2-K6Gbmg_+G`My+KbYQ_oKN@Cpb~y@)X}~c{v%<-ks`2HGM+dmVYR@8 zzE(+&iTX++8#on2y0%iQdR*0@SZBmfbE>V3i^5qPTFa1C~&<6k~LD8;DM?c2(+zWn1_Tk7a`SewT1mPlzr>^>-lJSrDJ5NY4 zHs>Bp`}!PYm>^z^dp6t|Z`YLq%p9uVXc)rhtH@4t^d$LJg)vVdMR2zUGw9Ze@8LN) zH9h2z-BVp$$RX7}XvgAqBgpDMa@jp?TH%ez=n+#Ak-}5sT2aF=-BY>kl_!7sINhH` z^pm)-JQ$lO+E1gv*ap1{ixFU3op$n%%wVXQP=E&X`mr_|7p*<%sXbfQ8X*e5Q)i_R z(k(*oFf}+?^NW36b4FZ~QeZoFCN&$!kAzv=lqkh%oo9@?Ef^PwL&Yh5;Ms56s(oVWL&gh^$3kr~j~hu%^j>&5AKCX5RXcZBb6;70MD5BTsc6if z-8SHfx}zS4E3417dJldz*Q<~23ii9g)k9;cV-8honYaJ_%|KZULGh>hYdnQCE;{E| zJl;H|mOV**ghCno`*8OJV-X&7w^*0_Bjx!Ch5jNuoZ;uT#eYAu#VGx@zZJ5$w~fux z^Yxheb^XlzgW%Fqm0U8F{(EWSD9J<&;}sRf&1e54Gu4)KjauF|pJvNC_^A-m4cR>$ zKKJB^yDp9^0fRi+AW#3s$9^~odiSsXKQOHMX0tTL9u=0_kbB2oSW#*!am+%zeh zpjzGbt3aMAY&!phA@3|*`dH0Ul^cn}qyjCG(fODE#N!88T%6%aGYTh5jxKx41ik5j#csM<=l;uUVYjo1(??2~b^6E(;khk@5bM-8~)e;cl z_=`hK{MWecw%TtPHd>2X;2~Iz;*AdQpN+!)l(VlD{LH($)QJO#(YGpxV=0 z?C0_cF!u9lofPukm_c$EaQOoK??r__0$e|z0Ey<4$KgI%iVYc%su9S@z8XdD7k?wb zGslLd3){BiFY3&IV`@F_b+R+dHjp%RYk4X5UR@pgIlg%UgWyecO8DDX4Zls z!_;56HD_!mOD>nqI?+LfRcx+?50*plt5I%8NwAgQZa-*p9S-_r?@7rZC@7vhkf+v% z7hq>QWEY@W0mbhM;D#&{LF^(*Gao@Y-JhRZTOJh0kWZ7J5W5SY%4^H8xDIMKVNqxK z&(mjMiw1 zVtoSu#gm!eyH;JMMT^vG>-UqH)2h_@n4O+xJ2;;>e@bqAVVD2LQo5*?>i~Cp{EfF( zRnIb%{d(TXvpY&8=Px@piVaMvR0nJo+!Hq8_53fBjKhLDf22t!r(4B4r=VkKBx=QH z^CmN{5d^sBt%?oxI#2CEdcXaZ#17xP50s^u%v>m@=dDmwvDHlazw?z)5rPRXpFah4 H0|oUz^@afa diff --git a/dist/python-instagram-1.1.0.tar.gz b/dist/python-instagram-1.1.0.tar.gz deleted file mode 100644 index fc1e38b162a9e6476da0aa668ec39704afd69daa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8164 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 diff --git a/python_instagram.egg-info/PKG-INFO b/python_instagram.egg-info/PKG-INFO deleted file mode 100644 index 13b71c3b..00000000 --- a/python_instagram.egg-info/PKG-INFO +++ /dev/null @@ -1,11 +0,0 @@ -Metadata-Version: 1.0 -Name: python-instagram -Version: 1.1.3 -Summary: Instagram API client -Home-page: http://github.com/Instagram/python-instagram -Author: Instagram, Inc -Author-email: apidevelopers@instagram.com -License: MIT -Description: UNKNOWN -Keywords: instagram -Platform: UNKNOWN diff --git a/python_instagram.egg-info/SOURCES.txt b/python_instagram.egg-info/SOURCES.txt deleted file mode 100644 index 02db67d7..00000000 --- a/python_instagram.egg-info/SOURCES.txt +++ /dev/null @@ -1,15 +0,0 @@ -setup.py -instagram/__init__.py -instagram/bind.py -instagram/client.py -instagram/helper.py -instagram/json_import.py -instagram/models.py -instagram/oauth2.py -instagram/subscriptions.py -python_instagram.egg-info/PKG-INFO -python_instagram.egg-info/SOURCES.txt -python_instagram.egg-info/dependency_links.txt -python_instagram.egg-info/requires.txt -python_instagram.egg-info/top_level.txt -python_instagram.egg-info/zip-safe \ No newline at end of file diff --git a/python_instagram.egg-info/dependency_links.txt b/python_instagram.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891..00000000 --- a/python_instagram.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python_instagram.egg-info/requires.txt b/python_instagram.egg-info/requires.txt deleted file mode 100644 index 14223b98..00000000 --- a/python_instagram.egg-info/requires.txt +++ /dev/null @@ -1,4 +0,0 @@ -simplejson -httplib2 -six -pytz diff --git a/python_instagram.egg-info/top_level.txt b/python_instagram.egg-info/top_level.txt deleted file mode 100644 index aebfbd98..00000000 --- a/python_instagram.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -instagram diff --git a/python_instagram.egg-info/zip-safe b/python_instagram.egg-info/zip-safe deleted file mode 100644 index 8b137891..00000000 --- a/python_instagram.egg-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - From f025c756ba3bac11ae8616222cb0f067cd755de5 Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 16:05:48 +0100 Subject: [PATCH 27/28] Update pypi package info --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 898d620f..cd82aaec 100644 --- a/setup.py +++ b/setup.py @@ -2,8 +2,8 @@ from setuptools import setup, find_packages setup( - name="python-instagram", - version="1.3.2", + name="instagram", + version="1.3", description="Instagram API client", license="MIT", install_requires=[ @@ -12,9 +12,9 @@ "six", "pytz", ], - author="Instagram, Inc", - author_email="apidevelopers@instagram.com", - url="http://github.com/Instagram/python-instagram", + author="instagram, wkoot", + author_email="pypi@rondarchief.nl", + url="http://github.com/wkoot/python-instagram", packages=find_packages(), keywords="instagram", zip_safe=True From 4fd43343f19fa9ecce361a3d0f03a3cc2639b03d Mon Sep 17 00:00:00 2001 From: wkoot Date: Mon, 27 Feb 2017 16:08:08 +0100 Subject: [PATCH 28/28] Set version to 1.3.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cd82aaec..d45be9c5 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="instagram", - version="1.3", + version="1.3.3", description="Instagram API client", license="MIT", install_requires=[