Source code for hal.internet.services.github

# -*- coding: utf-8 -*-

"""Common classes and entities in Github """

import json
import urllib

import requests
from bs4 import BeautifulSoup

from hal.internet.utils import add_params_to_url
from hal.wrappers.errors import none_returns

GITHUB_URL = "https://github.com"
API_URL = "https://api.github.com/"  # Github api url
GITHUB_TOKEN = None
GITHUB_REMOTE = "https://{}:x-oauth-basic@github.com/"


[docs]def get_token(): """Gets authentication token :return: authentication token """ return GITHUB_TOKEN
[docs]def get_clone_url(remote_shortcut, token): """Finds url of repo to clone :param remote_shortcut: relative path of repository to clone :param token: Github OAUTH token :return: Url to clone """ return GITHUB_REMOTE.format(token) + remote_shortcut
[docs]class GithubRawApi: """Generic Github API""" _API_TYPES = [ "users", "repos", "orgs", "authorizations", "gists", "feeds", "search" ] _API_URL_TYPE = { k: API_URL + k for k in _API_TYPES } # possible types of Github API def __init__(self, url=API_URL, url_params=None, get_api_content_now=False): """ :param url: Url of API content to get :param get_api_content_now: True iff you want to get API content response when building object """ self.api_url = url self.api_content = None if url_params: self.add_params_to_url(url_params) if get_api_content_now: self._get_api_content() def __getitem__(self, key): """ Gets value :param key: Dictionary key to find specific user field :return: Dictionary value of given key """ if self.api_content is None: # update API content self._get_api_content() try: return self.api_content[key] except: return None def _get_api_content(self): """Updates class api content by calling Github api and storing result""" if GITHUB_TOKEN is not None: self.add_params_to_url({ "access_token": GITHUB_TOKEN }) api_content_response = requests.get(self.api_url) self.api_content = json.loads( api_content_response.text ) # parse response
[docs] def add_params_to_url(self, params): """Adds params to url :param params: url params """ self.api_url = add_params_to_url(self.api_url, params)
[docs]class GithubApi(GithubRawApi): """Wrapper for generic Github API""" def __init__(self, api_type): """ :param api_type: str Type of API to build """ super(GithubApi, self).__init__( url=GithubRawApi._API_URL_TYPE[api_type], get_api_content_now=False )
[docs]class GithubUser(GithubApi): """Model of a generic Github user profile""" def __init__(self, username): """ :param username: Username of user """ super(GithubUser, self).__init__("users") self.username = str(username) self.api_url += "/" + self.username
[docs] @none_returns def get_email(self): """Gets email :return: Email of user """ api_url = self.api_url + "/events/public" api_content = GithubRawApi( api_url, get_api_content_now=True ).api_content for event in api_content: if event["type"] == "PushEvent": return event["payload"]["commits"][0]["author"]["email"]
@staticmethod def _get_repos(url): """Gets repos in url :param url: Url :return: List of repositories in given url """ current_page = 1 there_is_something_left = True repos_list = [] while there_is_something_left: api_driver = GithubRawApi( url, url_params={"page": current_page}, get_api_content_now=True ) # driver to parse API content for repo in api_driver.api_content: # list of raw repository repo_name = repo["name"] repo_user = repo["owner"]["login"] repos_list.append( GithubUserRepository(repo_user, repo_name)) there_is_something_left = bool(api_driver.api_content) current_page += 1 return repos_list
[docs] def get_repos(self): """Gets user public repos :return: List of user public repositories """ url = self["repos_url"] return self._get_repos(url)
[docs] def get_all_repos(self): """Gets user repos :return: List of all user repositories (public, orgs and private) """ url = "https://api.github.com/user/repos" params = { "access_token": GITHUB_TOKEN } # add auth params url = add_params_to_url(url, params) return self._get_repos(url)
[docs] def get_starred_repos(self): """Gets repos starred by user :return: List of starred repositories """ starred_url = self.api_url + "/starred" keep_finding = True # False when there are no more stars to find current_page = 1 repos_list = [] while keep_finding: api_url = starred_url + "?page=" + str( current_page) # request starred list url with page number api_driver = GithubRawApi( api_url, True ) # driver to parse API content for repo in api_driver: repo_username = repo["owner"]["login"] repo_name = repo["name"] repos_list.append( GithubUserRepository(repo_username, repo_name)) if len(api_driver.api_content) < 1: # no more repo to find keep_finding = False current_page += 1 # increase page counter return repos_list
[docs]class GithubUserRepository(GithubApi): """Model of a generic Github user repository""" def __init__(self, username, repository_name): """ :param username: Username of user :param repository_name: Name of repository """ super(GithubUserRepository, self).__init__("repos") self.username = str(username) self.repository_name = str(repository_name) self.api_url += "/" + self.username + "/" + self.repository_name def __eq__(self, other): same_username = self.username == other.username same_repo = self.repository_name == other.repository_name return same_username and same_repo