diff --git a/github/AuthenticatedUser.py b/github/AuthenticatedUser.py index 2f0b07a5..adb94d39 100644 --- a/github/AuthenticatedUser.py +++ b/github/AuthenticatedUser.py @@ -55,6 +55,8 @@ import github.Event import github.Authorization import github.Notification +import Consts + class AuthenticatedUser(github.GithubObject.CompletableGithubObject): """ @@ -446,7 +448,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): if client_secret is not github.GithubObject.NotSet: post_parameters["client_secret"] = client_secret if onetime_password is not None: - request_header = {'X-GitHub-OTP': onetime_password} # pragma no cover (Should be covered) + request_header = {Consts.headerOTP: onetime_password} # pragma no cover (Should be covered) else: request_header = None headers, data = self._requester.requestJsonAndCheck( diff --git a/github/CommitComment.py b/github/CommitComment.py index 99ab9d5c..d5224a11 100644 --- a/github/CommitComment.py +++ b/github/CommitComment.py @@ -33,9 +33,10 @@ ################################################################################ import github.GithubObject - import github.NamedUser +import Consts + class CommitComment(github.GithubObject.CompletableGithubObject): """ @@ -171,7 +172,7 @@ class CommitComment(github.GithubObject.CompletableGithubObject): self._requester, self.url + "/reactions", None, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) def create_reaction(self, reaction_type): @@ -192,7 +193,7 @@ class CommitComment(github.GithubObject.CompletableGithubObject): "POST", self.url + "/reactions", input=post_parameters, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) return github.Reaction.Reaction(self._requester, headers, data, completed=True) diff --git a/github/Consts.py b/github/Consts.py index c738c6a9..20a75e5f 100644 --- a/github/Consts.py +++ b/github/Consts.py @@ -40,3 +40,40 @@ PROCESSING_202_WAIT_TIME = 2 # ############################################################################## RES_ETAG = "etag" RES_LAST_MODIFIED = "last-modified" + +# Inspired by https://github.com/google/go-github + +# Headers + +headerRateLimit = "x-ratelimit-limit" +headerRateRemaining = "x-ratelimit-remaining" +headerRateReset = "x-ratelimit-reset" +headerOTP = "X-GitHub-OTP" + +defaultMediaType = "application/octet-stream" + +# Custom media type for preview API + +# https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/ +mediaTypeStarringPreview = "application/vnd.github.v3.star+json" + +# https://developer.github.com/changes/2016-02-19-source-import-preview-api/ +mediaTypeImportPreview = "application/vnd.github.barred-rock-preview" + +# https://developer.github.com/changes/2016-05-12-reactions-api-preview/ +mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview" + +# https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/ +mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json" + +# https://developer.github.com/changes/2017-01-05-commit-search-api/ +mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview" + +# https://developer.github.com/changes/2017-02-28-user-blocking-apis-and-webhook/ +mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json" + +# https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/ +mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json" + +# https://developer.github.com/changes/2018-02-22-label-description-search-preview/ +mediaTypeLabelDescriptionSearchPreview = "application/vnd.github.symmetra-preview+json" diff --git a/github/Installation.py b/github/Installation.py index f3f74757..79690d5f 100644 --- a/github/Installation.py +++ b/github/Installation.py @@ -39,7 +39,9 @@ import github.Event import github.Authorization import github.Notification -INTEGRATION_PREVIEW_HEADERS = {"Accept": "application/vnd.github.machine-man-preview+json"} +import Consts + +INTEGRATION_PREVIEW_HEADERS = {"Accept": Consts.mediaTypeIntegrationPreview} class Installation(github.GithubObject.NonCompletableGithubObject): diff --git a/github/Issue.py b/github/Issue.py index b415c6f8..f1d96d75 100644 --- a/github/Issue.py +++ b/github/Issue.py @@ -56,6 +56,8 @@ import github.IssueComment import github.IssuePullRequest import github.Reaction +import Consts + class Issue(github.GithubObject.CompletableGithubObject): """ @@ -465,7 +467,7 @@ class Issue(github.GithubObject.CompletableGithubObject): self._requester, self.url + "/reactions", None, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) def create_reaction(self, reaction_type): @@ -485,7 +487,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "POST", self.url + "/reactions", input=post_parameters, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) return github.Reaction.Reaction(self._requester, headers, data, completed=True) diff --git a/github/IssueComment.py b/github/IssueComment.py index cb037fad..dc689c5a 100644 --- a/github/IssueComment.py +++ b/github/IssueComment.py @@ -34,9 +34,10 @@ ################################################################################ import github.GithubObject - import github.NamedUser +import Consts + class IssueComment(github.GithubObject.CompletableGithubObject): """ @@ -148,7 +149,7 @@ class IssueComment(github.GithubObject.CompletableGithubObject): self._requester, self.url + "/reactions", None, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) def create_reaction(self, reaction_type): @@ -169,7 +170,7 @@ class IssueComment(github.GithubObject.CompletableGithubObject): "POST", self.url + "/reactions", input=post_parameters, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) return github.Reaction.Reaction(self._requester, headers, data, completed=True) diff --git a/github/Label.py b/github/Label.py index 08a2d88d..e2efac20 100644 --- a/github/Label.py +++ b/github/Label.py @@ -35,6 +35,8 @@ import urllib import github.GithubObject +import Consts + class Label(github.GithubObject.CompletableGithubObject): """ @@ -107,7 +109,7 @@ class Label(github.GithubObject.CompletableGithubObject): "PATCH", self.url, input=post_parameters, - headers={'Accept': 'application/vnd.github.symmetra-preview+json'} + headers={'Accept': Consts.mediaTypeLabelDescriptionSearchPreview} ) self._useAttributes(data) diff --git a/github/MainClass.py b/github/MainClass.py index 28b57ae7..2437778e 100644 --- a/github/MainClass.py +++ b/github/MainClass.py @@ -73,6 +73,8 @@ import InstallationAuthorization import GithubException import Invitation +import Consts + atLeastPython3 = sys.hexversion >= 0x03000000 DEFAULT_BASE_URL = "https://api.github.com" @@ -504,7 +506,7 @@ class Github(object): "/search/commits", url_parameters, headers={ - "Accept": "application/vnd.github.cloak-preview" + "Accept": Consts.mediaTypeCommitSearchPreview } ) @@ -721,7 +723,7 @@ class GithubIntegration(object): url="/installations/{}/access_tokens".format(installation_id), headers={ "Authorization": "Bearer {}".format(self.create_jwt()), - "Accept": "application/vnd.github.machine-man-preview+json", + "Accept": Consts.mediaTypeIntegrationPreview, "User-Agent": "PyGithub/Python" }, body=body diff --git a/github/PullRequestComment.py b/github/PullRequestComment.py index d0ce6653..05b438e8 100644 --- a/github/PullRequestComment.py +++ b/github/PullRequestComment.py @@ -35,9 +35,9 @@ ################################################################################ import github.GithubObject - import github.NamedUser +import Consts class PullRequestComment(github.GithubObject.CompletableGithubObject): """ @@ -205,7 +205,7 @@ class PullRequestComment(github.GithubObject.CompletableGithubObject): self._requester, self.url + "/reactions", None, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) def create_reaction(self, reaction_type): @@ -226,7 +226,7 @@ class PullRequestComment(github.GithubObject.CompletableGithubObject): "POST", self.url + "/reactions", input=post_parameters, - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) return github.Reaction.Reaction(self._requester, headers, data, completed=True) diff --git a/github/Reaction.py b/github/Reaction.py index b84c33b1..994ef755 100644 --- a/github/Reaction.py +++ b/github/Reaction.py @@ -25,9 +25,10 @@ ################################################################################ import github.GithubObject - import github.NamedUser +import Consts + class Reaction(github.GithubObject.CompletableGithubObject): """ @@ -77,7 +78,7 @@ class Reaction(github.GithubObject.CompletableGithubObject): self._requester.requestJsonAndCheck( "DELETE", self._parentUrl("") + "/reactions/" + str(self.id), - headers={'Accept': 'application/vnd.github.squirrel-girl-preview'} + headers={'Accept': Consts.mediaTypeReactionsPreview} ) def _initAttributes(self): diff --git a/github/Repository.py b/github/Repository.py index 0c7bfd45..55d9a7ba 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -123,6 +123,8 @@ import github.StatsParticipation import github.StatsPunchCard import github.Stargazer +import Consts + atLeastPython3 = sys.hexversion >= 0x03000000 @@ -1077,7 +1079,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/labels", input=post_parameters, - headers={'Accept': 'application/vnd.github.symmetra-preview+json'} + headers={'Accept': Consts.mediaTypeLabelDescriptionSearchPreview} ) return github.Label.Label(self._requester, headers, data, completed=True) @@ -1179,7 +1181,7 @@ class Repository(github.GithubObject.CompletableGithubObject): if vcs_password is not github.GithubObject.NotSet: put_parameters["vcs_password"] = vcs_password - import_header = {"Accept": "application/vnd.github.barred-rock-preview"} + import_header = {"Accept": Consts.mediaTypeImportPreview} headers, data = self._requester.requestJsonAndCheck( "PUT", @@ -2165,7 +2167,7 @@ class Repository(github.GithubObject.CompletableGithubObject): :calls: `GET /repos/:owner/:repo/import `_ :rtype: :class:`github.SourceImport.SourceImport` """ - import_header = {"Accept": "application/vnd.github.barred-rock-preview"} + import_header = {"Accept": Consts.mediaTypeImportPreview} headers, data = self._requester.requestJsonAndCheck( "GET", self.url + "/import", @@ -2198,7 +2200,7 @@ class Repository(github.GithubObject.CompletableGithubObject): self._requester, self.url + "/stargazers", None, - headers={'Accept': 'application/vnd.github.v3.star+json'} + headers={'Accept': Consts.mediaTypeStarringPreview} ) def get_stats_contributors(self): @@ -2366,7 +2368,7 @@ class Repository(github.GithubObject.CompletableGithubObject): headers, data = self._requester.requestJsonAndCheck( "GET", self.url + "/topics", - headers={'Accept': 'application/vnd.github.mercy-preview+json'} + headers={'Accept': Consts.mediaTypeTopicsPreview} ) return data['names'] @@ -2473,7 +2475,7 @@ class Repository(github.GithubObject.CompletableGithubObject): headers, data = self._requester.requestJsonAndCheck( "PUT", self.url + "/topics", - headers={'Accept': 'application/vnd.github.mercy-preview+json'}, + headers={'Accept': Consts.mediaTypeTopicsPreview}, input=post_parameters ) diff --git a/github/Requester.py b/github/Requester.py index f62d2124..5612eac3 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -289,7 +289,7 @@ class Requester: 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']): + elif status == 401 and Consts.headerOTP in headers and re.match(r'.*required.*', headers[Consts.headerOTP]): 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 @@ -340,7 +340,7 @@ class Requester: mime_type = headers["Content-Type"] else: guessed_type = mimetypes.guess_type(input) - mime_type = guessed_type[0] if guessed_type[0] is not None else "application/octet-stream" + mime_type = guessed_type[0] if guessed_type[0] is not None else Consts.defaultMediaType f = open(local_path, 'rb') return mime_type, f @@ -371,10 +371,10 @@ class Requester: 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 Consts.headerRateRemaining in responseHeaders and Consts.headerRateLimit in responseHeaders: + self.rate_limiting = (int(responseHeaders[Consts.headerRateRemaining]), int(responseHeaders[Consts.headerRateLimit])) + if Consts.headerRateReset in responseHeaders: + self.rate_limiting_resettime = int(responseHeaders[Consts.headerRateReset]) if "x-oauth-scopes" in responseHeaders: self.oauth_scopes = responseHeaders["x-oauth-scopes"].split(", ")