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/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'github3/helpers.py') diff --git a/github3/helpers.py b/github3/helpers.py index abdeb4a..498a005 100644 --- a/github3/helpers.py +++ b/github3/helpers.py @@ -166,4 +166,4 @@ def get_scope(f, args=None): # scrub readability.models namespace scope = scope.replace('readability.api.', '') - return scope \ No newline at end of file + return scope -- cgit v1.2.3-59-g8ed1b 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/helpers.py') 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.2.3-59-g8ed1b