8000 Merge pull request #598 from sigmavirus24/bug/597 · borgstrom/github3.py@7bb022a · GitHub
[go: up one dir, main page]

S 10000 kip to content

Commit 7bb022a

Browse files
Merge pull request sigmavirus24#598 from sigmavirus24/bug/597
Capture and re-raise exceptions from Requests
2 parents 1f0bc67 + 36a08aa commit 7bb022a

16 files changed

+195
-149
lines changed

github3/__init__.py

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,89 @@
1616
__url__,
1717
)
1818
from .api import (
19-
authorize, login, enterprise_login, emojis, gist, gitignore_template,
20-
create_gist, issue, markdown, octocat, organization, pull_request,
21-
followers_of, followed_by, public_gists, gists_by, issues_on,
22-
gitignore_templates, all_repositories, all_users, all_events,
23-
organizations_with, repositories_by, starred_by, subscriptions_for,
24-
rate_limit, repository, search_code, search_repositories, search_users,
25-
search_issues, user, zen
19+
all_events,
20+
all_repositories,
21+
all_users,
22+
authorize,
23+
create_gist,
24+
emojis,
25+
enterprise_login,
26+
followed_by,
27+
followers_of,
28+
gist,
29+
gists_by,
30+
gitignore_template,
31+
gitignore_templates,
32+
issue,
33+
issues_on,
34+
login,
35+
markdown,
36+
octocat,
37+
organization,
38+
organizations_with,
39+
public_gists,
40+
pull_request,
41+
rate_limit,
42+
repositories_by,
43+
repository,
44+
search_code,
45+
search_issues,
46+
search_repositories,
47+
search_users,
48+
starred_by,
49+
subscriptions_for,
50+
user,
51+
zen
2652
)
2753
from .github import GitHub, GitHubEnterprise, GitHubStatus
28-
from .exceptions import (
29-
BadRequest, AuthenticationFailed, ForbiddenError, GitHubError,
30-
MethodNotAllowed, NotFoundError, ServerError, NotAcceptable,
31-
UnprocessableEntity
32-
)
54+
from .exceptions import GitHubError
3355

3456
__all__ = (
35-
'AuthenticationFailed', 'BadRequest', 'ForbiddenError', 'GitHub',
36-
'GitHubEnterprise', 'GitHubError', 'GitHubStatus',
37-
'MethodNotAllowed', 'NotAcceptable', 'NotFoundError', 'ServerError',
38-
'UnprocessableEntity', 'authorize', 'login', 'enterprise_login', 'emojis',
39-
'gist', 'gitignore_template', 'create_gist', 'issue', 'markdown',
40-
'octocat', 'organization', 'pull_request', 'followers_of', 'followed_by',
41-
'public_gists', 'gists_by', 'issues_on', 'gitignore_templates',
42-
'all_repositories', 'all_users', 'all_events', 'organizations_with',
43-
'repositories_by', 'starred_by', 'subscriptions_for', 'rate_limit',
44-
'repository', 'search_code', 'search_repositories', 'search_users',
45-
'search_issues', 'user', 'zen',
57+
'GitHub',
58+
'GitHubEnterprise',
59+
'GitHubError',
60+
'GitHubStatus',
61+
'authorize',
62+
'login',
63+
'enterprise_login',
64+
'emojis',
65+
'gist',
66+
'gitignore_template',
67+
'create_gist',
68+
'issue',
69+
'markdown',
70+
'octocat',
71+
'organization',
72+
'pull_request',
73+
'followers_of',
74+
'followed_by',
75+
'public_gists',
76+
'gists_by',
77+
'issues_on',
78+
'gitignore_templates',
79+
'all_repositories',
80+
'all_users',
81+
'all_events',
82+
'organizations_with',
83+
'repositories_by',
84+
'starred_by',
85+
'subscriptions_for',
86+
'rate_limit',
87+
'repository',
88+
'search_code',
89+
'search_repositories',
90+
'search_users',
91+
'search_issues',
92+
'user',
93+
'zen',
4694
# Metadata attributes
47-
'__package_name__', '__title__', '__author__', '__author_email__',
48-
'__license__', '__copyright__', '__version__', '__version_info__',
95+
'__package_name__',
96+
'__title__',
97+
'__author__',
98+
'__author_email__',
99+
'__license__',
100+
'__copyright__',
101+
'__version__',
102+
'__version_info__',
49103
'__url__',
50104
)

github3/exceptions.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,32 @@ def message(self):
3434
return self.msg
3535

3636

37-
class UnprocessableResponseBody(GitHubError):
37+
class ResponseError(GitHubError):
38+
"""The base exception for errors stemming from GitHub responses."""
39+
pass
40+
41+
42+
class TransportError(GitHubError):
43+
"""Catch-all exception for errors coming from Requests."""
44+
45+
msg_format = 'An error occurred while making a request to GitHub: {0}'
46+
47+
def __init__(self, exception):
48+
Exception.__init__(self, exception)
49+
self.exception = exception
50+
self.msg = self.msg_format.format(str(exception))
51+
52+
def __str__(self):
53+
return '{0}: {1}'.format(type(self.exception), self.msg)
54+
55+
56+
class ConnectionError(TransportError):
57+
"""Exception for errors in connecting to or reading data from GitHub."""
58+
59+
msg_format = 'A connection-level exception occurred: {0}'
60+
61+
62+
class UnprocessableResponseBody(ResponseError):
3863
"""Exception class for response objects that cannot be handled."""
3964
def __init__(self, message, body):
4065
Exception.__init__(self, message)
@@ -48,12 +73,12 @@ def __str__(self):
4873
return self.message
4974

