Skip to content
This repository was archived by the owner on Oct 4, 2023. It is now read-only.

Commit f06399b

Browse files
committed
Merge pull request #10 from Jasdev/master
PEP 8, refactoring, and squashing bugs
2 parents 1e0bc64 + e0cbf7b commit f06399b

14 files changed

Lines changed: 249 additions & 235 deletions

File tree

README.md

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,63 @@
1-
Imgur API Example Usage
2-
=======================
1+
imgurpython
2+
===========
33

4-
This is a demo application of the [Imgur API](http://api.imgur.com/). It can be used to interrogate the Imgur API and
5-
examine its responses, as a simple command line utility, and it can be used as a library for working with the Imgur API.
4+
A Python client for the [Imgur API](http://api.imgur.com/). Also includes a friendly demo application. It can be used to
5+
interact with the Imgur API and examine its responses, as a command line utility, and it can be used as a library
6+
within your projects.
67

7-
You must [register](http://api.imgur.com/oauth2/addclient) your client with the Imgur API, and provide the client ID to
8-
do *any* request to the API. If you want to perform actions on accounts, the user will have to authorize it through OAuth.
9-
The **secret** field is required for OAuth.
8+
You must [register](http://api.imgur.com/oauth2/addclient) your client with the Imgur API, and provide the Client-ID to
9+
make *any* request to the API (see the [Authentication](https://api.imgur.com/#authentication) note). If you want to
10+
perform actions on accounts, the user will have to authorize your application through OAuth2.
11+
12+
Imgur API Documentation
13+
-----------------------
14+
15+
Our developer documentation can be found [here](https://api.imgur.com/).
16+
17+
Community
18+
---------
19+
20+
The best way to reach out to Imgur for API support would be our
21+
[Google Group](https://groups.google.com/forum/#!forum/imgur), [Twitter](https://twitter.com/imgurapi), or via
22+
api@imgur.com.
1023

1124
Installation
1225
------------
1326

1427
pip install imgurpython
1528

16-
Usage
17-
-----
29+
Configuration
30+
-------------
31+
32+
Configuration is done through the **config.json** (placed in `imgur-python/data`) file in JSON format. The contents of the file should be a JSON
33+
object with the following properties:
34+
35+
### client_id
36+
37+
**Key**: 'client_id'
38+
39+
**Type**: string [16 characters]
40+
41+
**Description**: The Client-ID you got when you registered. Required for any API call.
42+
43+
### secret
44+
45+
**Key**: 'secret'
46+
47+
**Type**: string [40 characters]
48+
49+
**Description**: The client secret you got when you registered, needed fo OAuth2 authentication.
50+
51+
### token_store
52+
53+
**Key**: 'token_store'
54+
55+
**Type**: object
56+
57+
**Description**: Future configuration to control where the tokens are stored for persistent **insecure** storage of refresh tokens.
58+
59+
Command Line Usage
60+
------------------
1861

1962
> Usage: python main.py (action) [options...]
2063
>
@@ -51,44 +94,14 @@ Usage
5194
>
5295
> ### Authorized Actions
5396
>
54-
> **upload-auth [access-token]**
97+
> **upload-auth [access-token] [file]**
5598
> Upload a file to your account
5699
>
57-
> **comment [access-token] [hash] [text ...]**
100+
> **comment [access-token] [hash] [text]**
58101
> Comment on a gallery post
59102
>
60103
> **vote-gallery [token] [hash] [direction]**
61-
> Vote on a gallery post. Direction either 'up', 'down', or 'veto'
104+
> Vote on a gallery post. Direction can be either 'up', 'down', or 'veto'
62105
>
63106
> **vote-comment [token] [id] [direction]**
64-
> Vote on a gallery comment. Direction either 'up', 'down', or 'veto'
65-
66-
Config
67-
------
68-
69-
Configuration is done through the **config.json** file in JSON format. The contents of the file should be a JSON
70-
object with the following properties:
71-
72-
### client_id
73-
74-
**Key**: 'client_id'
75-
76-
**Type**: String [16 characters]
77-
78-
**Description**: The client ID you got when you registered. Required for any API call.
79-
80-
### secret
81-
82-
**Key**: 'secret'
83-
84-
**Type**: String [40 characters]
85-
86-
**Description**: The client secret you got when you registered, if you want to do OAuth authentication.
87-
88-
### token_store
89-
90-
**Key**: 'token_store'
91-
92-
**Type**: Object
93-
94-
**Description**: Future configuration to control where the tokens are stored for persistent **insecure** storage of refresh tokens.
107+
> Vote on a gallery comment. Direction can be either 'up', 'down', or 'veto'

imgur-python/data/config.json.sample

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"client_id": "",
33
"secret": "",
44
"token_store": {}
5-
}
5+
}

imgur-python/docs/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21-
THE SOFTWARE.
21+
THE SOFTWARE.

imgur-python/helpers/__init__.py

Whitespace-only changes.

imgur-python/helpers/format.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import math
2+
3+
4+
def center_pad(s, length):
5+
num_dashes = float(length - len(s) - 2) / 2
6+
num_dashes_left = int(math.floor(num_dashes))
7+
num_dashes_right = int(math.ceil(num_dashes))
8+
9+
return ('=' * num_dashes_left) + ' ' + s + ' ' + ('=' * num_dashes_right)
10+
11+
12+
def two_column_with_period(left, right, length):
13+
num_periods = int(length - (len(left) + len(right) + 2))
14+
return left + ' ' + ('.' * num_periods) + ' ' + right

imgur-python/imgur/auth/accesstoken.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
#!/usr/bin/env python3
22

3-
from .base import base as authbase
4-
import time as dt
3+
from .base import Base as AuthBase
54

6-
class accesstoken(authbase):
75

6+
class AccessToken(AuthBase):
87
def __init__(self, access, refresh, expire_time):
98
self.access = access
109
self.refresh = refresh
1110
self.expire_time = expire_time
1211

1312
def need_to_authorize(self, time):
14-
return (self.expire_time <= time)
13+
return self.expire_time <= time
1514

1615
def add_authorization_header(self, request):
17-
request.add_header('Authorization', 'Bearer ' + self.access)
16+
request.add_header('Authorization', 'Bearer %s' % self.access)
1817
return request
1918

2019
def get_access_token(self):
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#!/usr/bin/env python3
22

3-
class anonymous:
3+
from .base import Base as AuthBase
4+
5+
6+
class Anonymous(AuthBase):
47
def __init__(self, client_id):
58
self.client_id = client_id
69

7-
def need_to_authorize(self):
10+
def need_to_authorize(self, time):
811
return False
912

10-
def authorize(self):
13+
def authorize(self, api, request_factory):
1114
pass
1215

1316
def add_authorization_header(self, request):
14-
request.add_header('Authorization', 'Client-ID ' + self.client_id)
15-
return request
17+
request.add_header('Authorization', 'Client-ID %s' % self.client_id)
18+
return request

imgur-python/imgur/auth/base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#!/usr/bin/env python3
22

3-
class base:
3+
4+
class Base:
45
def need_to_authorize(self, time):
5-
'''Do we need to refresh our authorization token?'''
6+
"""Do we need to refresh our authorization token?"""
67
pass
7-
def authorize(self, api, requestfactory):
8-
'''Refresh our access token'''
8+
9+
def authorize(self, api, request_factory):
10+
"""Refresh our access token"""
911
pass
12+
1013
def add_authorization_header(self, request):
11-
pass
12-
14+
pass

imgur-python/imgur/auth/expired.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
class expired(BaseException):
4-
def __str__(self):
5-
return "Access token invalid or expired."
63

4+
class Expired(BaseException):
5+
def __str__(self):
6+
return 'Access token invalid or expired.'

imgur-python/imgur/factory.py

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
#!/usr/bin/env python3
22

3-
import base64, os.path, time as dt
3+
import base64
4+
import os.path
5+
import time as dt
6+
from .imgur import Imgur
7+
from .ratelimit import RateLimit
8+
from .auth.anonymous import Anonymous
9+
from .auth.accesstoken import AccessToken
410

511
try:
6-
from urllib.request import Request as UrlLibRequest
7-
from urllib.parse import urlencode as UrlLibEncode
12+
from urllib.request import Request as urllibrequest
13+
from urllib.parse import urlencode as urllibencode
814
except ImportError:
9-
from urllib2 import Request as UrlLibRequest
10-
from urllib import urlencode as UrlLibEncode
11-
12-
from .imgur import imgur
13-
from .ratelimit import ratelimit
14-
from .auth.accesstoken import accesstoken
15-
from .auth.anonymous import anonymous
15+
from urllib2 import Request as urllibrequest
16+
from urllib import urlencode as urllibencode
1617

17-
class factory:
1818

19+
class Factory:
1920
API_URL = "https://api.imgur.com/"
2021

2122
def __init__(self, config):
@@ -26,61 +27,68 @@ def __init__(self, config):
2627
def get_api_url(self):
2728
return self.API_URL
2829

29-
def build_api(self, auth = None, ratelimit = None):
30+
def build_api(self, auth=None, rate_limit=None):
3031
if auth is None:
3132
auth = self.build_anonymous_auth()
32-
if ratelimit is None:
33-
ratelimit = self.build_rate_limit()
34-
return imgur(self.config['client_id'], self.config['secret'], auth, ratelimit)
33+
34+
if rate_limit is None:
35+
rate_limit = self.build_rate_limit()
36+
37+
return Imgur(self.config['client_id'], self.config['secret'], auth, rate_limit)
3538

3639
def build_anonymous_auth(self):
37-
return anonymous(self.config['client_id'])
40+
return Anonymous(self.config['client_id'])
3841

39-
def build_oauth(self, access, refresh, expire_time = None):
42+
@staticmethod
43+
def build_oauth(access, refresh, expire_time=None):
4044
now = int(dt.time())
4145
if expire_time is None:
42-
return accesstoken(access, refresh, now)
46+
return AccessToken(access, refresh, now)
4347
else:
44-
return accesstoken(access, refresh, expire_time)
48+
return AccessToken(access, refresh, expire_time)
4549

46-
def build_request(self, endpoint, data = None):
47-
'''Expects an endpoint like 'image.json' or a tuple like ('gallery', 'hot', 'viral', '0').
48-
49-
Prepends 3/ and appends \.json to the tuple-form, not the endpoint form.'''
50+
def build_request(self, endpoint, data=None):
51+
"""Expects an endpoint like 'image.json' or a tuple like ('gallery', 'hot', 'viral', '0').
52+
Prepends 3/ and appends \.json to the tuple-form, not the endpoint form."""
5053
if isinstance(endpoint, str):
5154
url = self.API_URL + endpoint
5255
else:
5356
url = self.API_URL + '3/' + ('/'.join(endpoint)) + ".json"
5457

55-
req = UrlLibRequest(url)
58+
req = urllibrequest(url)
5659
if data is not None:
57-
req.add_data(UrlLibEncode(data).encode('utf-8'))
60+
req.add_data(urllibencode(data).encode('utf-8'))
61+
5862
return req
59-
60-
def build_rate_limit(self, limits = None):
61-
'''If none, defaults to fresh rate limits. Else expects keys "client_limit", "user_limit", "user_reset"'''
63+
64+
@staticmethod
65+
def build_rate_limit(limits=None):
66+
"""If none, defaults to fresh rate limits. Else expects keys \"client_limit\", \"user_limit\", \"user_reset\""""
6267
if limits is not None:
63-
return ratelimit(limits['client_limit'], limits['user_limit'], limits['user_reset'])
68+
return RateLimit(limits['client_limit'], limits['user_limit'], limits['user_reset'])
6469
else:
65-
return ratelimit()
70+
return RateLimit()
6671

6772
def build_rate_limits_from_server(self, api):
68-
'''Get the rate limits for this application and build a rate limit model from it.'''
73+
"""Get the rate limits for this application and build a rate limit model from it."""
6974
req = self.build_request('credits')
7075
res = api.retrieve(req)
71-
return ratelimit(res['ClientRemaining'], res['UserRemaining'], res['UserReset'])
7276

73-
74-
def build_request_upload_from_path(self, path, params = dict()):
77+
return RateLimit(res['ClientRemaining'], res['UserRemaining'], res['UserReset'])
78+
79+
def build_request_upload_from_path(self, path, params=dict()):
7580
fd = open(path, 'rb')
7681
contents = fd.read()
7782
b64 = base64.b64encode(contents)
83+
7884
data = {
7985
'image': b64,
8086
'type': 'base64',
8187
'name': os.path.basename(path)
8288
}
89+
8390
data.update(params)
91+
8492
return self.build_request(('upload',), data)
8593

8694
def build_request_oauth_token_swap(self, grant_type, token):
@@ -92,7 +100,7 @@ def build_request_oauth_token_swap(self, grant_type, token):
92100

93101
if grant_type == 'authorization_code':
94102
data['code'] = token
95-
if grant_type == 'pin':
103+
elif grant_type == 'pin':
96104
data['pin'] = token
97105

98106
return self.build_request('oauth2/token', data)
@@ -104,4 +112,5 @@ def build_request_oauth_refresh(self, refresh_token):
104112
'client_secret': self.config['secret'],
105113
'grant_type': 'refresh_token'
106114
}
115+
107116
return self.build_request('oauth2/token', data)

0 commit comments

Comments
 (0)