Skip to content

Commit 3234a21

Browse files
authored
Allow for repo strings in all Team repo methods (#3356)
Harmonizes repo string support across all `Team` repo methods. Increases code reuse, adds tests for str/Repository logic and use. Fixes #3355.
1 parent e359b83 commit 3234a21

4 files changed

Lines changed: 57 additions & 29 deletions

File tree

github/Repository.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,17 @@ def web_commit_signoff_required(self) -> bool:
12611261
self._completeIfNotSet(self._web_commit_signoff_required)
12621262
return self._web_commit_signoff_required.value
12631263

1264+
@staticmethod
1265+
def as_url_param(repo: str | Repository) -> str:
1266+
assert isinstance(repo, (str, github.Repository.Repository))
1267+
if isinstance(repo, github.Repository.Repository):
1268+
return repo._identity # type: ignore
1269+
else:
1270+
# we expect exactly one slash in the repo name
1271+
assert len(repo.split("/")) == 2, repo
1272+
# do not quote the slash as this is expected to become part of URL path
1273+
return urllib.parse.quote(repo, safe="/")
1274+
12641275
def add_to_collaborators(self, collaborator: str | NamedUser, permission: Opt[str] = NotSet) -> Invitation | None:
12651276
"""
12661277
:calls: `PUT /repos/{owner}/{repo}/collaborators/{user} <https://docs.github.com/en/rest/collaborators/collaborators#add-a-repository-collaborator>`_

github/Team.py

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -301,26 +301,24 @@ def get_team_membership(self, member: str | NamedUser) -> Membership:
301301
headers, data = self._requester.requestJsonAndCheck("GET", f"{self.url}/memberships/{member}")
302302
return github.Membership.Membership(self._requester, headers, data, completed=True)
303303

304-
def add_to_repos(self, repo: Repository) -> None:
304+
def add_to_repos(self, repo: str | Repository) -> None:
305305
"""
306306
:calls: `PUT /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
307307
"""
308-
assert isinstance(repo, github.Repository.Repository), repo
309-
headers, data = self._requester.requestJsonAndCheck("PUT", f"{self.url}/repos/{repo._identity}")
308+
assert isinstance(repo, (str, github.Repository.Repository)), repo
309+
headers, data = self._requester.requestJsonAndCheck(
310+
"PUT", f"{self.url}/repos/{github.Repository.Repository.as_url_param(repo)}"
311+
)
310312

311-
def get_repo_permission(self, repo: Repository) -> Permissions | None:
313+
def get_repo_permission(self, repo: str | Repository) -> Permissions | None:
312314
"""
313315
:calls: `GET /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
314316
"""
315-
assert isinstance(repo, github.Repository.Repository) or isinstance(repo, str), repo
316-
if isinstance(repo, github.Repository.Repository):
317-
repo = repo._identity # type: ignore
318-
else:
319-
repo = urllib.parse.quote(repo, safe="")
317+
assert isinstance(repo, (str, github.Repository.Repository)), repo
320318
try:
321319
headers, data = self._requester.requestJsonAndCheck(
322320
"GET",
323-
f"{self.url}/repos/{repo}",
321+
f"{self.url}/repos/{github.Repository.Repository.as_url_param(repo)}",
324322
headers={"Accept": Consts.teamRepositoryPermissions},
325323
)
326324
return github.Permissions.Permissions(self._requester, headers, data["permissions"])
@@ -332,38 +330,33 @@ def get_repo_permission(self, repo: Repository) -> Permissions | None:
332330
Team.set_repo_permission() is deprecated, use Team.update_team_repository() instead.
333331
"""
334332
)
335-
def set_repo_permission(self, repo: Repository, permission: str) -> None:
333+
def set_repo_permission(self, repo: str | Repository, permission: str) -> None:
336334
"""
337335
:calls: `PUT /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
338336
:param repo: :class:`github.Repository.Repository`
339337
:param permission: string
340338
:rtype: None
341339
"""
342-
343-
assert isinstance(repo, github.Repository.Repository), repo
340+
assert isinstance(repo, (str, github.Repository.Repository)), repo
344341
put_parameters = {
345342
"permission": permission,
346343
}
347344
headers, data = self._requester.requestJsonAndCheck(
348-
"PUT", f"{self.url}/repos/{repo._identity}", input=put_parameters
345+
"PUT", f"{self.url}/repos/{github.Repository.Repository.as_url_param(repo)}", input=put_parameters
349346
)
350347

351-
def update_team_repository(self, repo: Repository, permission: str) -> bool:
348+
def update_team_repository(self, repo: str | Repository, permission: str) -> bool:
352349
"""
353350
:calls: `PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams#check-team-permissions-for-a-repository>`_
354351
"""
355-
assert isinstance(repo, github.Repository.Repository) or isinstance(repo, str), repo
352+
assert isinstance(repo, (str, github.Repository.Repository)), repo
356353
assert isinstance(permission, str), permission
357-
if isinstance(repo, github.Repository.Repository):
358-
repo_url_param = repo._identity
359-
else:
360-
repo_url_param = urllib.parse.quote(repo, safe="")
361354
put_parameters = {
362355
"permission": permission,
363356
}
364357
status, _, _ = self._requester.requestJson(
365358
"PUT",
366-
f"{self.organization.url}/teams/{self.slug}/repos/{repo_url_param}",
359+
f"{self.organization.url}/teams/{self.slug}/repos/{github.Repository.Repository.as_url_param(repo)}",
367360
input=put_parameters,
368361
)
369362
return status == 204
@@ -473,12 +466,14 @@ def has_in_members(self, member: NamedUser) -> bool:
473466
status, headers, data = self._requester.requestJson("GET", f"{self.url}/members/{member._identity}")
474467
return status == 204
475468

