Skip to content

Commit 3342198

Browse files
committed
reformat
1 parent 8d23c4e commit 3342198

File tree

1 file changed

+68
-30
lines changed

1 file changed

+68
-30
lines changed

tools/last_user_activity.py

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,36 @@
4747
"Accept": "application/vnd.github.v3+json",
4848
}
4949

50+
5051
class DateTimeCache(diskcache.Cache):
5152
"""Custom cache class that handles datetime serialization."""
52-
53+
5354
def __setitem__(self, key, value):
5455
"""Override to serialize datetime objects."""
5556
if isinstance(value, datetime):
56-
value = {'__datetime__': value.isoformat()}
57+
value = {"__datetime__": value.isoformat()}
5758
super().__setitem__(key, value)
58-
59+
5960
def __getitem__(self, key):
6061
"""Override to deserialize datetime objects."""
6162
value = super().__getitem__(key)
62-
if isinstance(value, dict) and '__datetime__' in value:
63-
return datetime.fromisoformat(value['__datetime__'])
63+
if isinstance(value, dict) and "__datetime__" in value:
64+
return datetime.fromisoformat(value["__datetime__"])
6465
return value
65-
66+
6667
def get(self, key, default=None, retry=False):
6768
"""Override to handle datetime deserialization in get method with retry."""
6869
try:
6970
return super().get(key, default=default, retry=retry)
7071
except KeyError:
7172
return default
7273

74+
7375
# Configure DiskCache in the current directory
7476
CACHE_DIR = "github_cache"
7577
cache = DateTimeCache(CACHE_DIR)
7678

