refactor: port discussions.py off requests onto PyGithub GraphQL - #800
Merged
Conversation
Closes #790 ## What/Why Move get_discussions() from a direct requests.post GraphQL call to PyGithub's github_connection.requester.graphql_query, so PyGithub owns all HTTP (auth, base URL, GitHub Enterprise /api/graphql routing) and requests is no longer a direct dependency. ## Proof it works uv run pytest -> 206 passed, 100% coverage (discussions.py 100%). make lint clean (flake8, isort, pylint 10.00/10, mypy, black). Spike verified graphql_query returns (headers, {"data": {...}}) and derives the GHE GraphQL endpoint from base_url (https://ghe.example.com/api/graphql). ## Risk + AI role Low. Signature changes to get_discussions(github_connection, search_query) with one internal caller updated. Manual status/errors ValueError checks are removed since graphql_query raises GithubException itself. AI-authored (Claude Opus 4.8) and reviewed by four models (Opus, Sonnet, Fable, Haiku). Behavioral notes (pre-existing inconsistencies, tracked in #799): App-auth GHE users must set GITHUB_APP_ENTERPRISE_ONLY=true for discussions to reach GHE (now consistent with every other call); the request timeout is now PyGithub's default rather than the old discussions-only 60s. ## Review focus The removal of the manual error checks (relying on GithubException to propagate) and the GHE routing note for GitHub App auth. Signed-off-by: jmeridth <jmeridth@gmail.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors the Discussions fetching path to use PyGithub’s requester.graphql_query instead of a direct requests.post, so HTTP concerns (auth, base URL, GitHub Enterprise routing) are owned by the existing Github connection rather than a separate client.
Changes:
- Refactor
get_discussions()to accept aGithubconnection and callgithub_connection.requester.graphql_query(...). - Update the single caller in
issue_metrics.pyand adjust unit tests to mock PyGithub’s GraphQL method (including a pagination cursor assertion). - Remove
requests/types-requestsas direct dependencies frompyproject.tomlanduv.lock.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
discussions.py |
Switches Discussions GraphQL calls from requests.post to PyGithub’s requester.graphql_query and updates the function signature accordingly. |
issue_metrics.py |
Updates the discussions path to pass the existing github_connection into get_discussions(). |
test_discussions.py |
Mocks requester.graphql_query, adds a pagination-cursor assertion, and tests exception propagation. |
pyproject.toml |
Drops requests and types-requests as direct dependencies. |
uv.lock |
Updates the lock file to reflect removal of the direct requests / types-requests entries. |
Comments suppressed due to low confidence (1)
discussions.py:18
- The parameter type in the docstring still refers to
github.Github, but the actual annotation/import usesGithubfromgithub. Updating the docstring keeps documentation consistent and avoids referencing a non-importedgithubmodule name.
Args:
github_connection (github.Github): An authenticated PyGithub connection.
GitHub Enterprise routing is handled by the connection's base URL.
Closes #790 ## What/Why Address a PR review note: the docstring referenced `github.Github` and `List[Dict]` while the module imports `Github` directly and returns a plain list. Use `Github` and `list` to match the imported names and the convention in search.py. ## Proof it works Docstring-only change. pytest test_discussions.py -> 3 passed. pylint 10.00/10, mypy and black clean. ## Risk + AI role Low. Documentation only, no runtime change. AI-assisted. ## Review focus None needed beyond the wording. Signed-off-by: jmeridth <jmeridth@gmail.com>
Closes #790 ## What/Why Address a PR review note: construct the test GithubException with a dict `data` payload ({"message": "server error"}) to match the convention used across test_search.py, rather than a bare string. ## Proof it works pytest test_discussions.py -> 3 passed. black clean. ## Risk + AI role Low. Test-only change, no runtime impact. AI-assisted. ## Review focus None needed. Signed-off-by: jmeridth <jmeridth@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #790
Relates to #799
Proposed Changes
Port
get_discussions()from a directrequests.postGraphQL call to PyGithub'sgithub_connection.requester.graphql_query, so PyGithub owns all HTTP (auth, base URL, and GitHub Enterprise/api/graphqlrouting) andrequestsis no longer a direct dependency.discussions.py: signature is nowget_discussions(github_connection, search_query). The manual status-code anderrorschecks are gone becausegraphql_queryraisesGithubExceptionon both HTTP and GraphQL errors, which now propagates.issue_metrics.py: the single caller passes the existinggithub_connection.test_discussions.py: mocks the PyGithub GraphQL call instead ofrequests.post, adds a pagination-cursor assertion, and replaces the two removed error-path tests with an exception-propagation test.pyproject.toml/uv.lock: droprequestsandtypes-requestsas direct dependencies.requestsremains transitively via PyGithub.Proof it works:
make testpasses (206 tests, 100% coverage,discussions.pyat 100%). A spike confirmedgraphql_queryreturns(headers, {"data": {...}})and derives the correct GHE endpoint from the connection base URL (https://ghe.example.com/api/graphql).Risk + AI role: Low. Narrow surface with one internal caller. AI-assisted implementation, independently reviewed across four models.
Behavioral notes (pre-existing inconsistencies, tracked in #799):
GITHUB_APP_ENTERPRISE_ONLY=truefor discussions to reach GHE (they already needed it for all other calls to work).Review focus: The removal of the manual error checks (relying on
GithubExceptionto propagate), and the GHE routing note for GitHub App auth.Readiness Checklist
Author/Contributor
make lintand fix any issues that you have introducedmake testand ensure you have test coverage for the lines you are introducing