88import random
99import datetime
1010import simplejson as json
11+ from typing import Union
1112
1213from collections import OrderedDict
14+ from warnings import warn
1315
1416# Pandas
1517try :
@@ -66,9 +68,9 @@ def create_event_dict(start_time, nodes_list):
6668 finish_delta = (node ["finish" ] - start_time ).total_seconds ()
6769
6870 # Populate dictionary
69- if events .get (start_delta ) or events . get ( finish_delta ) :
71+ if events .get (start_delta ):
7072 err_msg = "Event logged twice or events started at exact same time!"
71- raise KeyError (err_msg )
73+ warn (err_msg , category = Warning )
7274 events [start_delta ] = start_node
7375 events [finish_delta ] = finish_node
7476
@@ -101,15 +103,25 @@ def log_to_dict(logfile):
101103
102104 nodes_list = [json .loads (l ) for l in lines ]
103105
104- def _convert_string_to_datetime (datestring ):
105- try :
106+ def _convert_string_to_datetime (
107+ datestring : Union [str , datetime .datetime ],
108+ ) -> datetime .datetime :
109+ """Convert a date string to a datetime object."""
110+ if isinstance (datestring , datetime .datetime ):
111+ datetime_object = datestring
112+ elif isinstance (datestring , str ):
113+ date_format = (
114+ "%Y-%m-%dT%H:%M:%S.%f%z"
115+ if "+" in datestring
116+ else "%Y-%m-%dT%H:%M:%S.%f"
117+ )
106118 datetime_object : datetime .datetime = datetime .datetime .strptime (
107- datestring , "%Y-%m-%dT%H:%M:%S.%f"
119+ datestring , date_format
108120 )
109- return datetime_object
110- except Exception as _ :
111- pass
112- return datestring
121+ else :
122+ msg = f" { datestring } is not a string or datetime object."
123+ raise TypeError ( msg )
124+ return datetime_object
113125
114126 date_object_node_list : list = list ()
115127 for n in nodes_list :
@@ -154,12 +166,18 @@ def calculate_resource_timeseries(events, resource):
154166 # Iterate through the events
155167 for _ , event in sorted (events .items ()):
156168 if event ["event" ] == "start" :
157- if resource in event and event [resource ] != "Unknown" :
158- all_res += float (event [resource ])
169+ if resource in event :
170+ try :
171+ all_res += float (event [resource ])
172+ except ValueError :
173+ continue
159174 current_time = event ["start" ]
160175 elif event ["event" ] == "finish" :
161- if resource in event and event [resource ] != "Unknown" :
162- all_res -= float (event [resource ])
176+ if resource in event :
177+ try :
178+ all_res -= float (event [resource ])
179+ except ValueError :
180+ continue
163181 current_time = event ["finish" ]
164182 res [current_time ] = all_res
165183
@@ -284,7 +302,14 @@ def draw_nodes(start, nodes_list, cores, minute_scale, space_between_minutes, co
284302 # Left
285303 left = 60
286304 for core in range (len (end_times )):
287- if end_times [core ] < node_start :
305+ try :
306+ end_time_condition = end_times [core ] < node_start
307+ except TypeError :
308+ # if one has a timezone and one does not
309+ end_time_condition = end_times [core ].replace (
310+ tzinfo = None
311+ ) < node_start .replace (tzinfo = None )
312+ if end_time_condition :
288313 left += core * 30
289314 end_times [core ] = datetime .datetime (
290315 node_finish .year ,
@@ -307,7 +332,7 @@ def draw_nodes(start, nodes_list, cores, minute_scale, space_between_minutes, co
307332 "offset" : offset ,
308333 "scale_duration" : scale_duration ,
309334 "color" : color ,
310- "node_name" : node [ "name" ] ,
335+ "node_name" : node . get ( "name" , node . get ( "id" , "" )) ,
311336 "node_dur" : node ["duration" ] / 60.0 ,
312337 "node_start" : node_start .strftime ("%Y-%m-%d %H:%M:%S" ),
313338 "node_finish" : node_finish .strftime ("%Y-%m-%d %H:%M:%S" ),
@@ -527,6 +552,25 @@ def generate_gantt_chart(
527552 # Read in json-log to get list of node dicts
528553 nodes_list = log_to_dict (logfile )
529554
555+ # Only include nodes with timing information, and convert timestamps
556+ # from strings to datetimes
557+ nodes_list = [
558+ {
559+ k : (
560+ datetime .datetime .strptime (i [k ], "%Y-%m-%dT%H:%M:%S.%f" )
561+ if k in {"start" , "finish" } and isinstance (i [k ], str )
562+ else i [k ]
563+ )
564+ for k in i
565+ }
566+ for i in nodes_list
567+ if "start" in i and "finish" in i
568+ ]
569+
570+ for node in nodes_list :
571+ if "duration" not in node :
572+ node ["duration" ] = (node ["finish" ] - node ["start" ]).total_seconds ()
573+
530574 # Create the header of the report with useful information
531575 start_node = nodes_list [0 ]
532576 last_node = nodes_list [- 1 ]
0 commit comments