Skip to content

Instantly share code, notes, and snippets.

@ymmt2005
Created September 11, 2012 13:05
Show Gist options
  • Save ymmt2005/3698314 to your computer and use it in GitHub Desktop.
Save ymmt2005/3698314 to your computer and use it in GitHub Desktop.
GitHub v3 API client in Python
#!/usr/bin/env python
'''
GitHub API v3 client.
@see http://developer.github.com/v3/
@see https://support.enterprise.github.com/entries/21391237-using-the-api
'''
from argparse import ArgumentParser, REMAINDER
import base64
from getpass import getpass
import httplib
import json
import sys
### Constants
OFFICIAL = 'api.github.com'
PREFIX = '/api/v3'
### Implementation
def u2s(o):
if isinstance(o, list):
return [u2s(i) for i in o]
if isinstance(o, dict):
t = {}
for k, v in o.iteritems():
t[u2s(k)] = u2s(v)
return t
if isinstance(o, unicode):
return o.encode('utf-8')
return o
def basic_auth(user, password):
return 'Basic ' + base64.b64encode('%s:%s' % (user, password))
class GitHub(object):
def __init__(self, endpoint, user, password, ssl=False):
self._endpoint = endpoint
self._auth = basic_auth(user, password)
if ssl or endpoint == OFFICIAL:
self._conn = httplib.HTTPSConnection
else:
self._conn = httplib.HTTPConnection
def request(self, method, api, body=None):
if self._endpoint == OFFICIAL:
path = api
else:
path = PREFIX + api
conn = self._conn(self._endpoint, timeout=5)
headers = {'Authorization': self._auth}
if body is None:
conn.request(method, path, headers=headers)
else:
conn.request(method, path, body, headers)
r = conn.getresponse()
data = u2s(json.loads(r.read()))
status = r.status
if status < 200 or status >= 300:
raise RuntimeError('%s failed. status=%d, data:\n%s' %
(api, status, data))
conn.close()
return (status, data)
def createPullRequest(self, repo, title, base, head, msg=None):
api = '/repos/%s/pulls' % repo
body = {'title': title, 'head': head, 'base': base}
if msg is not None:
body['body'] = msg
status, data = self.request('POST', api, json.dumps(body))
return data
def cmd_new_request(github, args, p):
if len(args) < 4:
p.exit(1, '''Too few arguments.
Usage: github new_request repo title base head [message]
''')
if len(args) == 5:
msg = args[4]
else:
msg = None
data = github.createPullRequest(args[0], args[1], args[2], args[3], msg)
print data['html_url']
### Main
def main():
commands = {'new_request': cmd_new_request}
p = ArgumentParser(description='GitHub API command-line client.',
prog='github', add_help=False)
p.add_argument('API', choices=commands.keys(), nargs='?')
p.add_argument('args', nargs=REMAINDER)
p.add_argument('-u', '--user', metavar='USER', required=True,
help='GitHub user name')
p.add_argument('-p', '--password', metavar='PASSWORD',
help='GitHub password')
p.add_argument('-h', '--host', default=OFFICIAL, metavar='HOST',
help='GitHub hostname')
p.add_argument('-s', '--ssl', action='store_true', default=False,
help='Enable SSL')
ns = p.parse_args()
if ns.API is None:
p.print_help()
sys.exit(0)
if ns.password is None:
passwd = getpass('GitHub password: ')
else:
passwd = ns.password
github = GitHub(ns.host, ns.user, passwd, ns.ssl)
cmd = commands[ns.API]
cmd(github, ns.args, p)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment