fix: use REST API for team resolution (team_by_slug missing in github3.py v4.0.1)#25
Merged
fix: use REST API for team resolution (team_by_slug missing in github3.py v4.0.1)#25
Conversation
get_team_members() called organization.team_by_slug() which does not
exist in github3.py v4.0.1, causing an AttributeError displayed as
just 'team_by_slug' whenever FILTER_TEAMS was used.
The existing team_by_name() method does the same thing (accepts a slug,
hits GET /orgs/{org}/teams/{slug}) despite its misleading name.
Discovered by adding a curl debug step to the workflow in
github/new-user-experience which confirmed the token returns HTTP 200
for the teams endpoint outside the Docker container, proving the issue
is inside github3.py, not a permissions problem.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8fdea3b to
42fc7d6
Compare
MagicMock auto-creates any attribute accessed on it, so the original tests couldn't catch that team_by_slug didn't exist on the real github3.orgs.Organization class. This test checks the real class directly to prevent similar issues if the library changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jmeridth
approved these changes
Mar 14, 2026
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.
Problem
get_team_members()inauth.pycallsorganization.team_by_slug(slug), but this method does not exist in github3.py v4.0.1. The call raises anAttributeErrorthat gets caught by the broadexceptblock, displaying just"team_by_slug"as the error - which is misleading since it suggests a permissions issue.Root cause
github3.py v4.0.1 has these team methods on
Organization:team(id)- lookup by numeric IDteam_by_name(slug)- lookup by slug (misleading name, actually hitsGET /orgs/{org}/teams/{slug})teams()- list all teamsThere is no
team_by_slug. It was requested in github3.py#948 but the maintainer shipped it asteam_by_nameinstead. The method never existed in any released version.How we found this
Debugged in
github/new-user-experiencewhereFILTER_TEAMSwas configured:AttributeError("team_by_slug")"team_by_slug" in dir(github3.orgs.Organization)→False"team_by_name" in dir(github3.orgs.Organization)→True, and inspecting the source shows it takes a slug and hits the same endpointDebug run: https://github.com/github/new-user-experience/actions/runs/23080465650/job/67048787353
Why tests did not catch this
The existing tests use
MagicMock()which auto-creates any attribute accessed on it. Somock_org.team_by_slug.return_value = mock_teamworked perfectly in tests - MagicMock happily faked a method that does not exist on the real class.Added a guard test that checks the real
github3.orgs.Organizationclass directly to prevent this class of bug in the future.Fix
auth.py: Replaceorganization.team_by_slug(team_slug)withorganization.team_by_name(team_slug)test_auth.py: Update mocks to useteam_by_name+ add a guard test verifying the method exists on the real classLocal testing
Ran the action locally with
DRY_RUN=trueagainstgithub/new-user-experience:Single team:
Multiple teams:
Both teams that previously failed with
team_by_slugnow resolve correctly.CI
make lintclean (pylint 10.00/10, mypy clean, black formatted)