1919Actions runner, so there is nothing to install.
2020"""
2121
22- from __future__ import annotations
23-
2422import datetime as dt
25- import json
2623import os
2724import re
2825import sys
2926import time
30- import urllib .error
31- import urllib .parse
32- import urllib .request
27+
28+ import httpx2
3329
3430REPO = os .environ .get ("GITHUB_REPOSITORY" , "TheAlgorithms/Python" )
3531TOKEN = os .environ .get ("GITHUB_TOKEN" , "" )
4541STATS_HEADER = "## Automated statistics"
4642
4743
48- def _request (url : str ) -> tuple [dict | list , dict ]:
44+ def _request (url : str , params : dict | None = None ) -> tuple [dict | list , dict ]:
4945 """GET ``url`` and return ``(json_body, headers)``, retrying on 403/rate limit."""
5046 headers = {
5147 "Accept" : "application/vnd.github+json" ,
@@ -55,29 +51,26 @@ def _request(url: str) -> tuple[dict | list, dict]:
5551 if TOKEN :
5652 headers ["Authorization" ] = f"Bearer { TOKEN } "
5753 for attempt in range (4 ):
58- req = urllib .request .Request (url , headers = headers ) # noqa: S310
59- try :
60- with urllib .request .urlopen (req , timeout = 30 ) as resp : # noqa: S310
61- return json .load (resp ), dict (resp .headers )
62- except urllib .error .HTTPError as exc :
63- remaining = exc .headers .get ("X-RateLimit-Remaining" )
64- if exc .code in (403 , 429 ) and remaining == "0" :
65- reset = int (exc .headers .get ("X-RateLimit-Reset" , "0" ))
66- wait = max (1 , reset - int (time .time ())) + 1
67- print (f"Rate limited; sleeping { wait } s" , file = sys .stderr )
68- time .sleep (min (wait , 90 ))
69- continue
70- if exc .code >= 500 and attempt < 3 :
71- time .sleep (2 * (attempt + 1 ))
72- continue
73- raise
54+ resp = httpx2 .get (url , params = params , headers = headers , timeout = 30 )
55+ if resp .is_success :
56+ return resp .json (), dict (resp .headers )
57+ remaining = resp .headers .get ("X-RateLimit-Remaining" )
58+ if resp .status_code in (403 , 429 ) and remaining == "0" :
59+ reset = int (resp .headers .get ("X-RateLimit-Reset" , "0" ))
60+ wait = max (1 , reset - int (time .time ())) + 1
61+ print (f"Rate limited; sleeping { wait } s" , file = sys .stderr )
62+ time .sleep (min (wait , 90 ))
63+ continue
64+ if resp .status_code >= 500 and attempt < 3 :
65+ time .sleep (2 * (attempt + 1 ))
66+ continue
67+ resp .raise_for_status ()
7468 msg = f"giving up on { url } "
7569 raise RuntimeError (msg )
7670
7771
7872def _search_count (query : str ) -> int :
79- url = f"{ API } /search/issues?q={ urllib .parse .quote (query )} &per_page=1"
80- body , _ = _request (url )
73+ body , _ = _request (f"{ API } /search/issues" , {"q" : query , "per_page" : 1 })
8174 return int (body .get ("total_count" , 0 )) # type: ignore[union-attr]
8275
8376
@@ -98,17 +91,18 @@ def top_awaiting_directories(
9891 page = 1
9992 scanned = 0
10093 while scanned < max_prs :
101- url = (
102- f"{ API } /search/issues?q= { urllib . parse . quote ( query ) } "
103- f"& per_page= 100& page= { page } "
94+ body , _ = _request (
95+ f"{ API } /search/issues" ,
96+ { "q" : query , " per_page" : 100 , " page" : page },
10497 )
105- body , _ = _request (url )
10698 items = body .get ("items" , []) # type: ignore[union-attr]
10799 if not items :
108100 break
109101 for item in items :
110102 number = item ["number" ]
111- files , _ = _request (f"{ API } /repos/{ REPO } /pulls/{ number } /files?per_page=100" )
103+ files , _ = _request (
104+ f"{ API } /repos/{ REPO } /pulls/{ number } /files" , {"per_page" : 100 }
105+ )
112106 dirs = set ()
113107 for changed in files : # type: ignore[union-attr]
114108 parts = changed ["filename" ].split ("/" )
0 commit comments