Mercurial > repos > bcclaywell > argo_navis
diff venv/lib/python2.7/site-packages/github/Requester.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/venv/lib/python2.7/site-packages/github/Requester.py Mon Oct 12 17:43:33 2015 -0400 @@ -0,0 +1,332 @@ +# -*- coding: utf-8 -*- + +# ########################## Copyrights and license ############################ +# # +# Copyright 2012 Andrew Bettison <andrewb@zip.com.au> # +# Copyright 2012 Dima Kukushkin <dima@kukushkin.me> # +# Copyright 2012 Michael Woodworth <mwoodworth@upverter.com> # +# Copyright 2012 Petteri Muilu <pmuilu@xena.(none)> # +# Copyright 2012 Steve English <steve.english@navetas.com> # +# Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> # +# Copyright 2012 Zearin <zearin@gonk.net> # +# Copyright 2013 AKFish <akfish@gmail.com> # +# Copyright 2013 Ed Jackson <ed.jackson@gmail.com> # +# Copyright 2013 Jonathan J Hunt <hunt@braincorporation.com> # +# Copyright 2013 Mark Roddy <markroddy@gmail.com> # +# Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # +# # +# This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ # +# # +# PyGithub is free software: you can redistribute it and/or modify it under # +# the terms of the GNU Lesser General Public License as published by the Free # +# Software Foundation, either version 3 of the License, or (at your option) # +# any later version. # +# # +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # +# details. # +# # +# You should have received a copy of the GNU Lesser General Public License # +# along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # +# # +# ############################################################################## + +import logging +import httplib +import base64 +import urllib +import urlparse +import sys +import Consts +import re + +atLeastPython26 = sys.hexversion >= 0x02060000 +atLeastPython3 = sys.hexversion >= 0x03000000 + +if atLeastPython26: + import json +else: # pragma no cover (Covered by all tests with Python 2.5) + import simplejson as json # pragma no cover (Covered by all tests with Python 2.5) + +import GithubException + + +class Requester: + __httpConnectionClass = httplib.HTTPConnection + __httpsConnectionClass = httplib.HTTPSConnection + + @classmethod + def injectConnectionClasses(cls, httpConnectionClass, httpsConnectionClass): + cls.__httpConnectionClass = httpConnectionClass + cls.__httpsConnectionClass = httpsConnectionClass + + @classmethod + def resetConnectionClasses(cls): + cls.__httpConnectionClass = httplib.HTTPConnection + cls.__httpsConnectionClass = httplib.HTTPSConnection + + ############################################################# + # For Debug + @classmethod + def setDebugFlag(cls, flag): + cls.DEBUG_FLAG = flag + + @classmethod + def setOnCheckMe(cls, onCheckMe): + cls.ON_CHECK_ME = onCheckMe + + DEBUG_FLAG = False + + DEBUG_FRAME_BUFFER_SIZE = 1024 + + DEBUG_HEADER_KEY = "DEBUG_FRAME" + + ON_CHECK_ME = None + + def NEW_DEBUG_FRAME(self, requestHeader): + ''' + Initialize a debug frame with requestHeader + Frame count is updated and will be attached to respond header + The structure of a frame: [requestHeader, statusCode, responseHeader, raw_data] + Some of them may be None + ''' + if self.DEBUG_FLAG: # pragma no branch (Flag always set in tests) + new_frame = [requestHeader, None, None, None] + if self._frameCount < self.DEBUG_FRAME_BUFFER_SIZE - 1: # pragma no branch (Should be covered) + self._frameBuffer.append(new_frame) + else: + self._frameBuffer[0] = new_frame # pragma no cover (Should be covered) + + self._frameCount = len(self._frameBuffer) - 1 + + def DEBUG_ON_RESPONSE(self, statusCode, responseHeader, data): + ''' + Update current frame with response + Current frame index will be attached to responseHeader + ''' + if self.DEBUG_FLAG: # pragma no branch (Flag always set in tests) + self._frameBuffer[self._frameCount][1:4] = [statusCode, responseHeader, data] + responseHeader[self.DEBUG_HEADER_KEY] = self._frameCount + + def check_me(self, obj): + if self.DEBUG_FLAG and self.ON_CHECK_ME is not None: # pragma no branch (Flag always set in tests) + frame = None + if self.DEBUG_HEADER_KEY in obj._headers: + frame_index = obj._headers[self.DEBUG_HEADER_KEY] + frame = self._frameBuffer[frame_index] + self.ON_CHECK_ME(obj, frame) + + def _initializeDebugFeature(self): + self._frameCount = 0 + self._frameBuffer = [] + + ############################################################# + + def __init__(self, login_or_token, password, base_url, timeout, client_id, client_secret, user_agent, per_page): + self._initializeDebugFeature() + + if password is not None: + login = login_or_token + if atLeastPython3: + self.__authorizationHeader = "Basic " + base64.b64encode((login + ":" + password).encode("utf-8")).decode("utf-8").replace('\n', '') # pragma no cover (Covered by Authentication.testAuthorizationHeaderWithXxx with Python 3) + else: + self.__authorizationHeader = "Basic " + base64.b64encode(login + ":" + password).replace('\n', '') + elif login_or_token is not None: + token = login_or_token + self.__authorizationHeader = "token " + token + else: + self.__authorizationHeader = None + + self.__base_url = base_url + o = urlparse.urlparse(base_url) + self.__hostname = o.hostname + self.__port = o.port + self.__prefix = o.path + self.__timeout = timeout + self.__scheme = o.scheme + if o.scheme == "https": + self.__connectionClass = self.__httpsConnectionClass + elif o.scheme == "http": + self.__connectionClass = self.__httpConnectionClass + else: + assert False, "Unknown URL scheme" + self.rate_limiting = (-1, -1) + self.rate_limiting_resettime = 0 + self.FIX_REPO_GET_GIT_REF = True + self.per_page = per_page + + self.oauth_scopes = None + + self.__clientId = client_id + self.__clientSecret = client_secret + + assert user_agent is not None, 'github now requires a user-agent. ' \ + 'See http://developer.github.com/v3/#user-agent-required' + self.__userAgent = user_agent + + def requestJsonAndCheck(self, verb, url, parameters=None, headers=None, input=None, cnx=None): + return self.__check(*self.requestJson(verb, url, parameters, headers, input, cnx)) + + def requestMultipartAndCheck(self, verb, url, parameters=None, headers=None, input=None): + return self.__check(*self.requestMultipart(verb, url, parameters, headers, input)) + + def __check(self, status, responseHeaders, output): + output = self.__structuredFromJson(output) + if status >= 400: + raise self.__createException(status, responseHeaders, output) + return responseHeaders, output + + def __createException(self, status, headers, output): + if status == 401 and output.get("message") == "Bad credentials": + cls = GithubException.BadCredentialsException + elif status == 401 and 'x-github-otp' in headers and re.match(r'.*required.*', headers['x-github-otp']): + cls = GithubException.TwoFactorException # pragma no cover (Should be covered) + elif status == 403 and output.get("message").startswith("Missing or invalid User Agent string"): + cls = GithubException.BadUserAgentException + elif status == 403 and output.get("message").startswith("API Rate Limit Exceeded"): + cls = GithubException.RateLimitExceededException + elif status == 404 and output.get("message") == "Not Found": + cls = GithubException.UnknownObjectException + else: + cls = GithubException.GithubException + return cls(status, output) + + def __structuredFromJson(self, data): + if len(data) == 0: + return None + else: + if atLeastPython3 and isinstance(data, bytes): # pragma no branch (Covered by Issue142.testDecodeJson with Python 3) + data = data.decode("utf-8") # pragma no cover (Covered by Issue142.testDecodeJson with Python 3) + try: + return json.loads(data) + except ValueError, e: + return {'data': data} + + def requestJson(self, verb, url, parameters=None, headers=None, input=None, cnx=None): + def encode(input): + return "application/json", json.dumps(input) + + return self.__requestEncode(cnx, verb, url, parameters, headers, input, encode) + + def requestMultipart(self, verb, url, parameters=None, headers=None, input=None): + def encode(input): + boundary = "----------------------------3c3ba8b523b2" + eol = "\r\n" + + encoded_input = "" + for name, value in input.iteritems(): + encoded_input += "--" + boundary + eol + encoded_input += "Content-Disposition: form-data; name=\"" + name + "\"" + eol + encoded_input += eol + encoded_input += value + eol + encoded_input += "--" + boundary + "--" + eol + return "multipart/form-data; boundary=" + boundary, encoded_input + + return self.__requestEncode(None, verb, url, parameters, headers, input, encode) + + def __requestEncode(self, cnx, verb, url, parameters, requestHeaders, input, encode): + assert verb in ["HEAD", "GET", "POST", "PATCH", "PUT", "DELETE"] + if parameters is None: + parameters = dict() + if requestHeaders is None: + requestHeaders = dict() + + self.__authenticate(url, requestHeaders, parameters) + requestHeaders["User-Agent"] = self.__userAgent + + url = self.__makeAbsoluteUrl(url) + url = self.__addParametersToUrl(url, parameters) + + encoded_input = "null" + if input is not None: + requestHeaders["Content-Type"], encoded_input = encode(input) + + self.NEW_DEBUG_FRAME(requestHeaders) + + status, responseHeaders, output = self.__requestRaw(cnx, verb, url, requestHeaders, encoded_input) + + if "x-ratelimit-remaining" in responseHeaders and "x-ratelimit-limit" in responseHeaders: + self.rate_limiting = (int(responseHeaders["x-ratelimit-remaining"]), int(responseHeaders["x-ratelimit-limit"])) + if "x-ratelimit-reset" in responseHeaders: + self.rate_limiting_resettime = int(responseHeaders["x-ratelimit-reset"]) + + if "x-oauth-scopes" in responseHeaders: + self.oauth_scopes = responseHeaders["x-oauth-scopes"].split(", ") + + self.DEBUG_ON_RESPONSE(status, responseHeaders, output) + + return status, responseHeaders, output + + def __requestRaw(self, cnx, verb, url, requestHeaders, input): + if cnx is None: + cnx = self.__createConnection() + else: + assert cnx == "status" + cnx = self.__httpsConnectionClass("status.github.com", 443) + cnx.request( + verb, + url, + input, + requestHeaders + ) + response = cnx.getresponse() + + status = response.status + responseHeaders = dict((k.lower(), v) for k, v in response.getheaders()) + output = response.read() + + cnx.close() + + self.__log(verb, url, requestHeaders, input, status, responseHeaders, output) + + return status, responseHeaders, output + + def __authenticate(self, url, requestHeaders, parameters): + if self.__clientId and self.__clientSecret and "client_id=" not in url: + parameters["client_id"] = self.__clientId + parameters["client_secret"] = self.__clientSecret + if self.__authorizationHeader is not None: + requestHeaders["Authorization"] = self.__authorizationHeader + + def __makeAbsoluteUrl(self, url): + # URLs generated locally will be relative to __base_url + # URLs returned from the server will start with __base_url + if url.startswith("/"): + url = self.__prefix + url + else: + o = urlparse.urlparse(url) + assert o.scheme == self.__scheme or o.scheme == "https" and self.__scheme == "http" # Issue #80 + assert o.hostname == self.__hostname + assert o.path.startswith(self.__prefix) + assert o.port == self.__port + url = o.path + if o.query != "": + url += "?" + o.query + return url + + def __addParametersToUrl(self, url, parameters): + if len(parameters) == 0: + return url + else: + return url + "?" + urllib.urlencode(parameters) + + def __createConnection(self): + kwds = {} + if not atLeastPython3: # pragma no branch (Branch useful only with Python 3) + kwds["strict"] = True # Useless in Python3, would generate a deprecation warning + if atLeastPython26: # pragma no branch (Branch useful only with Python 2.5) + kwds["timeout"] = self.__timeout # Did not exist before Python2.6 + return self.__connectionClass(self.__hostname, self.__port, **kwds) + + def __log(self, verb, url, requestHeaders, input, status, responseHeaders, output): + logger = logging.getLogger(__name__) + if logger.isEnabledFor(logging.DEBUG): + if "Authorization" in requestHeaders: + if requestHeaders["Authorization"].startswith("Basic"): + requestHeaders["Authorization"] = "Basic (login and password removed)" + elif requestHeaders["Authorization"].startswith("token"): + requestHeaders["Authorization"] = "token (oauth token removed)" + else: # pragma no cover (Cannot happen, but could if we add an authentication method => be prepared) + requestHeaders["Authorization"] = "(unknown auth removed)" # pragma no cover (Cannot happen, but could if we add an authentication method => be prepared) + logger.debug("%s %s://%s%s %s %s ==> %i %s %s", str(verb), self.__scheme, self.__hostname, str(url), str(requestHeaders), str(input), status, str(responseHeaders), str(output))