5075

51-
class BadRequest(GitHubError):
76+
class BadRequest(ResponseError):
5277
"""Exception class for 400 responses."""
5378
pass
5479

5580

56-
class AuthenticationFailed(GitHubError):
81+
class AuthenticationFailed(ResponseError):
5782
"""Exception class for 401 responses.
5883
5984
Possible reasons:
@@ -64,7 +89,7 @@ class AuthenticationFailed(GitHubError):
6489
pass
6590

6691

67-
class ForbiddenError(GitHubError):
92+
class ForbiddenError(ResponseError):
6893
"""Exception class for 403 responses.
6994
7095
Possible reasons:
@@ -75,32 +100,32 @@ class ForbiddenError(GitHubError):
75100
pass
76101

77102

78-
class NotFoundError(GitHubError):
103+
class NotFoundError(ResponseError):
79104
"""Exception class for 404 responses."""
80105
pass
81106

82107

83-
class MethodNotAllowed(GitHubError):
108+
class MethodNotAllowed(ResponseError):
84109
"""Exception class for 405 responses."""
85110
pass
86111

87112

88-
class NotAcceptable(GitHubError):
113+
class NotAcceptable(ResponseError):
89114
"""Exception class for 406 responses."""
90115
pass
91116

92117

93-
class UnprocessableEntity(GitHubError):
118+
class UnprocessableEntity(ResponseError):
94119
"""Exception class for 422 responses."""
95120
pass
96121

97122

98-
class ClientError(GitHubError):
123+
class ClientError(ResponseError):
99124
"""Catch-all for 400 responses that aren't specific errors."""
100125
pass
101126

102127

103-
class ServerError(GitHubError):
128+
class ServerError(ResponseError):
104129
"""Exception class for 5xx responses."""
105130
pass
106131

github3/models.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from datetime import datetime
1414
from logging import getLogger
1515

16+
import requests
17+
1618
from . import exceptions
1719
from .decorators import requires_auth
1820
from .null import NullObject
@@ -176,27 +178,38 @@ def _boolean(self, response, true_code, false_code):
176178
raise exceptions.error_for(response)
177179
return False
178180

181+
def _request(self, method, *args, **kwargs):
182+
try:
183+
request_method = getattr(self.session, method)
184+
return request_method(*args, **kwargs)
185+
except (requests.exceptions.ConnectionError,
186+
requests.exceptions.Timeout,
187+
) as exc:
188+
raise exceptions.ConnectionError(exc)
189+
except requests.exceptions.RequestException as exc:
190+
raise exceptions.TransportError(exc)
191+
179192
def _delete(self, url, **kwargs):
180193
__logs__.debug('DELETE %s with %s', url, kwargs)
181-
return self.session.delete(url, **kwargs)
194+
return self._request('delete', url, **kwargs)
182195

183196
def _get(self, url, **kwargs):
184197
__logs__.debug('GET %s with %s', url, kwargs)
185-
return self.session.get(url, **kwargs)
198+
return self._request('get', url, **kwargs)
186199

187200
def _patch(self, url, **kwargs):
188201
__logs__.debug('PATCH %s with %s', url, kwargs)
189-
return self.session.patch(url, **kwargs)
202+
return self._request('patch', url, **kwargs)
190203

191204
def _post(self, url, data=None, json=True, **kwargs):
192205
if json:
193206
data = dumps(data) if data is not None else data
194207
__logs__.debug('POST %s with %s, %s', url, data, kwargs)
195-
return self.session.post(url, data, **kwargs)
208+
return self._request('post', url, data, **kwargs)
196209

197210
def _put(self, url, **kwargs):
198211
__logs__.debug('PUT %s with %s', url, kwargs)
199-
return self.session.put(url, **kwargs)
212+
return self._request('put', url, **kwargs)
200213

201214
def _build_url(self, *args, **kwargs):
202215
"""Builds a new API url from scratch."""

tests/cassettes/Comparison_diff.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/cassettes/Comparison_patch.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/cassettes/PullRequest_diff.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/cassettes/PullRequest_patch.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/cassettes/RepoCommit_diff.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/cassettes/RepoCommit_patch.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/unit/helper.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,13 @@ def after_setup(self):
217217
self.session.auth = None
218218
self.session.has_auth.return_value = False
219219

220-
def assert_requires_auth(self, func):
220+
def assert_requires_auth(self, func, *args, **kwargs):
221221
"""
222222
Assert error is raised if function is called without
223223
authentication.
224224
"""
225-
with pytest.raises(github3.AuthenticationFailed):
226-
func()
225+
with pytest.raises(github3.exceptions.AuthenticationFailed):
226+
func(*args, **kwargs)
227227

228228

229229
class UnitGitHubObjectHelper(UnitHelper):

0 commit comments

Comments
 (0)
0