diff --git a/github/AuthenticatedUser.py b/github/AuthenticatedUser.py index e6247558..5de2d804 100644 --- a/github/AuthenticatedUser.py +++ b/github/AuthenticatedUser.py @@ -159,7 +159,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters = emails headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/user/emails", + "/user/emails", None, post_parameters ) @@ -168,7 +168,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( following, NamedUser.NamedUser ), following headers, data = self._requester.requestAndCheck( "PUT", - "https://api.github.com/user/following/" + following._identity, + "/user/following/" + following._identity, None, None ) @@ -177,7 +177,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( watched, Repository.Repository ), watched headers, data = self._requester.requestAndCheck( "PUT", - "https://api.github.com/user/watched/" + watched._identity, + "/user/watched/" + watched._identity, None, None ) @@ -195,7 +195,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters[ "note_url" ] = note_url headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/authorizations", + "/authorizations", None, post_parameters ) @@ -205,7 +205,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( repo, Repository.Repository ), repo headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/repos/" + repo.owner.login + "/" + repo.name + "/forks", + "/repos/" + repo.owner.login + "/" + repo.name + "/forks", None, None ) @@ -223,7 +223,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters[ "description" ] = description headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/gists", + "/gists", None, post_parameters ) @@ -238,7 +238,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): } headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/user/keys", + "/user/keys", None, post_parameters ) @@ -269,7 +269,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters[ "has_downloads" ] = has_downloads headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/user/repos", + "/user/repos", None, post_parameters ) @@ -300,7 +300,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters[ "bio" ] = bio headers, data = self._requester.requestAndCheck( "PATCH", - "https://api.github.com/user", + "/user", None, post_parameters ) @@ -310,7 +310,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( id, int ), id headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/authorizations/" + str( id ), + "/authorizations/" + str( id ), None, None ) @@ -319,7 +319,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_authorizations( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/authorizations", + "/authorizations", None, None ) @@ -333,7 +333,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_emails( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/emails", + "/user/emails", None, None ) @@ -342,7 +342,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_events( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/events", + "/events", None, None ) @@ -356,7 +356,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_followers( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/followers", + "/user/followers", None, None ) @@ -370,7 +370,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_following( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/following", + "/user/following", None, None ) @@ -384,7 +384,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_gists( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/gists", + "/gists", None, None ) @@ -398,7 +398,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_issues( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/issues", + "/issues", None, None ) @@ -413,7 +413,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( id, int ), id headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/keys/" + str( id ), + "/user/keys/" + str( id ), None, None ) @@ -422,7 +422,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_keys( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/keys", + "/user/keys", None, None ) @@ -437,7 +437,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( org, Organization.Organization ), org headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/users/" + self.login + "/events/orgs/" + org.login, + "/users/" + self.login + "/events/orgs/" + org.login, None, None ) @@ -451,7 +451,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_orgs( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/orgs", + "/user/orgs", None, None ) @@ -466,7 +466,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( name, ( str, unicode ) ), name headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/repos/" + self.login + "/" + name, + "/repos/" + self.login + "/" + name, None, None ) @@ -485,7 +485,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): url_parameters[ "direction" ] = direction headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/repos", + "/user/repos", url_parameters, None ) @@ -499,7 +499,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_starred_gists( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/gists/starred", + "/gists/starred", None, None ) @@ -513,7 +513,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): def get_watched( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/user/watched", + "/user/watched", None, None ) @@ -528,7 +528,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( following, NamedUser.NamedUser ), following status, headers, data = self._requester.requestRaw( "GET", - "https://api.github.com/user/following/" + following._identity, + "/user/following/" + following._identity, None, None ) @@ -538,7 +538,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( watched, Repository.Repository ), watched status, headers, data = self._requester.requestRaw( "GET", - "https://api.github.com/user/watched/" + watched._identity, + "/user/watched/" + watched._identity, None, None ) @@ -549,7 +549,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): post_parameters = emails headers, data = self._requester.requestAndCheck( "DELETE", - "https://api.github.com/user/emails", + "/user/emails", None, post_parameters ) @@ -558,7 +558,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( following, NamedUser.NamedUser ), following headers, data = self._requester.requestAndCheck( "DELETE", - "https://api.github.com/user/following/" + following._identity, + "/user/following/" + following._identity, None, None ) @@ -567,7 +567,7 @@ class AuthenticatedUser( GithubObject.GithubObject ): assert isinstance( watched, Repository.Repository ), watched headers, data = self._requester.requestAndCheck( "DELETE", - "https://api.github.com/user/watched/" + watched._identity, + "/user/watched/" + watched._identity, None, None ) diff --git a/github/Gist.py b/github/Gist.py index 03c7b268..2a950291 100644 --- a/github/Gist.py +++ b/github/Gist.py @@ -150,7 +150,7 @@ class Gist( GithubObject.GithubObject ): assert isinstance( id, int ), id headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/gists/comments/" + str( id ), + "/gists/comments/" + str( id ), None, None ) diff --git a/github/Github.py b/github/Github.py index 53480ac1..360ae0eb 100644 --- a/github/Github.py +++ b/github/Github.py @@ -23,9 +23,11 @@ import Repository import Legacy import GithubObject +DEFAULT_BASE_URL = "https://api.github.com" + class Github( object ): - def __init__( self, login_or_token = None, password = None ): - self.__requester = Requester( login_or_token, password ) + def __init__( self, login_or_token = None, password = None, base_url = DEFAULT_BASE_URL ): + self.__requester = Requester( login_or_token, password, base_url ) @property def rate_limiting( self ): @@ -34,11 +36,11 @@ class Github( object ): def get_user( self, login = GithubObject.NotSet ): assert login is GithubObject.NotSet or isinstance( login, ( str, unicode ) ), login if login is GithubObject.NotSet: - return AuthenticatedUser.AuthenticatedUser( self.__requester, { "url": "https://api.github.com/user" }, completed = False ) + return AuthenticatedUser.AuthenticatedUser( self.__requester, { "url": "/user" }, completed = False ) else: headers, data = self.__requester.requestAndCheck( "GET", - "https://api.github.com/users/" + login, + "/users/" + login, None, None ) @@ -48,7 +50,7 @@ class Github( object ): assert isinstance( login, ( str, unicode ) ), login headers, data = self.__requester.requestAndCheck( "GET", - "https://api.github.com/orgs/" + login, + "/orgs/" + login, None, None ) @@ -58,14 +60,14 @@ class Github( object ): assert isinstance( id, ( str, unicode ) ), id headers, data = self.__requester.requestAndCheck( "GET", - "https://api.github.com/gists/" + id, + "/gists/" + id, None, None ) return Gist.Gist( self.__requester, data, completed = True ) def get_gists( self ): - headers, data = self.__requester.requestAndCheck( "GET", "https://api.github.com/gists/public", None, None ) + headers, data = self.__requester.requestAndCheck( "GET", "/gists/public", None, None ) return PaginatedList.PaginatedList( Gist.Gist, self.__requester, @@ -78,7 +80,7 @@ class Github( object ): assert language is GithubObject.NotSet or isinstance( language, ( str, unicode ) ), language args = {} if language is GithubObject.NotSet else { "language": language } return Legacy.PaginatedList( - "https://api.github.com/legacy/repos/search/" + urllib.quote( keyword ), + "/legacy/repos/search/" + urllib.quote( keyword ), args, self.__requester, "repositories", @@ -89,7 +91,7 @@ class Github( object ): def legacy_search_users( self, keyword ): assert isinstance( keyword, ( str, unicode ) ), keyword return Legacy.PaginatedList( - "https://api.github.com/legacy/user/search/" + urllib.quote( keyword ), + "/legacy/user/search/" + urllib.quote( keyword ), {}, self.__requester, "users", @@ -101,7 +103,7 @@ class Github( object ): assert isinstance( email, ( str, unicode ) ), email headers, data = self.__requester.requestAndCheck( "GET", - "https://api.github.com/legacy/user/email/" + email, + "/legacy/user/email/" + email, None, None ) @@ -118,7 +120,7 @@ class Github( object ): post_parameters[ "context" ] = context._identity status, headers, data = self.__requester.requestRaw( "POST", - "https://api.github.com/markdown", + "/markdown", None, post_parameters ) diff --git a/github/Legacy.py b/github/Legacy.py index 4c175d50..52b33e74 100644 --- a/github/Legacy.py +++ b/github/Legacy.py @@ -49,7 +49,7 @@ def convertUser( attributes ): login = attributes[ "login" ] return { "login": login, - "url": "https://api.github.com/users/" + login, + "url": "/users/" + login, } def convertRepo( attributes ): @@ -58,7 +58,7 @@ def convertRepo( attributes ): return { "owner": { "login": owner }, "name": name, - "url": "https://api.github.com/repos/" + owner + "/" + name, + "url": "/repos/" + owner + "/" + name, } def convertIssue( attributes ): @@ -66,7 +66,7 @@ def convertIssue( attributes ): title = attributes[ "title" ] html_url = attributes[ "html_url" ] assert html_url.startswith( "https://github.com/" ) - url = html_url.replace( "https://github.com/", "https://api.github.com/repos/" ) + url = html_url.replace( "https://github.com/", "/repos/" ) return { "title": title, "number": number, diff --git a/github/NamedUser.py b/github/NamedUser.py index f6f806ca..02e415a1 100644 --- a/github/NamedUser.py +++ b/github/NamedUser.py @@ -290,7 +290,7 @@ class NamedUser( GithubObject.GithubObject ): assert isinstance( name, ( str, unicode ) ), name headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/repos/" + self.login + "/" + name, + "/repos/" + self.login + "/" + name, None, None ) diff --git a/github/Organization.py b/github/Organization.py index 2ca1af19..3f52eb69 100644 --- a/github/Organization.py +++ b/github/Organization.py @@ -160,7 +160,7 @@ class Organization( GithubObject.GithubObject ): } headers, data = self._requester.requestAndCheck( "POST", - "https://api.github.com/repos/" + repo.owner.login + "/" + repo.name + "/forks", + "/repos/" + repo.owner.login + "/" + repo.name + "/forks", url_parameters, None ) @@ -293,7 +293,7 @@ class Organization( GithubObject.GithubObject ): assert isinstance( name, ( str, unicode ) ), name headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/repos/" + self.login + "/" + name, + "/repos/" + self.login + "/" + name, None, None ) @@ -321,7 +321,7 @@ class Organization( GithubObject.GithubObject ): assert isinstance( id, int ), id headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/teams/" + str( id ), + "/teams/" + str( id ), None, None ) diff --git a/github/Repository.py b/github/Repository.py index f39f2c6a..1779d31d 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -903,7 +903,7 @@ class Repository( GithubObject.GithubObject ): def get_network_events( self ): headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/networks/" + self.owner.login + "/" + self.name + "/events", + "/networks/" + self.owner.login + "/" + self.name + "/events", None, None ) @@ -1008,7 +1008,7 @@ class Repository( GithubObject.GithubObject ): assert isinstance( keyword, ( str, unicode ) ), keyword headers, data = self._requester.requestAndCheck( "GET", - "https://api.github.com/legacy/issues/search/" + self.owner.login + "/" + self.name + "/" + state + "/" + urllib.quote( keyword ), + "/legacy/issues/search/" + self.owner.login + "/" + self.name + "/" + state + "/" + urllib.quote( keyword ), {}, None ) diff --git a/github/Requester.py b/github/Requester.py index d6aa41ff..e83ab346 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -14,6 +14,7 @@ import httplib import base64 import urllib +import urlparse try: import json @@ -23,7 +24,7 @@ except ImportError: #pragma no cover: only for Python 2.5 import GithubException class Requester: - def __init__( self, login_or_token, password ): + def __init__( self, login_or_token, password, base_url ): if password is not None: login = login_or_token self.__authorizationHeader = "Basic " + base64.b64encode( login + ":" + password ).replace( '\n', '' ) @@ -32,6 +33,19 @@ class Requester: 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 + if o.scheme == "https": + self.__connection_class = httplib.HTTPSConnection + elif o.scheme == "http": + self.__connection_class = httplib.HTTPConnection + else: + assert( False ) + self.rate_limiting = ( 5000, 5000 ) def requestAndCheck( self, verb, url, parameters, input ): @@ -43,14 +57,21 @@ class Requester: def requestRaw( self, verb, url, parameters, input ): assert verb in [ "HEAD", "GET", "POST", "PATCH", "PUT", "DELETE" ] - assert url.startswith( "https://api.github.com" ) - url = url[ len( "https://api.github.com" ) : ] - + + #URLs generated locally will be relative to __base_url + #URLs returned from the server will start with __base_url + if url.startswith( self.__base_url ): + url = url[ len(self.__base_url): ] + elif url.startswith( "/" ): + url = url + else: + assert( False ) + headers = dict() if self.__authorizationHeader is not None: headers[ "Authorization" ] = self.__authorizationHeader - cnx = httplib.HTTPSConnection( "api.github.com", strict = True ) + cnx = self.__connection_class( host = self.__hostname, port = self.__port, strict = True ) cnx.request( verb, self.__completeUrl( url, parameters ), @@ -73,9 +94,9 @@ class Requester: def __completeUrl( self, url, parameters ): if parameters is None or len( parameters ) == 0: - return url + return self.__prefix + url else: - return url + "?" + urllib.urlencode( parameters ) + return self.__prefix + url + "?" + urllib.urlencode( parameters ) def __structuredFromJson( self, data ): if len( data ) == 0: