MCPcopy Index your code
hub / github.com/PyGithub/PyGithub / GithubRetry

Class GithubRetry

github/GithubRetry.py:54–234  ·  view source on GitHub ↗

A Github-specific implementation of `urllib3.Retry` This retries 403 responses if they are retry-able. Github requests are retry-able when the response provides a `"Retry-After"` header, or the content indicates a rate limit error. By default, response codes 403, and 500 up to 599

Source from the content-addressed store, hash-verified

52
53
54class GithubRetry(Retry):
55 """
56 A Github-specific implementation of `urllib3.Retry`
57
58 This retries 403 responses if they are retry-able. Github requests are retry-able when
59 the response provides a `"Retry-After"` header, or the content indicates a rate limit error.
60
61 By default, response codes 403, and 500 up to 599 are retried. This can be configured
62 via the `status_forcelist` argument.
63
64 By default, all methods defined in `Retry.DEFAULT_ALLOWED_METHODS` are retried, plus GET and POST.
65 This can be configured via the `allowed_methods` argument.
66
67 """
68
69 __logger: Logger | None = None
70
71 # used to mock datetime, mock.patch("github.GithubRetry.date") does not work as this
72 # references the class, not the module (due to re-exporting in github/__init__.py)
73 __datetime = datetime
74
75 def __init__(self, secondary_rate_wait: float = DEFAULT_SECONDARY_RATE_WAIT, **kwargs: Any) -> None:
76 """
77 :param secondary_rate_wait: seconds to wait before retrying secondary rate limit errors
78 :param kwargs: see urllib3.Retry for more arguments
79 """
80 self.secondary_rate_wait = secondary_rate_wait
81 # 403 is too broad to be retried, but GitHub API signals rate limits via 403
82 # we retry 403 and look into the response header via Retry.increment
83 # to determine if we really retry that 403
84 kwargs["status_forcelist"] = kwargs.get("status_forcelist", list(range(500, 600))) + [403]
85 kwargs["allowed_methods"] = kwargs.get("allowed_methods", Retry.DEFAULT_ALLOWED_METHODS.union({"GET", "POST"}))
86 super().__init__(**kwargs)
87
88 def new(self, **kw: Any) -> Self:
89 kw.update(dict(secondary_rate_wait=self.secondary_rate_wait))
90 return super().new(**kw) # type: ignore
91
92 def increment( # type: ignore[override]
93 self,
94 method: str | None = None,
95 url: str | None = None,
96 response: HTTPResponse | None = None, # type: ignore[override]
97 error: Exception | None = None,
98 _pool: ConnectionPool | None = None,
99 _stacktrace: TracebackType | None = None,
100 ) -> Retry:
101 if response:
102 # we retry 403 only when there is a Retry-After header (indicating it is retry-able)
103 # or the body message does imply a rate limit error
104 if response.status == 403:
105 self.__log(
106 logging.INFO,
107 f"Request {method} {url} failed with {response.status}: {response.reason}",
108 )
109 if "Retry-After" in response.headers:
110 # Sleeping 'Retry-After' seconds is implemented in urllib3.Retry.sleep() and called by urllib3
111 self.__log(

Callers 1

GithubClass · 0.90

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…