Skip to content
This repository was archived by the owner on Jan 13, 2022. It is now read-only.

Commit 74dd7aa

Browse files
author
Josh Watts
committed
first cut of python 3 support
1 parent 21ba5cb commit 74dd7aa

7 files changed

Lines changed: 63 additions & 42 deletions

File tree

instagram/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from bind import InstagramAPIError, InstagramClientError
2-
from client import InstagramAPI
1+
from .bind import InstagramAPIError, InstagramClientError
2+
from .client import InstagramAPI

instagram/bind.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import urllib
2-
from oauth2 import OAuth2Request
2+
from .oauth2 import OAuth2Request
33
import re
4-
from json_import import simplejson
4+
from .json_import import simplejson
55
import hmac
66
from hashlib import sha256
7+
import six
8+
from six.moves.urllib.parse import quote
9+
import sys
710

811
re_path_template = re.compile('{\w+}')
912

1013

1114
def encode_string(value):
1215
return value.encode('utf-8') \
13-
if isinstance(value, unicode) else str(value)
16+
if isinstance(value, six.text_type) else str(value)
17+
# if sys.version < '3':
18+
# return value.encode('utf-8') \
19+
# if isinstance(value, unicode) else str(value)
20+
# else:
21+
# return value.encode('utf-8')
1422

1523

1624
class InstagramClientError(Exception):
@@ -76,7 +84,7 @@ def _build_parameters(self, args, kwargs):
7684
except IndexError:
7785
raise InstagramClientError("Too many arguments supplied")
7886

79-
for key, value in kwargs.iteritems():
87+
for key, value in six.iteritems(kwargs):
8088
if value is None:
8189
continue
8290
if key in self.parameters:
@@ -91,7 +99,7 @@ def _build_path(self):
9199
name = variable.strip('{}')
92100

93101
try:
94-
value = urllib.quote(self.parameters[name])
102+
value = quote(self.parameters[name])
95103
except KeyError:
96104
raise Exception('No parameter value found for path variable: %s' % name)
97105
del self.parameters[name]
@@ -130,7 +138,7 @@ def _do_api_request(self, url, method="GET", body=None, headers=None):
130138
raise InstagramClientError('Unable to parse response, not valid JSON.', status_code=response['status'])
131139

132140
# Handle OAuthRateLimitExceeded from Instagram's Nginx which uses different format to documented api responses
133-
if not content_obj.has_key('meta'):
141+
if 'meta' not in content_obj:
134142
if content_obj.get('code') == 420 or content_obj.get('code') == 429:
135143
error_message = content_obj.get('error_message') or "Your client is making too many request per second"
136144
raise InstagramAPIError(content_obj.get('code'), "Rate limited", error_message)
@@ -166,7 +174,7 @@ def _do_api_request(self, url, method="GET", body=None, headers=None):
166174
def _paginator_with_url(self, url, method="GET", body=None, headers=None):
167175
headers = headers or {}
168176
pages_read = 0
169-
while url and (pages_read < self.max_pages or self.max_pages is None):
177+
while url and (self.max_pages is None or pages_read < self.max_pages):
170178
api_responses, url = self._do_api_request(url, method, body, headers)
171179
pages_read += 1
172180
yield api_responses, url

instagram/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import oauth2
2-
from bind import bind_method
3-
from models import MediaShortcode, Media, User, Location, Tag, Comment, Relationship
1+
from . import oauth2
2+
from .bind import bind_method
3+
from .models import MediaShortcode, Media, User, Location, Tag, Comment, Relationship
44

55
MEDIA_ACCEPT_PARAMETERS = ["count", "max_id"]
66
SEARCH_ACCEPT_PARAMETERS = ["q", "count"]

instagram/models.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from helper import timestamp_to_datetime
1+
from .helper import timestamp_to_datetime
2+
import six
23

34

45
class ApiModel(object):
@@ -12,7 +13,17 @@ def object_from_dictionary(cls, entry):
1213
return cls(**entry_str_dict)
1314

1415
def __repr__(self):
15-
return unicode(self).encode('utf8')
16+
return str(self)
17+
# if six.PY2:
18+
# return six.text_type(self).encode('utf8')
19+
# else:
20+
# return self.encode('utf8')
21+
22+
def __str__(self):
23+
if six.PY3:
24+
return self.__unicode__()
25+
else:
26+
return unicode(self).encode('utf-8')
1627

