diff options
-rw-r--r-- | README.md (renamed from README.rst) | 49 | ||||
-rw-r--r-- | github3/api.py | 29 | ||||
-rw-r--r-- | github3/errors.py | 3 | ||||
-rw-r--r-- | github3/handlers/users.py | 9 | ||||
-rw-r--r-- | github3/tests/test_core.py | 115 |
5 files changed, 156 insertions, 49 deletions
@@ -1,45 +1,34 @@ Fork -====================================== +==== Refactor and complete api wrapper. Intensive work in progress Use with auth user ---------------------- +------------------ -```python -from github3.api import Github + from github3.api import Github -gh = Github('user', 'password') + gh = Github('user', 'password') -users_handler = gh.users -for repo in users_handler.get_repos(): - print repo - -gists_handler = gh.gists -gists_handler.create_gist( - u'Description', - files={'file1.txt': {'content': u'Content of first file'}}) -``` + users_handler = gh.users + for repo in users_handler.get_repos(): + print repo + gists_handler = gh.gists + gists_handler.create_gist( + u'Description', + files={'file1.txt': {'content': u'Content of first file'}}) Installation ------------ -To install Github3, simply: :: - - $ pip install github3 - -Or, if you absolutely must: :: - - $ easy_install github3 - -But, you really shouldn't do that. - +To install Github3, simply: + $ pip -e git+https://copitux@github.com/copitux/python-github3#egg=python-github3 License ------- -ISC License. :: +ISC License. Copyright (c) 2011, Kenneth Reitz <me@kennethreitz.com> @@ -59,10 +48,9 @@ ISC License. :: Contribute ---------- -If you'd like to contribute, simply fork `the repository`_, commit your changes +If you'd like to contribute, simply fork `the repository`, commit your changes to the **develop** branch (or branch off of it), and send a pull request. Make -sure you add yourself to AUTHORS_. - +sure you add yourself to `AUTHORS`. Roadmap @@ -70,9 +58,6 @@ Roadmap - Unittests - Handlers -- Get it Started -- HTTP BASIC -- Get it working -- Sphinx Documetnation +- Sphinx Documentation - Examples - OAuth Last (how?) diff --git a/github3/api.py b/github3/api.py index e9eebb5..9dbe52f 100644 --- a/github3/api.py +++ b/github3/api.py @@ -10,6 +10,7 @@ from handlers import users, gists RESOURCES_PER_PAGE = 100 + class GithubCore(object): """ Wrapper to github api requests @@ -88,22 +89,21 @@ class GithubCore(object): """ Arg's parser to `_request` method - It check keyword args to parse extra request args to params - Sample: - _parse_args(arg1=1, arg2=2) => params = {'arg1': 1, 'arg2': 2} + Put extra request_args in params """ request_core = ( - 'params','data','headers','cookies','files','auth','tiemout', - 'allow_redirects','proxies','return_response','config') + 'params', 'data', 'headers', 'cookies', 'files', 'auth', 'tiemout', + 'allow_redirects', 'proxies', 'return_response', 'config') request_params = request_args.get('params') extra_params = {} for k, v in request_args.items(): - if k in request_core: continue + if k in request_core: + continue extra_params.update({k: v}) del request_args[k] - if request_params: + if request_params and getattr(request_params, 'update'): request_args['params'].update(extra_params) - else: + elif extra_params: request_args['params'] = extra_params return request_args @@ -117,15 +117,16 @@ class GithubCore(object): :param kwargs: Keyword args to request """ request = self.base_url + request - parsed_args = self._parse_args(kwargs) - response = self.session.request(verb, request, **parsed_args) + self._parse_args(kwargs) + response = self.session.request(verb, request, **kwargs) self.requests_remaining = response.headers.get( - 'x-ratelimit-remaining',-1) + 'x-ratelimit-remaining', -1) error = GithubError(response) error.process() return response + class Github(GithubCore): """ Library enter """ @@ -133,10 +134,10 @@ class Github(GithubCore): super(Github, self).__init__() self.authenticated = False auth = len(args) - if auth == 2: # Basic auth - self.session.auth = tuple(map(str,args)) + if auth == 2: # Basic auth + self.session.auth = tuple(map(str, args)) self.authenticated = True - elif auth == 1: # Token oauth + elif auth == 1: # Token oauth raise NotImplementedError elif auth > 2: raise TypeError("user, password or token") diff --git a/github3/errors.py b/github3/errors.py index 09e616b..bd85483 100644 --- a/github3/errors.py +++ b/github3/errors.py @@ -6,6 +6,7 @@ import json import github3.exceptions as exceptions + class GithubError(object): """ Handler for API errors """ @@ -14,7 +15,7 @@ class GithubError(object): self.status_code = response.status_code try: self.debug = self._parser.loads(response.content) - except ValueError: + except (ValueError, TypeError): self.debug = {'message': response.content} def error_400(self): diff --git a/github3/handlers/users.py b/github3/handlers/users.py index fb893b4..b990c65 100644 --- a/github3/handlers/users.py +++ b/github3/handlers/users.py @@ -7,6 +7,7 @@ from .base import Handler import github3.models as models from github3.converters import Rawlizer + class User(Handler): """ User handler with public access """ @@ -25,6 +26,7 @@ class User(Handler): parse_user = str(getattr(user, 'login', user)) self.username = parse_user self.prefix = '/'.join((self.prefix, parse_user)) + return self def get(self): """ Return user """ @@ -61,6 +63,7 @@ class User(Handler): return self._get_resources('gists', model=models.Gist) + class AuthUser(User): """ User handler with public and private access """ @@ -116,6 +119,8 @@ class AuthUser(User): Follow user :param `user`: User model or username string + + NOTE: Maybe bug in API, return text/html. Waitingf for answer """ parse_user = str(getattr(user, 'login', user)) @@ -151,8 +156,8 @@ class AuthUser(User): #TODO: render key.pub file key = { - 'title': kwargs.get('title',''), - 'key': kwargs.get('key','') + 'title': kwargs.get('title', ''), + 'key': kwargs.get('key', '') } return self._post_resource('keys', data=key, model=models.Key) diff --git a/github3/tests/test_core.py b/github3/tests/test_core.py new file mode 100644 index 0000000..258a737 --- /dev/null +++ b/github3/tests/test_core.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +from mock import Mock, patch +from unittest import TestCase +from github3 import api +from github3.exceptions import * +import json +import requests + + +@patch.object(requests.sessions.Session, 'request') +class TestGithubCore(TestCase): + + def setUp(self): + self.gh = api.GithubCore() + self.assertEquals(self.gh.base_url, 'https://api.github.com/') + self.assertEquals(self.gh._parser, json) + self.base_url = self.gh.base_url + self.parser = self.gh._parser + + def test_parse_args(self, request_method): + args = { + 'data': {'some': 'data'}, + 'params': {'arg0': 'some'}, + 'headers': 'out', + 'auth': 'out', + 'arg1': 'some', + 'arg2': 'some', + 'arg3': {'some': 'data', 'are': {'nested': 'true'}}, + } + self.gh._parse_args(args) + self.assertEquals(args, { + 'data': {'some': 'data'}, + 'params': {'arg0': 'some', 'arg1': 'some', 'arg2': 'some', + 'arg3': {'some': 'data', 'are': {'nested': 'true'}}}, + 'headers': 'out', + 'auth': 'out', + }) + + def test_raise_errors(self, request_method): + real_request = (self.gh._request, 'GET', 'test') + request_method.return_value.status_code = 404 + self.assertRaises(NotFound, *real_request) + + request_method.return_value.status_code = 400 + self.assertRaises(BadRequest, *real_request) + + request_method.return_value.status_code = 422 + self.assertRaises(UnprocessableEntity, *real_request) + + request_method.return_value.status_code = 401 + self.assertRaises(Unauthorized, *real_request) + + def test_get(self, request_method): + response = request_method.return_value + response.content = self.parser.dumps({'test': 'test'}) + content = self.gh.get('core') + request_method.assert_called_with('GET', self.base_url + 'core') + self.assertEquals(content, {'test': 'test'}) + + response = request_method.return_value + response.headers = {'link': 'url_with_links'} + response.content = self.parser.dumps({'test': 'test'}) + header, content = self.gh.get('core', paginate=True) + request_method.assert_called_with('GET', self.base_url + 'core') + self.assertEquals(header, 'url_with_links') + self.assertEquals(content, {'test': 'test'}) + + def test_head(self, request_method): + pass # It has no sense using mocks + + def test_post_and_patch(self, request_method): + data = {'login': 'test', 'bio': 'test'} + response = request_method.return_value + response.status_code = 201 + response.content = self.parser.dumps({'post': 'done'}) + + content = self.gh.post('core', data=data) + request_method.assert_called_with( + 'POST', self.base_url + 'core', + data=self.parser.dumps(data)) + self.assertEquals(content, {'post': 'done'}) + + content = self.gh.post('core') + request_method.assert_called_with( + 'POST', self.base_url + 'core', + data=self.parser.dumps(None)) + self.assertEquals(content, {'post': 'done'}) + + response.status_code = 200 + content = self.gh.patch('core', data=data) + request_method.assert_called_with( + 'PATCH', self.base_url + 'core', + data=self.parser.dumps(data)) + self.assertEquals(content, {'post': 'done'}) + + content = self.gh.patch('core') + request_method.assert_called_with( + 'PATCH', self.base_url + 'core', + data=self.parser.dumps(None)) + self.assertEquals(content, {'post': 'done'}) + + def test_delete(self, request_method): + data = {'test': 'test'} + response = request_method.return_value + response.status_code = 204 + response.content = self.parser.dumps({'delete': 'done'}) + delete = self.gh.delete('core', data=data) + request_method.assert_called_with( + 'DELETE', self.base_url + 'core', + data=self.parser.dumps(data)) + delete = self.gh.delete('core') + request_method.assert_called_with( + 'DELETE', self.base_url + 'core') |