Skip to content

Commit c1dad1a

Browse files
committed
Merge branch 'develop'
2 parents 5604cff + bb52626 commit c1dad1a

27 files changed

+1637
-314
lines changed

AUTHORS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ Development Lead
55
````````````````
66

77
- Kenneth Reitz <me@kennethreitz.com>
8+
- David Medina <davidmedina9@gmail.com>
89

910

1011
Patches and Suggestions
1112
```````````````````````
1213

1314
- Mahdi Yusuf
14-
- Rok Garbas
15+
- Rok Garbas
16+
- Antti Kaihola <akaihol+github@ambitone.com>
Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,34 @@
11
Fork
2-
======================================
2+
====
33
Refactor and complete api wrapper. Intensive work in progress
44

5-
Github3: Python wrapper for the (new) GitHub API v3
6-
===================================================
7-
8-
Github has a new API. This is the best Python wrapper for it.
9-
10-
**This a work in progress.** Should be relased soon.
11-
12-
13-
14-
Usage
15-
-----
16-
17-
::
18-
19-
import github3
20-
21-
gh = github3.basic_auth('username', 'password')
22-
23-
gh.get_repo('kennethreitz', 'python-github3')
5+
Use with auth user
6+
------------------
247

8+
from github3.api import Github
259

10+
gh = Github('user', 'password')
2611

12+
users_handler = gh.users
13+
for repo in users_handler.get_repos():
14+
print repo
2715

16+
gists_handler = gh.gists
17+
gists_handler.create_gist(
18+
u'Description',
19+
files={'file1.txt': {'content': u'Content of first file'}})
2820

2921
Installation
3022
------------
3123

32-
To install Github3, simply: ::
33-
34-
$ pip install github3
35-
36-
Or, if you absolutely must: ::
37-
38-
$ easy_install github3
39-
40-
But, you really shouldn't do that.
41-
24+
To install Github3, simply:
4225

26+
$ pip -e git+https://copitux@github.com/copitux/python-github3#egg=python-github3
4327

4428
License
4529
-------
4630

47-
ISC License. ::
31+
ISC License.
4832

4933
Copyright (c) 2011, Kenneth Reitz <me@kennethreitz.com>
5034

@@ -64,19 +48,16 @@ ISC License. ::
6448
Contribute
6549
----------
6650

67-
If you'd like to contribute, simply fork `the repository`_, commit your changes
51+
If you'd like to contribute, simply fork `the repository`, commit your changes
6852
to the **develop** branch (or branch off of it), and send a pull request. Make
69-
sure you add yourself to AUTHORS_.
70-
53+
sure you add yourself to `AUTHORS`.
7154

7255

7356
Roadmap
7457
-------
7558

76-
- Get it Started
77-
- HTTP BASIC
78-
- Get it working
79-
- Sphinx Documetnation
80-
- Examples
8159
- Unittests
60+
- Handlers
61+
- Sphinx Documentation
62+
- Examples
8263
- OAuth Last (how?)

github3/api.py

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#!/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
#
4-
# author: David Medina
53

64
import requests
75
import json
86
from errors import GithubError
7+
from handlers import users, gists
98

109
RESOURCES_PER_PAGE = 100
1110

11+
12+
#TODO: refactor: loads json in request editing Response object
1213
class GithubCore(object):
1314
"""
1415
Wrapper to github api requests
@@ -69,7 +70,9 @@ def patch(self, request, data=None, **kwargs):
6970

7071
def put(self, request, **kwargs):
7172
""" PUT request """
72-
response = self._request('PUT', request, **kwargs)
73+
74+
response = self._request('PUT', request,
75+
headers={'Content-length': '0'}, **kwargs)
7376
assert response.status_code == 204
7477
return response
7578

@@ -87,22 +90,21 @@ def _parse_args(self, request_args):
8790
"""
8891
Arg's parser to `_request` method
8992
90-
It check keyword args to parse extra request args to params
91-
Sample:
92-
_parse_args(arg1=1, arg2=2) => params = {'arg1': 1, 'arg2': 2}
93+
Put extra request_args in params
9394
"""
9495
request_core = (
95-
'params','data','headers','cookies','files','auth','tiemout',
96-
'allow_redirects','proxies','return_response','config')
96+
'params', 'data', 'headers', 'cookies', 'files', 'auth', 'tiemout',
97+
'allow_redirects', 'proxies', 'return_response', 'config')
9798
request_params = request_args.get('params')
9899
extra_params = {}
99100
for k, v in request_args.items():
100-
if k in request_core: continue
101+
if k in request_core:
102+
continue
101103
extra_params.update({k: v})
102104
del request_args[k]
103-
if request_params:
105+
if request_params and getattr(request_params, 'update'):
104106
request_args['params'].update(extra_params)
105-
else:
107+
elif extra_params:
106108
request_args['params'] = extra_params
107109

108110
return request_args
@@ -116,14 +118,42 @@ def _request(self, verb, request, **kwargs):
116118
:param kwargs: Keyword args to request
117119
"""
118120
request = self.base_url + request
119-
parsed_args = self._parse_args(kwargs)
120-
response = self.session.request(verb, request, **parsed_args)
121+
self._parse_args(kwargs)
122+
response = self.session.request(verb, request, **kwargs)
121123
self.requests_remaining = response.headers.get(
122-
'x-ratelimit-remaining',-1)
124+
'x-ratelimit-remaining', -1)
123125
error = GithubError(response)
124126
error.process()
125127

126128
return response
127129

130+
return response
131+
128132
class Github(GithubCore):
129-
pass
133+
""" Library enter """
134+
135+
def __init__(self, *args):
136+
super(Github, self).__init__()
137+
self.authenticated = False
138+
auth = len(args)
139+
if auth == 2: # Basic auth
140+
self.session.auth = tuple(map(str, args))
141+
self.authenticated = True
142+
elif auth == 1: # Token oauth
143+
raise NotImplementedError
144+
elif auth > 2:
145+
raise TypeError("user, password or token")
146+
147+
@property
148+
def users(self):
149+
if self.authenticated:
150+
return users.AuthUser(self)
151+
else:
152+
return users.User(self)
153+
154+
@property
155+
def gists(self):
156+
if self.authenticated:
157+
return gists.AuthGist(self)
158+
else:
159+
return gists.Gist(self)

github3/converters.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
#
4-
# author: David Medina
3+
54
from .core import Converter
65

6+
77
class Rawlizer(Converter):
88
""" Raw converter """
99

@@ -16,6 +16,7 @@ def loads(self, raw_resource):
1616
def dumps(self):
1717
pass
1818

19+
1920
class Json(Converter):
2021
""" Json converter """
2122

@@ -32,6 +33,7 @@ def loads(self, raw_resource):
3233
def dumps(self):
3334
pass
3435

36+
3537
class Modelizer(Converter):
3638
""" Own model converter """
3739

@@ -52,17 +54,18 @@ def inject(self, model):
5254
self.model = model
5355

5456
def _parse_map(self, model, raw_resource):
55-
return Modelizer(model).loads(raw_resource)
57+
if hasattr(raw_resource, 'items'):
58+
return Modelizer(model).loads(raw_resource)
5659

5760
def _parse_collection_map(self, model, raw_resources):
5861
# Dict of resources (Ex: Gist file)
59-
if getattr(raw_resources, 'items', False):
62+
if hasattr(raw_resources, 'items'):
6063
dict_map = {}
6164
for key, raw_resource in raw_resources.items():
6265
dict_map[key] = Modelizer(model).loads(raw_resource)
6366
return dict_map
6467
# list of resources
65-
else:
68+
elif hasattr(raw_resources, '__iter__'):
6669
return [Modelizer(model).loads(raw_resource)
6770
for raw_resource in raw_resources]
6871

@@ -73,25 +76,25 @@ def loads(self, raw_resource):
7376
self.__class__.__name__)
7477
idl = self.model.idl()
7578
attrs.update(
76-
{attr: raw_resource[attr] for attr in idl.get('strs',())
77-
if raw_resource.get(attr)})
79+
{attr: raw_resource[attr] for attr in idl.get('strs', ())
80+
if attr in raw_resource})
7881
attrs.update(
79-
{attr: raw_resource[attr] for attr in idl.get('ints',())
80-
if raw_resource.get(attr)})
82+
{attr: raw_resource[attr] for attr in idl.get('ints', ())
83+
if attr in raw_resource})
8184
attrs.update(
8285
{attr: self._parse_date(raw_resource[attr])
83-
for attr in idl.get('dates',()) if raw_resource.get(attr)})
86+
for attr in idl.get('dates', ()) if attr in raw_resource})
8487
attrs.update(
85-
{attr: raw_resource[attr] for attr in idl.get('bools',())
86-
if raw_resource.get(attr)})
88+
{attr: raw_resource[attr] for attr in idl.get('bools', ())
89+
if attr in raw_resource})
8790
attrs.update(
8891
{attr: self._parse_map(model, raw_resource[attr])
89-
for attr, model in idl.get('maps',{}).items()
90-
if raw_resource.get(attr)})
92+
for attr, model in idl.get('maps', {}).items()
93+
if attr in raw_resource})
9194
attrs.update(
9295
{attr: self._parse_collection_map(model, raw_resource[attr])
93-
for attr, model in idl.get('collection_maps',{}).items()
94-
if raw_resource.get(attr)})
96+
for attr, model in idl.get('collection_maps', {}).items()
97+
if attr in raw_resource})
9598

9699
return self.model(attrs)
97100

github3/core.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#!/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
#
4-
# author: David Medina
3+
54

65
class Paginate:
76
""" Paginate resource iterator
@@ -29,12 +28,14 @@ def _last_page(self, link):
2928

3029
return self.last
3130

32-
# TODO: reset iterators... multiple?
3331
def __iter__(self):
3432
return self
3533

3634
def initial(self):
37-
""" First request. Force requester to paginate returning link header """
35+
"""
36+
First request
37+
Force requester to paginate returning link header
38+
"""
3839
link, content = self.requester(self.resource, paginate=True,
3940
page=1, **self.kwargs)
4041
self.last = self._last_page(link) if link else 1
@@ -54,6 +55,7 @@ def next(self):
5455
self.page += 1
5556
return content
5657

58+
5759
class Converter(object):
5860
""" Abstract converter class """
5961

github3/errors.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#!/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
#
4-
# author: David Medina
53

64
import json
75
import github3.exceptions as exceptions
86

7+
98
class GithubError(object):
109
""" Handler for API errors """
1110

@@ -14,12 +13,15 @@ def __init__(self, response):
1413
self.status_code = response.status_code
1514
try:
1615
self.debug = self._parser.loads(response.content)
17-
except ValueError:
16+
except (ValueError, TypeError):
1817
self.debug = {'message': response.content}
1918

2019
def error_400(self):
2120
return exceptions.BadRequest("400 - %s" % self.debug.get('message'))
2221

22+
def error_401(self):
23+
return exceptions.Unauthorized("401 - %s" % self.debug.get('message'))
24+
2325
def error_404(self):
2426
return exceptions.NotFound("404 - %s" % self.debug.get('message'))
2527

github3/exceptions.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#!/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
#
4-
# author: David Medina
53

64
class BadRequest(Exception):
75
pass
86
class UnprocessableEntity(Exception):
97
pass
108
class NotFound(Exception):
119
pass
12-
class AnomUser(Exception):
13-
""" Exception for AnomUser handler """
10+
class Unauthorized(Exception):
11+
pass
12+
class UserIsAnonymous(Exception):
1413
pass

0 commit comments

Comments
 (0)