Skip to content

Commit a600ba4

Browse files
committed
add github stars stat
1 parent 06824e4 commit a600ba4

File tree

1 file changed

+80
-57
lines changed

1 file changed

+80
-57
lines changed

src/writegithubstat/githubstat.py

Lines changed: 80 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
from abc import ABC, abstractmethod
22
import os
3+
from pathlib import Path
34
import logging
45
import requests
56
from datetime import date
67

78
import pandas as pd
89

910

10-
class _GithubAuth:
11+
class GithubAuth:
1112
def __init__(self, owner: str, repo: str, token: str) -> None:
12-
self._header = _GithubAuth._get_auth_header(token)
13-
self._repo_id = _GithubAuth._get_repo_id(owner, repo, self._header)
13+
self._owner = owner
14+
self._repo = repo
15+
self._header = GithubAuth._get_auth_header(token)
16+
self._repo_id = GithubAuth._get_repo_id(self._owner, self._repo, self._header)
1417

1518
@staticmethod
1619
def _get_auth_header(token: str) -> dict:
@@ -29,42 +32,33 @@ def _get_repo_id(owner: str, repo: str, auth_header: str) -> str:
2932
return repository["id"]
3033
else:
3134
raise requests.HTTPError(
32-
f"Request failed with status code {response.status_code}"
35+
f"Request failed with status code {response.status_code}: {response.text}"
3336
)
3437

3538
@property
36-
def header(self) -> dict:
37-
return self._header
39+
def owner(self) -> str:
40+
return self._owner
41+
42+
@property
43+
def repo(self) -> str:
44+
return self._repo
3845

3946
@property
4047
def repo_id(self) -> str:
4148
return self._repo_id
4249

50+
@property
51+
def header(self) -> dict:
52+
return self._header
4353

44-
class _GithubStat:
45-
@staticmethod
46-
def _dict_to_dataframe(data) -> pd.DataFrame:
47-
df = pd.DataFrame(data)
48-
return df
49-
50-
@staticmethod
51-
def _get_stat(auth: _GithubAuth, path: str) -> pd.DataFrame:
52-
url = f"https://api.github.com/repositories/{auth.repo_id}/{path}"
53-
response = requests.get(url, headers=auth.header)
54-
if response.status_code == 200:
55-
raw_data = response.json()
56-
data = _GithubStat._dict_to_dataframe(raw_data)
57-
return data
58-
else:
59-
raise requests.HTTPError(
60-
f"Request failed with status code {response.status_code}"
61-
)
6254

55+
class GithubStatType(ABC):
56+
def __init__(self, auth: GithubAuth) -> None:
57+
self._auth = auth
6358

64-
class _GithubStatType(ABC):
6559
@property
6660
@abstractmethod
67-
def path(self):
61+
def url(self):
6862
pass
6963

7064
@property
@@ -77,16 +71,15 @@ def dimensions(self):
7771
def measures(self):
7872
pass
7973

80-
@property
81-
@abstractmethod
82-
def name(self):
74+
@staticmethod
75+
def process_stat(data):
8376
pass
8477

8578

86-
class Referrers(_GithubStatType):
79+
class Referrers(GithubStatType):
8780
@property
88-
def path(self):
89-
return "traffic/popular/referrers"
81+
def url(self):
82+
return f"https://api.github.com/repositories/{self._auth.repo_id}/traffic/popular/referrers"
9083

9184
@property
9285
def dimensions(self):
@@ -96,15 +89,16 @@ def dimensions(self):
9689
def measures(self):
9790
return ["count", "uniques"]
9891

99-
@property
100-
def name(self):
101-
return "referrers"
92+
@staticmethod
93+
def process_stat(data):
94+
df = pd.DataFrame(data)
95+
return df
10296

10397

104-
class Paths(_GithubStatType):
98+
class Paths(GithubStatType):
10599
@property
106-
def path(self):
107-
return "traffic/popular/paths"
100+
def url(self):
101+
return f"https://api.github.com/repositories/{self._auth.repo_id}/traffic/popular/paths"
108102

109103
@property
110104
def dimensions(self):
@@ -114,34 +108,63 @@ def dimensions(self):
114108
def measures(self):
115109
return ["count", "uniques"]
116110

