Skip to content

Commit 2722225

Browse files
authored
Rework GraphQL mutations (PyGithub#3046)
This contains the following breaking changes: - use mutation name as given in Github GraphQL documentation - remove capitalized mutation name from mutation request - rename `variables` argument to `mutation_input` - rename `output` argument to `output_schema` - return response data according to output schema (drop outer data.mutationName path)
1 parent 72fa627 commit 2722225

15 files changed

+66
-68
lines changed

doc/changes.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ Change log
44
Stable versions
55
~~~~~~~~~~~~~~~
66

7+
Version 2.5.0 (XXXXXXX)
8+
-----------------------
9+
10+
Breaking Changes
11+
^^^^^^^^^^^^^^^^
12+
13+
* Parameters of method ``github.Requester.Requester.graphql_named_mutation`` have been renamed:
14+
15+
* Parameter ``variables`` renamed to ``mutation_input``
16+
* Parameter ``output`` renamed to ``output_schema``
17+
* Default value of parameter ``output`` has been removed
18+
719
Version 2.4.0 (August 26, 2024)
820
-------------------------------
921

github/IssueComment.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,11 @@ def minimize(self, reason: str = "OUTDATED") -> bool:
204204
"classifier": reason,
205205
}
206206
_, data = self._requester.graphql_named_mutation(
207-
mutation_name="minimize_comment",
208-
variables={"input": NotSet.remove_unset_items(variables)},
209-
output="minimizedComment { isMinimized }",
207+
mutation_name="minimizeComment",
208+
mutation_input=NotSet.remove_unset_items(variables),
209+
output_schema="minimizedComment { isMinimized }",
210210
)
211-
return data["data"]["minimizeComment"]["minimizedComment"]["isMinimized"] is True
211+
return data["minimizedComment"]["isMinimized"] is True
212212

