Skip to content

Commit 65f4a0e

Browse files
committed
performance boost/ code cleanup
1 parent e242007 commit 65f4a0e

File tree

3 files changed

+68
-34
lines changed

3 files changed

+68
-34
lines changed

github_stats.py

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import aiohttp
88
import requests
9+
import uvloop
910

11+
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) # use uvloop
1012

1113
###############################################################################
1214
# Main Classes
@@ -37,17 +39,19 @@ async def query(self, generated_query: str) -> Dict:
3739
}
3840
try:
3941
async with self.semaphore:
40-
r = await self.session.post("https://api.github.com/graphql",
41-
headers=headers,
42-
json={"query": generated_query})
42+
r = await self.session.post(
43+
"https://api.github.com/graphql",
44+
headers=headers,
45+
json={"query": generated_query}
46+
)
4347
return await r.json()
4448
except:
45-
print("aiohttp failed for GraphQL query")
46-
# Fall back on non-async requests
4749
async with self.semaphore:
48-
r = requests.post("https://api.github.com/graphql",
49-
headers=headers,
50-
json={"query": generated_query})
50+
r = requests.post(
51+
"https://api.github.com/graphql",
52+
headers=headers,
53+
json={"query": generated_query}
54+
)
5155
return r.json()
5256

5357
async def query_rest(self, path: str, params: Optional[Dict] = None) -> Dict:
@@ -58,21 +62,21 @@ async def query_rest(self, path: str, params: Optional[Dict] = None) -> Dict:
5862
:return: deserialized REST JSON output
5963
"""
6064

61-
for _ in range(60):
62-
headers = {
63-
"Authorization": f"token {self.access_token}",
65+
headers = {
66+
"Authorization": f"token {self.access_token}",
6467
}
65-
if params is None:
66-
params = dict()
67-
if path.startswith("/"):
68-
path = path[1:]
68+
if params is None:
69+
params = dict()
70+
if path.startswith("/"):
71+
path = path[1:]
72+
73+
for _ in range(60):
6974
try:
7075
async with self.semaphore:
7176
r = await self.session.get(f"https://api.github.com/{path}",
7277
headers=headers,
7378
params=tuple(params.items()))
7479
if r.status == 202:
75-
# print(f"{path} returned 202. Retrying...")
7680
print(f"A path returned 202. Retrying...")
7781
await asyncio.sleep(2)
7882
continue
@@ -466,24 +470,23 @@ async def lines_changed(self) -> Tuple[int, int]:
466470
"""
467471
if self._lines_changed is not None:
468472
return self._lines_changed
469-
additions = 0
470-
deletions = 0
471-
for repo in await self.all_repos:
473+
474+
async def fetch(repo):
475+
additions, deletions = 0, 0
472476
r = await self.queries.query_rest(f"/repos/{repo}/stats/contributors")
473477
for author_obj in r:
474-
# Handle malformed response from the API by skipping this repo
475-
if (not isinstance(author_obj, dict)
476-
or not isinstance(author_obj.get("author", {}), dict)):
478+
if not isinstance(author_obj, dict) or not isinstance(author_obj.get("author", {}), dict):
477479
continue
478-
author = author_obj.get("author", {}).get("login", "")
479-
if author != self.username:
480+
if author_obj.get("author", {}).get("login", "") != self.username:
480481
continue
481-
482482
for week in author_obj.get("weeks", []):
483483
additions += week.get("a", 0)
484484
deletions += week.get("d", 0)
485+
self._lines_changed = (additions, deletions)
486+
return additions, deletions
485487

486-
self._lines_changed = (additions, deletions)
488+
results = await asyncio.gather(*[fetch(repo) for repo in await self.all_repos])
489+
self._lines_changed = (sum(r[0] for r in results), sum(r[1] for r in results))
487490
return self._lines_changed
488491

489492
@property
@@ -495,15 +498,12 @@ async def views(self) -> int:
495498
if self._views is not None:
496499
return self._views
497500

498-
total = 0
499-
for repo in await self.repos:
501+
async def fetch(repo):
500502
r = await self.queries.query_rest(f"/repos/{repo}/traffic/views")
501-
for view in r.get("views", []):
502-
total += view.get("count", 0)
503-
504-
self._views = total
505-
return total
503+
return sum(view.get("count", 0) for view in r.get("views", []))
506504

505+
self._views = sum(await asyncio.gather(*[fetch(repo) for repo in await self.repos]))
506+
return self._views
507507

508508
###############################################################################
509509
# Main Function
@@ -519,6 +519,5 @@ async def main() -> None:
519519
s = Stats(user, access_token, session)
520520
print(await s.to_str())
521521

522-
523522
if __name__ == "__main__":
524523
asyncio.run(main())

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ requires-python = ">=3.12"
77
dependencies = [
88
"aiohttp>=3.13.2",
99
"requests>=2.32.5",
10+
"uvloop>=0.22.1",
1011
]

uv.lock

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)