Implementing Licenses API for github3.py

I came across this license issue while searching on GitHub. So, I thought I’d give it a shot. I pinged sigmavirus24 in #github3.py seeing if this was a feature I could implement. He gave the thumbs up and I was off.

Testing manually first

Before any implementation, I always like to get a better understanding of the API by using good ol’ fashion curl.

curl https://api.github.com/licenses \
-H "Accept: application/vnd.github.drax-preview+json"

Sending a custom Accept: Header

In the code base, most classes inherit from github3.GitHubCore, which inherits from requests.Session. We can pass in**kwargs, and requests.Session.get accepts a headers as a kwarg. So, we can pass a custom Accept: header like so:

headers = {
    'Accepts': 'application/vnd.github.drax-preview+json'
}

url = self._build_url('license')
json = self._json(self._get(url, headers=headers))

How to add attributes to License model

By default, the model will not expose any attributes. How do we do that? The key is implementing __update_attributesmethod.

github3.licenses.License inherits from github3.models.GitHubObject, which calls __update_attriubtes in its__init__.

class GitHubObject(object):
    """The :class:`GitHubObject <GitHubObject>` object. A basic class to be
    subclassed by GitHubCore and other classes that would otherwise subclass
    object."""
    def __init__(self, json):
        super(GitHubObject, self).__init__()
        if json is not None:
            self.etag = json.pop('ETag', None)
            self.last_modified = json.pop('Last-Modified', None)
            self._uniq = json.get('url', None)
        self._json_data = json
        self._update_attributes(json)

So, let’s add License attributes

def _update_attributes(self, license):
    self.name = license.get('name')
    self.permitted = license.get('permitted')
    self.category = license.get('category')
    self.forbidden = license.get('forbidden')
    self.featured = license.get('featured')
    self.html_url = license.get('html_url')
    self.body = license.get('body')
    self.key = license.get('key')
    self.description = license.get('description')
    self.implementation = license.get('implementation')
    self.required = license.get('required')

Writing test

This guide is a great place to start. But, just a few pointers. For unit tests, copy/paste example data the API docs. For example, grab the JSON data from the license documentation. Save it under tests/unit/.

For integration tests, you’ll need to perform HTTP request(s). The betamax wrapper will record it to tests/cassettes.

Summary

This feature was merged in this pull request. I really enjoy contributing to this project. Primarily since sigmavirus24 is a pleasure to work with and extremely helpful. He’s super patient and I appreciate he takes the time onboarding new contributors.