Skip to content

Commit

Permalink
Export headers in GithubException (#1887)
Browse files Browse the repository at this point in the history
Since the headers that led to an exception are also useful, firstly pass
them into the constructor, and then export them in a property. Test one
specific use case to make sure of coverage.

Fixes #1814
  • Loading branch information
s-t-e-v-e-n-k committed Mar 23, 2021
1 parent e0acd8f commit ddd437a
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 7 deletions.
12 changes: 10 additions & 2 deletions github/GithubException.py
Expand Up @@ -38,11 +38,12 @@ class GithubException(Exception):
Some other types of exceptions might be raised by underlying libraries, for example for network-related issues.
"""

def __init__(self, status, data):
def __init__(self, status, data, headers):
super().__init__()
self.__status = status
self.__data = data
self.args = [status, data]
self.__headers = headers
self.args = [status, data, headers]

@property
def status(self):
Expand All @@ -58,6 +59,13 @@ def data(self):
"""
return self.__data

@property
def headers(self):
"""
The headers returned by the Github API
"""
return self.__headers

def __str__(self):
return "{status} {data}".format(status=self.status, data=json.dumps(self.data))

Expand Down
5 changes: 4 additions & 1 deletion github/GithubException.pyi
@@ -1,13 +1,16 @@
from typing import Any, Dict, List, Optional, Tuple, Type, Union

class GithubException(Exception):
def __init__(self, status: Union[int, str], data: Any,) -> None: ...
def __init__(self, status: Union[int, str], data: Any, headers: Optional[Dict[str, str]]) -> None: ...
def __str__(self) -> str: ...
@property
def data(self) -> Dict[str, Union[str, List[str], List[Dict[str, str]]]]: ...
@property
def status(self) -> int: ...

@property
def headers(self) -> Union[None, Dict[str, str]]: ...

class BadAttributeException(GithubException):
def __init__(
self,
Expand Down
2 changes: 1 addition & 1 deletion github/GithubObject.py
Expand Up @@ -300,7 +300,7 @@ def _completeIfNeeded(self):
def __complete(self):
if self._url.value is None:
raise GithubException.IncompletableObject(
400, "Returned object contains no URL"
400, "Returned object contains no URL", None
)
headers, data = self._requester.requestJsonAndCheck("GET", self._url.value)
self._storeAndUseAttributes(headers, data)
Expand Down
2 changes: 1 addition & 1 deletion github/Requester.py
Expand Up @@ -435,7 +435,7 @@ def __createException(self, status, headers, output):
cls = GithubException.UnknownObjectException
else:
cls = GithubException.GithubException
return cls(status, output)
return cls(status, output, headers)

def __structuredFromJson(self, data):
if len(data) == 0:
Expand Down
6 changes: 4 additions & 2 deletions tests/Exceptions.py
Expand Up @@ -90,7 +90,7 @@ def testBadAuthentication(self):
self.assertEqual(str(raisedexp.exception), '401 {"message": "Bad credentials"}')

def testExceptionPickling(self):
pickle.loads(pickle.dumps(github.GithubException("foo", "bar")))
pickle.loads(pickle.dumps(github.GithubException("foo", "bar", None)))


class SpecificExceptions(Framework.TestCase):
Expand Down Expand Up @@ -134,7 +134,9 @@ def exceed():
res = self.g.search_code("jacquev6")
res.get_page(0)

self.assertRaises(github.RateLimitExceededException, exceed)
with self.assertRaises(github.RateLimitExceededException) as raised:
exceed()
self.assertEqual(raised.exception.headers.get("retry-after"), "60")

def testIncompletableObject(self):
github.UserKey.UserKey.setCheckAfterInitFlag(False)
Expand Down

0 comments on commit ddd437a

Please sign in to comment.