213213
def unminimize(self) -> bool:
214214
"""
@@ -219,11 +219,11 @@ def unminimize(self) -> bool:
219219
"subjectId": self.node_id,
220220
}
221221
_, data = self._requester.graphql_named_mutation(
222-
mutation_name="unminimize_comment",
223-
variables={"input": NotSet.remove_unset_items(variables)},
224-
output="unminimizedComment { isMinimized }",
222+
mutation_name="unminimizeComment",
223+
mutation_input=NotSet.remove_unset_items(variables),
224+
output_schema="unminimizedComment { isMinimized }",
225225
)
226-
return data["data"]["unminimizeComment"]["unminimizedComment"]["isMinimized"] is False
226+
return data["unminimizedComment"]["isMinimized"] is False
227227

228228
def _useAttributes(self, attributes: dict[str, Any]) -> None:
229229
if "body" in attributes: # pragma no branch

github/PullRequest.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,9 @@ def enable_automerge(
817817

818818
# Make the request
819819
_, data = self._requester.graphql_named_mutation(
820-
mutation_name="enable_pull_request_auto_merge",
821-
variables={"input": NotSet.remove_unset_items(variables)},
822-
output="actor { avatarUrl login resourcePath url } clientMutationId",
820+
mutation_name="enablePullRequestAutoMerge",
821+
mutation_input=NotSet.remove_unset_items(variables),
822+
output_schema="actor { avatarUrl login resourcePath url } clientMutationId",
823823
)
824824
return data
825825

@@ -841,9 +841,9 @@ def disable_automerge(
841841

842842
# Make the request
843843
_, data = self._requester.graphql_named_mutation(
844-
mutation_name="disable_pull_request_auto_merge",
845-
variables={"input": NotSet.remove_unset_items(variables)},
846-
output="actor { avatarUrl login resourcePath url } clientMutationId",
844+
mutation_name="disablePullRequestAutoMerge",
845+
mutation_input=NotSet.remove_unset_items(variables),
846+
output_schema="actor { avatarUrl login resourcePath url } clientMutationId",
847847
)
848848
return data
849849

github/Requester.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -632,23 +632,21 @@ def graphql_query(self, query: str, variables: Dict[str, Any]) -> Tuple[Dict[str
632632
return response_headers, data
633633

634634
def graphql_named_mutation(
635-
self, mutation_name: str, variables: Dict[str, Any], output: Optional[str] = None
635+
self, mutation_name: str, mutation_input: Dict[str, Any], output_schema: str
636636
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
637637
"""
638638
Create a mutation in the format:
639-
mutation MutationName($input: MutationNameInput!) {
640-
mutationName(input: $input) {
641-
<output>
642-
}
639+
mutation Mutation($input: MutationNameInput!) {
640+
mutationName(input: $input) { <output_schema> }
643641
}
644-
and call the self.graphql_query method
645-
"""
646-
title = "".join([x.capitalize() for x in mutation_name.split("_")])
647-
mutation_name = title[:1].lower() + title[1:]
648-
output = output or ""
649-
query = f"mutation {title}($input: {title}Input!) {{ {mutation_name}(input: $input) {{ {output} }} }}"
642+
and call the self.graphql_query method.
650643
651-
return self.graphql_query(query, variables)
644+
Returns the response data according to given output schema.
645+
"""
646+
mutation_input_name = mutation_name[:1].upper() + mutation_name[1:] + "Input!"
647+
query = f"mutation Mutation($input: {mutation_input_name}) {{ {mutation_name}(input: $input) {{ {output_schema} }} }}"
648+
headers, data = self.graphql_query(query, {"input": mutation_input})
649+
return headers, data.get("data", {}).get(mutation_name, {})
652650

653651
def __check(
654652
self,

tests/GraphQl.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,13 @@ def setUp(self):
3434

3535
def expected(self, base_url: str = "https://github.com") -> Dict[Any, Any]:
3636
return {
37-
"data": {
38-
"disablePullRequestAutoMerge": {
39-
"actor": {
40-
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
41-
"login": "heitorpolidoro",
42-
"resourcePath": "/heitorpolidoro",
43-
"url": f"{base_url}/heitorpolidoro",
44-
},
45-
"clientMutationId": None,
46-
}
47-
}
37+
"actor": {
38+
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
39+
"login": "heitorpolidoro",
40+
"resourcePath": "/heitorpolidoro",
41+
"url": f"{base_url}/heitorpolidoro",
42+
},
43+
"clientMutationId": None,
4844
}
4945

5046
def testRequesterGraphQlPrefix(self):

tests/PullRequest.py

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -522,17 +522,13 @@ def testEnableAutomerge(self):
522522
expected_head_oid="0283d46537193f1fed7d46859f15c5304b9836f9",
523523
)
524524
assert response == {
525-
"data": {
526-
"enablePullRequestAutoMerge": {
527-
"actor": {
528-
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
529-
"login": "heitorpolidoro",
530-
"resourcePath": "/heitorpolidoro",
531-
"url": "https://github.com/heitorpolidoro",
532-
},
533-
"clientMutationId": None,
534-
}
535-
}
525+
"actor": {
526+
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
527+
"login": "heitorpolidoro",
528+
"resourcePath": "/heitorpolidoro",
529+
"url": "https://github.com/heitorpolidoro",
530+
},
531+
"clientMutationId": None,
536532
}
537533

538534
def testEnableAutomergeDefaultValues(self):
@@ -566,15 +562,11 @@ def testEnableAutomergeError(self):
566562
def testDisableAutomerge(self):
567563
response = self.pull.disable_automerge()
568564
assert response == {
569-
"data": {
570-
"disablePullRequestAutoMerge": {
571-
"actor": {
572-
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
573-
"login": "heitorpolidoro",
574-
"resourcePath": "/heitorpolidoro",
575-
"url": "https://github.com/heitorpolidoro",
576-
},
577-
"clientMutationId": None,
578-
}
579-
}
565+
"actor": {
566+
"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4",
567+
"login": "heitorpolidoro",
568+
"resourcePath": "/heitorpolidoro",
569+
"url": "https://github.com/heitorpolidoro",
570+
},
571+
"clientMutationId": None,
580572
}

tests/ReplayData/GraphQl.testDefaultUrl.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ api.github.com
2626
None
2727
/graphql
2828
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
29-
{"query": "mutation DisablePullRequestAutoMerge($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
29+
{"query": "mutation Mutation($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
3030
200
3131
[('Server', 'GitHub.com'), ('Date', 'Wed, 07 Jun 2023 08:27:45 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"1573389419d98a2b3d9a6b1fc058a68f1fc3d31108ccfdab8ca4121153626211"'), ('Last-Modified', 'Wed, 07 Jun 2023 04:02:03 GMT'), ('X-OAuth-Scopes', 'public_repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4959'), ('X-RateLimit-Reset', '1686126614'), ('X-RateLimit-Used', '41'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', '8A96:10854:895AE2:8AB25B:64803F81')]
3232
{"data": {"disablePullRequestAutoMerge": {"actor": {"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4", "login": "heitorpolidoro", "resourcePath": "/heitorpolidoro", "url": "https://github.com/heitorpolidoro"}, "clientMutationId": null}}}

tests/ReplayData/GraphQl.testOtherPort.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ my.enterprise.com
2626
8080
2727
/api/graphql
2828
{'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
29-
{"query": "mutation DisablePullRequestAutoMerge($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
29+
{"query": "mutation Mutation($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
3030
200
3131
[('Server', 'enterprise.com'), ('Date', 'Wed, 07 Jun 2023 08:27:45 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"1573389419d98a2b3d9a6b1fc058a68f1fc3d31108ccfdab8ca4121153626211"'), ('Last-Modified', 'Wed, 07 Jun 2023 04:02:03 GMT'), ('X-OAuth-Scopes', 'public_repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4959'), ('X-RateLimit-Reset', '1686126614'), ('X-RateLimit-Used', '41'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', '8A96:10854:895AE2:8AB25B:64803F81')]
3232
{"data": {"disablePullRequestAutoMerge": {"actor": {"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4", "login": "heitorpolidoro", "resourcePath": "/heitorpolidoro", "url": "https://my.enterprise.com:8080/api/v3/heitorpolidoro"}, "clientMutationId": null}}}

tests/ReplayData/GraphQl.testOtherUrl.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ my.enterprise.com
2626
None
2727
/api/graphql
2828
{'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
29-
{"query": "mutation DisablePullRequestAutoMerge($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
29+
{"query": "mutation Mutation($input: DisablePullRequestAutoMergeInput!) { disablePullRequestAutoMerge(input: $input) { actor { avatarUrl login resourcePath url } clientMutationId } }", "variables": {"input": {"pullRequestId": "MDExOlB1bGxSZXF1ZXN0MTQzNjIxNQ=="}}}
3030
200
3131
[('Server', 'enterprise.com'), ('Date', 'Wed, 07 Jun 2023 08:27:45 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"1573389419d98a2b3d9a6b1fc058a68f1fc3d31108ccfdab8ca4121153626211"'), ('Last-Modified', 'Wed, 07 Jun 2023 04:02:03 GMT'), ('X-OAuth-Scopes', 'public_repo'), ('X-Accepted-OAuth-Scopes', 'repo'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4959'), ('X-RateLimit-Reset', '1686126614'), ('X-RateLimit-Used', '41'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', '8A96:10854:895AE2:8AB25B:64803F81')]
3232
{"data": {"disablePullRequestAutoMerge": {"actor": {"avatarUrl": "https://avatars.githubusercontent.com/u/14806300?u=786f9f8ef8782d45381b01580f7f7783cf9c7e37&v=4", "login": "heitorpolidoro", "resourcePath": "/heitorpolidoro", "url": "https://my.enterprise.com/api/v3/heitorpolidoro"}, "clientMutationId": null}}}

tests/ReplayData/IssueComment.testMinimize.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ api.github.com
44
None
55
/graphql
66
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python', 'Content-Type': 'application/json'}
7-
{"query": "mutation MinimizeComment($input: MinimizeCommentInput!) { minimizeComment(input: $input) { minimizedComment { isMinimized } } }", "variables": {"input": {"subjectId": "IC_kwDOGpsAJ86Gecc_", "classifier": "OUTDATED"}}}
7+
{"query": "mutation Mutation($input: MinimizeCommentInput!) { minimizeComment(input: $input) { minimizedComment { isMinimized } } }", "variables": {"input": {"subjectId": "IC_kwDOGpsAJ86Gecc_", "classifier": "OUTDATED"}}}
88
200
99
[('Server', 'GitHub.com'), ('Date', 'Mon, 29 Jul 2024 14:43:44 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('github-authentication-token-expiration', '2024-08-28 16:30:05 +0200'), ('X-GitHub-Media-Type', 'github.v4; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4991'), ('X-RateLimit-Reset', '1722267171'), ('X-RateLimit-Used', '9'), ('X-RateLimit-Resource', 'graphql'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'C08C:1A4F2F:3A882EB:3B486EE:66A7AAA0')]
1010
{"data":{"minimizeComment":{"minimizedComment":{"isMinimized":true}}}}

0 commit comments

Comments
 (0)