3
3
An async client for accessing GitHub.
4
4
"""
5
5
6
+ import json
6
7
import logging
7
8
from collections .abc import AsyncGenerator
8
9
from enum import Enum
27
28
DEFAULT_MAX_RETRIES = 20
28
29
DEFAULT_PAGE_SIZE = 100
29
30
DEFAULT_MAX_RETRY_WAIT_SECONDS = 300 # 5 minutes
31
+ DEFAULT_GITHUB_HOST = "api.github.com"
30
32
31
33
32
34
logger = get_plugin_logger (__name__ )
@@ -41,36 +43,39 @@ def __init__(self, url: str | httpx.URL):
41
43
super ().__init__ (f"Rate limited when calling { url } " )
42
44
43
45
46
+ def _safe_get_json_error_message (response : httpx .Response ) -> str :
47
+ try :
48
+ return response .json ().get ("message" )
49
+ except AttributeError :
50
+ # ignore if no message
51
+ return json .dumps (response .json ())
52
+ except ValueError :
53
+ # ignore if no json
54
+ return response .text
55
+
56
+
44
57
def _fetch_problem (title : str , e : httpx .HTTPError ):
45
- if isinstance (e , httpx .HTTPStatusError ):
46
- error_message = None
47
- try :
48
- error_message = e .response .json ().get ("message" )
49
- except AttributeError :
50
- # ignore if no message
51
- pass
52
- except ValueError :
53
- # ignore if no json
54
- pass
55
-
56
- logger .warning (
57
- "%s %s - %s%s" ,
58
- e .response .status_code ,
59
- e .response .reason_phrase ,
60
- e .request .url .path ,
61
- f" - { error_message } " if error_message else "" ,
62
- stacklevel = 2 ,
63
- )
64
- else :
65
- logger .warning ("Problem fetching %s" , title , exc_info = e , stacklevel = 2 )
58
+ match e :
59
+ case httpx .HTTPStatusError (response = response ):
60
+ error_message = _safe_get_json_error_message (response )
61
+ logger .warning (
62
+ "%s %s - %s%s" ,
63
+ response .status_code ,
64
+ response .reason_phrase ,
65
+ e .request .url .path ,
66
+ f" - { error_message } " if error_message else "" ,
67
+ stacklevel = 2 ,
68
+ )
69
+ case _:
70
+ logger .warning ("Problem fetching %s" , title , exc_info = e , stacklevel = 2 )
66
71
67
72
68
73
class GithubRestApiClient :
69
74
def __init__ (
70
75
self ,
71
- auth_token : str ,
72
- github_hostname : str = "api.github.com" ,
73
76
* ,
77
+ auth_token : str | None = None ,
78
+ github_hostname : str | None = None ,
74
79
user_agent : str | None = None ,
75
80
per_page : int | None = None ,
76
81
max_retries : int | None = None ,
@@ -90,15 +95,18 @@ def __init__(
90
95
raise ValueError (msg )
91
96
92
97
self ._auth_token = auth_token
93
- if github_hostname != "api.github.com" :
94
- self ._base_url = f"https://{ github_hostname } /api/v3"
95
- else :
98
+ if github_hostname == "api.github.com" or github_hostname is None :
96
99
self ._base_url = "https://api.github.com"
100
+ else :
101
+ self ._base_url = f"https://{ github_hostname } /api/v3"
102
+
97
103
self ._per_page = per_page
98
104
self ._limit_storage = MemoryStorage ()
105
+ if not self .auth_token :
106
+ logger .warning ("Missing auth_token." )
99
107
self ._default_headers = httpx .Headers ({
100
108
"Accept" : "application/vnd.github+json" ,
101
- "Authorization" : "Bearer " + self .auth_token ,
109
+ "Authorization" : f "Bearer { self .auth_token } " ,
102
110
"X-GitHub-Api-Version" : "2022-11-28" ,
103
111
})
104
112
if user_agent :
0 commit comments