476-
def has_in_repos(self, repo: Repository) -> bool:
469+
def has_in_repos(self, repo: str | Repository) -> bool:
477470
"""
478471
:calls: `GET /teams/{id}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
479472
"""
480-
assert isinstance(repo, github.Repository.Repository), repo
481-
status, headers, data = self._requester.requestJson("GET", f"{self.url}/repos/{repo._identity}")
473+
assert isinstance(repo, (str, github.Repository.Repository)), repo
474+
status, headers, data = self._requester.requestJson(
475+
"GET", f"{self.url}/repos/{github.Repository.Repository.as_url_param(repo)}"
476+
)
482477
return status == 204
483478

484479
def remove_membership(self, member: NamedUser) -> None:
@@ -498,12 +493,14 @@ def remove_from_members(self, member: NamedUser) -> None:
498493
assert isinstance(member, github.NamedUser.NamedUser), member
499494
headers, data = self._requester.requestJsonAndCheck("DELETE", f"{self.url}/members/{member._identity}")
500495

501-
def remove_from_repos(self, repo: Repository) -> None:
496+
def remove_from_repos(self, repo: str | Repository) -> None:
502497
"""
503498
:calls: `DELETE /teams/{id}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
504499
"""
505-
assert isinstance(repo, github.Repository.Repository), repo
506-
headers, data = self._requester.requestJsonAndCheck("DELETE", f"{self.url}/repos/{repo._identity}")
500+
assert isinstance(repo, (str, github.Repository.Repository)), repo
501+
headers, data = self._requester.requestJsonAndCheck(
502+
"DELETE", f"{self.url}/repos/{github.Repository.Repository.as_url_param(repo)}"
503+
)
507504

508505
def _useAttributes(self, attributes: dict[str, Any]) -> None:
509506
if "created_at" in attributes: # pragma no branch

tests/Repository.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
from unittest import mock
105105

106106
import github
107+
import github.Repository
107108

108109
from . import Framework
109110

@@ -268,6 +269,15 @@ def testAttributes(self):
268269
self.assertEqual(self.repo.web_commit_signoff_required, False)
269270
self.assertEqual(self.repo.custom_properties, {})
270271

272+
def testAsUrlParam(self):
273+
self.assertEqual(github.Repository.Repository.as_url_param(self.repo), "PyGithub/PyGithub")
274+
self.assertEqual(github.Repository.Repository.as_url_param(self.repo._identity), "PyGithub/PyGithub")
275+
276+
for repo in ["repo", "repo/name/slash"]:
277+
with self.assertRaises(AssertionError) as raisedexp:
278+
github.Repository.Repository.as_url_param(repo)
279+
self.assertEqual(raisedexp.exception.args, (repo,))
280+
271281
def testEditWithoutArguments(self):
272282
self.repo.edit("PyGithub")
273283

tests/Team.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@
5353

5454
import warnings
5555
from datetime import datetime, timezone
56+
from typing import TYPE_CHECKING
5657

5758
from . import Framework
5859

60+
if TYPE_CHECKING:
61+
from github.Repository import Repository
62+
5963

6064
class Team(Framework.TestCase):
6165
def setUp(self):
@@ -162,8 +166,7 @@ def testUpdateTeamRepository(self):
162166
repo = self.org.get_repo("FatherBeaver")
163167
self.assertTrue(self.team.update_team_repository(repo, "admin"))
164168

165-
def testRepos(self):
166-
repo = self.org.get_repo("FatherBeaver")
169+
def doTestRepos(self, repo: str | Repository):
167170
self.assertListKeyEqual(self.team.get_repos(), None, [])
168171
self.assertFalse(self.team.has_in_repos(repo))
169172
self.assertIsNone(self.team.get_repo_permission(repo))
@@ -176,6 +179,13 @@ def testRepos(self):
176179
self.assertListKeyEqual(self.team.get_repos(), None, [])
177180
self.assertFalse(self.team.has_in_repos(repo))
178181

182+
def testRepos(self):
183+
self.doTestRepos(self.org.get_repo("FatherBeaver"))
184+
185+
def testReposStr(self):
186+
with self.replayData("Team.testRepos.txt"):
187+
self.doTestRepos(self.org.get_repo("FatherBeaver")._identity)
188+
179189
def testEditWithoutArguments(self):
180190
self.team.edit("Name edited by PyGithub")
181191
self.assertEqual(self.team.name, "Name edited by PyGithub")

0 commit comments

Comments
 (0)