Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
134 lines (117 loc) · 4.32 KB
/
Copy pathutils.py
File metadata and controls
134 lines (117 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import pandas as pd
from datetime import datetime, timedelta
import streamlit as st
import json
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
def filter_repos_by_date(repos, start_date, end_date):
"""Filter repositories by creation date."""
filtered = []
for repo in repos:
created_at = datetime.strptime(repo['created_at'], '%Y-%m-%dT%H:%M:%SZ')
if start_date <= created_at.date() <= end_date:
filtered.append(repo)
return filtered
def filter_repos_by_size(repos, min_size, max_size):
"""Filter repositories by size (in KB)."""
return [repo for repo in repos if min_size <= repo['size'] <= max_size]
def calculate_total_languages(repos, api):
"""Calculate total language distribution across all repos."""
total_languages = {}
for repo in repos:
languages = api.get_repo_languages(repo['owner']['login'], repo['name'])
for lang, bytes_count in languages.items():
total_languages[lang] = total_languages.get(lang, 0) + bytes_count
return total_languages
def export_to_csv(data, filename):
"""Export data to CSV file."""
df = pd.DataFrame(data)
csv = df.to_csv(index=False)
return csv
@st.cache_data(ttl=3600) # Cache for 1 hour
def get_cached_repo_data(username, token):
"""Cache repository data to reduce API calls."""
cache_dir = ".cache"
if not os.path.exists(cache_dir):
os.makedirs(cache_dir)
cache_file = os.path.join(cache_dir, f".cache_{username}.json")
# Check if cache exists and is recent
if os.path.exists(cache_file):
try:
with open(cache_file, 'r') as f:
cache_data = json.load(f)
cache_time = datetime.fromisoformat(cache_data['timestamp'])
if datetime.now() - cache_time < timedelta(hours=1):
return cache_data['data']
except Exception:
pass # fallback to fetching fresh data if cache read/parse fails
# Fetch fresh data
from github_api import GitHubAPI
api = GitHubAPI(token)
repos = api.get_user_repos(username)
# Save to cache
cache_data = {
'timestamp': datetime.now().isoformat(),
'data': repos
}
try:
with open(cache_file, 'w') as f:
json.dump(cache_data, f)
except Exception:
pass
return repos
def fetch_single_repo_details(api, repo):
"""Fetch details for a single repository."""
owner = repo['owner']['login']
name = repo['name']
try:
issues_count = api.get_repo_issues(owner, name)
pulls_count = api.get_repo_pulls(owner, name)
contributors = api.get_repo_contributors(owner, name, limit=5)
contributors_count = len(contributors)
except Exception:
issues_count = 0
pulls_count = 0
contributors_count = 0
return {
'Repository': name,
'Stars': repo['stargazers_count'],
'Forks': repo['forks_count'],
'Issues': issues_count,
'Pull Requests': pulls_count,
'Contributors': contributors_count,
'Language': repo['language'] or 'None',
'Size (KB)': repo['size'],
'Created': repo['created_at'][:10],
'Updated': repo['updated_at'][:10],
'URL': repo['html_url'],
'owner_login': owner
}
def fetch_repos_details_concurrently(repos, api, max_workers=10):
"""Fetch details for multiple repositories concurrently."""
results = []
if not repos:
return results
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# Submit tasks
future_to_repo = {
executor.submit(fetch_single_repo_details, api, repo): repo
for repo in repos
}
# Collect results
for future in as_completed(future_to_repo):
try:
repo_details = future.result()
results.append(repo_details)
except Exception:
pass
# Sort results to match original ordering or stars descending
results.sort(key=lambda x: x['Stars'], reverse=True)
return results
def format_number(num):
"""Format large numbers with K/M suffix."""
if num >= 1_000_000:
return f"{num/1_000_000:.1f}M"
elif num >= 1_000:
return f"{num/1_000:.1f}K"
return str(num)