Skip to content

Commit

Permalink
Project import
Browse files Browse the repository at this point in the history
  • Loading branch information
fridex committed Jan 3, 2018
0 parents commit 1ad0a51
Show file tree
Hide file tree
Showing 22 changed files with 1,034 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
Empty file added Makefile
Empty file.
19 changes: 19 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[[source]]

url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"


[packages]

attrs = "*"
requests = "*"
click = "*"
daiquiri = "*"
voluptuous = "*"
pyyaml = "*"


[dev-packages]

113 changes: 113 additions & 0 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions githubcap-cli
13 changes: 13 additions & 0 deletions githubcap/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

from .configuration import Configuration
from .enums import Filtering
from .enums import State
from .enums import Sorting
from .enums import SortingDirection
from .utils import setup_logging

__version__ = '1.0.0rc1'
__title__ = 'githubcap'
__author__ = 'Fridolin Pokorny'
__license__ = 'ASL 2.0'
__copyright__ = 'Copyright 2018 Fridolin Pokorny'
112 changes: 112 additions & 0 deletions githubcap/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import attr

from datetime import datetime
import time
import typing
import logging
from .configuration import Configuration
import requests
import copy
from .exceptions import MissingPassword
from .exceptions import HTTPError
from .utils import next_pagination_page

_LOG = logging.getLogger(__name__)


@attr.s
class GitHubHandlerBase(object):
DEFAULT_PER_PAGE: typing.ClassVar[int] = Configuration().per_page_listing
config: typing.ClassVar[Configuration] = Configuration()

@classmethod
def call(cls, uri, payload=None, method=None):
requests_kwargs = {
'headers': copy.copy(Configuration().headers)
}

if Configuration().token:
_LOG.debug("Using OAuth2 token '%s***' for GitHub call", Configuration().token[:4])
requests_kwargs['headers']['Authorization'] = 'token {!s}'.format(Configuration().token)
elif Configuration().user:
if not Configuration().password:
raise MissingPassword("No password set for user {!s}".format(Configuration().user))

_LOG.debug("Using basic authentication for user %s", Configuration().user)
requests_kwargs['auth'].append((Configuration().user, Configuration().password))
else:
_LOG.debug("No authentication is used")

url = "{!s}/{!s}".format(Configuration().github_api, uri)
requests_func = getattr(requests, method.lower())
if payload:
requests_kwargs['json'] = payload

while True:
_LOG.debug("%s %s", method, url)
response = requests_func(url, **requests_kwargs)

_LOG.debug("Request took %s and the HTTP status code for response was %d",
response.elapsed, response.status_code)

if not (response.status_code == 403 and
response.json()['message'].startswith("API rate limit exceeded") and
cls.config.omit_rate_limiting):
break

reset_datetime = datetime.fromtimestamp(int(response.headers['X-RateLimit-Reset']))
sleep_time = (reset_datetime - datetime.now()).total_seconds()
_LOG.debug("API rate limit hit, retrying in %d seconds...", sleep_time)
time.sleep(sleep_time)

try:
# Rely on request's checks here
response.raise_for_status()
except requests.exceptions.HTTPError as exc:
raise HTTPError(response.json(), response.status_code) from exc

return response.json(), response.headers

@classmethod
def head(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='HEAD')

@classmethod
def get(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='GET')

@classmethod
def post(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='POST')

@classmethod
def patch(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='PATCH')

@classmethod
def put(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='PUT')

@classmethod
def delete(cls, *args, **kwargs):
return cls.call(*args, **kwargs, method='DELETE')

def _do_listing(self, base_uri):
while True:
uri = '{!s}?{!s}'.format(base_uri, self._get_query_string())
response, headers = self.get(uri)

for entry in response:
yield entry

if not self.config.pagination:
return

next_page = next_pagination_page(headers)
if next_page is None:
return
self.page = next_page


class GitHubBase(object):
pass

0 comments on commit 1ad0a51

Please sign in to comment.