Skip to content

Commit 7d1ba28

Browse files
Fix getting release by tag in lazy mode (PyGithub#3469)
Getting a release by tag cannot return a lazy release. The URL that is used to fetch the release by tag cannot be used for subsequent requests (like getting assets). The URL first has to be turned into the URL that contains the release id. This requires an API call. Supersedes PyGithub#3468. Fixes PyGithub#3467. Co-authored-by: Sebastien NICOT <sebastien.nicot@enterprisedb.com>
1 parent 3a17ecf commit 7d1ba28

4 files changed

Lines changed: 70 additions & 6 deletions

File tree

github/Repository.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3672,10 +3672,12 @@ def get_release(self, id: int | str) -> GitRelease:
36723672
assert isinstance(id, (int, str)), id
36733673
if isinstance(id, int):
36743674
url = f"{self.url}/releases/{id}"
3675+
return github.GitRelease.GitRelease(self._requester, url=url)
36753676
else:
36763677
tag = urllib.parse.quote(id, safe="")
36773678
url = f"{self.url}/releases/tags/{tag}"
3678-
return github.GitRelease.GitRelease(self._requester, url=url)
3679+
# a release by tag cannot be lazy, we need to get the url with release id
3680+
return github.GitRelease.GitRelease(self._requester, url=url).complete()
36793681

36803682
def get_latest_release(self) -> GitRelease:
36813683
"""

tests/GitRelease.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,16 +200,25 @@ def testLazyAttributes(self):
200200
self.assertEqual(id_release.id, 42)
201201
self.assertEqual(id_release.url, "/repos/lazy/repo/releases/42")
202202

203-
id_release = self.g.withLazy(True).get_repo("lazy/repo").get_release("v42")
204-
self.assertEqual(str(id_release), "GitRelease(name=None)")
205-
self.assertEqual(id_release.tag_name, "v42")
206-
self.assertEqual(id_release.url, "/repos/lazy/repo/releases/tags/v42")
207-
208203
def testGetRelease(self):
209204
release_by_id = self.release
210205
release_by_tag = self.repo.get_release(tag)
211206
self.assertEqual(release_by_id, release_by_tag)
212207

208+
def testGetReleaseByTag(self):
209+
release = self.g.get_repo("EnricoMi/PyGithub").get_release("v1.55")
210+
assets = list(release.get_assets())
211+
self.assertEqual(len(assets), 2)
212+
self.assertEqual(assets[0].name, "asset1.md")
213+
self.assertEqual(assets[1].name, "asset2.gz")
214+
215+
def testGetLazyReleaseByTag(self):
216+
release = self.g.withLazy(True).get_repo("EnricoMi/PyGithub").get_release("v1.55")
217+
assets = list(release.get_assets())
218+
self.assertEqual(len(assets), 2)
219+
self.assertEqual(assets[0].name, "asset1.md")
220+
self.assertEqual(assets[1].name, "asset2.gz")
221+
213222
def testGetLatestRelease(self):
214223
latest_release = self.repo.get_latest_release()
215224
self.assertEqual(latest_release.tag_name, tag)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
https
2+
GET
3+
api.github.com
4+
None
5+
/repos/EnricoMi/PyGithub/releases/tags/v1.55
6+
{'Authorization': 'token private_token_removed', 'User-Agent': 'PyGithub/Python'}
7+
None
8+
200
9+
[('Date', 'Mon, 23 Mar 2026 20:31:36 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"3f4a76a23708f483c60f4df2840f7b5f0ce3b57e1627434b494bd6fb48fb0816"'), ('Last-Modified', 'Thu, 30 Jan 2025 11:12:00 GMT'), ('github-authentication-token-expiration', '2026-05-16 11:52:29 +0200'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-accepted-github-permissions', 'contents=read'), ('x-github-api-version-selected', '2022-11-28'), ('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'), ('Transfer-Encoding', 'chunked'), ('Server', 'github.com'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4993'), ('X-RateLimit-Reset', '1774301230'), ('X-RateLimit-Used', '7'), ('X-RateLimit-Resource', 'core'), ('X-GitHub-Request-Id', 'F876:162E:160795EC:1307CB04:69C1A328')]
10+
{"url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/197548596","assets_url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/197548596/assets","upload_url":"https://uploads.github.com/repos/EnricoMi/PyGithub/releases/197548596/assets{?name,label}","html_url":"https://github.com/EnricoMi/PyGithub/releases/tag/v1.55","id":197548596,"author":{"login":"EnricoMi","id":44700269,"node_id":"MDQ6VXNlcjQ0NzAwMjY5","avatar_url":"https://avatars.githubusercontent.com/u/44700269?v=4","gravatar_id":"","url":"https://api.github.com/users/EnricoMi","html_url":"https://github.com/EnricoMi","followers_url":"https://api.github.com/users/EnricoMi/followers","following_url":"https://api.github.com/users/EnricoMi/following{/other_user}","gists_url":"https://api.github.com/users/EnricoMi/gists{/gist_id}","starred_url":"https://api.github.com/users/EnricoMi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EnricoMi/subscriptions","organizations_url":"https://api.github.com/users/EnricoMi/orgs","repos_url":"https://api.github.com/users/EnricoMi/repos","events_url":"https://api.github.com/users/EnricoMi/events{/privacy}","received_events_url":"https://api.github.com/users/EnricoMi/received_events","type":"User","user_view_type":"public","site_admin":false},"node_id":"MDc6UmVsZWFzZTE5NzU0ODU5Ng==","tag_name":"v1.55","target_commitish":"main","name":"Test Release","draft":false,"immutable":false,"prerelease":true,"created_at":"2021-04-26T04:43:40Z","updated_at":"2025-01-30T11:12:00Z","published_at":"2025-01-30T11:12:00Z","assets":[{"url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/assets/224868540","id":224868540,"node_id":"RA_kwDOGpsAJ84NZzi8","name":"asset1.md","label":null,"uploader":{"login":"EnricoMi","id":44700269,"node_id":"MDQ6VXNlcjQ0NzAwMjY5","avatar_url":"https://avatars.githubusercontent.com/u/44700269?v=4","gravatar_id":"","url":"https://api.github.com/users/EnricoMi","html_url":"https://github.com/EnricoMi","followers_url":"https://api.github.com/users/EnricoMi/followers","following_url":"https://api.github.com/users/EnricoMi/following{/other_user}","gists_url":"https://api.github.com/users/EnricoMi/gists{/gist_id}","starred_url":"https://api.github.com/users/EnricoMi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EnricoMi/subscriptions","organizations_url":"https://api.github.com/users/EnricoMi/orgs","repos_url":"https://api.github.com/users/EnricoMi/repos","events_url":"https://api.github.com/users/EnricoMi/events{/privacy}","received_events_url":"https://api.github.com/users/EnricoMi/received_events","type":"User","user_view_type":"public","site_admin":false},"content_type":"text/markdown","state":"uploaded","size":2524,"digest":null,"download_count":39,"created_at":"2025-01-30T11:11:32Z","updated_at":"2025-01-30T11:12:00Z","browser_download_url":"https://github.com/EnricoMi/PyGithub/releases/download/v1.55/asset1.md"},{"url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/assets/224868556","id":224868556,"node_id":"RA_kwDOGpsAJ84NZzjM","name":"asset2.gz","label":null,"uploader":{"login":"EnricoMi","id":44700269,"node_id":"MDQ6VXNlcjQ0NzAwMjY5","avatar_url":"https://avatars.githubusercontent.com/u/44700269?v=4","gravatar_id":"","url":"https://api.github.com/users/EnricoMi","html_url":"https://github.com/EnricoMi","followers_url":"https://api.github.com/users/EnricoMi/followers","following_url":"https://api.github.com/users/EnricoMi/following{/other_user}","gists_url":"https://api.github.com/users/EnricoMi/gists{/gist_id}","starred_url":"https://api.github.com/users/EnricoMi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EnricoMi/subscriptions","organizations_url":"https://api.github.com/users/EnricoMi/orgs","repos_url":"https://api.github.com/users/EnricoMi/repos","events_url":"https://api.github.com/users/EnricoMi/events{/privacy}","received_events_url":"https://api.github.com/users/EnricoMi/received_events","type":"User","user_view_type":"public","site_admin":false},"content_type":"application/gzip","state":"uploaded","size":1199,"digest":null,"download_count":31,"created_at":"2025-01-30T11:11:37Z","updated_at":"2025-01-30T11:12:00Z","browser_download_url":"https://github.com/EnricoMi/PyGithub/releases/download/v1.55/asset2.gz"}],"tarball_url":"https://api.github.com/repos/EnricoMi/PyGithub/tarball/v1.55","zipball_url":"https://api.github.com/repos/EnricoMi/PyGithub/zipball/v1.55","body":"This is a test released used by PyGithub tests."}
11+
12+
https
13+
GET
14+
api.github.com
15+
None
16+
/repos/EnricoMi/PyGithub/releases/197548596/assets
17+
{'Authorization': 'token private_token_removed', 'User-Agent': 'PyGithub/Python'}
18+
None
19+
200
20+
[('Date', 'Mon, 23 Mar 2026 20:31:37 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"02f2c96627cfc5be40bfaaa25813a5dc4b58711b13a846cb8d3c526b81ede7b1"'), ('github-authentication-token-expiration', '2026-05-16 11:52:29 +0200'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-accepted-github-permissions', 'contents=read'), ('x-github-api-version-selected', '2022-11-28'), ('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'), ('Transfer-Encoding', 'chunked'), ('Server', 'github.com'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4992'), ('X-RateLimit-Reset', '1774301230'), ('X-RateLimit-Used', '8'), ('X-RateLimit-Resource', 'core'), ('X-GitHub-Request-Id', 'F0E4:1633:B919C6:9A117B:69C1A328')]
21+
[{"url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/assets/224868540","id":224868540,"node_id":"RA_kwDOGpsAJ84NZzi8","name":"asset1.md","label":null,"uploader":{"login":"EnricoMi","id":44700269,"node_id":"MDQ6VXNlcjQ0NzAwMjY5","avatar_url":"https://avatars.githubusercontent.com/u/44700269?v=4","gravatar_id":"","url":"https://api.github.com/users/EnricoMi","html_url":"https://github.com/EnricoMi","followers_url":"https://api.github.com/users/EnricoMi/followers","following_url":"https://api.github.com/users/EnricoMi/following{/other_user}","gists_url":"https://api.github.com/users/EnricoMi/gists{/gist_id}","starred_url":"https://api.github.com/users/EnricoMi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EnricoMi/subscriptions","organizations_url":"https://api.github.com/users/EnricoMi/orgs","repos_url":"https://api.github.com/users/EnricoMi/repos","events_url":"https://api.github.com/users/EnricoMi/events{/privacy}","received_events_url":"https://api.github.com/users/EnricoMi/received_events","type":"User","user_view_type":"public","site_admin":false},"content_type":"text/markdown","state":"uploaded","size":2524,"digest":null,"download_count":39,"created_at":"2025-01-30T11:11:32Z","updated_at":"2025-01-30T11:12:00Z","browser_download_url":"https://github.com/EnricoMi/PyGithub/releases/download/v1.55/asset1.md"},{"url":"https://api.github.com/repos/EnricoMi/PyGithub/releases/assets/224868556","id":224868556,"node_id":"RA_kwDOGpsAJ84NZzjM","name":"asset2.gz","label":null,"uploader":{"login":"EnricoMi","id":44700269,"node_id":"MDQ6VXNlcjQ0NzAwMjY5","avatar_url":"https://avatars.githubusercontent.com/u/44700269?v=4","gravatar_id":"","url":"https://api.github.com/users/EnricoMi","html_url":"https://github.com/EnricoMi","followers_url":"https://api.github.com/users/EnricoMi/followers","following_url":"https://api.github.com/users/EnricoMi/following{/other_user}","gists_url":"https://api.github.com/users/EnricoMi/gists{/gist_id}","starred_url":"https://api.github.com/users/EnricoMi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EnricoMi/subscriptions","organizations_url":"https://api.github.com/users/EnricoMi/orgs","repos_url":"https://api.github.com/users/EnricoMi/repos","events_url":"https://api.github.com/users/EnricoMi/events{/privacy}","received_events_url":"https://api.github.com/users/EnricoMi/received_events","type":"User","user_view_type":"public","site_admin":false},"content_type":"application/gzip","state":"uploaded","size":1199,"digest":null,"download_count":31,"created_at":"2025-01-30T11:11:37Z","updated_at":"2025-01-30T11:12:00Z","browser_download_url":"https://github.com/EnricoMi/PyGithub/releases/download/v1.55/asset2.gz"}]

0 commit comments

Comments
 (0)