79+
7780
async def get_org_members(session: aiohttp.ClientSession, org: str) -> List[Dict]:
7881
"""Fetch all members of a GitHub organization with caching.
7982
@@ -99,7 +102,7 @@ async def get_org_members(session: aiohttp.ClientSession, org: str) -> List[Dict
99102
Pagination is handled automatically (100 items per page).
100103
"""
101104
cache_key = f"org_members_{org}"
102-
105+
103106
# Try to get from cache with retry
104107
cached_data = cache.get(cache_key, retry=True)
105108
if cached_data is not None:
@@ -108,42 +111,47 @@ async def get_org_members(session: aiohttp.ClientSession, org: str) -> List[Dict
108111

109112
print(f"[yellow]Cache miss for {org} members - fetching from API[/yellow]")
110113
members = []
111-
114+
112115
try:
113116
for page in count(1):
114117
url = f"https://api.github.com/orgs/{org}/members?page={page}&per_page=100"
115118
async with session.get(url, headers=headers) as response:
116119
if response.status != 200:
117-
print(f"[red]Error fetching members for {org}: {response.status}[/red]")
120+
print(
121+
f"[red]Error fetching members for {org}: {response.status}[/red]"
122+
)
118123
break
119-
124+
120125
page_members = await response.json()
121126
if not page_members:
122127
break
123-
128+
124129
members.extend(page_members)
125-
130+
126131
# Cache the results
127132
cache[cache_key] = members # Using __setitem__ instead of set()
128133
print(f"[green]Cached {len(members)} members for {org}[/green]")
129134
return members
130-
135+
131136
except Exception as e:
132137
print(f"[red]Error fetching members for {org}: {str(e)}[/red]")
133138
return []
134139

135-
async def get_user_activity(session: aiohttp.ClientSession, username: str) -> Optional[datetime]:
140+
141+
async def get_user_activity(
142+
session: aiohttp.ClientSession, username: str
143+
) -> Optional[datetime]:
136144
"""Fetch the last public activity date for a GitHub user."""
137145
cache_key = f"user_activity_{username}"
138-
146+
139147
# Try to get from cache
140148
cached_data = cache.get(cache_key)
141149
if cached_data is not None:
142150
print(f"[cyan]Cache hit for {username} activity[/cyan]")
143151
return cached_data
144152

145153
print(f"[yellow]Cache miss for {username} activity - fetching from API[/yellow]")
146-
154+
147155
try:
148156
print(f"Getting activity for {username}")
149157
url = f"https://api.github.com/users/{username}/events/public"
@@ -152,32 +160,42 @@ async def get_user_activity(session: aiohttp.ClientSession, username: str) -> Op
152160
print(f"Got activity for {username}")
153161
events = await response.json()
154162
if events:
155-
last_activity = datetime.fromisoformat(events[0]["created_at"].replace('Z', '+00:00'))
163+
last_activity = datetime.fromisoformat(
164+
events[0]["created_at"].replace("Z", "+00:00")
165+
)
156166
# Cache the results
157-
cache[cache_key] = last_activity # Using __setitem__ instead of set()
167+
cache[cache_key] = (
168+
last_activity # Using __setitem__ instead of set()
169+
)
158170
print(f"[green]Cached activity for {username}[/green]")
159171
return last_activity
160172
else:
161173
print(f"[yellow]No activity found for {username}[/yellow]")
162174
cache[cache_key] = None # Using __setitem__ instead of set()
163175
else:
164-
print(f"[red]Error fetching activity for {username}: {response.status}[/red]")
176+
print(
177+
f"[red]Error fetching activity for {username}: {response.status}[/red]"
178+
)
165179
except Exception as e:
166180
print(f"[red]Error fetching activity for {username}: {str(e)}[/red]")
167-
181+
168182
return None
169183

184+
170185
def get_cache_size() -> str:
171186
"""Get the current cache size in a human-readable format."""
172187
try:
173188
cache_path = pathlib.Path(CACHE_DIR)
174189
if cache_path.exists():
175-
total_size = sum(f.stat().st_size for f in cache_path.rglob('*') if f.is_file())
190+
total_size = sum(
191+
f.stat().st_size for f in cache_path.rglob("*") if f.is_file()
192+
)
176193
return f"{total_size / 1024 / 1024:.1f} MB"
177194
except Exception:
178195
pass
179196
return "unknown size"
180197

198+
181199
def clear_cache() -> None:
182200
"""Clear the disk cache."""
183201
try:
@@ -186,6 +204,7 @@ def clear_cache() -> None:
186204
except Exception as e:
187205
print(f"[red]Error clearing cache: {str(e)}[/red]")
188206

207+
189208
async def main():
190209
"""Main execution function."""
191210
# Show cache status
@@ -194,16 +213,22 @@ async def main():
194213

195214
async with aiohttp.ClientSession() as session:
196215
# Check rate limit
197-
async with session.get("https://api.github.com/rate_limit", headers=headers) as response:
216+
async with session.get(
217+
"https://api.github.com/rate_limit", headers=headers
218+
) as response:
198219
if response.status == 200:
199220
rate_data = await response.json()
200221
remaining = rate_data["resources"]["core"]["remaining"]
201-
reset_time = datetime.fromtimestamp(rate_data["resources"]["core"]["reset"])
222+
reset_time = datetime.fromtimestamp(
223+
rate_data["resources"]["core"]["reset"]
224+
)
202225
reset_in = humanize.naturaltime(reset_time)
203226
print(f"Rate limit remaining: {remaining}")
204227
print(f"Rate limit resets {reset_in}")
205228
if remaining < 100:
206-
print(f"[yellow]Warning: Low rate limit ({remaining} remaining)[/yellow]")
229+
print(
230+
f"[yellow]Warning: Low rate limit ({remaining} remaining)[/yellow]"
231+
)
207232
if remaining < 10:
208233
print("[red]Aborting due to very low rate limit[/red]")
209234
return
@@ -230,18 +255,31 @@ async def main():
230255
for (username, _), last_activity in zip(tasks, results):
231256
user_activities.append((username, last_activity, all_members[username]))
232257

233-
for username, last_activity, user_orgs in sorted(user_activities, key=lambda x: x[1] if x[1] is not None else datetime.fromtimestamp(0), reverse=True):
234-
last_activity_ago = humanize.naturaltime(datetime.now(last_activity.tzinfo) - last_activity) if last_activity else "[red]never[/red]"
258+
for username, last_activity, user_orgs in sorted(
259+
user_activities,
260+
key=lambda x: x[1] if x[1] is not None else datetime.fromtimestamp(0),
261+
reverse=True,
262+
):
263+
last_activity_ago = (
264+
humanize.naturaltime(datetime.now(last_activity.tzinfo) - last_activity)
265+
if last_activity
266+
else "[red]never[/red]"
267+
)
235268
orgs_str = ", ".join(user_orgs)
236-
print(f"{username:<20}: Last activity {last_activity_ago} in orgs: {orgs_str}")
269+
print(
270+
f"{username:<20}: Last activity {last_activity_ago} in orgs: {orgs_str}"
271+
)
272+
237273

238274
if __name__ == "__main__":
239275
parser = argparse.ArgumentParser(description="GitHub Organization Activity Tracker")
240-
parser.add_argument('--clear-cache', action='store_true', help='Clear the cache before running')
241-
parser.add_argument('--debug', action='store_true', help='Show debug information')
276+
parser.add_argument(
277+
"--clear-cache", action="store_true", help="Clear the cache before running"
278+
)
279+
parser.add_argument("--debug", action="store_true", help="Show debug information")
242280
args = parser.parse_args()
243281

244282
if args.clear_cache:
245283
clear_cache()
246-
284+
247285
asyncio.run(main())

0 commit comments

Comments
 (0)