зеркало из https://github.com/github/octokit.py.git
Merge pull request #21 from octokit/eduardo-pep8
converted style to pep8
This commit is contained in:
Коммит
8f7642523c
|
@ -7,50 +7,51 @@ octokit.client
|
|||
This module contains the main Client class for octokit.py
|
||||
"""
|
||||
|
||||
# https://code.google.com/p/uri-templates/wiki/Implementations
|
||||
import requests
|
||||
|
||||
from .exceptions import handle_status
|
||||
from .pagination import Pagination
|
||||
from .ratelimit import RateLimit
|
||||
from .resources import Resource
|
||||
|
||||
import requests
|
||||
|
||||
class BaseClient(Resource):
|
||||
"""The main class for using octokit.py.
|
||||
"""The main class for using octokit.py.
|
||||
|
||||
This class accepts as arguments any attributes that can be set on a
|
||||
Requests.Session() object. After instantiation, the session may be modified
|
||||
by accessing the `session` attribute.
|
||||
This class accepts as arguments any attributes that can be set on a
|
||||
Requests.Session() object. After instantiation, the session may be modified
|
||||
by accessing the `session` attribute.
|
||||
|
||||
Example usage:
|
||||
Example usage:
|
||||
|
||||
>>> client = octokit.Client(auth = ('mastahyeti', 'oauth-token'))
|
||||
>>> client.session.proxies = {'http': 'foo.bar:3128'}
|
||||
>>> client.current_user.login
|
||||
'mastahyeti'
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, session=requests.Session(), api_endpoint='https://api.github.com', **kwargs):
|
||||
self.session = session
|
||||
self.url = api_endpoint
|
||||
self.schema = {}
|
||||
self.name = 'Client'
|
||||
self.auto_paginate = False
|
||||
def __init__(self, session=requests.Session(),
|
||||
api_endpoint='https://api.github.com', **kwargs):
|
||||
self.session = session
|
||||
self.url = api_endpoint
|
||||
self.schema = {}
|
||||
self.name = 'Client'
|
||||
self.auto_paginate = False
|
||||
|
||||
self.session.hooks = dict(response=self.response_callback)
|
||||
for key in kwargs:
|
||||
setattr(self.session, key, kwargs[key])
|
||||
self.session.hooks = dict(response=self.response_callback)
|
||||
for key in kwargs:
|
||||
setattr(self.session, key, kwargs[key])
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return super(BaseClient, self).__getattr__(name)
|
||||
except:
|
||||
handle_status(404)
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return super(BaseClient, self).__getattr__(name)
|
||||
except AttributeError:
|
||||
handle_status(404)
|
||||
|
||||
def response_callback(self, r, *args, **kwargs):
|
||||
data = r.json() if r.text != "" else {}
|
||||
handle_status(r.status_code, data)
|
||||
|
||||
def response_callback(self, r, *args, **kwargs):
|
||||
data = r.json() if r.text != "" else {}
|
||||
handle_status(r.status_code, data)
|
||||
|
||||
class Client(Pagination, RateLimit, BaseClient):
|
||||
pass
|
||||
pass
|
||||
|
|
|
@ -7,56 +7,75 @@ octokit.exceptions
|
|||
This module contains octokit.py exceptions.
|
||||
"""
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
""" Something went wrong. """
|
||||
def __init__(self, data={'message':'Something went wrong.'}):
|
||||
self.message = data['message']
|
||||
def __str__(self):
|
||||
return repr(self.message)
|
||||
"""Something went wrong."""
|
||||
|
||||
def __init__(self, data={'message': 'Something went wrong.'}):
|
||||
self.message = data['message']
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.message)
|
||||
|
||||
|
||||
class ClientError(Error):
|
||||
""" Status 4xx: Client error. """
|
||||
"""Status 4xx: Client error."""
|
||||
|
||||
|
||||
class BadRequest(ClientError):
|
||||
""" Status 400: Bad request. """
|
||||
"""Status 400: Bad request."""
|
||||
|
||||
|
||||
class Unauthorized(ClientError):
|
||||
""" Status 401/403: Not authorized to view the resource """
|
||||
"""Status 401/403: Not authorized to view the resource"""
|
||||
|
||||
|
||||
class NotFound(ClientError):
|
||||
""" Status 404: The resource wasn't found. """
|
||||
def __init__(self, data={"message": "Not Found"}):
|
||||
super(NotFound, self).__init__(data)
|
||||
"""Status 404: The resource wasn't found."""
|
||||
|
||||
def __init__(self, data={"message": "Not Found"}):
|
||||
super(NotFound, self).__init__(data)
|
||||
|
||||
|
||||
class MethodNotAllowed(ClientError):
|
||||
""" Status 405: The method is not allowed. """
|
||||
"""Status 405: The method is not allowed."""
|
||||
|
||||
|
||||
class NotAcceptable(ClientError):
|
||||
""" Status 406: The response is unacceptable. """
|
||||
"""Status 406: The response is unacceptable."""
|
||||
|
||||
|
||||
class Conflict(ClientError):
|
||||
""" Status 409: There was a conflict with the current state of the resource. """
|
||||
"""Status 409: Conflict with the current state of the resource."""
|
||||
|
||||
|
||||
class UnsupportedMediaType(ClientError):
|
||||
""" Status 415: Unsupported media type. """
|
||||
"""Status 415: Unsupported media type."""
|
||||
|
||||
|
||||
class UnprocessableEntity(ClientError):
|
||||
""" Status 422: Unprocessable entity. """
|
||||
"""Status 422: Unprocessable entity."""
|
||||
|
||||
|
||||
class ServerError(Error):
|
||||
""" Status 5xx: Server error. """
|
||||
"""Status 5xx: Server error."""
|
||||
|
||||
|
||||
class InternalServerError(ServerError):
|
||||
""" Status 500: Internal server error. """
|
||||
"""Status 500: Internal server error."""
|
||||
|
||||
|
||||
class NotImplemented(ServerError):
|
||||
""" Status 501: Not implemented. """
|
||||
"""Status 501: Not implemented."""
|
||||
|
||||
|
||||
class BadGateway(ServerError):
|
||||
""" Status 502: Bad gateway. """
|
||||
"""Status 502: Bad gateway."""
|
||||
|
||||
|
||||
class ServiceUnavailable(ServerError):
|
||||
""" Status 503: Service unavailable. """
|
||||
"""Status 503: Service unavailable."""
|
||||
|
||||
|
||||
# Mapping of status code to Exception
|
||||
STATUS_ERRORS = {
|
||||
|
@ -77,16 +96,17 @@ STATUS_ERRORS = {
|
|||
599: ServerError
|
||||
}
|
||||
|
||||
|
||||
def handle_status(status, data=None):
|
||||
""" Raise the appropriate error given a status code. """
|
||||
if status >= 400:
|
||||
error = STATUS_ERRORS.get(status)
|
||||
if error is None:
|
||||
if status <= 499:
|
||||
error = STATUS_ERRORS.get(499)
|
||||
elif status <= 599:
|
||||
error = STATUS_ERRORS.get(599)
|
||||
else:
|
||||
error = Error
|
||||
errorException = error(data) if data else error()
|
||||
raise errorException
|
||||
"""Raise the appropriate error given a status code."""
|
||||
if status >= 400:
|
||||
error = STATUS_ERRORS.get(status)
|
||||
if error is None:
|
||||
if status <= 499:
|
||||
error = STATUS_ERRORS.get(499)
|
||||
elif status <= 599:
|
||||
error = STATUS_ERRORS.get(599)
|
||||
else:
|
||||
error = Error
|
||||
errorException = error(data) if data else error()
|
||||
raise errorException
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
from .resources import Resource
|
||||
|
||||
|
||||
class Pagination(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
# TODO (howei): possibly extract auto_paginate from kwargs
|
||||
# so users can do client = Client(auto_paginate=True)
|
||||
self.auto_paginate = False
|
||||
super(Pagination, self).__init__(*args, **kwargs)
|
||||
def __init__(self, *args, **kwargs):
|
||||
# TODO (howei): possibly extract auto_paginate from kwargs
|
||||
# so users can do client = Client(auto_paginate=True)
|
||||
self.auto_paginate = False
|
||||
super(Pagination, self).__init__(*args, **kwargs)
|
||||
|
||||
def response_callback(self, r, **kwargs):
|
||||
# TODO (howei): possibly implement auto pagination logic here
|
||||
return super(Pagination, self).response_callback(r, **kwargs)
|
||||
def response_callback(self, r, **kwargs):
|
||||
# TODO (howei): possibly implement auto pagination logic here
|
||||
return super(Pagination, self).response_callback(r, **kwargs)
|
||||
|
||||
def paginate(self, url, *args, **kwargs):
|
||||
session = self.session
|
||||
params = {}
|
||||
if 'per_page' in kwargs:
|
||||
params['per_page'] = kwargs['per_page']
|
||||
del kwargs['per_page']
|
||||
elif self.auto_paginate:
|
||||
# if per page is not defined, default to 100 per page
|
||||
params['per_page'] = 100
|
||||
def paginate(self, *args, **kwargs):
|
||||
params = {}
|
||||
if 'per_page' in kwargs:
|
||||
params['per_page'] = kwargs['per_page']
|
||||
del kwargs['per_page']
|
||||
elif self.auto_paginate:
|
||||
# if per page is not defined, default to 100 per page
|
||||
params['per_page'] = 100
|
||||
|
||||
if 'page' in kwargs:
|
||||
params['page'] = kwargs['page']
|
||||
del kwargs['page']
|
||||
if 'page' in kwargs:
|
||||
params['page'] = kwargs['page']
|
||||
del kwargs['page']
|
||||
|
||||
kwargs['params'] = params
|
||||
resource = Resource(session, url=url, name=url).get(*args, **kwargs)
|
||||
data = list(resource.schema)
|
||||
kwargs['params'] = params
|
||||
resource = self.get(*args, **kwargs)
|
||||
data = list(resource.schema)
|
||||
|
||||
if self.auto_paginate:
|
||||
while 'next' in resource.rels and self.rate_limit.remaining > 0:
|
||||
resource = resource.rels['next'].get()
|
||||
data.extend(list(resource.schema))
|
||||
if self.auto_paginate:
|
||||
while 'next' in resource.rels and self.rate_limit.remaining > 0:
|
||||
resource = resource.rels['next'].get()
|
||||
data.extend(list(resource.schema))
|
||||
|
||||
return Resource(session, schema=data, url=self.url, name=self.name)
|
||||
return Resource(self.session, schema=data,
|
||||
url=resource.url, name=resource.name)
|
||||
|
|
|
@ -1,45 +1,42 @@
|
|||
import calendar
|
||||
import time
|
||||
from collections import namedtuple
|
||||
try:
|
||||
from urllib.parse import urljoin
|
||||
except ImportError:
|
||||
from urlparse import urljoin
|
||||
|
||||
|
||||
class RateLimit(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._rate_limit = _RateLimit()
|
||||
self.last_response = None
|
||||
super(RateLimit, self).__init__(*args, **kwargs)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._rate_limit = _RateLimit()
|
||||
self.last_response = None
|
||||
super(RateLimit, self).__init__(*args, **kwargs)
|
||||
|
||||
def response_callback(self, r, **kwargs):
|
||||
self.last_response = r
|
||||
return super(RateLimit, self).response_callback(r, **kwargs)
|
||||
def response_callback(self, r, **kwargs):
|
||||
self.last_response = r
|
||||
return super(RateLimit, self).response_callback(r, **kwargs)
|
||||
|
||||
@property
|
||||
def rate_limit(self):
|
||||
self.update_rate_limit()
|
||||
return self._rate_limit
|
||||
@property
|
||||
def rate_limit(self):
|
||||
self.update_rate_limit()
|
||||
return self._rate_limit
|
||||
|
||||
def update_rate_limit(self):
|
||||
if not self.last_response:
|
||||
self.head()
|
||||
def update_rate_limit(self):
|
||||
if not self.last_response:
|
||||
self.head()
|
||||
|
||||
rate_limit = self._rate_limit
|
||||
response = self.last_response
|
||||
rate_limit = self._rate_limit
|
||||
headers = self.last_response.headers
|
||||
|
||||
rate_limit.limit = int(headers['X-RateLimit-Limit'])
|
||||
rate_limit.remaining = int(headers['X-RateLimit-Remaining'])
|
||||
rate_limit.resets_at = int(headers['X-RateLimit-Reset'])
|
||||
delta = rate_limit.resets_at - calendar.timegm(time.gmtime())
|
||||
rate_limit.resets_in = max(delta, 0)
|
||||
|
||||
rate_limit.limit = int(response.headers['X-RateLimit-Limit'])
|
||||
rate_limit.remaining = int(response.headers['X-RateLimit-Remaining'])
|
||||
rate_limit.resets_at = int(response.headers['X-RateLimit-Reset'])
|
||||
delta = rate_limit.resets_at - calendar.timegm(time.gmtime())
|
||||
rate_limit.resets_in = max(delta, 0)
|
||||
|
||||
class _RateLimit(object):
|
||||
__slots__ = ('limit', 'remaining', 'resets_at', 'resets_in')
|
||||
__slots__ = ('limit', 'remaining', 'resets_at', 'resets_in')
|
||||
|
||||
def __repr__(self):
|
||||
s = ', '.join(
|
||||
'{}={}'.format(slot, getattr(self, slot))
|
||||
for slot in self.__slots__
|
||||
)
|
||||
return '%s(%s)' % (self.__class__, s)
|
||||
def __repr__(self):
|
||||
s = ', '.join(
|
||||
'{}={}'.format(slot, getattr(self, slot))
|
||||
for slot in self.__slots__
|
||||
)
|
||||
return '%s(%s)' % (self.__class__, s)
|
||||
|
|
|
@ -7,190 +7,176 @@ octokit.resources
|
|||
This module contains the workhorse of octokit.py, the Resources.
|
||||
"""
|
||||
|
||||
from inflection import humanize, singularize
|
||||
import requests
|
||||
import uritemplate
|
||||
from inflection import humanize, singularize
|
||||
|
||||
|
||||
class Resource(object):
|
||||
"""The workhorse of octokit.py, this class makes the API calls and interprets
|
||||
them into an accessible schema. The API calls and schema parsing are lazy and
|
||||
only happen when an attribute of the resource is requested.
|
||||
"""
|
||||
"""The workhorse of octokit.py, this class makes the API calls and
|
||||
interprets them into an accessible schema. The API calls and schema parsing
|
||||
are lazy and only happen when an attribute of the resource is requested.
|
||||
"""
|
||||
|
||||
def __init__(self, session, name=None, url=None, schema=None, response=None):
|
||||
self.session = session
|
||||
self.name = name
|
||||
self.url = url
|
||||
self.schema = schema
|
||||
self.response = response
|
||||
self.rels = {}
|
||||
def __init__(self, session, name=None, url=None, schema=None,
|
||||
response=None):
|
||||
self.session = session
|
||||
self.name = name
|
||||
self.url = url
|
||||
self.schema = schema
|
||||
self.response = response
|
||||
self.rels = {}
|
||||
|
||||
if response:
|
||||
self.schema = self.parse_schema(response)
|
||||
self.rels = self.parse_rels(response)
|
||||
self.url = response.url
|
||||
if response:
|
||||
self.schema = self.parse_schema(response.json())
|
||||
self.rels = self.parse_rels(response)
|
||||
self.url = response.url
|
||||
|
||||
if type(self.schema) == dict and 'url' in self.schema:
|
||||
self.url = self.schema['url']
|
||||
if type(self.schema) == dict and 'url' in self.schema:
|
||||
self.url = self.schema['url']
|
||||
|
||||
def __getattr__(self, name):
|
||||
self.ensure_schema_loaded()
|
||||
if name in self.schema:
|
||||
return self.schema[name]
|
||||
else:
|
||||
raise AttributeError
|
||||
|
||||
def __getitem__(self, name):
|
||||
self.ensure_schema_loaded()
|
||||
return self.schema[name]
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
self.ensure_schema_loaded()
|
||||
schema_type = type(self.schema)
|
||||
if schema_type == dict:
|
||||
subtitle = ', '.join(self.schema.keys())
|
||||
elif schema_type == list:
|
||||
subtitle = str(len(self.schema))
|
||||
else:
|
||||
subtitle = str(self.schema)
|
||||
|
||||
return '<Octokit %s(%s)>' % (self.name, subtitle)
|
||||
|
||||
# Returns the variables the URI takes
|
||||
def variables(self):
|
||||
return uritemplate.variables(self.url)
|
||||
|
||||
# Returns the links this resource can follow
|
||||
def keys(self):
|
||||
self.ensure_schema_loaded()
|
||||
return self.schema.keys()
|
||||
|
||||
# Check if the current resources' schema has been loaded, otherwise load it
|
||||
def ensure_schema_loaded(self):
|
||||
if self.schema:
|
||||
return
|
||||
|
||||
self.schema = self.get().schema
|
||||
|
||||
# Fetch the current request and return its schema
|
||||
def parse_schema(self, response):
|
||||
# If content of response is empty, then default to empty dictionary
|
||||
data = response.json() if response.text != "" else {}
|
||||
data_type = type(data)
|
||||
|
||||
if data_type == dict:
|
||||
schema = self.parse_schema_dict(data)
|
||||
elif data_type == list:
|
||||
schema = self.parse_schema_list(data, self.name)
|
||||
else:
|
||||
# TODO (eduardo) -- handle request that don't return anything
|
||||
raise Exception("Unknown type of response from the API.")
|
||||
|
||||
return schema
|
||||
|
||||
# Convert the JSON returned by the request into a dictionary of resources
|
||||
def parse_schema_dict(self, data):
|
||||
schema = {}
|
||||
for key in data:
|
||||
name = key.split('_url')[0]
|
||||
if key.endswith('_url'):
|
||||
if data[key]:
|
||||
schema[name] = Resource(self.session, url=data[key], name=humanize(name))
|
||||
def __getattr__(self, name):
|
||||
self.ensure_schema_loaded()
|
||||
if name in self.schema:
|
||||
return self.schema[name]
|
||||
else:
|
||||
schema[name] = data[key]
|
||||
else:
|
||||
data_type = type(data[key])
|
||||
raise AttributeError
|
||||
|
||||
def __getitem__(self, name):
|
||||
self.ensure_schema_loaded()
|
||||
return self.schema[name]
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
self.ensure_schema_loaded()
|
||||
schema_type = type(self.schema)
|
||||
if schema_type == dict:
|
||||
subtitle = ', '.join(self.schema.keys())
|
||||
elif schema_type == list:
|
||||
subtitle = str(len(self.schema))
|
||||
else:
|
||||
subtitle = str(self.schema)
|
||||
|
||||
return '<Octokit %s(%s)>' % (self.name, subtitle)
|
||||
|
||||
def variables(self):
|
||||
"""Returns the variables the URI takes"""
|
||||
return uritemplate.variables(self.url)
|
||||
|
||||
def keys(self):
|
||||
"""Returns the links this resource can follow"""
|
||||
self.ensure_schema_loaded()
|
||||
return self.schema.keys()
|
||||
|
||||
def ensure_schema_loaded(self):
|
||||
"""Check if resources' schema has been loaded, otherwise load it"""
|
||||
if self.schema:
|
||||
return
|
||||
elif self.variables():
|
||||
raise Exception("You need to call this resource with variables %s"
|
||||
% repr(list(variables)))
|
||||
|
||||
self.schema = self.get().schema
|
||||
|
||||
def parse_schema(self, response):
|
||||
"""Parse the response and return its schema"""
|
||||
data_type = type(response)
|
||||
|
||||
if data_type == dict:
|
||||
schema[name] = Resource(self.session, schema=data[key], name=humanize(name))
|
||||
schema = self.parse_schema_dict(response)
|
||||
elif data_type == list:
|
||||
schema[name] = self.parse_schema_list(data[key], name=name)
|
||||
schema = self.parse_schema_list(response, self.name)
|
||||
else:
|
||||
schema[name] = data[key]
|
||||
# TODO (eduardo) -- handle request that don't return anything
|
||||
raise Exception("Unknown type of response from the API.")
|
||||
|
||||
return schema
|
||||
return schema
|
||||
|
||||
# Convert the JSON returned by the request into a list of resources
|
||||
def parse_schema_list(self, data, name):
|
||||
return [
|
||||
Resource(self.session, schema=s, name=humanize(singularize(name)))
|
||||
for s in data
|
||||
]
|
||||
def parse_schema_dict(self, data):
|
||||
"""Convert the responses' JSON into a dictionary of resources"""
|
||||
schema = {}
|
||||
for key in data:
|
||||
name = key.split('_url')[0]
|
||||
if key.endswith('_url'):
|
||||
if data[key]:
|
||||
schema[name] = Resource(self.session, url=data[key],
|
||||
name=humanize(name))
|
||||
else:
|
||||
schema[name] = data[key]
|
||||
else:
|
||||
data_type = type(data[key])
|
||||
if data_type == dict:
|
||||
schema[name] = Resource(self.session, schema=data[key],
|
||||
name=humanize(name))
|
||||
elif data_type == list:
|
||||
schema[name] = self.parse_schema_list(data[key], name=name)
|
||||
else:
|
||||
schema[name] = data[key]
|
||||
|
||||
# Parse relation links from the headers
|
||||
def parse_rels(self, response):
|
||||
return {
|
||||
link['rel']: Resource(self.session, url=link['url'], name=self.name)
|
||||
for link in response.links.values()
|
||||
}
|
||||
return schema
|
||||
|
||||
# Makes an API request with the resource using HEAD.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def head(self, *args, **kwargs):
|
||||
return self.fetch_resource('HEAD', *args, **kwargs)
|
||||
def parse_schema_list(self, data, name):
|
||||
"""Convert the responses' JSON into a list of resources"""
|
||||
return [
|
||||
Resource(self.session, schema=s, name=humanize(singularize(name)))
|
||||
for s in data
|
||||
]
|
||||
|
||||
# Makes an API request with the curent resource using GET.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def get(self, *args, **kwargs):
|
||||
return self.fetch_resource('GET', *args, **kwargs)
|
||||
def parse_rels(self, response):
|
||||
"""Parse relation links from the headers"""
|
||||
return {
|
||||
link['rel']: Resource(self.session, url=link['url'], name=self.name)
|
||||
for link in response.links.values()
|
||||
}
|
||||
|
||||
# Makes an API request with the curent resource using POST.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def post(self, *args, **kwargs):
|
||||
return self.fetch_resource('POST', *args, **kwargs)
|
||||
def head(self, *args, **kwargs):
|
||||
"""Make a HTTP HEAD request to the endpoint of resource."""
|
||||
return self.fetch_resource('HEAD', *args, **kwargs)
|
||||
|
||||
# Makes an API request with the curent resource using PUT.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def put(self, *args, **kwargs):
|
||||
return self.fetch_resource('PUT', *args, **kwargs)
|
||||
def get(self, *args, **kwargs):
|
||||
"""Make a HTTP GET request to the endpoint of resource."""
|
||||
return self.fetch_resource('GET', *args, **kwargs)
|
||||
|
||||
# Makes an API request with the curent resource using PATCH.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def patch(self, *args, **kwargs):
|
||||
return self.fetch_resource('PATCH', *args, **kwargs)
|
||||
def post(self, *args, **kwargs):
|
||||
"""Make a HTTP POST request to the endpoint of resource."""
|
||||
return self.fetch_resource('POST', *args, **kwargs)
|
||||
|
||||
# Makes an API request with the curent resource using DELETE.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def delete(self, *args, **kwargs):
|
||||
return self.fetch_resource('DELETE', *args, **kwargs)
|
||||
def put(self, *args, **kwargs):
|
||||
"""Make a HTTP PUT request to the endpoint of resource."""
|
||||
return self.fetch_resource('PUT', *args, **kwargs)
|
||||
|
||||
# Makes an API request with the curent resource using OPTIONS.
|
||||
#
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def options(self, *args, **kwargs):
|
||||
return self.fetch_resource('OPTIONS', *args, **kwargs)
|
||||
def patch(self, *args, **kwargs):
|
||||
"""Make a HTTP PATCH request to the endpoint of resource."""
|
||||
return self.fetch_resource('PATCH', *args, **kwargs)
|
||||
|
||||
# Public: Makes an API request with the curent resource
|
||||
#
|
||||
# method - HTTP method.
|
||||
# *args - Uri template argument
|
||||
# **kwargs – Uri template arguments
|
||||
def fetch_resource(self, method, *args, **kwargs):
|
||||
variables = self.variables()
|
||||
if len(args) == 1 and len(variables) == 1:
|
||||
kwargs[next(iter(variables))] = args[0]
|
||||
def delete(self, *args, **kwargs):
|
||||
"""Make a HTTP DELETE request to the endpoint of resource."""
|
||||
return self.fetch_resource('DELETE', *args, **kwargs)
|
||||
|
||||
url_args = {k: kwargs[k] for k in kwargs if k in variables}
|
||||
req_args = {k: kwargs[k] for k in kwargs if k not in variables}
|
||||
def options(self, *args, **kwargs):
|
||||
"""Make a HTTP OPTIONS request to the endpoint of resource."""
|
||||
return self.fetch_resource('OPTIONS', *args, **kwargs)
|
||||
|
||||
url = uritemplate.expand(self.url, url_args)
|
||||
request = requests.Request(method, url, **req_args)
|
||||
prepared_req = self.session.prepare_request(request)
|
||||
response = self.session.send(prepared_req)
|
||||
def fetch_resource(self, method, *args, **kwargs):
|
||||
"""Fetch the endpoint from the API and return it as a Resource.
|
||||
|
||||
return Resource(self.session, response=response, name=humanize(self.name))
|
||||
method - HTTP method.
|
||||
*args - Uri template argument
|
||||
**kwargs – Uri template arguments
|
||||
"""
|
||||
variables = self.variables()
|
||||
if len(args) == 1 and len(variables) == 1:
|
||||
kwargs[next(iter(variables))] = args[0]
|
||||
|
||||
url_args = {k: kwargs[k] for k in kwargs if k in variables}
|
||||
req_args = {k: kwargs[k] for k in kwargs if k not in variables}
|
||||
|
||||
url = uritemplate.expand(self.url, url_args)
|
||||
request = requests.Request(method, url, **req_args)
|
||||
prepared_req = self.session.prepare_request(request)
|
||||
response = self.session.send(prepared_req)
|
||||
|
||||
return Resource(self.session, response=response,
|
||||
name=humanize(self.name))
|
||||
|
|
13
script/test
13
script/test
|
@ -6,11 +6,14 @@ echo "===> Bootstrapping..."
|
|||
script/bootstrap --quiet
|
||||
|
||||
echo "===> Setting test environment variables..."
|
||||
export OCTOKIT_TEST_GITHUB_LOGIN="api-padawan"
|
||||
export OCTOKIT_TEST_GITHUB_PASSWORD="MYSOCRATESNOTE"
|
||||
export OCTOKIT_TEST_GITHUB_TOKEN="6a21f190e3422bf89afa8b360d923b0c30e8fbfa"
|
||||
export OCTOKIT_TEST_GITHUB_CLIENT_ID='abcdefabcdefabcdefab'
|
||||
export OCTOKIT_TEST_GITHUB_CLIENT_SECRET='abcdefabcdefabcdefababcdefabcdefabcdefab'
|
||||
for testvar in LOGIN PASSWORD TOKEN CLIENT_ID CLIENT_SECRET
|
||||
do
|
||||
octokitvar="OCTOKIT_TEST_GITHUB_${testvar}"
|
||||
if [[ -z "${!octokitvar}" ]]; then
|
||||
echo "Please export ${octokitvar}";
|
||||
fi
|
||||
done
|
||||
|
||||
export OCTOKIT_SILENT=true
|
||||
|
||||
echo "===> Running tests..."
|
||||
|
|
|
@ -3,6 +3,7 @@ import unittest
|
|||
import octokit
|
||||
from .util import MockOctokitTestCase
|
||||
|
||||
|
||||
class TestApi(MockOctokitTestCase):
|
||||
def test_current_user(self):
|
||||
login = self.client.current_user.login
|
||||
|
|
|
@ -4,6 +4,7 @@ import requests_mock
|
|||
|
||||
import octokit
|
||||
|
||||
|
||||
class TestExceptions(unittest.TestCase):
|
||||
"""Tests the exception handling code in octokit/exceptions.py"""
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import uritemplate
|
|||
|
||||
import octokit
|
||||
|
||||
|
||||
class TestPagination(unittest.TestCase):
|
||||
"""Tests the functionality in octokit/pagination.py"""
|
||||
|
||||
|
@ -15,39 +16,39 @@ class TestPagination(unittest.TestCase):
|
|||
self.client.session.mount('mock', self.adapter)
|
||||
|
||||
def test_pagination(self):
|
||||
self.client.auto_paginate = True
|
||||
url = uritemplate.expand(self.client.url, {'param':'foo'})
|
||||
self.client.auto_paginate = True
|
||||
url = uritemplate.expand(self.client.url, {'param': 'foo'})
|
||||
|
||||
headers1 = {
|
||||
'Link': '<'+url+'?page=2&per_page=100>; rel="next"',
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
headers2 = {
|
||||
'Link': '<'+url+'?page=3&per_page=100>; rel="next"',
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
headers3 = {
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
data1 = '["a","b"]'
|
||||
data2 = '["c","d"]'
|
||||
data3 = '["e","f"]'
|
||||
h1 = {
|
||||
'Link': '<'+url+'?page=2&per_page=100>; rel="next"',
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
h2 = {
|
||||
'Link': '<'+url+'?page=3&per_page=100>; rel="next"',
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
h3 = {
|
||||
'X-RateLimit-Remaining': '56',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
res1 = '["a","b"]'
|
||||
res2 = '["c","d"]'
|
||||
res3 = '["e","f"]'
|
||||
|
||||
self.adapter.register_uri('GET', url, headers=headers1, text=data1)
|
||||
self.adapter.register_uri('GET', url+'?page=2', headers=headers2, text=data2)
|
||||
self.adapter.register_uri('GET', url+'?page=3', headers=headers3, text=data3)
|
||||
self.adapter.register_uri('GET', url, headers=h1, text=res1)
|
||||
self.adapter.register_uri('GET', url+'?page=2', headers=h2, text=res2)
|
||||
self.adapter.register_uri('GET', url+'?page=3', headers=h3, text=res3)
|
||||
|
||||
response = self.client.paginate(self.client.url, param='foo')
|
||||
resultSchema = [r.schema for r in response.schema]
|
||||
expectedSchema = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
response = self.client.paginate(param='foo')
|
||||
resultSchema = [r.schema for r in response.schema]
|
||||
expectedSchema = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
|
||||
self.assertEqual(resultSchema, expectedSchema)
|
||||
self.assertEqual(resultSchema, expectedSchema)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -6,6 +6,7 @@ import uritemplate
|
|||
|
||||
import octokit
|
||||
|
||||
|
||||
class TestRateLimit(unittest.TestCase):
|
||||
"""Tests the functionality in octokit/ratelimit.py"""
|
||||
|
||||
|
@ -15,39 +16,39 @@ class TestRateLimit(unittest.TestCase):
|
|||
self.client.session.mount('mock', self.adapter)
|
||||
|
||||
def test_rate_limit(self):
|
||||
self.client.auto_paginate = True
|
||||
url = uritemplate.expand(self.client.url, {'param':'foo'})
|
||||
self.client.auto_paginate = True
|
||||
url = uritemplate.expand(self.client.url, {'param': 'foo'})
|
||||
|
||||
headers1 = {
|
||||
'Link': '<'+url+'?page=2>; rel="next"',
|
||||
'X-RateLimit-Remaining': '1',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
headers2 = {
|
||||
'Link': '<'+url+'?page=3>; rel="next"',
|
||||
'X-RateLimit-Remaining': '0',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
headers3 = {
|
||||
'X-RateLimit-Remaining': '0',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
data1 = '["a","b"]'
|
||||
data2 = '["c","d"]'
|
||||
data3 = '["e","f"]'
|
||||
h1 = {
|
||||
'Link': '<'+url+'?page=2>; rel="next"',
|
||||
'X-RateLimit-Remaining': '1',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
h2 = {
|
||||
'Link': '<'+url+'?page=3>; rel="next"',
|
||||
'X-RateLimit-Remaining': '0',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
h3 = {
|
||||
'X-RateLimit-Remaining': '0',
|
||||
'X-RateLimit-Reset': '1446804464',
|
||||
'X-RateLimit-Limit': '60'
|
||||
}
|
||||
res1 = '["a","b"]'
|
||||
res2 = '["c","d"]'
|
||||
res3 = '["e","f"]'
|
||||
|
||||
self.adapter.register_uri('GET', url, headers=headers1, text=data1)
|
||||
self.adapter.register_uri('GET', url+'?page=2', headers=headers2, text=data2)
|
||||
self.adapter.register_uri('GET', url+'?page=3', headers=headers3, text=data3)
|
||||
self.adapter.register_uri('GET', url, headers=h1, text=res1)
|
||||
self.adapter.register_uri('GET', url+'?page=2', headers=h2, text=res2)
|
||||
self.adapter.register_uri('GET', url+'?page=3', headers=h3, text=res3)
|
||||
|
||||
response = self.client.paginate(url=self.client.url, param='foo')
|
||||
resultSchema = [r.schema for r in response.schema]
|
||||
expectedSchema = ['a', 'b', 'c', 'd']
|
||||
response = self.client.paginate(param='foo')
|
||||
resultSchema = [r.schema for r in response.schema]
|
||||
expectedSchema = ['a', 'b', 'c', 'd']
|
||||
|
||||
self.assertEqual(resultSchema, expectedSchema)
|
||||
self.assertEqual(resultSchema, expectedSchema)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -6,6 +6,7 @@ import uritemplate
|
|||
|
||||
import octokit
|
||||
|
||||
|
||||
class TestResources(unittest.TestCase):
|
||||
"""Tests the functionality in octokit/resources.py"""
|
||||
|
||||
|
@ -27,7 +28,7 @@ class TestResources(unittest.TestCase):
|
|||
assert response.success
|
||||
|
||||
def test_httpverb(self):
|
||||
"""Test that each HTTP verb functions properly when JSON is returned."""
|
||||
"""Test that each HTTP verb works properly when JSON is returned."""
|
||||
verbs_to_methods = [
|
||||
('GET', self.client.get),
|
||||
('POST', self.client.post),
|
||||
|
|
|
@ -7,6 +7,7 @@ from betamax.fixtures import unittest
|
|||
|
||||
import octokit
|
||||
|
||||
|
||||
class MockOctokitTestCase(unittest.BetamaxTestCase):
|
||||
"""unittest test case that wraps and configures betamax for tests that
|
||||
require mocking HTTP requests in octokit.py
|
||||
|
|
Загрузка…
Ссылка в новой задаче