8
8
import random
9
9
import datetime
10
10
import simplejson as json
11
+ from typing import Union
11
12
12
13
from collections import OrderedDict
14
+ from warnings import warn
13
15
14
16
# Pandas
15
17
try :
@@ -66,9 +68,9 @@ def create_event_dict(start_time, nodes_list):
66
68
finish_delta = (node ["finish" ] - start_time ).total_seconds ()
67
69
68
70
# Populate dictionary
69
- if events .get (start_delta ) or events . get ( finish_delta ) :
71
+ if events .get (start_delta ):
70
72
err_msg = "Event logged twice or events started at exact same time!"
71
- raise KeyError (err_msg )
73
+ warn (err_msg , category = Warning )
72
74
events [start_delta ] = start_node
73
75
events [finish_delta ] = finish_node
74
76
@@ -101,15 +103,25 @@ def log_to_dict(logfile):
101
103
102
104
nodes_list = [json .loads (l ) for l in lines ]
103
105
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
+ )
106
118
datetime_object : datetime .datetime = datetime .datetime .strptime (
107
- datestring , "%Y-%m-%dT%H:%M:%S.%f"
119
+ datestring , date_format
108
120
)
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
113
125
114
126
date_object_node_list : list = list ()
115
127
for n in nodes_list :
@@ -154,12 +166,18 @@ def calculate_resource_timeseries(events, resource):
154
166
# Iterate through the events
155
167
for _ , event in sorted (events .items ()):
156
168
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
159
174
current_time = event ["start" ]
160
175
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
163
181
current_time = event ["finish" ]
164
182
res [current_time ] = all_res
165
183
@@ -284,7 +302,14 @@ def draw_nodes(start, nodes_list, cores, minute_scale, space_between_minutes, co
284
302
# Left
285
303
left = 60
286
304
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 :
288
313
left += core * 30
289
314
end_times [core ] = datetime .datetime (
290
315
node_finish .year ,
@@ -307,7 +332,7 @@ def draw_nodes(start, nodes_list, cores, minute_scale, space_between_minutes, co
307
332
"offset" : offset ,
308
333
"scale_duration" : scale_duration ,
309
334
"color" : color ,
310
- "node_name" : node [ "name" ] ,
335
+ "node_name" : node . get ( "name" , node . get ( "id" , "" )) ,
311
336
"node_dur" : node ["duration" ] / 60.0 ,
312
337
"node_start" : node_start .strftime ("%Y-%m-%d %H:%M:%S" ),
313
338
"node_finish" : node_finish .strftime ("%Y-%m-%d %H:%M:%S" ),
@@ -527,6 +552,25 @@ def generate_gantt_chart(
527
552
# Read in json-log to get list of node dicts
528
553
nodes_list = log_to_dict (logfile )
529
554
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
+
530
574
# Create the header of the report with useful information
531
575
start_node = nodes_list [0 ]
532
576
last_node = nodes_list [- 1 ]
0 commit comments