1728

1829
class Image(ApiModel):
@@ -36,7 +47,7 @@ class Media(ApiModel):
3647

3748
def __init__(self, id=None, **kwargs):
3849
self.id = id
39-
for key, value in kwargs.iteritems():
50+
for key, value in six.iteritems(kwargs):
4051
setattr(self, key, value)
4152

4253
def get_standard_resolution_url(self):
@@ -67,12 +78,12 @@ def object_from_dictionary(cls, entry):
6778
new_media.user = User.object_from_dictionary(entry['user'])
6879

6980
new_media.images = {}
70-
for version, version_info in entry['images'].iteritems():
81+
for version, version_info in six.iteritems(entry['images']):
7182
new_media.images[version] = Image.object_from_dictionary(version_info)
7283

7384
if new_media.type == 'video':
7485
new_media.videos = {}
75-
for version, version_info in entry['videos'].iteritems():
86+
for version, version_info in six.iteritems(entry['videos']):
7687
new_media.videos[version] = Video.object_from_dictionary(version_info)
7788

7889
if 'user_has_liked' in entry:
@@ -113,14 +124,14 @@ class MediaShortcode(Media):
113124

114125
def __init__(self, shortcode=None, **kwargs):
115126
self.shortcode = shortcode
116-
for key, value in kwargs.iteritems():
127+
for key, value in six.iteritems(kwargs):
117128
setattr(self, key, value)
118129

119130

120131
class Tag(ApiModel):
121132
def __init__(self, name, **kwargs):
122133
self.name = name
123-
for key, value in kwargs.iteritems():
134+
for key, value in six.iteritems(kwargs):
124135
setattr(self, key, value)
125136

126137
def __unicode__(self):
@@ -129,7 +140,7 @@ def __unicode__(self):
129140

130141
class Comment(ApiModel):
131142
def __init__(self, *args, **kwargs):
132-
for key, value in kwargs.iteritems():
143+
for key, value in six.iteritems(kwargs):
133144
setattr(self, key, value)
134145

135146
@classmethod
@@ -156,7 +167,7 @@ def __unicode__(self):
156167
class Location(ApiModel):
157168
def __init__(self, id, *args, **kwargs):
158169
self.id = str(id)
159-
for key, value in kwargs.iteritems():
170+
for key, value in six.iteritems(kwargs):
160171
setattr(self, key, value)
161172

162173
@classmethod
@@ -178,7 +189,7 @@ class User(ApiModel):
178189

179190
def __init__(self, id, *args, **kwargs):
180191
self.id = id
181-
for key, value in kwargs.iteritems():
192+
for key, value in six.iteritems(kwargs):
182193
setattr(self, key, value)
183194

184195
def __unicode__(self):

instagram/oauth2.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from json_import import simplejson
2-
import urllib
1+
from .json_import import simplejson
2+
from six.moves.urllib.parse import urlencode
33
from httplib2 import Http
44
import mimetypes
55

@@ -67,7 +67,7 @@ def _url_for_authorize(self, scope=None):
6767
}
6868
if scope:
6969
client_params.update(scope=' '.join(scope))
70-
url_params = urllib.urlencode(client_params)
70+
url_params = urlencode(client_params)
7171
return "%s?%s" % (self.api.authorize_url, url_params)
7272