111+
@staticmethod
112+
def process_stat(data):
113+
df = pd.DataFrame(data)
114+
return df
115+
116+
117+
class Stars(GithubStatType):
118+
@property
119+
def url(self):
120+
return f"https://api.github.com/repos/{self._auth.owner}/{self._auth.repo}"
121+
117122
@property
118-
def name(self):
119-
return "paths"
123+
def dimensions(self):
124+
return []
125+
126+
@property
127+
def measures(self):
128+
return ["stars_cumulative"]
129+
130+
@staticmethod
131+
def process_stat(data):
132+
stars = data["stargazers_count"]
133+
df = pd.DataFrame({"stars_cumulative": [stars]})
134+
return df
135+
136+
137+
class _GithubStat:
138+
@staticmethod
139+
def _get_stat(stat_type: GithubStatType, auth_header: dict) -> pd.DataFrame:
140+
response = requests.get(stat_type.url, headers=auth_header)
141+
if response.status_code == 200:
142+
return stat_type.process_stat(response.json())
143+
else:
144+
raise requests.HTTPError(
145+
f"Request failed with status code {response.status_code}: {response.text}"
146+
)
120147

121148

122149
class WriteGithubStat:
123-
def __init__(self, owner: str, repo: str, token: str) -> None:
150+
def __init__(self, auth: GithubAuth) -> None:
124151
self._date = date.today().strftime("%Y-%m-%d")
125-
self._owner = owner
126-
self._repo = repo
127-
self._auth = _GithubAuth(self._owner, self._repo, token)
152+
self._auth = auth
128153

129-
def write_stats(self, outdir: str, prefix: str) -> None:
130-
os.makedirs(outdir, exist_ok=True)
131-
for stat_type in Referrers(), Paths():
132-
self._write_stat(stat_type, outdir, prefix)
154+
@property
155+
def date(self) -> str:
156+
return self._date
133157

134-
def _write_stat(self, stat_type: _GithubStatType, outdir: str, prefix: str) -> None:
135-
year = self._date[0:4]
136-
csv = f"{outdir}/{year}_{prefix}_githubstat_{stat_type.name}.csv"
158+
def write_stat(self, stat_type: GithubStatType, csv: Path) -> None:
159+
os.makedirs(csv.parent, exist_ok=True)
137160
stats = self._get_stats(stat_type)
138161
logging.info(stats)
139162
stored_stats = self._get_stored_stats(csv)
140163
merged_stats = self._merge_stats(stored_stats, stats)
141164
merged_stats.to_csv(csv, index=False)
142165

143-
def _get_stats(self, stat_type: _GithubStatType) -> pd.DataFrame:
144-
stat = _GithubStat._get_stat(self._auth, stat_type.path)
166+
def _get_stats(self, stat_type: GithubStatType) -> pd.DataFrame:
167+
stat = _GithubStat._get_stat(stat_type, self._auth.header)
145168
if stat.empty:
146169
empty = {
147170
**{col: "-" for col in stat_type.dimensions},
@@ -153,8 +176,8 @@ def _get_stats(self, stat_type: _GithubStatType) -> pd.DataFrame:
153176

154177
def _insert_metadata(self, df: pd.DataFrame) -> pd.DataFrame:
155178
df.insert(0, "date", self._date)
156-
df.insert(1, "owner", self._owner)
157-
df.insert(2, "repo", self._repo)
179+
df.insert(1, "owner", self._auth.owner)
180+
df.insert(2, "repo", self._auth.repo)
158181
return df
159182

160183
def _get_stored_stats(self, path: str) -> pd.DataFrame:
@@ -171,8 +194,8 @@ def _merge_stats(
171194
stored_stats = stored_stats.drop(
172195
stored_stats[
173196
(stored_stats["date"] == self._date)
174-
& (stored_stats["owner"] == self._owner)
175-
& (stored_stats["repo"] == self._repo)
197+
& (stored_stats["owner"] == self._auth.owner)
198+
& (stored_stats["repo"] == self._auth.repo)
176199
].index
177200
)
178201
stats = pd.concat([stored_stats, stats])

0 commit comments

Comments
 (0)