diff --git a/github/Requester.py b/github/Requester.py index 01782f1a..b9512de7 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -422,7 +422,9 @@ class Requester: return cnx def __createException(self, status, headers, output): - if status == 401 and output.get("message") == "Bad credentials": + message = output.get("message", "").lower() if output is not None else "" + + if status == 401 and message == "bad credentials": cls = GithubException.BadCredentialsException elif ( status == 401 @@ -430,18 +432,16 @@ class Requester: and re.match(r".*required.*", headers[Consts.headerOTP]) ): cls = GithubException.TwoFactorException - elif status == 403 and output.get("message").startswith( - "Missing or invalid User Agent string" + elif status == 403 and message.startswith( + "missing or invalid user agent string" ): cls = GithubException.BadUserAgentException elif status == 403 and ( - output.get("message").lower().startswith("api rate limit exceeded") - or output.get("message") - .lower() - .endswith("please wait a few minutes before you try again.") + message.startswith("api rate limit exceeded") + or message.endswith("please wait a few minutes before you try again.") ): cls = GithubException.RateLimitExceededException - elif status == 404 and output.get("message") == "Not Found": + elif status == 404 and message == "not found": cls = GithubException.UnknownObjectException else: cls = GithubException.GithubException diff --git a/tests/Requester.py b/tests/Requester.py index 1fee84ef..a9bfb2a1 100644 --- a/tests/Requester.py +++ b/tests/Requester.py @@ -1,6 +1,6 @@ ############################ Copyrights and license ############################ # # -# Copyright 2023 Enrico Minack # +# Copyright 2022 Enrico Minack # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # @@ -91,3 +91,125 @@ class Requester(Framework.TestCase): self.logger.info.assert_called_once_with( "Following Github server redirection from /api/v3/repos/PyGithub/PyGithub to /repos/PyGithub/PyGithub" ) + + def assertException(self, exception, exception_type, status, data, headers, string): + self.assertIsInstance(exception, exception_type) + self.assertEqual(exception.status, status) + if data is None: + self.assertIsNone(exception.data) + else: + self.assertEqual(exception.data, data) + self.assertEqual(exception.headers, headers) + self.assertEqual(str(exception), string) + + def testShouldCreateBadCredentialsException(self): + exc = self.g._Github__requester.__createException( + 401, {"header": "value"}, {"message": "Bad credentials"} + ) + self.assertException( + exc, + github.BadCredentialsException, + 401, + {"message": "Bad credentials"}, + {"header": "value"}, + '401 {"message": "Bad credentials"}', + ) + + def testShouldCreateTwoFactorException(self): + exc = self.g._Github__requester.__createException( + 401, + {"x-github-otp": "required; app"}, + { + "message": "Must specify two-factor authentication OTP code.", + "documentation_url": "https://developer.github.com/v3/auth#working-with-two-factor-authentication", + }, + ) + self.assertException( + exc, + github.TwoFactorException, + 401, + { + "message": "Must specify two-factor authentication OTP code.", + "documentation_url": "https://developer.github.com/v3/auth#working-with-two-factor-authentication", + }, + {"x-github-otp": "required; app"}, + '401 {"message": "Must specify two-factor authentication OTP code.", "documentation_url": "https://developer.github.com/v3/auth#working-with-two-factor-authentication"}', + ) + + def testShouldCreateBadUserAgentException(self): + exc = self.g._Github__requester.__createException( + 403, + {"header": "value"}, + {"message": "Missing or invalid User Agent string"}, + ) + self.assertException( + exc, + github.BadUserAgentException, + 403, + {"message": "Missing or invalid User Agent string"}, + {"header": "value"}, + '403 {"message": "Missing or invalid User Agent string"}', + ) + + def testShouldCreateRateLimitExceededException(self): + for message in [ + "API Rate Limit Exceeded for 92.104.200.119", + "You have triggered an abuse detection mechanism. Please wait a few minutes before you try again.", + "You have exceeded a secondary rate limit. Please wait a few minutes before you try again.", + ]: + with self.subTest(message=message): + exc = self.g._Github__requester.__createException( + 403, {"header": "value"}, {"message": message} + ) + self.assertException( + exc, + github.RateLimitExceededException, + 403, + {"message": message}, + {"header": "value"}, + f'403 {{"message": "{message}"}}', + ) + + def testShouldCreateUnknownObjectException(self): + exc = self.g._Github__requester.__createException( + 404, {"header": "value"}, {"message": "Not Found"} + ) + self.assertException( + exc, + github.UnknownObjectException, + 404, + {"message": "Not Found"}, + {"header": "value"}, + '404 {"message": "Not Found"}', + ) + + def testShouldCreateGithubException(self): + for status in range(400, 600): + with self.subTest(status=status): + exc = self.g._Github__requester.__createException( + status, {"header": "value"}, {"message": "Something unknown"} + ) + self.assertException( + exc, + github.GithubException, + status, + {"message": "Something unknown"}, + {"header": "value"}, + f'{status} {{"message": "Something unknown"}}', + ) + + def testShouldCreateExceptionWithoutMessage(self): + for status in range(400, 600): + with self.subTest(status=status): + exc = self.g._Github__requester.__createException(status, {}, {}) + self.assertException( + exc, github.GithubException, status, {}, {}, f"{status} {{}}" + ) + + def testShouldCreateExceptionWithoutOutput(self): + for status in range(400, 600): + with self.subTest(status=status): + exc = self.g._Github__requester.__createException(status, {}, None) + self.assertException( + exc, github.GithubException, status, None, {}, f"{status} null" + )