gidgethub — An async library for calling GitHub’s API
While there are many GitHub libraries for Python, when this library was created there were none oriented towards asynchronous usage. On top of that, there were also no libraries which took a sans-I/O approach to their design. Because of that, this project was created.
This project has three primary layers to it. The base layer is
gidgethub.sansio
and gidgethub.routing
which provide the
tools necessary to work with GitHub’s API. The next layer up is
gidgethub.abc
which provides an abstract base class for a
cleaner, unified API. Finally, the top layer is using an
implementation of the abstract base class,
e.g. gidgethub.aiohttp
.
Quickstart
Here is a complete example of a production server that responds to
webhooks which will add a needs review
label to all new pull
requests (this is taken from the
Bedevere bot used by the
Python project; the only change is inlining some code and showing code
responding to only a single type of webhook event):
import asyncio
import importlib
import os
import sys
import traceback
import aiohttp
from aiohttp import web
import cachetools
from gidgethub import aiohttp as gh_aiohttp
from gidgethub import routing
from gidgethub import sansio
router = routing.Router()
cache = cachetools.LRUCache(maxsize=500)
@router.register("pull_request", action="opened")
async def opened_pr(event, gh, *arg, **kwargs):
"""Mark new PRs as needing a review."""
pull_request = event.data["pull_request"]
await gh.post(pull_request["labels_url"], data=["needs review"])
async def main(request):
try:
body = await request.read()
secret = os.environ.get("GH_SECRET")
event = sansio.Event.from_http(request.headers, body, secret=secret)
print('GH delivery ID', event.delivery_id, file=sys.stderr)
if event.event == "ping":
return web.Response(status=200)
oauth_token = os.environ.get("GH_AUTH")
async with aiohttp.ClientSession() as session:
gh = gh_aiohttp.GitHubAPI(session, "brettcannon/gidgethub-example",
oauth_token=oauth_token,
cache=cache)
# Give GitHub some time to reach internal consistency.
await asyncio.sleep(1)
await router.dispatch(event, gh)
try:
print('GH requests remaining:', gh.rate_limit.remaining)
except AttributeError:
pass
return web.Response(status=200)
except Exception as exc:
traceback.print_exc(file=sys.stderr)
return web.Response(status=500)
if __name__ == "__main__":
app = web.Application()
app.router.add_post("/", main)
port = os.environ.get("PORT")
if port is not None:
port = int(port)
web.run_app(app, port=port)
Motivation
The vast majority of users will want to use one of the concrete
implementations, but for those that have an HTTP library which is not
supported or simply want the base tools, this library will still be
useful. And the higher-level API has been designed to abstract away
GitHub-specific details in making API calls, but it does not try to
separate you from the GitHub API itself, e.g. to get the details of
the bug
label for this project you don’t call something like:
org("brettcannon").repo("gidgethub").label("bug")
Instead, you call:
await gh.getitem("/repos/brettcannon/gidgethub/labels/bug")
This makes it so that you can follow GitHub’s documentation for their API closely. You also don’t have to wait for an update to this library to use new features of the GitHub API.
Installation
python3 -m pip install gidgethub
Contents
- Changelog
gidgethub
— Exceptionsgidgethub.sansio
— sans-I/O supportgidgethub.actions
— Support for GitHub Actionsgidgethub.apps
— Support for GitHub Appgidgethub.routing
— A router for webhook eventsgidgethub.abc
— Abstract base class for simplified requestsgidgethub.aiohttp
— aiohttp supportgidgethub.tornado
— Tornado supportgidgethub.httpx
— httpx support
About the title
With there being so many pre-existing GitHub libraries, it was tough to come up with a new name. So in the end I just named it after my cat. 😊
“Gidget” sounds somewhat like an elongated version of “git” so that made some sense phonetically. And with the octocat being the mascot of GitHub, it seemed fitting to have the name to be feline-related somehow.