aboutsummaryrefslogtreecommitdiffstats
path: root/pygithub3
diff options
context:
space:
mode:
authorDavid Medina <davidmedina9@gmail.com>2012-02-06 21:39:59 +0100
committerDavid Medina <davidmedina9@gmail.com>2012-02-07 19:22:59 +0100
commit86453d2fb40e21280aeeee7e5ee11229bcb5eaac (patch)
tree2490c76fbbdef9bc14e5c1c2b83b632b1401eb2e /pygithub3
parentSomething confusing about PUT request (diff)
downloadpython-github3-86453d2fb40e21280aeeee7e5ee11229bcb5eaac.tar.xz
python-github3-86453d2fb40e21280aeeee7e5ee11229bcb5eaac.zip
Clean requests interface
Refactorize on build request to support specific requests cleaner *Also support to verbose on requests library
Diffstat (limited to 'pygithub3')
-rw-r--r--pygithub3/core/client.py8
-rw-r--r--pygithub3/core/errors.py19
-rw-r--r--pygithub3/core/result.py2
-rw-r--r--pygithub3/exceptions.py36
-rw-r--r--pygithub3/requests/__init__.py106
-rw-r--r--pygithub3/requests/users/__init__.py2
-rw-r--r--pygithub3/requests/users/emails.py36
-rw-r--r--pygithub3/requests/users/followers.py56
-rw-r--r--pygithub3/requests/users/keys.py59
-rw-r--r--pygithub3/requests/users/user.py25
-rw-r--r--pygithub3/resources/base.py3
-rw-r--r--pygithub3/services/base.py84
-rw-r--r--pygithub3/services/users.py72
13 files changed, 224 insertions, 284 deletions
diff --git a/pygithub3/core/client.py b/pygithub3/core/client.py
index 866d40a..d9ecf81 100644
--- a/pygithub3/core/client.py
+++ b/pygithub3/core/client.py
@@ -18,7 +18,7 @@ class Client(object):
"""
It can be configurated
- :login, :password, :user, :repo, :token, :per_page, :base_url
+ :login, :password, :user, :repo, :token, :per_page, :base_url, :verbose
"""
self.requester = requests.session()
@@ -58,6 +58,8 @@ class Client(object):
def __set_params(self, config):
self.requester.params['per_page'] = config.get('per_page')
+ if config.get('verbose'):
+ self.requester.config = {'verbose': config['verbose']}
def __parse_kwargs(func):
""" Decorator to put extra args into requests.params """
@@ -106,4 +108,6 @@ class Client(object):
return response
def head(self, request, **kwargs):
- return self.request('head', request, **kwargs)
+ response = self.request('head', request, **kwargs)
+ assert response.status_code != '200'
+ return response
diff --git a/pygithub3/core/errors.py b/pygithub3/core/errors.py
index 1a9ed0c..ae7bcc4 100644
--- a/pygithub3/core/errors.py
+++ b/pygithub3/core/errors.py
@@ -1,19 +1,12 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
-import json
+try:
+ import simplejson as json
+except ImportError:
+ import json
-
-class BadRequest(Exception):
- pass
-
-
-class UnprocessableEntity(Exception):
- pass
-
-
-class NotFound(Exception):
- pass
+from pygithub3.exceptions import NotFound, BadRequest, UnprocessableEntity
class GithubError(object):
@@ -34,7 +27,7 @@ class GithubError(object):
raise BadRequest("400 - %s" % self.debug.get('message'))
def error_422(self):
- errors = self.debug.get('errors')
+ errors = self.debug.get('errors', ())
errors = ['Resource: {resource}: {field} => {message} ({code})'.format(
**error)
for error in errors]
diff --git a/pygithub3/core/result.py b/pygithub3/core/result.py
index 5d8ea7a..226d6ab 100644
--- a/pygithub3/core/result.py
+++ b/pygithub3/core/result.py
@@ -48,7 +48,7 @@ class Method(object):
all_args.update(page=page)
response = self.method(self.request, **all_args)
self.__set_last_page_from(response)
- resource = self.request.get_resource()
+ resource = self.request.resource
self.cache[str(page)] = resource.loads(response.content)
return self.cache[str(page)]
diff --git a/pygithub3/exceptions.py b/pygithub3/exceptions.py
new file mode 100644
index 0000000..65881bb
--- /dev/null
+++ b/pygithub3/exceptions.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+
+class DoesNotExists(Exception):
+ """ Raised when `Request` factory can't find the subclass """
+ pass
+
+
+class UriInvalid(Exception):
+ """ Raised when `Request` factory's maker isn't in a valid form """
+ pass
+
+
+class ValidationError(Exception):
+ """ Raised when a `Request` doesn't have the necessary args to make a
+ valid URI """
+ pass
+
+
+class BadRequest(Exception):
+ """ Raised when server response is 400 """
+ pass
+
+
+class UnprocessableEntity(Exception):
+ """ Raised when server response is 400 """
+ pass
+
+
+class NotFound(Exception):
+ """ Raised when server response is 404
+
+ Catched with a pygithub3-exception to `services.base.Base._bool` method
+ """
+ pass
diff --git a/pygithub3/requests/__init__.py b/pygithub3/requests/__init__.py
index 725ea12..9fdde27 100644
--- a/pygithub3/requests/__init__.py
+++ b/pygithub3/requests/__init__.py
@@ -8,60 +8,77 @@ try:
except ImportError:
import json
-ABS_IMPORT_PREFIX = 'pygithub3.requests'
+from pygithub3.exceptions import DoesNotExists, UriInvalid, ValidationError
+from pygithub3.resources.base import Raw
+ABS_IMPORT_PREFIX = 'pygithub3.requests'
-class RequestNotFound(Exception):
- pass
+class Body(object):
-class RequestUriInvalid(Exception):
- pass
+ def __init__(self, content, schema):
+ self.content = content
+ self.schema = schema
+ def dumps(self):
+ if not self.content:
+ return None
+ return json.dumps(self.parse())
-class RequestValidationError(Exception):
- pass
+ def parse(self):
+ if not self.schema:
+ return self.content
+ if not hasattr(self.content, 'items'):
+ raise ValidationError("'%s' needs a content dictionary"
+ % self.__class__.__name__)
+ return {key: self.content[key] for key in self.schema
+ if key in self.content}
class Request(object):
""" """
+ uri = ''
+ resource = Raw
+ body_schema = ()
+
def __init__(self, args):
""" """
+ self.body = args.pop('body', None)
self.args = args
- self.validate()
- self.uri = self.set_uri()
+ self.clean()
- def validate(self):
- raise NotImplementedError
+ def clean(self):
+ self.uri = self.clean_uri() or self.uri
+ self.body = Body(self.clean_body(), self.body_schema)
- def set_uri(self):
- raise NotImplementedError
+ def clean_body(self):
+ return self.body
- def get_data(self):
- raise NotImplementedError
+ def clean_uri(self):
+ return None
- def get_uri(self):
- return str(self.uri).strip('/')
-
- def get_resource(self):
- return getattr(self, 'resource', '')
+ @property
+ def resource(self):
+ return self.resource
def __getattr__(self, name):
return self.args.get(name)
def __str__(self):
- return self.get_uri()
+ return self.populate_uri()
+
+ def populate_uri(self):
+ try:
+ populated_uri = self.uri.format(**self.args)
+ except KeyError:
+ raise ValidationError(
+ "'%s' request wasn't be able to populate the uri '%s' with "
+ "'%s' args" % (self.__class__.__name__, self.uri, self.args))
+ return str(populated_uri).strip('/')
- def _parse_simple_dict(self, to_parse):
- if not hasattr(to_parse, 'items'):
- raise RequestValidationError("'%s' needs a data dictionary"
- % self.__class__.__name__)
- update_params = {
- valid_key: to_parse[valid_key]
- for valid_key in self.valid
- if valid_key in to_parse}
- return update_params
+ def get_body(self):
+ return self.body.dumps()
class Factory(object):
@@ -69,29 +86,19 @@ class Factory(object):
import_pattern = re.compile(r'^(\w+\.)+\w+$')
- def __init__(self):
- """ """
- self.args = {}
-
- def config_with(self, **kwargs):
- self.args = kwargs
-
- def clear_config(self):
- self.args = {}
-
def __validate(func):
""" """
- def wrapper(self, request_uri):
+ def wrapper(self, request_uri, **kwargs):
if not Factory.import_pattern.match(request_uri):
- raise RequestUriInvalid("'%s' isn't valid form" % request_uri)
- return func(self, request_uri.lower())
+ raise UriInvalid("'%s' isn't valid form" % request_uri)
+ return func(self, request_uri.lower(), **kwargs)
return wrapper
def __dispatch(func):
""" """
- def wrapper(self, request_uri):
+ def wrapper(self, request_uri, **kwargs):
module_chunk, s, request_chunk = request_uri.rpartition('.')
try:
# TODO: CamelCase and under_score support, now only Class Name
@@ -99,19 +106,18 @@ class Factory(object):
% (ABS_IMPORT_PREFIX, module_chunk))
request = getattr(module, request_chunk.capitalize())
except ImportError:
- raise RequestNotFound("'%s' module does not exists"
+ raise DoesNotExists("'%s' module does not exists"
% module_chunk)
except AttributeError:
- raise RequestNotFound(
+ raise DoesNotExists(
"'%s' request doesn't exists into '%s' module"
% (request_chunk.capitalize(), module_chunk))
- return func(self, request)
+ return func(self, request, **kwargs)
return wrapper
@__validate
@__dispatch
- def __call__(self, request=''):
- request = request(self.args)
- self.clear_config()
+ def __call__(self, request='', **kwargs):
+ request = request(kwargs)
assert isinstance(request, Request)
return request
diff --git a/pygithub3/requests/users/__init__.py b/pygithub3/requests/users/__init__.py
index 93ab7b6..11e6a39 100644
--- a/pygithub3/requests/users/__init__.py
+++ b/pygithub3/requests/users/__init__.py
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
-from pygithub3.requests import Request, json, RequestValidationError
+from pygithub3.requests import Request, ValidationError
from user import *
diff --git a/pygithub3/requests/users/emails.py b/pygithub3/requests/users/emails.py
index f7fb284..7622fcc 100644
--- a/pygithub3/requests/users/emails.py
+++ b/pygithub3/requests/users/emails.py
@@ -1,44 +1,28 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
-from . import Request, json
-from pygithub3.resources.base import Raw
+import re
+from . import Request
-class List(Request):
-
- resource = Raw
- def validate(self):
- pass
+class List(Request):
- def set_uri(self):
- return 'user/emails'
+ uri = 'users/emails'
class Add(Request):
- resource = Raw
+ uri = 'user/emails'
- def validate(self):
- pass
+ def clean_body(self):
- def get_data(self):
- return json.dumps(self.emails)
+ def is_email(email):
+ return re.match(r'.*', email) # TODO: email regex ;)
- def set_uri(self):
- return 'user/emails'
+ return filter(is_email, self.body)
class Delete(Request):
- resource = Raw
-
- def validate(self):
- pass
-
- def get_data(self):
- return json.dumps(self.emails)
-
- def set_uri(self):
- return 'user/emails'
+ uri = 'user/emails'
diff --git a/pygithub3/requests/users/followers.py b/pygithub3/requests/users/followers.py
index f2bfc1a..5f59032 100644
--- a/pygithub3/requests/users/followers.py
+++ b/pygithub3/requests/users/followers.py
@@ -1,76 +1,40 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
-from . import Request, RequestValidationError
+from . import Request
from pygithub3.resources.users import User
-from pygithub3.resources.base import Raw
class List(Request):
resource = User
+ uri = 'users/{user}/followers'
- def validate(self):
- pass
-
- def set_uri(self):
- if self.user:
- return 'users/%s/followers' % self.user
- else:
+ def clean_uri(self):
+ if not self.user:
return 'user/followers'
class Listfollowing(Request):
resource = User
+ uri = 'users/{user}/following'
- def validate(self):
- pass
-
- def set_uri(self):
- if self.user:
- return 'users/%s/following' % self.user
- else:
+ def clean_uri(self):
+ if not self.user:
return 'user/following'
class Isfollowing(Request):
- resource = Raw
-
- def validate(self):
- if not self.user:
- raise RequestValidationError(
- "'%s' request needs a user" % self.__class__.__name__)
-
- def set_uri(self):
- return 'user/following/%s' % self.user
+ uri = 'user/following/{user}'
class Follow(Request):
- resource = Raw
-
- def validate(self):
- if not self.user:
- raise RequestValidationError(
- "'%s' request needs a user" % self.__class__.__name__)
-
- def set_uri(self):
- return 'user/following/%s' % self.user
+ uri = 'user/following/{user}'
class Unfollow(Request):
- resource = User
-
- def validate(self):
- if not self.user:
- raise RequestValidationError(
- "'%s' request needs a user" % self.__class__.__name__)
-
- def set_uri(self):
- return 'user/following/%s' % self.user
-
- def get_data(self):
- pass
+ uri = 'user/following/{user}'
diff --git a/pygithub3/requests/users/keys.py b/pygithub3/requests/users/keys.py
index f5bb386..9afa3cd 100644
--- a/pygithub3/requests/users/keys.py
+++ b/pygithub3/requests/users/keys.py
@@ -1,79 +1,36 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
-from . import Request, json, RequestValidationError
+from . import Request
from pygithub3.resources.users import Key
-from pygithub3.resources.base import Raw
class List(Request):
resource = Key
-
- def validate(self):
- pass
-
- def set_uri(self):
- return 'user/keys'
+ uri = 'user/key'
class Get(Request):
resource = Key
-
- def validate(self):
- if not self.key_id:
- raise RequestValidationError("'%s' needs key_id"
- % self.__class__.__name__)
-
- def set_uri(self):
- return 'user/keys/%s' % self.key_id
+ uri = 'user/keys/{key_id}'
class Add(Request):
resource = Key
- valid = ('title', 'key')
-
- def validate(self):
- self.add_data = self._parse_simple_dict(self.add_data)
-
- def set_uri(self):
- return 'user/keys'
-
- def get_data(self):
- return json.dumps(self.add_data)
+ uri = 'user/keys'
+ body_schema = ('title', 'key')
class Update(Request):
resource = Key
- valid = ('title', 'key')
-
- def validate(self):
- if not self.key_id:
- raise RequestValidationError("'%s' needs key_id"
- % self.__class__.__name__)
- self.update_params = self._parse_simple_dict(self.update_with)
-
- def set_uri(self):
- return 'user/keys/%s' % self.key_id
-
- def get_data(self):
- return json.dumps(self.update_params)
+ body_schema = ('title', 'key')
+ uri = 'user/keys/{key_id}'
class Delete(Request):
- resource = Raw
-
- def validate(self):
- if not self.key_id:
- raise RequestValidationError("'%s' needs key_id"
- % self.__class__.__name__)
-
- def set_uri(self):
- return 'user/keys/%s' % self.key_id
-
- def get_data(self):
- return None
+ uri = 'user/keys/{key_id}'
diff --git a/pygithub3/requests/users/user.py b/pygithub3/requests/users/user.py
index d4b3667..78ab6cd 100644
--- a/pygithub3/requests/users/user.py
+++ b/pygithub3/requests/users/user.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
-from . import Request, json
+from . import Request, ValidationError
from pygithub3.resources.users import User
__all__ = ('Get', 'Update')
@@ -10,27 +10,16 @@ __all__ = ('Get', 'Update')
class Get(Request):
resource = User
+ uri = 'users/{user}'
- def validate(self):
- pass
-
- def set_uri(self):
- if self.user:
- return 'users/%s' % self.user
- else:
+ def clean_uri(self):
+ if not self.user:
return 'user'
class Update(Request):
resource = User
- valid = ('name', 'email', 'blog', 'company', 'location', 'hireable', 'bio')
-
- def validate(self):
- self.update_params = self._parse_simple_dict(self.update_with)
-
- def get_data(self):
- return json.dumps(self.update_params)
-
- def set_uri(self):
- return 'user'
+ uri = 'user'
+ body_schema = (
+ 'name', 'email', 'blog', 'company', 'location','hireable', 'bio')
diff --git a/pygithub3/resources/base.py b/pygithub3/resources/base.py
index 620df3e..ae038bd 100644
--- a/pygithub3/resources/base.py
+++ b/pygithub3/resources/base.py
@@ -22,6 +22,9 @@ class Resource(object):
for attr in self._attrs:
setattr(self, attr, self._attrs[attr])
+ def __repr__(self):
+ return self.__str__()
+
@classmethod
def loads(self, json_content):
resource_chunk = json.loads(json_content)
diff --git a/pygithub3/services/base.py b/pygithub3/services/base.py
index 1ade763..c659470 100644
--- a/pygithub3/services/base.py
+++ b/pygithub3/services/base.py
@@ -10,42 +10,40 @@ from pygithub3.core.errors import NotFound
class Base(object):
def __init__(self, **config):
- self.client = Client(**config)
- self.get_request = Factory()
+ self._client = Client(**config)
+ self.make_request = Factory()
def get_user(self):
- return self.client.user
+ return self._client.user
def set_user(self, user):
- self.client.user = user
+ self._client.user = user
def get_repo(self):
- return self.client.repo
+ return self._client.repo
def set_repo(self, repo):
- self.client.repo = repo
+ self._client.repo = repo
- def _config_request(self, **kwargs):
- self.get_request.config_with(**kwargs)
+ def set_credentials(self, login, password):
+ self._client.set_credentials(login, password)
- def _bool(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
+ def set_token(self, token):
+ self._client.set_token(token)
+
+ def _bool(self, request, **kwargs):
try:
- self.client.head(request, **kwargs)
+ self._client.head(request, **kwargs)
return True
except NotFound:
return False
- def _patch(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- resource = request.get_resource()
- input_data = request.get_data()
- response = self.client.patch(request, data=input_data, **kwargs)
- return resource.loads(response.content)
+ def _patch(self, request, **kwargs):
+ input_data = request.get_body()
+ response = self._client.patch(request, data=input_data, **kwargs)
+ return request.resource.loads(response.content)
- def _put(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- resource = request.get_resource()
+ def _put(self, request, **kwargs):
""" Bug in Github API? requests library?
I must send data as empty string when the specifications' of some PUT
@@ -60,31 +58,25 @@ class Base(object):
For that reason I must do a conditional because I don't want to return
an empty string on follow-user request because it could be confused
- Related: ht
+ Related: https://github.com/github/developer.github.com/pull/52
"""
- input_data = request.get_data() or ''
- response = self.client.put(request, data=input_data, **kwargs)
+ input_data = request.get_body() or ''
+ response = self._client.put(request, data=input_data, **kwargs)
if response.status_code != '204': # != NO_CONTENT
- return resource.loads(response.content)
-
- def _delete(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- input_data = request.get_data()
- self.client.delete(request, data=input_data, **kwargs)
-
- def _post(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- resource = request.get_resource()
- input_data = request.get_data()
- response = self.client.post(request, data=input_data, **kwargs)
- return resource.loads(response.content)
-
- def _get(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- resource = request.get_resource()
- response = self.client.get(request, **kwargs)
- return resource.loads(response.content)
-
- def _get_result(self, request_uri, **kwargs):
- request = self.get_request(request_uri)
- return Result(self.client, request, **kwargs)
+ return request.resource.loads(response.content)
+
+ def _delete(self, request, **kwargs):
+ input_data = request.get_body()
+ self._client.delete(request, data=input_data, **kwargs)
+
+ def _post(self, request, **kwargs):
+ input_data = request.get_body()
+ response = self._client.post(request, data=input_data, **kwargs)
+ return request.resource.loads(response.content)
+
+ def _get(self, request, **kwargs):
+ response = self._client.get(request, **kwargs)
+ return request.resource.loads(response.content)
+
+ def _get_result(self, request, **kwargs):
+ return Result(self._client, request, **kwargs)
diff --git a/pygithub3/services/users.py b/pygithub3/services/users.py
index 9ec15e8..84002b2 100644
--- a/pygithub3/services/users.py
+++ b/pygithub3/services/users.py
@@ -7,60 +7,71 @@ from .base import Base
class Keys(Base):
def list(self):
- return self._get_result('users.keys.list')
+ request = self.make_request('users.keys.list')
+ return self._get_result(request)
def get(self, key_id):
- self._config_request(key_id=key_id)
- return self._get('users.keys.get')
+ request = self.make_request('users.keys.get',
+ key_id=key_id)
+ return self._get(request)
def add(self, data):
- self._config_request(add_data=data)
- return self._post('users.keys.add')
+ request = self.make_request('users.keys.add',
+ body=data)
+ return self._post(request)
def update(self, key_id, data):
- self._config_request(key_id=key_id, update_with=data)
- return self._patch('users.keys.update')
+ request = self.make_request('users.keys.update',
+ key_id=key_id, body=data)
+ return self._patch(request)
def delete(self, key_id):
- self._config_request(key_id=key_id)
- self._delete('users.keys.delete')
+ request = self.make_request('users.keys.delete',
+ key_id=key_id)
+ self._delete(request)
class Followers(Base):
def list(self, user=None):
- self._config_request(user=user or self.get_user())
- return self._get_result('users.followers.list')
+ request = self.make_request('users.followers.list',
+ user=user or self.get_user())
+ return self._get_result(request)
def list_following(self, user=None):
- self._config_request(user=user or self.get_user())
- return self._get_result('users.followers.listfollowing')
+ request = self.make_request('users.followers.listfollowing',
+ user=user or self.get_user())
+ return self._get_result(request)
def is_following(self, user):
- self._config_request(user=user)
- return self._bool('users.followers.isfollowing')
+ request = self.make_request('users.followers.isfollowing',
+ user=user)
+ return self._bool(request)
def follow(self, user):
- self._config_request(user=user)
- self._put('users.followers.follow')
+ request = self.make_request('users.followers.follow',
+ user=user)
+ self._put(request)
def unfollow(self, user):
- self._config_request(user=user)
- self._delete('users.followers.unfollow')
+ request = self.make_request('users.followers.unfollow',
+ user=user)
+ self._delete(request)
class Emails(Base):
def list(self):
- return self._get_result('users.emails.list')
+ request = self.make_request('users.emails.list')
+ return self._get_result(request)
- def add(self, *args):
- self._config_request(emails=args)
- return self._post('users.emails.add')
+ def add(self, *emails):
+ request = self.make_request('users.emails.add', body=emails)
+ return self._post(request)
- def delete(self, *args):
- self._config_request(emails=args)
- self._delete('users.emails.delete')
+ def delete(self, *emails):
+ request = self.make_request('users.emails.delete', body=emails)
+ self._delete(request)
class User(Base):
@@ -72,9 +83,10 @@ class User(Base):
super(User, self).__init__(**kwargs)
def get(self, user=None):
- self._config_request(user=user or self.get_user())
- return self._get('users.get')
+ request = self.make_request('users.get',
+ user=user or self.get_user())
+ return self._get(request)
def update(self, data):
- self._config_request(update_with=data)
- return self._patch('users.update')
+ request = self.make_request('users.update', body=data)
+ return self._patch(request)