7373
def _data_for_exchange(self, code=None, username=None, password=None, scope=None, user_id=None):
@@ -87,7 +87,7 @@ def _data_for_exchange(self, code=None, username=None, password=None, scope=None
8787
client_params.update(scope=' '.join(scope))
8888
elif user_id:
8989
client_params.update(user_id=user_id)
90-
return urllib.urlencode(client_params)
90+
return urlencode(client_params)
9191

9292
def get_authorize_url(self, scope=None):
9393
return self._url_for_authorize(scope=scope)
@@ -137,7 +137,7 @@ def _full_url_with_params(self, path, params, include_secret=False):
137137
return (self._full_url(path, include_secret) + self._full_query_with_params(params))
138138

139139
def _full_query_with_params(self, params):
140-
params = ("&" + urllib.urlencode(params)) if params else ""
140+
params = ("&" + urlencode(params)) if params else ""
141141
return params
142142

143143
def _auth_query(self, include_secret=False):
@@ -150,7 +150,7 @@ def _auth_query(self, include_secret=False):
150150
return base
151151

152152
def _post_body(self, params):
153-
return urllib.urlencode(params)
153+
return urlencode(params)
154154

155155
def _encode_multipart(params, files):
156156
boundary = "MuL7Ip4rt80uND4rYF0o"

instagram/subscriptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import hmac
22
import hashlib
3-
from json_import import simplejson
3+
from .json_import import simplejson
44

55
class SubscriptionType:
66
TAG = 'tag'

tests.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#!/usr/bin/env python
22

33
import types
4+
import six
45
try:
56
import simplejson as json
67
except ImportError:
78
import json
89
import getpass
910
import unittest
10-
import urlparse
11+
from six.moves.urllib.parse import urlparse, parse_qs
1112
from instagram import client, oauth2, InstagramAPIError
1213

1314
TEST_AUTH = False
@@ -26,8 +27,8 @@ def request(self, url, method="GET", body=None, headers={}):
2627
'status':'400'
2728
}, "{}"
2829

29-
parsed = urlparse.urlparse(url)
30-
options = urlparse.parse_qs(parsed.query)
30+
parsed = urlparse(url)
31+
options = parse_qs(parsed.query)
3132

3233
fn_name = str(active_call)
3334
if fn_name == 'get_authorize_login_url':
@@ -43,6 +44,7 @@ def request(self, url, method="GET", body=None, headers={}):
4344

4445
fl = open('fixtures/%s.json' % fn_name)
4546
content = fl.read()
47+
fl.close()
4648
json_content = json.loads(content)
4749
status = json_content['meta']['code']
4850
return {
@@ -67,7 +69,7 @@ def setUp(self):
6769
def test_authorize_login_url(self):
6870
redirect_uri = self.unauthenticated_api.get_authorize_login_url()
6971
assert redirect_uri
70-
print "Please visit and authorize at:\n%s" % redirect_uri
72+
print("Please visit and authorize at:\n%s" % redirect_uri)
7173
code = raw_input("Paste received code (blank to skip): ").strip()
7274
if not code:
7375
return
@@ -129,7 +131,7 @@ def test_generator_user_feed(self):
129131
def test_generator_user_feed_all(self):
130132
generator = self.api.user_media_feed(as_generator=True, max_pages=None)
131133
for i in range(10):
132-
page = generator.next()
134+
page = six.advance_iterator(generator)
133135
str(generator)
134136

135137
generator = self.api.user_media_feed(as_generator=True, max_pages=0)
@@ -145,34 +147,34 @@ def test_user_recent_media(self):
145147
self.assertTrue( all( [hasattr(obj, 'type') for obj in media] ) )
146148

147149
image = media[0]
148-
self.assertEquals(
150+
self.assertEqual(
149151
image.get_standard_resolution_url(),
150152
"http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_7.jpg")
151153

152-
self.assertEquals(
154+
self.assertEqual(
153155
image.get_low_resolution_url(),
154156
"http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_6.jpg")
155157

156-
self.assertEquals(
158+
self.assertEqual(
157159
image.get_thumbnail_url(),
158160
"http://distillery-dev.s3.amazonaws.com/media/2011/02/02/1ce5f3f490a640ca9068e6000c91adc5_5.jpg")
159161

160-
self.assertEquals( False, hasattr(image, 'videos') )
162+
self.assertEqual( False, hasattr(image, 'videos') )
161163

162164
video = media[1]
163-
self.assertEquals(
165+
self.assertEqual(
164166
video.get_standard_resolution_url(),
165167
video.videos['standard_resolution'].url)
166168

167-
self.assertEquals(
169+
self.assertEqual(
168170
video.get_standard_resolution_url(),
169171
"http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_101.mp4")
170172

171-
self.assertEquals(
173+
self.assertEqual(
172174
video.get_low_resolution_url(),
173175
"http://distilleryvesper9-13.ak.instagram.com/090d06dad9cd11e2aa0912313817975d_102.mp4")
174176

175-
self.assertEquals(
177+
self.assertEqual(
176178
video.get_thumbnail_url(),
177179
"http://distilleryimage2.ak.instagram.com/11f75f1cd9cc11e2a0fd22000aa8039a_5.jpg")
178180

0 commit comments

Comments
 (0)