asyncgh 0.3.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {asyncgh-0.3.2 → asyncgh-0.4.0}/PKG-INFO +1 -1
- {asyncgh-0.3.2 → asyncgh-0.4.0}/pyproject.toml +1 -1
- {asyncgh-0.3.2 → asyncgh-0.4.0}/src/asyncgh/client.py +18 -6
- {asyncgh-0.3.2 → asyncgh-0.4.0}/tests/test_client.py +26 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/.gitignore +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/LICENSE +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/README.md +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/src/asyncgh/__init__.py +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/src/asyncgh/endpoints.py +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/src/asyncgh/py.typed +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/tests/conftest.py +0 -0
- {asyncgh-0.3.2 → asyncgh-0.4.0}/tests/test_endpoints.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: asyncgh
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Minimal async GitHub REST + GraphQL transport: auth, retry, pagination -- no generated models
|
|
5
5
|
Project-URL: Homepage, https://github.com/hugoh/gh-workflows/tree/main/asyncgh
|
|
6
6
|
Project-URL: Issues, https://github.com/hugoh/gh-workflows/issues
|
|
@@ -106,6 +106,22 @@ def _should_retry_graphql(exc: Exception) -> bool | float:
|
|
|
106
106
|
return _should_retry(exc)
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
def _format_graphql_errors(errors: list[dict]) -> str:
|
|
110
|
+
"""Joins GraphQL `errors[]` into one message, appending each error's
|
|
111
|
+
`path` (e.g. `r3.pullRequests.nodes.0.commits`) when present -- a
|
|
112
|
+
partial-permission failure names only "Resource not accessible by
|
|
113
|
+
personal access token" otherwise, with no hint which repo or field.
|
|
114
|
+
"""
|
|
115
|
+
parts = []
|
|
116
|
+
for error in errors:
|
|
117
|
+
message = error.get("message", str(error))
|
|
118
|
+
path = error.get("path")
|
|
119
|
+
if path:
|
|
120
|
+
message = f"{message} (at {'.'.join(str(segment) for segment in path)})"
|
|
121
|
+
parts.append(message)
|
|
122
|
+
return "; ".join(parts)
|
|
123
|
+
|
|
124
|
+
|
|
109
125
|
def error_message(response: httpx2.Response) -> str:
|
|
110
126
|
"""Extracts GitHub's own `message` field from an error response body,
|
|
111
127
|
falling back to the raw response text if the body isn't JSON, or isn't
|
|
@@ -294,13 +310,9 @@ class GitHubClient:
|
|
|
294
310
|
if not errors:
|
|
295
311
|
return body["data"]
|
|
296
312
|
if any(error.get("type") == "RATE_LIMITED" for error in errors):
|
|
297
|
-
raise _GraphQLRateLimited(
|
|
298
|
-
"; ".join(
|
|
299
|
-
error.get("message", str(error)) for error in errors
|
|
300
|
-
)
|
|
301
|
-
)
|
|
313
|
+
raise _GraphQLRateLimited(_format_graphql_errors(errors))
|
|
302
314
|
raise GhError(
|
|
303
|
-
|
|
315
|
+
_format_graphql_errors(errors),
|
|
304
316
|
error_type=errors[0].get("type"),
|
|
305
317
|
)
|
|
306
318
|
except _GraphQLRateLimited as exc:
|
|
@@ -244,6 +244,32 @@ async def test_graphql_raises_gh_error_when_errors_present_alongside_partial_dat
|
|
|
244
244
|
await graphql("query { r0 r1 }")
|
|
245
245
|
|
|
246
246
|
|
|
247
|
+
async def test_graphql_error_message_includes_the_error_path(
|
|
248
|
+
httpx2_mock: respx.Router,
|
|
249
|
+
):
|
|
250
|
+
httpx2_mock.post(f"{API_BASE}/graphql").mock(
|
|
251
|
+
return_value=httpx.Response(
|
|
252
|
+
200,
|
|
253
|
+
json={
|
|
254
|
+
"data": {"r3": None},
|
|
255
|
+
"errors": [
|
|
256
|
+
{
|
|
257
|
+
"type": "FORBIDDEN",
|
|
258
|
+
"message": "Resource not accessible by personal access token",
|
|
259
|
+
"path": ["r3", "pullRequests", "nodes", 0, "commits"],
|
|
260
|
+
}
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
with pytest.raises(
|
|
266
|
+
GhError,
|
|
267
|
+
match=r"personal access token \(at r3\.pullRequests\.nodes\.0\.commits\)",
|
|
268
|
+
) as exc_info:
|
|
269
|
+
await graphql("query { r3 { pullRequests { nodes { commits } } } }")
|
|
270
|
+
assert exc_info.value.error_type == "FORBIDDEN"
|
|
271
|
+
|
|
272
|
+
|
|
247
273
|
async def test_graphql_retries_on_transport_error(httpx2_mock: respx.Router):
|
|
248
274
|
route = httpx2_mock.post(f"{API_BASE}/graphql").mock(
|
|
249
275
|
side_effect=[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|