refactor: migrate from github3.py to PyGithub#789
Merged
Conversation
## What/Why Replace github3-py with PyGithub>=2.6.0 to align with the 6 sibling OSPO repos (cleanowners, measure-innersource, pr-conflict-detector, evergreen, contributors, stale-repos) that have already migrated. ## Proof it works - 194 tests pass with 100% coverage - All pre-commit hooks pass (secrets, end-of-file, trailing whitespace, flake8, isort, pylint, mypy, black) ## Risk + AI role Medium -- touches auth, search, and all metric calculation modules. All code AI-generated (Claude Opus 4.6) following established patterns from sibling repo PRs. ## Review focus - Auth module changes (App auth, token auth, GHE paths) - PyGithub object access patterns (NamedUser.login vs dict, Label.name vs dict, native datetime handling) Signed-off-by: jmeridth <jmeridth@gmail.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR migrates the action’s GitHub API client from github3.py to PyGithub>=2.6.0, updating the authentication flow, search layer, and metric-calculation modules to use PyGithub’s object model and datetime handling.
Changes:
- Replace
github3.pyusage with PyGithub types and access patterns across auth, search, and metric modules. - Update metric logic to use native
datetimefields from PyGithub objects instead of ISO string parsing. - Refresh unit tests and dependency locks to reflect the new client library and object shapes.
Reviewed changes
Copilot reviewed 25 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Removes github3-py and locks pygithub (+ transitive deps like pynacl). |
| pyproject.toml | Swaps runtime dependency from github3-py to PyGithub>=2.6.0 and drops direct requests / types-requests. |
| auth.py | Reworks PAT + GitHub App auth to use PyGithub Auth / GithubIntegration. |
| search.py | Ports issue search and exception handling to GithubException. |
| issue_metrics.py | Updates per-issue metric extraction to PyGithub issue/PR fields and helpers. |
| labels.py | Updates label event parsing (event.label.name) and datetime arithmetic. |
| pr_comments.py | Updates comment/review-comment retrieval to PyGithub APIs (get_comments, get_review_comments). |
| most_active_mentors.py | Ports comment/review iteration to PyGithub and adds explicit max-eval limiting. |
| time_to_ready_for_review.py | Uses Issue.get_events() for ready-for-review event detection. |
| time_to_merge.py | Switches to PyGithub PullRequest and native datetime fields. |
| time_to_first_review.py | Uses PullRequest.get_reviews() and PyGithub user objects. |
| time_to_first_response.py | Uses Issue.get_comments() / PullRequest.get_reviews() and native datetime fields. |
| time_to_close.py | Uses native datetime fields for issue close duration calculation. |
| time_in_draft.py | Ports PR draft tracking logic to PyGithub (as_pull_request, get_events). |
| test_auth.py | Updates auth tests to mock PyGithub Auth, Github, and GithubIntegration behavior. |
| test_search.py | Updates search tests to use GithubException and new search return shapes. |
| test_issue_metrics.py | Updates issue/PR mocks to match PyGithub field shapes and datetime types. |
| test_time_to_ready_for_review.py | Updates event access to get_events(). |
| test_time_to_first_review.py | Updates review access to get_reviews() and datetime inputs. |
| test_time_to_first_response.py | Updates comment/review accessors and user shapes for PyGithub. |
| test_time_to_close.py | Updates to use datetime objects for created/closed timestamps. |
| test_time_in_draft.py | Updates mocks to use get_events() / as_pull_request() and PyGithub-like issue shape. |
| test_labels.py | Updates label mocks to .name attribute objects and datetime fields. |
| test_pr_comments.py | Updates to PyGithub comment/review-comment accessors. |
| test_most_active_mentors.py | Updates comment/review accessors and adds review limit branch coverage. |
| .github/linters/.python-lint | Removes suggestion-mode setting from pylint config. |
| .coveragerc | Formatting-only change (no behavioral change). |
## What/Why Fix issues identified by PR review and agent analysis: ConnectionError class hierarchy bug, dropped per_page parameter, docstring mismatches, and a test relying on MagicMock auto-attribute behavior. ## Proof it works - 195 tests pass with 100% coverage - All pre-commit hooks pass ## Risk + AI role Low -- targeted fixes to exception handling, pagination, docs, and tests. All code AI-assisted (Claude Opus 4.6). ## Review focus - ConnectionError catch broadened to include OSError (search.py:68) - per_page=100 restored on search_issues call (search.py:39) Signed-off-by: jmeridth <jmeridth@gmail.com>
zkoppert
reviewed
Jul 5, 2026
zkoppert
left a comment
Collaborator
There was a problem hiding this comment.
A few follow-ups from a closer look at the migration, mostly around the search rate-limit handling and dependency declarations. I left the specifics inline.
…prove error handling - Remove rate_limit_bypass parameter entirely (unused since PyGithub migration) - Catch RateLimitExceededException before GithubException for clearer errors - Re-add requests as explicit dependency (used by discussions.py) - Pin PyGithub==2.9.1 for consistency with other pinned deps - Add types-requests back to dev dependencies - Remove dead None guard in auth_to_github (PyGithub never returns None) - Remove corresponding test_auth_to_github_invalid_credentials test Signed-off-by: jmeridth <jmeridth@gmail.com>
zkoppert
reviewed
Jul 6, 2026
PyGithub returns comment.user as None for ghost (deleted) accounts. Both ignore_comment functions now return True for None users to prevent AttributeError on .login/.type access. Added tests covering the ghost user path in both time_to_first_response and most_active_mentors. 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.
What/Why
Migrate from github3-py to PyGithub>=2.6.0, aligning with the 6 sibling OSPO repos (cleanowners, measure-innersource, pr-conflict-detector, evergreen, contributors, stale-repos) that have already completed this migration.
Proof it works
Risk + AI role
Medium -- touches auth, search, and all metric calculation modules. All code AI-assisted (Claude Opus 4.6) following established patterns from sibling repo PRs.
Review focus
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