From c23698e64f3244636290ffa4065f3b70ba5151e9 Mon Sep 17 00:00:00 2001 From: David Medina Date: Sat, 29 Oct 2011 16:11:27 +0200 Subject: Wip on handlers --- github3/models/__init__.py | 0 github3/models/base.py | 178 +++++++++++++++++++++++++++++++++++++++++++++ github3/models/user.py | 79 ++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 github3/models/__init__.py create mode 100644 github3/models/base.py create mode 100644 github3/models/user.py (limited to 'github3/models') diff --git a/github3/models/__init__.py b/github3/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/github3/models/base.py b/github3/models/base.py new file mode 100644 index 0000000..618e57f --- /dev/null +++ b/github3/models/base.py @@ -0,0 +1,178 @@ +""" +github3.models +~~~~~~~~~~~~~~ + +This module provides the Github3 object model. +""" + +import json + +from .helpers import to_python, to_api, key_diff + + +class BaseResource(object): + """A BaseResource object.""" + + _strs = [] + _ints = [] + _dates = [] + _bools = [] + _map = {} + _writeable = [] + _cache = {} + + + def __init__(self): + self._bootstrap() + super(BaseResource, self).__init__() + + + def __dir__(self): + return self.keys() + + def _bootstrap(self): + """Bootstraps the model object based on configured values.""" + + for attr in self.keys(): + setattr(self, attr, None) + + def keys(self): + return self._strs + self._ints + self._dates + self._bools + self._map.keys() + + def dict(self): + d = dict() + for k in self.keys(): + d[k] = self.__dict__.get(k) + + return d + + @classmethod + def new_from_dict(cls, d, gh=None): + + return to_python( + obj=cls(), in_dict=d, + str_keys = cls._strs, + int_keys = cls._ints, + date_keys = cls._dates, + bool_keys = cls._bools, + object_map = cls._map, + _gh = gh + ) + + + def update(self): + deploy = key_diff(self._cache, self.dict(), pack=True) + + deploy = to_api(deploy, int_keys=self._ints, date_keys=self._dates, bool_keys=self._bools) + deploy = json.dumps(deploy) + + r = self._gh._patch_resource(self.ri, deploy) + return r + + +class Plan(BaseResource): + """Github Plan object model.""" + + _strs = ['name'] + _ints = ['space', 'collaborators', 'private_repos'] + + def __repr__(self): + return ''.format(str(self.name)) + +class Org(BaseResource): + """Github Organization object model.""" + + _strs = [ + 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' + 'html_url', 'type', 'billing_email'] + _ints = [ + 'id', 'public_repos', 'public_gists', 'followers', 'following', + 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', + 'collaborators'] + _dates = ['created_at'] + _map = {'plan': Plan} + _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] + + @property + def ri(self): + return ('orgs', self.login) + + def __repr__(self): + return ''.format(self.login) + + def repos(self, limit=None): + return self._gh._get_resources(('orgs', self.login, 'repos'), Repo, limit=limit) + + def members(self, limit=None): + return self._gh._get_resources(('orgs', self.login, 'members'), User, limit=limit) + + def is_member(self, username): + if isinstance(username, User): + username = username.login + + r = self._gh._http_resource('GET', ('orgs', self.login, 'members', username), check_status=False) + return (r.status_code == 204) + + def publicize_member(self, username): + if isinstance(username, User): + username = username.login + + r = self._gh._http_resource('PUT', ('orgs', self.login, 'public_members', username), check_status=False, data='') + return (r.status_code == 204) + + def conceal_member(self, username): + if isinstance(username, User): + username = username.login + + r = self._gh._http_resource('DELETE', ('orgs', self.login, 'public_members', username), check_status=False) + return (r.status_code == 204) + + def remove_member(self, username): + if isinstance(username, User): + username = username.login + + r = self._gh._http_resource('DELETE', ('orgs', self.login, 'members', username), check_status=False) + return (r.status_code == 204) + + def public_members(self, limit=None): + return self._gh._get_resources(('orgs', self.login, 'public_members'), User, limit=limit) + + def is_public_member(self, username): + if isinstance(username, User): + username = username.login + + r = self._gh._http_resource('GET', ('orgs', self.login, 'public_members', username), check_status=False) + return (r.status_code == 204) + + +class Gist(BaseResource): + _strs = ['url', 'description', 'html_url', 'git_pull_url', 'git_push_url'] + _ints = ['id', 'comments'] + _bools = ['public'] + _dates = ['created_at'] + _map = {'user': User} #TODO: file + + @property + def ri(self): + return ('users', self.user.login, self.id) + + def __repr__(self): + return '' % (self.user.login, self.description) + +class Repo(BaseResource): + _strs = [ + 'url', 'html_url', 'clone_url', 'git_url', 'ssh_url', 'svn_url', + 'name', 'description', 'homepage', 'language', 'master_branch'] + _bools = ['private', 'fork'] + _ints = ['forks', 'watchers', 'size',] + _dates = ['pushed_at', 'created_at'] + _map = {'owner': User} + + + @property + def ri(self): + return ('repos', self.owner.login, self.name) + + def __repr__(self): + return ''.format(self.owner.login, self.name) + # owner diff --git a/github3/models/user.py b/github3/models/user.py new file mode 100644 index 0000000..cdbd04f --- /dev/null +++ b/github3/models/user.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# author: David Medina + +from .base import BaseResource + +class User(BaseResource): + """Github User object model.""" + + _strs = [ + 'login','avatar_url', 'url', 'name', 'company', 'blog', 'location', + 'email', 'bio', 'html_url'] + + _ints = ['id', 'public_repos', 'public_gists', 'followers', 'following'] + _dates = ['created_at',] + _bools = ['hireable', ] + # _map = {} + # _writeable = [] + + @property + def ri(self): + return ('users', self.login) + + def __repr__(self): + return ''.format(self.login) + + @property + def handler(self): + return self._gh.user_handler(self.login) + + def get_followers(self, limit=None): + return self.handler.followers(limit) + + def get_following(self, limit=None): + return self.handler.following(limit) + + def repos(self, limit=None): + return self._gh._get_resources(('users', self.login, 'repos'), Repo, limit=limit) + def repo(self, reponame): + return self._gh._get_resource(('repos', self.login, reponame), Repo) + + def orgs(self): + return self._gh._get_resources(('users', self.login, 'orgs'), Org) + + def gists(self): + return self._gh._get_resources(('users', self.login, 'gists'), Gist) + +class AuthUser(User): + """Github Current User object model.""" + + _ints = [ + 'id', 'public_repos', 'public_gists', 'followers', 'following', + 'total_private_repos', 'owned_private_repos', 'private_gists', + 'disk_usage', 'collaborators'] + _map = {'plan': Plan} + _writeable = ['name', 'email', 'blog', 'company', 'location', 'hireable', 'bio'] + + @property + def ri(self): + return ('user',) + + def __repr__(self): + return ''.format(self.login) + + def repos(self, limit=None): + return self._gh._get_resources(('user', 'repos'), Repo, limit=limit) + + def repo(self, reponame): + return self._gh._get_resource(('repos', self.login, reponame), Repo) + + def orgs(self, limit=None): + return self._gh._get_resources(('user', 'orgs'), Org, limit=limit) + + def org(self, orgname): + return self._gh._get_resource(('orgs', orgname), Org) + + def gists(self, limit=None): + return self._gh._get_resources('gists', Gist, limit=limit) -- cgit v1.3-6-gb490 From b17dbea56f59aa5403e5722e12878c7183742551 Mon Sep 17 00:00:00 2001 From: David Medina Date: Tue, 1 Nov 2011 12:30:25 +0100 Subject: Decouple Handlers and Models Handler User complete --- github3/api.py | 18 ++--- github3/handlers/__init__.py | 1 + github3/handlers/base.py | 3 +- github3/handlers/user.py | 19 ++++- github3/helpers.py | 19 +++++ github3/models/__init__.py | 4 + github3/models/base.py | 187 ++++++++++++++++++------------------------- github3/models/gists.py | 49 ++++++++++++ github3/models/orgs.py | 28 +++++++ github3/models/repos.py | 30 +++++++ github3/models/user.py | 49 +++--------- 11 files changed, 244 insertions(+), 163 deletions(-) create mode 100644 github3/models/gists.py create mode 100644 github3/models/orgs.py create mode 100644 github3/models/repos.py (limited to 'github3/models') diff --git a/github3/api.py b/github3/api.py index 7b63b2d..d99682a 100644 --- a/github3/api.py +++ b/github3/api.py @@ -15,7 +15,6 @@ from decorator import decorator from .packages import omnijson as json from .packages.link_header import parse_link_value -from .models import * from .helpers import is_collection, to_python, to_api, get_scope from .config import settings import handlers @@ -170,6 +169,9 @@ class GithubCore(object): page += 1 + def _get_bool(self, resource): + resp = self._http_resource('GET', resource, check_status=False) + return True if resp.status_code == 204 else False def _to_map(self, obj, iterable): """Maps given dict iterable to a given Resource object.""" @@ -181,16 +183,6 @@ class GithubCore(object): return a - def _get_url(self, resource): - - if is_collection(resource): - resource = map(str, resource) - resource = '/'.join(resource) - - return resource - - - class Github(GithubCore): """docstring for Github""" @@ -198,8 +190,8 @@ class Github(GithubCore): super(Github, self).__init__() self.is_authenticated = False - def user_handler(self, username=None): - if not getattr(self, '_user_handler'): + def user_handler(self, username=None, force=False): + if force or not getattr(self, '_user_handler', False): if self.is_authenticated: self._user_handler = handlers.AuthUser(self) else: diff --git a/github3/handlers/__init__.py b/github3/handlers/__init__.py index e69de29..126efcb 100644 --- a/github3/handlers/__init__.py +++ b/github3/handlers/__init__.py @@ -0,0 +1 @@ +from user import AuthUser, User diff --git a/github3/handlers/base.py b/github3/handlers/base.py index 6a5ac65..93a4680 100644 --- a/github3/handlers/base.py +++ b/github3/handlers/base.py @@ -3,8 +3,6 @@ # # author: David Medina -import models - class Handler(object): """ Abstract handler, that inject github.api """ @@ -24,3 +22,4 @@ class Handler(object): url = self._extend_url(*args) map_model = kwargs.get('model', self._model) return self._gh._get_resources(url, map_model, **kwargs) + diff --git a/github3/handlers/user.py b/github3/handlers/user.py index 16f8363..c59607d 100644 --- a/github3/handlers/user.py +++ b/github3/handlers/user.py @@ -4,6 +4,7 @@ # author: David Medina from .base import Handler +import github3.models as models class User(Handler): """ Handler to query public user api """ @@ -13,7 +14,7 @@ class User(Handler): raise exceptions.AnomUser("%s need a username" % self.__class__) self._url = ('users', username) - self._model = models.AnomUser + self._model = models.User self.username = username super(User, self).__init__(gh) @@ -29,12 +30,24 @@ class User(Handler): def get_following(self, limit=None): return self._get_resources('following') -class AuthUser(AnomUser): + def get_repos(self, limit=None): + return self._get_resources('repos', model=models.Repo) + + def get_watched(self, limit=None): + return self._get_resources('watched', model=models.Repo) + + def get_orgs(self, limit=None): + return self._get_resources('orgs', model=models.Org) + + def get_gists(self, limit=None): + return self._get_resources('gists', model=models.Gist) + +class AuthUser(User): """ Handler to query public/private api for authenticated user """ def __init__(self, gh): self._url = ('user',) - self._model = models.User + self._model = models.AuthUser super(AnomUser, self).__init__(gh) def __repr__(self): diff --git a/github3/helpers.py b/github3/helpers.py index 498a005..205e097 100644 --- a/github3/helpers.py +++ b/github3/helpers.py @@ -57,6 +57,7 @@ def to_python(obj, date_keys=None, int_keys=None, object_map=None, + list_map=None, bool_keys=None, **kwargs): """Extends a given object for API Consumption. @@ -96,14 +97,32 @@ def to_python(obj, if object_map: for (k, v) in object_map.items(): if in_dict.get(k): + if v == 'self': + v = obj.__class__ d[k] = v.new_from_dict(in_dict.get(k)) + if list_map: + for k, model in list_map.items(): + nested_map = in_dict.get(k) + if nested_map: + if getattr(nested_map, 'items', False): + map_dict = {} + for nested_item, nested_dict in nested_map.items(): + map_dict[nested_item] = model.new_from_dict(nested_dict) + d[k] = map_dict + else: + map_list = [] + for item_map in nested_map: + map_list.append(model.new_from_dict(item_map)) + d[k] = map_list + obj.__dict__.update(d) obj.__dict__.update(kwargs) # Save the dictionary, for write comparisons. obj._cache = d obj.__cache = in_dict + obj.post_map() return obj diff --git a/github3/models/__init__.py b/github3/models/__init__.py index e69de29..6e4db1b 100644 --- a/github3/models/__init__.py +++ b/github3/models/__init__.py @@ -0,0 +1,4 @@ +from .user import AuthUser, User +from .repos import Repo +from .orgs import Org +from .gists import Gist diff --git a/github3/models/base.py b/github3/models/base.py index 618e57f..1b1ce89 100644 --- a/github3/models/base.py +++ b/github3/models/base.py @@ -6,9 +6,9 @@ This module provides the Github3 object model. """ import json +import inspect -from .helpers import to_python, to_api, key_diff - +from github3.helpers import to_python, to_api, key_diff class BaseResource(object): """A BaseResource object.""" @@ -18,15 +18,24 @@ class BaseResource(object): _dates = [] _bools = [] _map = {} + _list_map = {} _writeable = [] _cache = {} + def post_map(self): + try: + handler = self.handler() + methods = filter(lambda x: x[0].startswith('get') and callable(x), + inspect.getmembers(handler, inspect.ismethod)) + for name, callback in methods: + setattr(self, method, callback) + except: + pass def __init__(self): self._bootstrap() super(BaseResource, self).__init__() - def __dir__(self): return self.keys() @@ -56,6 +65,7 @@ class BaseResource(object): date_keys = cls._dates, bool_keys = cls._bools, object_map = cls._map, + list_map = cls._list_map, _gh = gh ) @@ -70,109 +80,70 @@ class BaseResource(object): return r -class Plan(BaseResource): - """Github Plan object model.""" - - _strs = ['name'] - _ints = ['space', 'collaborators', 'private_repos'] - - def __repr__(self): - return ''.format(str(self.name)) - -class Org(BaseResource): - """Github Organization object model.""" - - _strs = [ - 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' - 'html_url', 'type', 'billing_email'] - _ints = [ - 'id', 'public_repos', 'public_gists', 'followers', 'following', - 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', - 'collaborators'] - _dates = ['created_at'] - _map = {'plan': Plan} - _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] - - @property - def ri(self): - return ('orgs', self.login) - - def __repr__(self): - return ''.format(self.login) - - def repos(self, limit=None): - return self._gh._get_resources(('orgs', self.login, 'repos'), Repo, limit=limit) - - def members(self, limit=None): - return self._gh._get_resources(('orgs', self.login, 'members'), User, limit=limit) - - def is_member(self, username): - if isinstance(username, User): - username = username.login - - r = self._gh._http_resource('GET', ('orgs', self.login, 'members', username), check_status=False) - return (r.status_code == 204) - - def publicize_member(self, username): - if isinstance(username, User): - username = username.login - - r = self._gh._http_resource('PUT', ('orgs', self.login, 'public_members', username), check_status=False, data='') - return (r.status_code == 204) - - def conceal_member(self, username): - if isinstance(username, User): - username = username.login - - r = self._gh._http_resource('DELETE', ('orgs', self.login, 'public_members', username), check_status=False) - return (r.status_code == 204) - - def remove_member(self, username): - if isinstance(username, User): - username = username.login - - r = self._gh._http_resource('DELETE', ('orgs', self.login, 'members', username), check_status=False) - return (r.status_code == 204) - - def public_members(self, limit=None): - return self._gh._get_resources(('orgs', self.login, 'public_members'), User, limit=limit) - - def is_public_member(self, username): - if isinstance(username, User): - username = username.login - - r = self._gh._http_resource('GET', ('orgs', self.login, 'public_members', username), check_status=False) - return (r.status_code == 204) - - -class Gist(BaseResource): - _strs = ['url', 'description', 'html_url', 'git_pull_url', 'git_push_url'] - _ints = ['id', 'comments'] - _bools = ['public'] - _dates = ['created_at'] - _map = {'user': User} #TODO: file - - @property - def ri(self): - return ('users', self.user.login, self.id) - - def __repr__(self): - return '' % (self.user.login, self.description) - -class Repo(BaseResource): - _strs = [ - 'url', 'html_url', 'clone_url', 'git_url', 'ssh_url', 'svn_url', - 'name', 'description', 'homepage', 'language', 'master_branch'] - _bools = ['private', 'fork'] - _ints = ['forks', 'watchers', 'size',] - _dates = ['pushed_at', 'created_at'] - _map = {'owner': User} - - - @property - def ri(self): - return ('repos', self.owner.login, self.name) - def __repr__(self): - return ''.format(self.owner.login, self.name) - # owner +#class Org(BaseResource): +# """Github Organization object model.""" +# +# _strs = [ +# 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' +# 'html_url', 'type', 'billing_email'] +# _ints = [ +# 'id', 'public_repos', 'public_gists', 'followers', 'following', +# 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', +# 'collaborators'] +# _dates = ['created_at'] +# _map = {'plan': Plan} +# _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] +# +# @property +# def ri(self): +# return ('orgs', self.login) +# +# def __repr__(self): +# return ''.format(self.login) +# +# def repos(self, limit=None): +# return self._gh._get_resources(('orgs', self.login, 'repos'), Repo, limit=limit) +# +# def members(self, limit=None): +# return self._gh._get_resources(('orgs', self.login, 'members'), User, limit=limit) +# +# def is_member(self, username): +# if isinstance(username, User): +# username = username.login +# +# r = self._gh._http_resource('GET', ('orgs', self.login, 'members', username), check_status=False) +# return (r.status_code == 204) +# +# def publicize_member(self, username): +# if isinstance(username, User): +# username = username.login +# +# r = self._gh._http_resource('PUT', ('orgs', self.login, 'public_members', username), check_status=False, data='') +# return (r.status_code == 204) +# +# def conceal_member(self, username): +# if isinstance(username, User): +# username = username.login +# +# r = self._gh._http_resource('DELETE', ('orgs', self.login, 'public_members', username), check_status=False) +# return (r.status_code == 204) +# +# def remove_member(self, username): +# if isinstance(username, User): +# username = username.login +# +# r = self._gh._http_resource('DELETE', ('orgs', self.login, 'members', username), check_status=False) +# return (r.status_code == 204) +# +# def public_members(self, limit=None): +# return self._gh._get_resources(('orgs', self.login, 'public_members'), User, limit=limit) +# +# def is_public_member(self, username): +# if isinstance(username, User): +# username = username.login +# +# r = self._gh._http_resource('GET', ('orgs', self.login, 'public_members', username), check_status=False) +# return (r.status_code == 204) +# +# diff --git a/github3/models/gists.py b/github3/models/gists.py new file mode 100644 index 0000000..5ad61c3 --- /dev/null +++ b/github3/models/gists.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# author: David Medina + +from .base import BaseResource +from .user import User + +class File(BaseResource): + _strs = ['filename', 'raw_url', 'content', 'language', 'type'] + _ints = ['size'] + + def __repr__(self): + return ' %s' % self.filename + +class GistFork(BaseResource): + _strs = ['url'] + _dates = ['created_at'] + _map = {'user': User} + + def __repr__(self): + return ' %s>' % self.user.login + +class ChangeStatus(BaseResource): + _ints = ['deletions', 'additions', 'total'] + + def __repr__(self): + return ' change_status>' + +class GistHistory(BaseResource): + _strs = ['url', 'version'] + _map = {'user': User, 'change_status': ChangeStatus} + _dates = ['committed_at'] + +class Gist(BaseResource): + _strs = ['url', 'description', 'html_url', 'git_pull_url', 'git_push_url'] + _ints = ['id', 'comments'] + _bools = ['public'] + _dates = ['created_at'] + _map = {'user': User} + _list_map = {'files': File, 'forks': GistFork, 'history': GistHistory} + + @property + def ri(self): + return ('users', self.user.login, self.id) + + def __repr__(self): + return '' % (self.user.login, self.description) + diff --git a/github3/models/orgs.py b/github3/models/orgs.py new file mode 100644 index 0000000..1ce638e --- /dev/null +++ b/github3/models/orgs.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# author: David Medina + +from .base import BaseResource +from .user import Plan + +class Org(BaseResource): + """Github Organization object model.""" + + _strs = [ + 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' + 'html_url', 'type', 'billing_email'] + _ints = [ + 'id', 'public_repos', 'public_gists', 'followers', 'following', + 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', + 'collaborators'] + _dates = ['created_at'] + _map = {'plan': Plan} + _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] + + @property + def ri(self): + return ('orgs', self.login) + + def __repr__(self): + return ''.format(self.login) diff --git a/github3/models/repos.py b/github3/models/repos.py new file mode 100644 index 0000000..8dbe970 --- /dev/null +++ b/github3/models/repos.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# author: David Medina + +from .base import BaseResource +from .user import User +from .orgs import Org + +class Repo(BaseResource): + _strs = [ + 'url', 'html_url', 'clone_url', 'git_url', 'ssh_url', 'svn_url', + 'name', 'description', 'homepage', 'language', 'master_branch'] + _bools = ['private', 'fork', 'has_issues', 'has_wiki', 'has_downloads'] + _ints = ['forks', 'watchers', 'size', 'open_issues'] + _dates = ['pushed_at', 'created_at'] + _map = { + 'owner': User, + 'organization': Org, + 'parent': 'self', + 'source': 'self', + } + + @property + def ri(self): + return ('repos', self.owner.login, self.name) + + def __repr__(self): + return ''.format(self.owner.login, self.name) + # owner diff --git a/github3/models/user.py b/github3/models/user.py index cdbd04f..d58d9b2 100644 --- a/github3/models/user.py +++ b/github3/models/user.py @@ -5,18 +5,25 @@ from .base import BaseResource +class Plan(BaseResource): + """Github Plan object model.""" + + _strs = ['name'] + _ints = ['space', 'collaborators', 'private_repos'] + + def __repr__(self): + return ''.format(str(self.name)) + class User(BaseResource): """Github User object model.""" _strs = [ 'login','avatar_url', 'url', 'name', 'company', 'blog', 'location', - 'email', 'bio', 'html_url'] + 'email', 'bio', 'html_url', 'type'] _ints = ['id', 'public_repos', 'public_gists', 'followers', 'following'] _dates = ['created_at',] _bools = ['hireable', ] - # _map = {} - # _writeable = [] @property def ri(self): @@ -25,26 +32,8 @@ class User(BaseResource): def __repr__(self): return ''.format(self.login) - @property def handler(self): - return self._gh.user_handler(self.login) - - def get_followers(self, limit=None): - return self.handler.followers(limit) - - def get_following(self, limit=None): - return self.handler.following(limit) - - def repos(self, limit=None): - return self._gh._get_resources(('users', self.login, 'repos'), Repo, limit=limit) - def repo(self, reponame): - return self._gh._get_resource(('repos', self.login, reponame), Repo) - - def orgs(self): - return self._gh._get_resources(('users', self.login, 'orgs'), Org) - - def gists(self): - return self._gh._get_resources(('users', self.login, 'gists'), Gist) + return self._gh.user_handler(self.login, force=True) class AuthUser(User): """Github Current User object model.""" @@ -61,19 +50,5 @@ class AuthUser(User): return ('user',) def __repr__(self): - return ''.format(self.login) - - def repos(self, limit=None): - return self._gh._get_resources(('user', 'repos'), Repo, limit=limit) - - def repo(self, reponame): - return self._gh._get_resource(('repos', self.login, reponame), Repo) - - def orgs(self, limit=None): - return self._gh._get_resources(('user', 'orgs'), Org, limit=limit) - - def org(self, orgname): - return self._gh._get_resource(('orgs', orgname), Org) + return ''.format(self.login) - def gists(self, limit=None): - return self._gh._get_resources('gists', Gist, limit=limit) -- cgit v1.3-6-gb490 From c0a5c2c68764112afcbf9795c7194a8eafc8352c Mon Sep 17 00:00:00 2001 From: David Medina Date: Tue, 1 Nov 2011 13:14:29 +0100 Subject: Fix bug. PEP8 --- github3/models/base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'github3/models') diff --git a/github3/models/base.py b/github3/models/base.py index 1b1ce89..f98af2d 100644 --- a/github3/models/base.py +++ b/github3/models/base.py @@ -25,10 +25,11 @@ class BaseResource(object): def post_map(self): try: handler = self.handler() - methods = filter(lambda x: x[0].startswith('get') and callable(x), - inspect.getmembers(handler, inspect.ismethod)) + methods = filter( + lambda x: x[0].startswith('get') and callable(x[1]), + inspect.getmembers(handler, inspect.ismethod)) for name, callback in methods: - setattr(self, method, callback) + setattr(self, name, callback) except: pass -- cgit v1.3-6-gb490 From 15b7cc0fe44d02a9f2271041cd69140d63279ff1 Mon Sep 17 00:00:00 2001 From: David Medina Date: Tue, 1 Nov 2011 19:24:15 +0100 Subject: Fix names. Added raw request Think about return user handler more elegant --- github3/api.py | 10 +++++++--- github3/handlers/base.py | 4 ++++ github3/handlers/user.py | 15 +++++++++++---- github3/models/user.py | 7 +++++-- 4 files changed, 27 insertions(+), 9 deletions(-) (limited to 'github3/models') diff --git a/github3/api.py b/github3/api.py index d99682a..b0a2c96 100644 --- a/github3/api.py +++ b/github3/api.py @@ -173,6 +173,10 @@ class GithubCore(object): resp = self._http_resource('GET', resource, check_status=False) return True if resp.status_code == 204 else False + def _get_raw(self, resource): + resp = self._http_resource('GET', resource) + return self._resource_deserialize(resp.content) + def _to_map(self, obj, iterable): """Maps given dict iterable to a given Resource object.""" @@ -190,9 +194,9 @@ class Github(GithubCore): super(Github, self).__init__() self.is_authenticated = False - def user_handler(self, username=None, force=False): - if force or not getattr(self, '_user_handler', False): - if self.is_authenticated: + def user_handler(self, username=None, **kwargs): + if kwargs.get('force') or not getattr(self, '_user_handler', False): + if kwargs.get('private'): self._user_handler = handlers.AuthUser(self) else: self._user_handler = handlers.User(self, username) diff --git a/github3/handlers/base.py b/github3/handlers/base.py index 93a4680..3bd4bd1 100644 --- a/github3/handlers/base.py +++ b/github3/handlers/base.py @@ -13,6 +13,10 @@ class Handler(object): def _extend_url(self, *args): return self._url + args + def _get_raw(self, *args, **kwargs): + url = self._extend_url(*args) + return self._gh._get_raw(url, **kwargs) + def _get_resource(self, *args, **kwargs): url = self._extend_url(*args) map_model = kwargs.get('model', self._model) diff --git a/github3/handlers/user.py b/github3/handlers/user.py index 09ea031..47f1a92 100644 --- a/github3/handlers/user.py +++ b/github3/handlers/user.py @@ -20,7 +20,7 @@ class User(Handler): super(User, self).__init__(gh) def __repr__(self): - return ' %s' % self.username + return ' %s' % self.username def get(self): return self._get_resource() @@ -48,8 +48,15 @@ class AuthUser(User): def __init__(self, gh): self._url = ('user',) - self._model = models.AuthUser - super(AnomUser, self).__init__(gh) + self._model = models.User + super(User, self).__init__(gh) def __repr__(self): - return '' + return '' + + def get(self): + return self._get_resource(model=models.AuthUser) + + def get_emails(self): + return self._get_raw('emails') + diff --git a/github3/models/user.py b/github3/models/user.py index d58d9b2..7c730f6 100644 --- a/github3/models/user.py +++ b/github3/models/user.py @@ -30,7 +30,7 @@ class User(BaseResource): return ('users', self.login) def __repr__(self): - return ''.format(self.login) + return ''.format(self.login) def handler(self): return self._gh.user_handler(self.login, force=True) @@ -45,10 +45,13 @@ class AuthUser(User): _map = {'plan': Plan} _writeable = ['name', 'email', 'blog', 'company', 'location', 'hireable', 'bio'] + def handler(self): + return self._gh.user_handler(self.login, force=True, private=True) + @property def ri(self): return ('user',) def __repr__(self): - return ''.format(self.login) + return ''.format(self.login) -- cgit v1.3-6-gb490 From 81f483aabf6d40f7d3379fb2a85ecb6a5fd218fb Mon Sep 17 00:00:00 2001 From: David Medina Date: Tue, 1 Nov 2011 22:23:41 +0100 Subject: Complete AuthUser handler --- github3/handlers/user.py | 12 ++++++++++++ github3/models/__init__.py | 2 +- github3/models/user.py | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'github3/models') diff --git a/github3/handlers/user.py b/github3/handlers/user.py index 47f1a92..5f5d130 100644 --- a/github3/handlers/user.py +++ b/github3/handlers/user.py @@ -60,3 +60,15 @@ class AuthUser(User): def get_emails(self): return self._get_raw('emails') + def get_is_following(self, user): + username = getattr(user, 'login', False) + if not username: + username = user + return self._get_bool('following', username) + + def get_keys(self): + return self._get_resources('keys', model=models.Key) + + def get_key(self, key_id): + return self._get_resource('keys', key_id, model=models.Key) + diff --git a/github3/models/__init__.py b/github3/models/__init__.py index 6e4db1b..ff0c28a 100644 --- a/github3/models/__init__.py +++ b/github3/models/__init__.py @@ -1,4 +1,4 @@ -from .user import AuthUser, User +from .user import AuthUser, User, Key from .repos import Repo from .orgs import Org from .gists import Gist diff --git a/github3/models/user.py b/github3/models/user.py index 7c730f6..3f0efc4 100644 --- a/github3/models/user.py +++ b/github3/models/user.py @@ -14,6 +14,15 @@ class Plan(BaseResource): def __repr__(self): return ''.format(str(self.name)) +class Key(BaseResource): + """Github Key object model.""" + + _strs = ['url', 'title', 'key'] + _ints = ['id'] + + def __repr__(self): + return ''.format(str(self.title)) + class User(BaseResource): """Github User object model.""" -- cgit v1.3-6-gb490 From 6f2d2115fa578e2d5aa611fe03474341d73f73cc Mon Sep 17 00:00:00 2001 From: David Medina Date: Sun, 6 Nov 2011 18:14:51 +0100 Subject: Modelizer class. json<->model parser Also reorganize code --- github3/__init__.py | 2 - github3/core.py | 124 +++++++++++++++++++++++++++++++++------- github3/handlers/base.py | 62 +++++--------------- github3/models/base.py | 145 +++-------------------------------------------- github3/models/gists.py | 68 +++++++++++++++------- github3/models/orgs.py | 27 ++++----- github3/models/repos.py | 35 ++++++------ github3/models/user.py | 69 +++++++++++----------- 8 files changed, 236 insertions(+), 296 deletions(-) (limited to 'github3/models') diff --git a/github3/__init__.py b/github3/__init__.py index fcb882b..40a96af 100644 --- a/github3/__init__.py +++ b/github3/__init__.py @@ -1,3 +1 @@ # -*- coding: utf-8 -*- - -from core import * diff --git a/github3/core.py b/github3/core.py index d6eed22..0aa5949 100644 --- a/github3/core.py +++ b/github3/core.py @@ -1,30 +1,114 @@ -# -*- coding: utf-8 -*- +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# author: David Medina -""" -github3.core -~~~~~~~~~~~~ +class Paginate: + """ Paginate resource iterator -This module provides the entrance point for the GitHub3 module. -""" + :param resource: URL resource + :param requester: Bound method to request. See `GithubCore.get` + """ -__version__ = '0.0.0' -__license__ = 'MIT' -__author__ = 'Kenneth Reitz' + def __init__(self, resource, requester): + self.resource = resource + self.requester = requester + self.page = 1 -from .api import Github + def _last_page(self, link): + """ Get and cached last page from link header """ + if not getattr(self, 'last', False): + from github3.packages.link_header import parse_link_value + from urlparse import urlparse, parse_qs + for link, rels in parse_link_value(link).items(): + if rels.get('rel') == 'last': + query = urlparse(link).query + self.last = int(parse_qs(query).get('page').pop()) -def no_auth(): - """Returns an un-authenticated Github object.""" + return self.last - gh = Github() + def __iter__(self): + return self - return gh + def initial(self): + """ First request. Force requester to paginate returning link header """ + link, content = self.requester(self.resource, paginate=True, page=1) + self.last = self._last_page(link) if link else 1 + return content -def basic_auth(username, password): - """Returns an authenticated Github object, via HTTP Basic.""" + def next(self): + if self.page == 1: + content = self.initial() + self.page += 1 + return content + else: + if self.page > self.last: + raise StopIteration + else: + content = self.requester(self.resource, page=self.page) + self.page += 1 + return content - gh = Github() - gh.is_authenticated = True - gh.session.auth = (username, password) +class Modelizer(object): + """ Converter json into model and vice versa """ - return gh + def __init__(self, model): + self.model = model + self.attrs = {} + + def _parse_date(self, string_date): + from datetime import datetime + try: + date = datetime.strptime(string_date, '%Y-%m-%dT%H:%M:%SZ') + except TypeError: + date = None + + return date + + def _parse_map(self, model, raw_resource): + if model == 'self': + model = self.model + + return Modelizer(model).loads(raw_resource) + + def _parse_collection_map(self, model, raw_resources): + # Dict of resources (Ex: Gist file) + if getattr(raw_resources, 'items', False): + dict_map = {} + for key, raw_resource in raw_resources.items(): + dict_map[key] = Modelizer(model).loads(raw_resource) + return dict_map + # list of resources + else: + return [Modelizer(model).loads(raw_resource) + for raw_resource in raw_resources] + + def loads(self, raw_resource): + attrs = {} + idl = self.model.idl() + attrs.update( + {attr: raw_resource[attr] for attr in idl.get('strs',()) + if raw_resource.get(attr)}) + attrs.update( + {attr: raw_resource[attr] for attr in idl.get('ints',()) + if raw_resource.get(attr)}) + attrs.update( + {attr: self._parse_date(raw_resource[attr]) + for attr in idl.get('dates',()) if raw_resource.get(attr)}) + attrs.update( + {attr: raw_resource[attr] for attr in idl.get('bools',()) + if raw_resource.get(attr)}) + attrs.update( + {attr: self._parse_map(model, raw_resource[attr]) + for attr, model in idl.get('maps',{}).items() + if raw_resource.get(attr)}) + attrs.update( + {attr: self._parse_collection_map(model, raw_resource[attr]) + for attr, model in idl.get('collection_maps',{}).items() + if raw_resource.get(attr)}) + + return self.model(attrs) + + def dumps(self): + # return JSON + pass diff --git a/github3/handlers/base.py b/github3/handlers/base.py index 3f82817..0d8be0e 100644 --- a/github3/handlers/base.py +++ b/github3/handlers/base.py @@ -3,53 +3,7 @@ # # author: David Medina -import github3.exceptions as ghexceptions - -class Paginate: - """ Paginate resource iterator - - :param resource: URL resource - :param requester: Bound method to request. See `GithubCore.get` - """ - - def __init__(self, resource, requester): - self.resource = resource - self.requester = requester - self.page = 1 - - def _last_page(self, link): - """ Get and cached last page from link header """ - if not getattr(self, 'last', False): - from github3.packages.link_header import parse_link_value - from urlparse import urlparse, parse_qs - for link, rels in parse_link_value(link).items(): - if rels.get('rel') == 'last': - query = urlparse(link).query - self.last = int(parse_qs(query).get('page').pop()) - - return self.last - - def __iter__(self): - return self - - def initial(self): - """ First request. Force requester to paginate returning link header """ - link, content = self.requester(self.resource, paginate=True, page=1) - self.last = self._last_page(link) if link else 1 - return content - - def next(self): - if self.page == 1: - content = self.initial() - self.page += 1 - return content - else: - if self.page > self.last: - raise StopIteration - else: - content = self.requester(self.resource, page=self.page) - self.page += 1 - return content +from github3.core import Paginate, Modelizer class Handler(object): """ Handler base. Requests to API and modelize responses """ @@ -60,9 +14,11 @@ class Handler(object): def _bool(self, resource, **kwargs): """ Handler request to boolean response """ + + from github3.exceptions import NotFound try: response = self._gh.head(resource, **kwargs) - except ghexceptions.NotFound: + except NotFound: return False assert response.status_code == 204 return True @@ -70,13 +26,21 @@ class Handler(object): #TODO: if limit is multiple of per_page... it do another request for nothing def _get_resources(self, resource, model=None, limit=None): """ Hander request to multiple resources """ + page_resources = Paginate(resource, self._gh.get) counter = 1 for page in page_resources: for raw_resource in page: if limit and counter > limit: break counter += 1 - yield raw_resource + yield Modelizer(model or self.model).loads(raw_resource) + #yield raw_resource else: continue break + + def _get_resource(self, resource, model=None): + """ Handler request to single request """ + + raw_resource = self._gh.get(resource) + return Modelizer(model or self.model).loads(raw_resource) diff --git a/github3/models/base.py b/github3/models/base.py index f98af2d..df0c82b 100644 --- a/github3/models/base.py +++ b/github3/models/base.py @@ -2,149 +2,18 @@ github3.models ~~~~~~~~~~~~~~ -This module provides the Github3 object model. +This package provides the Github3 object model. """ -import json -import inspect - -from github3.helpers import to_python, to_api, key_diff - class BaseResource(object): """A BaseResource object.""" - _strs = [] - _ints = [] - _dates = [] - _bools = [] - _map = {} - _list_map = {} - _writeable = [] - _cache = {} - - def post_map(self): - try: - handler = self.handler() - methods = filter( - lambda x: x[0].startswith('get') and callable(x[1]), - inspect.getmembers(handler, inspect.ismethod)) - for name, callback in methods: - setattr(self, name, callback) - except: - pass - - def __init__(self): - self._bootstrap() + def __init__(self, attrs=None): + if attrs: + for attr, value in attrs.items(): + setattr(self, attr, value) super(BaseResource, self).__init__() - def __dir__(self): - return self.keys() - - def _bootstrap(self): - """Bootstraps the model object based on configured values.""" - - for attr in self.keys(): - setattr(self, attr, None) - - def keys(self): - return self._strs + self._ints + self._dates + self._bools + self._map.keys() - - def dict(self): - d = dict() - for k in self.keys(): - d[k] = self.__dict__.get(k) - - return d - @classmethod - def new_from_dict(cls, d, gh=None): - - return to_python( - obj=cls(), in_dict=d, - str_keys = cls._strs, - int_keys = cls._ints, - date_keys = cls._dates, - bool_keys = cls._bools, - object_map = cls._map, - list_map = cls._list_map, - _gh = gh - ) - - - def update(self): - deploy = key_diff(self._cache, self.dict(), pack=True) - - deploy = to_api(deploy, int_keys=self._ints, date_keys=self._dates, bool_keys=self._bools) - deploy = json.dumps(deploy) - - r = self._gh._patch_resource(self.ri, deploy) - return r - - - -#class Org(BaseResource): -# """Github Organization object model.""" -# -# _strs = [ -# 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' -# 'html_url', 'type', 'billing_email'] -# _ints = [ -# 'id', 'public_repos', 'public_gists', 'followers', 'following', -# 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', -# 'collaborators'] -# _dates = ['created_at'] -# _map = {'plan': Plan} -# _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] -# -# @property -# def ri(self): -# return ('orgs', self.login) -# -# def __repr__(self): -# return ''.format(self.login) -# -# def repos(self, limit=None): -# return self._gh._get_resources(('orgs', self.login, 'repos'), Repo, limit=limit) -# -# def members(self, limit=None): -# return self._gh._get_resources(('orgs', self.login, 'members'), User, limit=limit) -# -# def is_member(self, username): -# if isinstance(username, User): -# username = username.login -# -# r = self._gh._http_resource('GET', ('orgs', self.login, 'members', username), check_status=False) -# return (r.status_code == 204) -# -# def publicize_member(self, username): -# if isinstance(username, User): -# username = username.login -# -# r = self._gh._http_resource('PUT', ('orgs', self.login, 'public_members', username), check_status=False, data='') -# return (r.status_code == 204) -# -# def conceal_member(self, username): -# if isinstance(username, User): -# username = username.login -# -# r = self._gh._http_resource('DELETE', ('orgs', self.login, 'public_members', username), check_status=False) -# return (r.status_code == 204) -# -# def remove_member(self, username): -# if isinstance(username, User): -# username = username.login -# -# r = self._gh._http_resource('DELETE', ('orgs', self.login, 'members', username), check_status=False) -# return (r.status_code == 204) -# -# def public_members(self, limit=None): -# return self._gh._get_resources(('orgs', self.login, 'public_members'), User, limit=limit) -# -# def is_public_member(self, username): -# if isinstance(username, User): -# username = username.login -# -# r = self._gh._http_resource('GET', ('orgs', self.login, 'public_members', username), check_status=False) -# return (r.status_code == 204) -# -# + def idl(self): + raise NotImplementedError('Each model need subcass that method') diff --git a/github3/models/gists.py b/github3/models/gists.py index 5ad61c3..d1b416d 100644 --- a/github3/models/gists.py +++ b/github3/models/gists.py @@ -7,43 +7,71 @@ from .base import BaseResource from .user import User class File(BaseResource): - _strs = ['filename', 'raw_url', 'content', 'language', 'type'] - _ints = ['size'] + """ File model """ + + @classmethod + def idl(self): + return { + 'strs': ['filename', 'raw_url', 'content', 'language', 'type'], + 'ints': ['size'], + } def __repr__(self): return ' %s' % self.filename class GistFork(BaseResource): - _strs = ['url'] - _dates = ['created_at'] - _map = {'user': User} + """ GistFork model """ + + @classmethod + def idl(self): + return { + 'strs': ['url'], + 'dates': ['created_at'], + 'maps': {'user': User} + } def __repr__(self): return ' %s>' % self.user.login class ChangeStatus(BaseResource): - _ints = ['deletions', 'additions', 'total'] + """ ChangeStatus model """ + + @classmethod + def idl(self): + return { + 'ints': ['deletions', 'additions', 'total'], + } def __repr__(self): return ' change_status>' class GistHistory(BaseResource): - _strs = ['url', 'version'] - _map = {'user': User, 'change_status': ChangeStatus} - _dates = ['committed_at'] + """ """ + + @classmethod + def idl(self): + return { + 'strs': ['url', 'version'], + 'maps': {'user': User, 'change_status': ChangeStatus}, + 'dates': ['committed_at'], + } + + def __repr__(self): + return '' % (self.user, self.committed_at) class Gist(BaseResource): - _strs = ['url', 'description', 'html_url', 'git_pull_url', 'git_push_url'] - _ints = ['id', 'comments'] - _bools = ['public'] - _dates = ['created_at'] - _map = {'user': User} - _list_map = {'files': File, 'forks': GistFork, 'history': GistHistory} + """ """ - @property - def ri(self): - return ('users', self.user.login, self.id) + @classmethod + def idl(self): + return { + 'strs': ['url', 'description', 'html_url', 'git_pull_url', 'git_push_url'], + 'ints': ['id', 'comments'], + 'bools': ['public'], + 'dates': ['created_at'], + 'maps': {'user': User}, + 'collection_maps': {'files': File, 'forks': GistFork, 'history': GistHistory}, + } def __repr__(self): - return '' % (self.user.login, self.description) - + return '' % (self.user, self.description) diff --git a/github3/models/orgs.py b/github3/models/orgs.py index 1ce638e..840b51a 100644 --- a/github3/models/orgs.py +++ b/github3/models/orgs.py @@ -9,20 +9,17 @@ from .user import Plan class Org(BaseResource): """Github Organization object model.""" - _strs = [ - 'login', 'url', 'avatar_url', 'name', 'company', 'blog', 'location', 'email' - 'html_url', 'type', 'billing_email'] - _ints = [ - 'id', 'public_repos', 'public_gists', 'followers', 'following', - 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', - 'collaborators'] - _dates = ['created_at'] - _map = {'plan': Plan} - _writable = ['billing_email', 'blog', 'company', 'email', 'location', 'name'] - - @property - def ri(self): - return ('orgs', self.login) + @classmethod + def idl(self): + return { + 'strs': ['login', 'url', 'avatar_url', 'name', 'company', 'blog', + 'location', 'email', 'html_url', 'type', 'billing_email'], + 'ints': ['id', 'public_repos', 'public_gists', 'followers', + 'following', 'total_private_repos', 'owned_private_repos', + 'private_gists', 'disk_usage', 'collaborators'], + 'dates': ['created_at'], + 'maps': {'plan': plan} + } def __repr__(self): - return ''.format(self.login) + return '' % self.login diff --git a/github3/models/repos.py b/github3/models/repos.py index 8dbe970..ba6ac33 100644 --- a/github3/models/repos.py +++ b/github3/models/repos.py @@ -8,23 +8,24 @@ from .user import User from .orgs import Org class Repo(BaseResource): - _strs = [ - 'url', 'html_url', 'clone_url', 'git_url', 'ssh_url', 'svn_url', - 'name', 'description', 'homepage', 'language', 'master_branch'] - _bools = ['private', 'fork', 'has_issues', 'has_wiki', 'has_downloads'] - _ints = ['forks', 'watchers', 'size', 'open_issues'] - _dates = ['pushed_at', 'created_at'] - _map = { - 'owner': User, - 'organization': Org, - 'parent': 'self', - 'source': 'self', - } + """ Repo model """ - @property - def ri(self): - return ('repos', self.owner.login, self.name) + @classmethod + def idl(self): + return { + 'strs': [ + 'url', 'html_url', 'clone_url', 'git_url', 'ssh_url', 'svn_url', + 'name', 'description', 'homepage', 'language', 'master_branch'], + 'ints': ['forks', 'watchers', 'size', 'open_issues'], + 'dates': ['created_at', 'pushed_at'], + 'bools': ['private', 'fork', 'has_issues', 'has_wiki', 'has_downloads'], + 'maps': { + 'owner': User, + 'organization': Org, + 'parent': 'self', + 'source': 'self', + } + } def __repr__(self): - return ''.format(self.owner.login, self.name) - # owner + return '' % (self.owner.login, self.name) diff --git a/github3/models/user.py b/github3/models/user.py index 3f0efc4..7ec7999 100644 --- a/github3/models/user.py +++ b/github3/models/user.py @@ -8,59 +8,58 @@ from .base import BaseResource class Plan(BaseResource): """Github Plan object model.""" - _strs = ['name'] - _ints = ['space', 'collaborators', 'private_repos'] + @classmethod + def idl(self): + return { + 'strs': ['name'], + 'ints': ['space', 'collaborators', 'private_repos'], + } def __repr__(self): - return ''.format(str(self.name)) + return '' % self.name class Key(BaseResource): """Github Key object model.""" - _strs = ['url', 'title', 'key'] - _ints = ['id'] + @classmethod + def idl(self): + return { + 'strs': ['url', 'title', 'key'], + 'ints': ['id'], + } def __repr__(self): - return ''.format(str(self.title)) + return '' % self.title class User(BaseResource): """Github User object model.""" - _strs = [ - 'login','avatar_url', 'url', 'name', 'company', 'blog', 'location', - 'email', 'bio', 'html_url', 'type'] - - _ints = ['id', 'public_repos', 'public_gists', 'followers', 'following'] - _dates = ['created_at',] - _bools = ['hireable', ] - - @property - def ri(self): - return ('users', self.login) + @classmethod + def idl(self): + return { + 'strs': ['login','avatar_url', 'url', 'name', 'company', 'blog', + 'location', 'email', 'bio', 'html_url', 'type'], + 'ints': [ + 'id', 'public_repos', 'public_gists', 'followers', 'following', + 'total_private_repos', 'owned_private_repos', 'private_gists', + 'disk_usage', 'collaborators'], + 'maps': {'plan': Plan}, + 'dates': ['created_at',], + 'bools': ['hireable', ], + } def __repr__(self): - return ''.format(self.login) + return '' % self.login - def handler(self): - return self._gh.user_handler(self.login, force=True) + #def handler(self): + # return self._gh.user_handler(self.login, force=True) class AuthUser(User): - """Github Current User object model.""" - - _ints = [ - 'id', 'public_repos', 'public_gists', 'followers', 'following', - 'total_private_repos', 'owned_private_repos', 'private_gists', - 'disk_usage', 'collaborators'] - _map = {'plan': Plan} - _writeable = ['name', 'email', 'blog', 'company', 'location', 'hireable', 'bio'] - - def handler(self): - return self._gh.user_handler(self.login, force=True, private=True) + """Github Authenticated User object model.""" - @property - def ri(self): - return ('user',) + #def handler(self): + # return self._gh.user_handler(self.login, force=True, private=True) def __repr__(self): - return ''.format(self.login) + return '' % self.login -- cgit v1.3-6-gb490 From 40cbe596f0d726461d65d6473c2d197f63232641 Mon Sep 17 00:00:00 2001 From: David Medina Date: Wed, 9 Nov 2011 02:10:29 +0100 Subject: Fixing bugs. Crazy night :S --- github3/api.py | 8 +++++++- github3/errors.py | 6 +++--- github3/handlers/base.py | 16 +++++++--------- github3/handlers/user.py | 26 +++++++++++++------------- github3/models/orgs.py | 2 +- github3/models/repos.py | 4 ++-- 6 files changed, 33 insertions(+), 29 deletions(-) (limited to 'github3/models') diff --git a/github3/api.py b/github3/api.py index 2066e94..b7435ff 100644 --- a/github3/api.py +++ b/github3/api.py @@ -43,7 +43,7 @@ class GithubCore(object): def head(self, request, **kwargs): """ HEAD request """ - return self._request('HEAD', request, **kwargs).headers + return self._request('HEAD', request, **kwargs) def post(self, request, data=None, **kwargs): """ @@ -71,11 +71,17 @@ class GithubCore(object): """ PUT request """ response = self._request('PUT', request, **kwargs) assert response.status_code == 204 + return response def delete(self, request, **kwargs): """ DELETE request """ + + data = kwargs.get('data') + if data: + kwargs['data'] = self._parser.dumps(data) response = self._request('DELETE', request, **kwargs) assert response.status_code == 204 + return response def _parse_args(self, request_args): """ diff --git a/github3/errors.py b/github3/errors.py index 96693be..09e616b 100644 --- a/github3/errors.py +++ b/github3/errors.py @@ -12,10 +12,10 @@ class GithubError(object): def __init__(self, response): self._parser = json self.status_code = response.status_code - if response.content: + try: self.debug = self._parser.loads(response.content) - else: - self.debug = {} + except ValueError: + self.debug = {'message': response.content} def error_400(self): return exceptions.BadRequest("400 - %s" % self.debug.get('message')) diff --git a/github3/handlers/base.py b/github3/handlers/base.py index 6bf13bf..50e2df8 100644 --- a/github3/handlers/base.py +++ b/github3/handlers/base.py @@ -15,9 +15,9 @@ class Handler(object): def _prefix_resource(self, resource): prefix = getattr(self, 'prefix', '') - return '/'.join((prefix, resource)) + return '/'.join((prefix, resource)).rstrip('/') - def _get_converter(self, kwargs): + def _get_converter(self, **kwargs): converter = kwargs.get( 'converter', # 1. in kwargs getattr(self, 'converter', # 2. in handler @@ -28,13 +28,11 @@ class Handler(object): def _put(self, resource, **kwargs): """ Put proxy request""" - resource = self._prefix_resource(resource) return self._bool(resource, method='put', **kwargs) def _delete(self, resource, **kwargs): """ Delete proxy request""" - resource = self._prefix_resource(resource) return self._bool(resource, method='delete', **kwargs) def _bool(self, resource, **kwargs): @@ -43,7 +41,7 @@ class Handler(object): from github3.exceptions import NotFound resource = self._prefix_resource(resource) try: - callback = getattr(self._gh, kwargs.get(method,''), self._gh.head) + callback = getattr(self._gh, kwargs.get('method',''), self._gh.head) response = callback(resource, **kwargs) except NotFound: return False @@ -55,13 +53,13 @@ class Handler(object): """ Hander request to multiple resources """ resource = self._prefix_resource(resource) - page_resources = Paginate(resource, self._gh.get, kwargs) + page_resources = Paginate(resource, self._gh.get, **kwargs) counter = 1 for page in page_resources: for raw_resource in page: if limit and counter > limit: break counter += 1 - converter = self._get_converter(kwargs) + converter = self._get_converter(**kwargs) converter.inject(model) yield converter.loads(raw_resource) else: @@ -73,7 +71,7 @@ class Handler(object): resource = self._prefix_resource(resource) raw_resource = self._gh.get(resource) - converter = self._get_converter(kwargs) + converter = self._get_converter(**kwargs) converter.inject(model) return converter.loads(raw_resource) @@ -82,6 +80,6 @@ class Handler(object): resource = self._prefix_resource(resource) raw_resource = self._gh.post(resource, data=data) - converter = self._get_converter(kwargs) + converter = self._get_converter(**kwargs) converter.inject(model) return converter.loads(raw_resource) diff --git a/github3/handlers/user.py b/github3/handlers/user.py index 75a0d3f..fb893b4 100644 --- a/github3/handlers/user.py +++ b/github3/handlers/user.py @@ -29,37 +29,37 @@ class User(Handler): def get(self): """ Return user """ - self._get_resource('', model=models.User) + return self._get_resource('', model=models.User) def get_followers(self): """ Return user's followers """ - self._get_resources('followers', model=models.User) + return self._get_resources('followers', model=models.User) def get_following(self): """ Return users that follow """ - self._get_resources('following', model=models.User) + return self._get_resources('following', model=models.User) def get_repos(self): """ Return user's public repositories """ - self._get_resources('repos', model=models.Repo) + return self._get_resources('repos', model=models.Repo) def get_watched(self): """ Return repositories that user whatch """ - self._get_resources('watched', model=models.Repo) + return self._get_resources('watched', model=models.Repo) def get_orgs(self): """ Return user's public organizations """ - self._get_resources('orgs', model=models.Org) + return self._get_resources('orgs', model=models.Org) def get_gists(self): """ Return user's gists """ - self._get_resources('gists', model=models.Gist) + return self._get_resources('gists', model=models.Gist) class AuthUser(User): """ User handler with public and private access """ @@ -70,7 +70,7 @@ class AuthUser(User): return ' %s>' % self._gh.session.auth[0] def get(self): - self._get_resource('', model=models.AuthUser) + return self._get_resource('', model=models.AuthUser) def get_emails(self): """ Return list of emails """ @@ -119,9 +119,9 @@ class AuthUser(User): """ parse_user = str(getattr(user, 'login', user)) - return self._put('following/%s', % parse_user) + return self._put('following/%s' % parse_user) - def unfollow(self, user) + def unfollow(self, user): """ Unfollow user @@ -129,14 +129,14 @@ class AuthUser(User): """ parse_user = str(getattr(user, 'login', user)) - return self._delete('following/%s', % parse_user) + return self._delete('following/%s' % parse_user) def get_keys(self): """ Get public keys """ return self._get_resources('keys', model=models.Key) - def get_key(self, key_id) + def get_key(self, key_id): """ Get public key by id """ return self._get_resource('keys/%s' % key_id, model=models.Key) @@ -151,7 +151,7 @@ class AuthUser(User): #TODO: render key.pub file key = { - 'title': kwargs.get('title','') + 'title': kwargs.get('title',''), 'key': kwargs.get('key','') } return self._post_resource('keys', data=key, model=models.Key) diff --git a/github3/models/orgs.py b/github3/models/orgs.py index 840b51a..5e66c35 100644 --- a/github3/models/orgs.py +++ b/github3/models/orgs.py @@ -18,7 +18,7 @@ class Org(BaseResource): 'following', 'total_private_repos', 'owned_private_repos', 'private_gists', 'disk_usage', 'collaborators'], 'dates': ['created_at'], - 'maps': {'plan': plan} + 'maps': {'plan': Plan} } def __repr__(self): diff --git a/github3/models/repos.py b/github3/models/repos.py index ba6ac33..d1b7b75 100644 --- a/github3/models/repos.py +++ b/github3/models/repos.py @@ -22,8 +22,8 @@ class Repo(BaseResource): 'maps': { 'owner': User, 'organization': Org, - 'parent': 'self', - 'source': 'self', + 'parent': self.__class__, + 'source': self.__class__, } } -- cgit v1.3-6-gb490