diff options
Diffstat (limited to 'github3/handlers')
-rw-r--r-- | github3/handlers/base.py | 76 | ||||
-rw-r--r-- | github3/handlers/gists.py | 145 | ||||
-rw-r--r-- | github3/handlers/users.py | 299 |
3 files changed, 502 insertions, 18 deletions
diff --git a/github3/handlers/base.py b/github3/handlers/base.py index 50e2df8..565978f 100644 --- a/github3/handlers/base.py +++ b/github3/handlers/base.py @@ -1,11 +1,43 @@ #!/usr/bin/env python # -*- encoding: utf-8 -*- -# -# author: David Medina from github3.core import Paginate from github3.converters import Modelizer + +class MimeTypeMixin(object): + + VERSION = 'beta' + + def __init__(self): + self.mimetypes = set() + + def _parse_mime_type(self, type): + return 'application/vnd.github.%s.%s+json' % ( + self.VERSION, type) + + def add_raw(self): + self.mimetypes.add(self._parse_mime_type('raw')) + return self + + def add_text(self): + self.mimetypes.add(self._parse_mime_type('text')) + return self + + def add_html(self): + self.mimetypes.add(self._parse_mime_type('html')) + return self + + def add_full(self): + self.mimetypes.add(self._parse_mime_type('full')) + return self + + def mime_header(self): + if self.mimetypes: + return {'Accept': ', '.join(self.mimetypes)} + return None + + class Handler(object): """ Handler base. Requests to API and modelize responses """ @@ -13,17 +45,23 @@ class Handler(object): self._gh = gh super(Handler, self).__init__() + def _inject_handler(self, handler, prefix=''): + import inspect + for method, callback in inspect.getmembers(handler): + if method.startswith(prefix) and inspect.ismethod(callback): + setattr(self, method, callback) + def _prefix_resource(self, resource): prefix = getattr(self, 'prefix', '') - return '/'.join((prefix, resource)).rstrip('/') + return '/'.join((prefix, str(resource))).strip('/') - def _get_converter(self, **kwargs): - converter = kwargs.get( - 'converter', # 1. in kwargs - getattr(self, 'converter', # 2. in handler - Modelizer())) # 3. Default + def _get_converter(self, kwargs={}): + converter = kwargs.pop( + 'converter', # 1. in kwargs + getattr(self, 'converter', # 2. in handler + Modelizer)) # 3. Default - return converter + return converter() def _put(self, resource, **kwargs): """ Put proxy request""" @@ -41,27 +79,29 @@ 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 assert response.status_code == 204 return True - #TODO: if limit is multiple of per_page... it do another request for nothing def _get_resources(self, resource, model=None, limit=None, **kwargs): """ Hander request to multiple resources """ + if limit: + limit = abs(limit) resource = self._prefix_resource(resource) - page_resources = Paginate(resource, self._gh.get, **kwargs) + converter = self._get_converter(kwargs) counter = 1 - for page in page_resources: + for page in Paginate(resource, self._gh.get, **kwargs): for raw_resource in page: - if limit and counter > limit: break counter += 1 - converter = self._get_converter(**kwargs) converter.inject(model) yield converter.loads(raw_resource) + if limit and counter > limit: + break else: continue break @@ -70,8 +110,8 @@ class Handler(object): """ Handler request to single resource """ resource = self._prefix_resource(resource) - raw_resource = self._gh.get(resource) - converter = self._get_converter(**kwargs) + converter = self._get_converter(kwargs) + raw_resource = self._gh.get(resource, **kwargs) converter.inject(model) return converter.loads(raw_resource) @@ -80,6 +120,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/gists.py b/github3/handlers/gists.py new file mode 100644 index 0000000..ed03c31 --- /dev/null +++ b/github3/handlers/gists.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +from .base import Handler, MimeTypeMixin +from github3 import models + + +class Gist(Handler, MimeTypeMixin): + """ Gist handler with public access """ + + prefix = 'gists' + + def __repr__(self): + return '<Gist handler>' + + def all_gists(self, limit=None): + """ Return all public gists + + NOTE: It returns all gists in github environment. Maybe you + want to use `limit` parameter + """ + + return self._get_resources('', model=models.Gist, limit=limit) + + def get(self, gist_id): + """ Return gist + + param `gist_id`: Gist id + """ + + return self._get_resource(gist_id, model=models.Gist) + + def get_comments(self, gist_id, limit=None): + """ Return gist's comments + + param `gist_id`: Gist id + param `limit`: Number of comments + """ + + return self._get_resources('%s/comments' % gist_id, + model=models.GistComment, limit=limit, + headers=self.mime_header()) + + def get_comment(self, comment_id): + """ Return gist's comment + + param `comment_id`: Comment id + """ + + return self._get_resource('comments/%s' % comment_id, + model=models.GistComment, headers=self.mime_header()) + + +class AuthGist(Gist): + + def all_gists(self, limit=None): + """ Return all public gists + + NOTE: It returns all gists in github environment. Maybe you + want to use `limit` parameter + """ + + return self._get_resources('public', model=models.Gist, limit=limit) + + def my_gists(self, limit=None): + """ Return authenticated user's gists + + param `limit`: Number of gists + """ + + return self._get_resources('', model=models.Gist, limit=limit) + + def my_starred_gists(self, limit=None): + """ Return authenticated user's starred gists + + param `limit`: Number of gists + """ + + return self._get_resources('starred', model=models.Gist, limit=limit) + + def create_gist(self, is_public, files, desc=None): + """ Create and return a gist """ + + data = { + 'public': bool(is_public), + 'files': files, # TODO: Issue #1 + 'desc': desc or '', + } + return self._post_resource('', data=data, model=models.Gist) + + def star_gist(self, gist_id): + """ Star a gist + + param `gist_id`: Gist id to star + """ + + return self._put('%s/star' % gist_id) + + def unstar_gist(self, gist_id): + """ Unstar a gist + + param `gist_id`: Gist id to unstar + """ + + return self._delete('%s/star' % gist_id) + + def is_starred(self, gist_id): + """ True if gist is starred + + param `gist_id`: Gist id + """ + + return self._bool('%s/star' % gist_id) + + def fork_gist(self, gist_id): + """ Return forked gist from id + + param `gist_id`: Gist id to be forked... + """ + + return self._post_resource('%s/fork' % gist_id, data=None, + model=models.Gist) + + def delete_gist(self, gist_id): + """ Delete the gist + + param `gist_id`: Gist id + """ + + return self._delete(str(gist_id)) + + def create_comment(self, gist_id, comment): + """ Create comment into gist """ + + data = {'body': comment} + return self._post_resource('%s/comments' % gist_id, data=data, + model=models.GistComment) + + def delete_comment(self, comment_id): + """ Delete comment + + param `comment_id`: Comment id + """ + + return self._delete('comments/%s' % comment_id) diff --git a/github3/handlers/users.py b/github3/handlers/users.py new file mode 100644 index 0000000..2f12184 --- /dev/null +++ b/github3/handlers/users.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +from .base import Handler +from github3 import models +from github3.converters import Rawlizer +from github3.exceptions import UserIsAnonymous + + +class User(Handler): + """ User handler with public access """ + + prefix = 'users' + + def __repr__(self): + return '<User handler> %s>' % getattr(self, 'username', 'without user') + + def _parse_user(self, user): + """ Parse user, and if it fails then try with username in handler + + :param user: It can be a `models.User` or alphanumeric user string + + """ + username = getattr(user, 'login', user) + if not username or not str(username).isalpha(): + username = getattr(self, 'username', False) + if not username: + raise UserIsAnonymous('%s user is not valid' % username) + return str(username) + + def set_username(self, user): + """ Set username to query public handler + Helper to less writing + + :param user: It can be a `models.User` or alphanumeric user string + + """ + self.username = self._parse_user(user) + return self + + def get(self, user=None): + """ Return user + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resource(user, model=models.User) + + def get_followers(self, user=None, limit=None): + """ Return user's followers + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/followers' % user, model=models.User, + limit=limit) + + def get_following(self, user=None, limit=None): + """ Return users that follow + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/following' % user, model=models.User, + limit=limit) + + def get_repos(self, user=None, limit=None): + """ Return user's public repositories + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/repos' % user, model=models.Repo, + limit=limit) + + def get_watched(self, user=None, limit=None): + """ Return repositories that user watch + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/watched' % user, model=models.Repo, + limit=limit) + + def get_orgs(self, user=None, limit=None): + """ Return user's public organizations + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/orgs' % user, model=models.Org, + limit=limit) + + def get_gists(self, user=None, limit=None): + """ Return user's gists + + :param `user`: User model or username string + + """ + user = self._parse_user(user) + return self._get_resources('%s/gists' % user, model=models.Gist, + limit=limit) + + +class AuthUser(Handler): + """ User handler with public and private access """ + + prefix = 'user' + + def __init__(self, gh): + super(AuthUser, self).__init__(gh) + self._inject_handler(User(gh), prefix='get') + + def __repr__(self): + return '<AuthUser handler> %s>' % self._gh.session.auth[0] + + def me(self): + """ Return authenticated user """ + + return self._get_resource('', model=models.AuthUser) + + def my_followers(self, limit=None): + """ Return authenticated user followers """ + + return self._get_resources('followers', model=models.User, + limit=limit) + + def my_following(self, limit=None): + """ Return authenticated user following """ + + return self._get_resources('following', model=models.User, + limit=limit) + + def get_emails(self): + """ Return list of emails """ + + # Ignore converter, it must be Rawlizer + emails = self._get_resource('emails', converter=Rawlizer) + return emails + + def create_emails(self, *args): + """ + Add emails + + :param args: Collection of emails + create_emails(*('test1@example.com', 'test2@example.cm')) + """ + parsed_emails = map(str, args) + all_mails = self._post_resource( + 'emails', data=parsed_emails, converter=Rawlizer) + return all_mails + + def delete_emails(self, *args): + """ + Delete emails + + :param args: Collection of emails + create_emails(*('test1@example.com', 'test2@example.cm')) + """ + parsed_emails = map(str, args) + return self._delete('emails', data=parsed_emails) + + def is_following(self, user): + """ + Return true if you are following the user + + :param `user`: User model or username string + """ + + parse_user = getattr(user, 'login', user) + return self._bool('following/%s' % parse_user) + + def follow(self, user): + """ + Follow user + + :param `user`: User model or username string + + """ + + parse_user = getattr(user, 'login', user) + return self._put('following/%s' % parse_user) + + def unfollow(self, user): + """ + Unfollow user + + :param `user`: User model or username string + """ + + parse_user = getattr(user, 'login', user) + return self._delete('following/%s' % parse_user) + + def get_keys(self, limit=None): + """ Get public keys """ + + return self._get_resources('keys', model=models.Key, + limit=limit) + + def get_key(self, key): + """ Get public key + + :param `key`: Key model or key id + + """ + + parse_key_id = getattr(key, 'id', key) + return self._get_resource('keys/%s' % parse_key_id, model=models.Key) + + def create_key(self, **kwargs): + """ + Create public key + + :param title + :param key: Key string (It must starts with 'ssh-rsa') + """ + + #TODO: render key.pub file + key = { + 'title': kwargs.get('title', ''), + 'key': kwargs.get('key', '') + } + return self._post_resource('keys', data=key, model=models.Key) + + def delete_key(self, key): + """ Delete public key + + :param `key`: Key model or key id + + """ + + parse_key_id = getattr(key, 'id', key) + return self._delete('keys/%s' % parse_key_id) + + def my_repos(self, filter='all', limit=None): + """ + Return user's public repositories + + param: filter: 'all', 'owner', 'public', 'private' or 'member' + """ + + return self._get_resources('repos', model=models.Repo, + limit=limit, type=str(filter)) + + def my_watched(self, limit=None): + """ Return authenticated user repos that he watch """ + + return self._get_resources('watched', model=models.Repo, + limit=limit) + + def is_watching_repo(self, owner, repo): + """ + Return true if you are watching the user repository + + :param owner: Model user or username string + :param repo: Model repo or repo name string + is_watching_repo('copitux', 'python-github3') + """ + + owner = getattr(owner, 'login', owner) + repo = getattr(repo, 'name', repo) + return self._bool('watched/%s/%s' % (owner, repo)) + + def watch_repo(self, owner, repo): + """ + Watch the repository + + :param owner: Model user or username string + :param repo: Model repo or repo name string + """ + + owner = getattr(owner, 'login', owner) + repo = getattr(repo, 'name', repo) + return self._put('watched/%s/%s' % (owner, repo)) + + def unwatch_repo(self, owner, repo): + """ + Unwatch the repository + + :param owner: Model user or username string + :param repo: Model repo or repo name string + """ + + owner = getattr(owner, 'login', owner) + repo = getattr(repo, 'name', repo) + return self._delete('watched/%s/%s' % (owner, repo)) + + def my_orgs(self, limit=None): + """ List public and private organizations + for the authenticated user + """ + + return self._get_resources('orgs', model=models.Org, limit=limit) |