@@ -51,7 +51,7 @@ async def query(self, generated_query: str) -> Dict:
5151 result = await r_async .json ()
5252 if result is not None :
5353 return result
54- except :
54+ except Exception :
5555 print ("aiohttp failed for GraphQL query" )
5656 # Fall back on non-async requests
5757 async with self .semaphore :
@@ -97,7 +97,7 @@ async def query_rest(self, path: str, params: Optional[Dict] = None) -> Dict:
9797 result = await r_async .json ()
9898 if result is not None :
9999 return result
100- except :
100+ except Exception :
101101 print ("aiohttp failed for rest query" )
102102 # Fall back on non-async requests
103103 async with self .semaphore :
@@ -111,11 +111,47 @@ async def query_rest(self, path: str, params: Optional[Dict] = None) -> Dict:
111111 await asyncio .sleep (2 )
112112 continue
113113 elif r_requests .status_code == 200 :
114- return r_requests .json ()
114+ result_json = r_requests .json ()
115+ if result_json is not None :
116+ return result_json
115117 # print(f"There were too many 202s. Data for {path} will be incomplete.")
116118 print ("There were too many 202s. Data for this repository will be incomplete." )
117119 return dict ()
118120
121+ @staticmethod
122+ def summary_query () -> str :
123+ """
124+ :return: GraphQL query with summary of user stats
125+ """
126+ return f"""query {{
127+ viewer {{
128+ login
129+ name
130+ repositories(first: 100, ownerAffiliations: OWNER, isFork: false) {{
131+ totalCount
132+ edges {{
133+ node {{
134+ stargazers {{
135+ totalCount
136+ }}
137+ forkCount
138+ }}
139+ }}
140+ }}
141+ pullRequests(first: 1) {{
142+ totalCount
143+ }}
144+ issues(first: 1) {{
145+ totalCount
146+ }}
147+ contributionsCollection {{
148+ totalCommitContributions
149+ restrictedContributionsCount
150+ }}
151+ }}
152+ }}
153+ """
154+
119155 @staticmethod
120156 def repos_overview (
121157 contrib_cursor : Optional [str ] = None , owned_cursor : Optional [str ] = None
@@ -125,8 +161,8 @@ def repos_overview(
125161 """
126162 return f"""{{
127163 viewer {{
128- login,
129- name,
164+ login
165+ name
130166 repositories(
131167 first: 100,
132168 orderBy: {{
@@ -258,22 +294,26 @@ def __init__(
258294 exclude_repos : Optional [Set ] = None ,
259295 exclude_langs : Optional [Set ] = None ,
260296 ignore_forked_repos : bool = False ,
297+ emails : Optional [List [str ]] = None ,
261298 ):
262299 self .username = username
263300 self ._ignore_forked_repos = ignore_forked_repos
264301 self ._exclude_repos = set () if exclude_repos is None else exclude_repos
265302 self ._exclude_langs = set () if exclude_langs is None else exclude_langs
266303 self .queries = Queries (username , access_token , session )
304+ self ._emails = emails
267305
268306 self ._name : Optional [str ] = None
269307 self ._stargazers : Optional [int ] = None
270308 self ._forks : Optional [int ] = None
271309 self ._total_contributions : Optional [int ] = None
310+ self ._total_commits : Optional [int ] = None
311+ self ._prs : Optional [int ] = None
312+ self ._issues : Optional [int ] = None
272313 self ._languages : Optional [Dict [str , Any ]] = None
273314 self ._repos : Optional [Set [str ]] = None
274315 self ._lines_changed : Optional [Tuple [int , int ]] = None
275316 self ._views : Optional [int ] = None
276- self ._emails : Optional [Set [str ]] = None # Add this line
277317
278318 async def to_str (self ) -> str :
279319 """
@@ -296,6 +336,36 @@ async def to_str(self) -> str:
296336Languages:
297337 - { formatted_languages } """
298338
339+ async def get_summary_stats (self ) -> None :
340+ """
341+ Get lots of summary statistics using one big query. Sets many attributes
342+ """
343+ raw_results = await self .queries .query (self .queries .summary_query ())
344+ if raw_results is None :
345+ return
346+ viewer = raw_results .get ("data" , {}).get ("viewer" , {})
347+ if not viewer :
348+ return
349+
350+ self ._name = viewer .get ("name" ) or viewer .get ("login" , "No Name" )
351+ self ._stargazers = sum (
352+ [
353+ repo ["node" ]["stargazers" ]["totalCount" ]
354+ for repo in viewer ["repositories" ]["edges" ]
355+ ]
356+ )
357+ self ._forks = sum (
358+ [repo ["node" ]["forkCount" ] for repo in viewer ["repositories" ]["edges" ]]
359+ )
360+
361+ self ._prs = viewer .get ("pullRequests" , {}).get ("totalCount" , 0 )
362+ self ._issues = viewer .get ("issues" , {}).get ("totalCount" , 0 )
363+ contributions = viewer .get ("contributionsCollection" , {})
364+ self ._total_commits = (
365+ contributions .get ("totalCommitContributions" , 0 )
366+ + contributions .get ("restrictedContributionsCount" , 0 )
367+ )
368+
299369 async def get_stats (self ) -> None :
300370 """
301371 Get lots of summary statistics using one big query. Sets many attributes
@@ -345,8 +415,8 @@ async def get_stats(self) -> None:
345415 if name in self ._repos or name in self ._exclude_repos :
346416 continue
347417 self ._repos .add (name )
348- self ._stargazers += repo .get ("stargazers" ).get ("totalCount" , 0 )
349- self ._forks += repo .get ("forkCount" , 0 )
418+ # self._stargazers += repo.get("stargazers").get("totalCount", 0)
419+ # self._forks += repo.get("forkCount", 0)
350420
351421 for lang in repo .get ("languages" , {}).get ("edges" , []):
352422 name = lang .get ("node" , {}).get ("name" , "Other" )
@@ -375,11 +445,9 @@ async def get_stats(self) -> None:
375445 else :
376446 break
377447
378- # TODO: Improve languages to scale by number of contributions to
379- # specific filetypes
380448 langs_total = sum ([v .get ("size" , 0 ) for v in self ._languages .values ()])
381449 for k , v in self ._languages .items ():
382- v ["prop" ] = 100 * (v .get ("size" , 0 ) / langs_total )
450+ v ["prop" ] = 100 * (v .get ("size" , 0 ) / langs_total ) if langs_total > 0 else 0
383451
384452 @property
385453 async def name (self ) -> str :
@@ -388,7 +456,7 @@ async def name(self) -> str:
388456 """
389457 if self ._name is not None :
390458 return self ._name
391- await self .get_stats ()
459+ await self .get_summary_stats ()
392460 assert self ._name is not None
393461 return self ._name
394462
@@ -399,7 +467,7 @@ async def stargazers(self) -> int:
399467 """
400468 if self ._stargazers is not None :
401469 return self ._stargazers
402- await self .get_stats ()
470+ await self .get_summary_stats ()
403471 assert self ._stargazers is not None
404472 return self ._stargazers
405473
@@ -410,7 +478,7 @@ async def forks(self) -> int:
410478 """
411479 if self ._forks is not None :
412480 return self ._forks
413- await self .get_stats ()
481+ await self .get_summary_stats ()
414482 assert self ._forks is not None
415483 return self ._forks
416484
@@ -493,7 +561,7 @@ async def lines_changed(self) -> Tuple[int, int]:
493561 ):
494562 continue
495563 author = author_obj .get ("author" , {}).get ("login" , "" )
496- if author != self .username :
564+ if author . lower () != self .username . lower () :
497565 continue
498566
499567 for week in author_obj .get ("weeks" , []):
@@ -520,62 +588,39 @@ async def views(self) -> int:
520588
521589 self ._views = total
522590 return total
523-
591+
592+ @property
524593 async def total_commits (self ) -> int :
525594 """
526595 Get the total number of commits made by the user.
527596 """
597+ if self ._total_commits is not None :
598+ return self ._total_commits
599+ await self .get_summary_stats ()
600+ assert self ._total_commits is not None
601+ return self ._total_commits
528602
529- total_commits = 0
530- for email in self ._emails :
531- query = """
532- query {
533- user(login: "%s") {
534- contributionsCollection {
535- totalCommitContributions
536- }
537- }
538- }
539- """ % self .username
540- print (f"Running query for email: { email } " )
541- response = await self .queries .query (query )
542- print (f"Response for email { email } : { response } " )
543- if 'data' in response and 'user' in response ['data' ]:
544- total_commits += response ['data' ]['user' ]['contributionsCollection' ]['totalCommitContributions' ]
545- else :
546- print (f"Error: 'data' or 'user' not found in response for email { email } " )
547- print (response )
548- print (f"Total commits: { total_commits } " )
549- return total_commits
550-
551- query = """
552- query {
553- user(login: "%s") {
554- contributionsCollection {
555- totalCommitContributions
556- }
557- }
558- }
559- """ % self .username
560- response = await self .queries .query (query )
561- return response ["data" ]["user" ]["contributionsCollection" ]["totalCommitContributions" ]
562-
563-
564- async def total_prs (self ) -> int :
603+ @property
604+ async def prs (self ) -> int :
565605 """
566606 Get the total number of pull requests made by the user.
567607 """
568- query = """
569- query {
570- user(login: "%s") {
571- pullRequests {
572- totalCount
573- }
574- }
575- }
576- """ % self .username
577- response = await self .queries .query (query )
578- return response ["data" ]["user" ]["pullRequests" ]["totalCount" ]
608+ if self ._prs is not None :
609+ return self ._prs
610+ await self .get_summary_stats ()
611+ assert self ._prs is not None
612+ return self ._prs
613+
614+ @property
615+ async def issues (self ) -> int :
616+ """
617+ Get the total number of issues opened by the user.
618+ """
619+ if self ._issues is not None :
620+ return self ._issues
621+ await self .get_summary_stats ()
622+ assert self ._issues is not None
623+ return self ._issues
579624
580625###############################################################################
581626# Main Function
0 commit comments