1414import subprocess
1515import sys
1616from concurrent .futures import ThreadPoolExecutor , as_completed
17- from datetime import datetime , timezone , timedelta
17+ from datetime import datetime , timezone
1818from functools import partial
19- from typing import Dict , List , Optional
2019
2120from dateutil import parser as date_parser
2221
3433
3534err = partial (print , file = sys .stderr )
3635
37- def run_command (cmd : List [str ]) -> Optional [ str ] :
36+ def run_command (cmd : list [str ]) -> str | None :
3837 """Run a command and return output, or None on error."""
3938 try :
4039 result = subprocess .run (cmd , capture_output = True , text = True , check = True )
@@ -49,7 +48,7 @@ def run_command(cmd: List[str]) -> Optional[str]:
4948
5049
5150
52- def get_log_streams (instance_id : str , log_group : str = None ) -> List [ Dict ]:
51+ def get_log_streams (instance_id : str , log_group : str = None ) -> list [ dict ]:
5352 if log_group is None :
5453 log_group = DEFAULT_CLOUDWATCH_LOG_GROUP
5554 """Get CloudWatch log streams for an instance."""
@@ -69,7 +68,7 @@ def get_log_streams(instance_id: str, log_group: str = None) -> List[Dict]:
6968 return []
7069
7170
72- def get_log_events (log_group : str , log_stream : str , limit : int = 100 , start_from_head : bool = False ) -> List [ Dict ]:
71+ def get_log_events (log_group : str , log_stream : str , limit : int = 100 , start_from_head : bool = False ) -> list [ dict ]:
7372 """Get events from a CloudWatch log stream."""
7473 cmd = [
7574 "aws" , "logs" , "get-log-events" ,
@@ -91,7 +90,7 @@ def get_log_events(log_group: str, log_stream: str, limit: int = 100, start_from
9190 return []
9291
9392
94- def parse_timestamp (ts_str : str ) -> Optional [ datetime ] :
93+ def parse_timestamp (ts_str : str ) -> datetime | None :
9594 """Parse various timestamp formats and ensure timezone is set."""
9695 try :
9796 dt = date_parser .parse (ts_str )
@@ -103,7 +102,7 @@ def parse_timestamp(ts_str: str) -> Optional[datetime]:
103102 return None
104103
105104
106- def extract_timestamp_from_log (message : str ) -> Optional [ datetime ] :
105+ def extract_timestamp_from_log (message : str ) -> datetime | None :
107106 """Extract timestamp from log message."""
108107 # Pattern: [Thu Aug 14 00:29:25 UTC 2025]
109108 match = re .search (r'\[([^]]+UTC \d{4})\]' , message )
@@ -118,7 +117,7 @@ def extract_timestamp_from_log(message: str) -> Optional[datetime]:
118117 return None
119118
120119
121- def analyze_instance (instance_id : str , log_group : str = None ) -> Dict :
120+ def analyze_instance (instance_id : str , log_group : str = None ) -> dict :
122121 if log_group is None :
123122 log_group = DEFAULT_CLOUDWATCH_LOG_GROUP
124123 """Analyze runtime and job execution for an instance."""
@@ -307,7 +306,7 @@ def analyze_instance(instance_id: str, log_group: str = None) -> Dict:
307306 return result
308307
309308
310- def get_instances_from_github_url (url : str ) -> List [str ]:
309+ def get_instances_from_github_url (url : str ) -> list [str ]:
311310 """Extract instance IDs from a GitHub Actions URL."""
312311 # Parse the URL
313312 match = re .match (r'https://github\.com/([^/]+)/([^/]+)/actions/runs/(\d+)(?:/job/(\d+))?' , url )
0 commit comments