11from abc import ABC , abstractmethod
22import os
3+ from pathlib import Path
34import logging
45import requests
56from datetime import date
67
78import 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
122149class 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