66from typing import TYPE_CHECKING , Any , ClassVar , Dict , Iterable , List , Mapping , Union
77from uuid import UUID
88
9+ from rich import box
10+
911if TYPE_CHECKING :
1012 from kiara .interfaces .python_api .models .info import (
1113 DataTypeClassesInfo ,
1214 DataTypeClassInfo ,
15+ JobInfo ,
16+ JobsInfo ,
1317 KiaraPluginInfo ,
1418 KiaraPluginInfos ,
1519 ModuleTypeInfo ,
@@ -237,7 +241,9 @@ def get_job_comment(self, job_id: Union[str, uuid.UUID]) -> Union[str, None]:
237241 )
238242 return metadata .comment
239243
240- def retrieve_augmented_value_lineage (self , value : Union [str , "UUID" , "Value" , "Path" ]) -> Dict [int , Dict [str , Any ]]:
244+ def retrieve_augmented_value_lineage (
245+ self , value : Union [str , "UUID" , "Value" , "Path" ]
246+ ) -> Dict [int , Dict [str , Any ]]:
241247 """Retrieve lineage data for the specified value, augmented with additional metadata.
242248
243249 The format of the returned data is a dictionary with the following keys:
@@ -261,44 +267,208 @@ def retrieve_augmented_value_lineage(self, value: Union[str, "UUID", "Value", "P
261267 nodes = graph .nodes .data ()
262268 augmented_nodes = {}
263269
264-
265270 def get_info (node ):
266- # all this is terribly inefficient
271+ # all this is terribly inefficient
267272
268- if node [1 ]["node_type" ] == "operation" :
273+ if node [1 ]["node_type" ] == "operation" :
269274
270- result = self .retrieve_module_type_info (node [1 ]["module_type" ]).model_dump ()
275+ result = self .retrieve_module_type_info (
276+ node [1 ]["module_type" ]
277+ ).model_dump ()
271278
272- elif node [1 ]["node_type" ] == "value" :
279+ elif node [1 ]["node_type" ] == "value" :
273280
274- value_id = node [0 ][6 :]
281+ value_id = node [0 ][6 :]
275282
276- v = self .get_value (value_id )
277- if v .is_set :
278- render_result = self ._api .render_value (value = v , target_format = "string" ).rendered
283+ v = self .get_value (value_id )
284+ if v .is_set :
285+ render_result = self ._api .render_value (
286+ value = v , target_format = "string"
287+ ).rendered
279288
280- else :
281- render_result = "None"
282-
283- result = {
284- "preview" : render_result
285- }
286289 else :
287- raise Exception (f"Unknown node type: { node [1 ]} " )
290+ render_result = "None"
291+
292+ result = {"preview" : render_result }
293+ else :
294+ raise Exception (f"Unknown node type: { node [1 ]} " )
288295
289- return result
296+ return result
290297
291298 for idx , node in enumerate (nodes ):
292- node_dict = {
293- "id" : node [0 ],
294- "desc" : node [1 ],
295- "parentIds" : list (graph .predecessors (node [0 ])),
296- "info" : get_info (node )
297- }
298- augmented_nodes [idx ] = node_dict
299+ node_dict = {
300+ "id" : node [0 ],
301+ "desc" : node [1 ],
302+ "parentIds" : list (graph .predecessors (node [0 ])),
303+ "info" : get_info (node ),
304+ }
305+ augmented_nodes [idx ] = node_dict
299306
300307 return augmented_nodes
301308
309+ def print_all_jobs_info_data (self , aliases : bool = True , max_char : int = 0 , show_inputs : bool = False , show_outputs : bool = False ) -> None :
310+ """Prints a table with all jobs info data.
311+
312+ If max_char > 0, the value previews will be truncated to max_char characters, unless aliases is True, in which case the aliases of a value will be shown (if available).
313+
314+ Arguments:
315+ max_char: the maximum number of characters to show for value previews
316+ aliases: whether to show aliases for values (if max_char is exceeded by preview)
317+ show_inputs: whether to show the inputs of the jobs
318+ show_outputs: whether to show the outputs of the jobs
319+ """
320+
321+ from rich .table import Table
322+
323+ from kiara .utils .cli import terminal_print
324+
325+ data = self .get_all_jobs_info_data (aliases = aliases , max_char = max_char , add_inputs_preview = show_inputs , add_outputs_preview = show_outputs )
326+
327+ table = Table (show_lines = True , box = box .SIMPLE )
328+ table .add_column ("Module name" )
329+ table .add_column ("Comment" )
330+ table .add_column ("Time submitted" )
331+ table .add_column ("Runtime" )
332+ if show_inputs :
333+ table .add_column ("Inputs" )
334+ if show_outputs :
335+ table .add_column ("Outputs" )
336+
337+ for row_data in data :
338+
339+ row = [
340+ row_data ["module_name" ],
341+ row_data ["comment" ],
342+ str (row_data ["time_submitted" ]),
343+ str (row_data ["runtime" ]),
344+ ]
345+ if show_inputs :
346+ inputs = row_data ["inputs" ]
347+ inputs_table = Table (
348+ show_lines = False , box = box .SIMPLE , show_header = False
349+ )
350+ inputs_table .add_column ("Field" , style = "b" )
351+ inputs_table .add_column ("Value" )
352+ for input_name , input_value in inputs .items ():
353+ inputs_table .add_row (input_name , str (input_value ))
354+
355+ row .append (inputs_table )
356+
357+ if show_outputs :
358+ outputs = row_data ["outputs" ]
359+ outputs_table = Table (
360+ show_lines = False , box = box .SIMPLE , show_header = False
361+ )
362+ outputs_table .add_column ("Field" , style = "b" )
363+ outputs_table .add_column ("Value" )
364+ for output_name , output_value in outputs .items ():
365+ outputs_table .add_row (output_name , str (output_value ))
366+ row .append (outputs_table )
367+
368+ table .add_row (* row )
369+
370+ terminal_print (table )
371+
372+ def get_all_jobs_info_data (self , aliases : bool = True , max_char : int = 0 , add_inputs_preview : bool = False , add_outputs_preview : bool = False ) -> List [Dict [str , Any ]]:
373+ """Retrieve all job info as a list of dicts.
374+
375+ If max_char > 0, the value previews will be truncated to max_char characters, unless aliases is True, in which case the aliases of a value will be shown (if available).
376+
377+ The result list items are dicts with the following keys:
378+
379+ - job_id: the job id
380+ - module_name: the module name
381+ - module_config: the module config that was used (if applicable, otherwise this key will not be present)
382+ - time_submitted: the time the job was submitted
383+ - runtime: the runtime of the job
384+ - comment: the comment for the job
385+ - inputs: a dict of input field names and values (when 'add_inputs_preview' is set)
386+ - outputs: a dict of output field names and values (when 'add_outputs_preview' is set)
387+
388+ Arguments:
389+ max_char: the maximum number of characters to show for value previews
390+ aliases: whether to show aliases for values (if max_char is exceeded by preview)
391+ add_inputs_preview: whether to add preview data for input fields
392+ add_outputs_preview: whether to add preview data for output fields
393+ """
394+
395+ job_infos = self .retrieve_jobs_info (allow_internal = False )
396+
397+ def get_value_str (value_info : "ValueInfo" ) -> str :
398+
399+ if not value_info ._value :
400+ value_obj = self .get_value (value_info .value_id )
401+ else :
402+ value_obj = value_info ._value
403+
404+ if value_obj .is_set :
405+ rendered : str = self ._api .render_value (
406+ value = value_obj , target_format = "string"
407+ ).rendered # type: ignore
408+
409+ if max_char > 0 and len (rendered ) <= max_char :
410+ return rendered
411+
412+ if aliases is True :
413+ value_aliases = value_info .aliases
414+ if value_aliases :
415+ value_aliases_str = ", " .join (value_aliases )
416+ return value_aliases_str
417+
418+ # means no aliases
419+ if max_char > 0 :
420+ return rendered [0 :max_char ] + "..."
421+ else :
422+ return rendered
423+
424+ else :
425+ return value_obj .value_status .value
426+
427+ result = []
428+ for job_id , job_info in job_infos .item_infos .items ():
429+
430+ module_name = job_info .job_record .module_type
431+ module_config = job_info .job_record .module_config
432+ comment = self .get_job_comment (job_info .job_record .job_id )
433+ time_submitted = job_info .job_record .job_submitted
434+ runtime_details = job_info .job_record .runtime_details
435+ if not runtime_details :
436+ runtime = "n/a"
437+ else :
438+ runtime = str (runtime_details .runtime )
439+
440+ inputs = {}
441+ if add_inputs_preview :
442+ for field_name , value_info in job_info .inputs .items ():
443+ value_str = get_value_str (value_info )
444+ inputs [field_name ] = value_str
445+ outputs = {}
446+ if add_outputs_preview :
447+ for field_name , value_info in job_info .outputs .items ():
448+ value_str = get_value_str (value_info )
449+ outputs [field_name ] = value_str
450+
451+ result_item = {
452+ "job_id" : str (job_id ),
453+ "module_name" : module_name ,
454+ "time_submitted" : time_submitted ,
455+ "comment" : comment ,
456+ "runtime" : runtime ,
457+ }
458+
459+ if add_inputs_preview :
460+ result_item ["inputs" ] = inputs
461+ if add_outputs_preview :
462+ result_item ["outputs" ] = outputs
463+
464+
465+ if module_config :
466+ result_item ["module_config" ] = module_config
467+
468+ result .append (result_item )
469+
470+ return sorted (result , key = lambda x : x ["time_submitted" ])
471+
302472 # BEGIN IMPORTED-ENDPOINTS
303473 def list_available_plugin_names (
304474 self , regex : str = r"^kiara[-_]plugin\..*"
@@ -757,9 +927,6 @@ def retrieve_value_info(
757927 result : "ValueInfo" = self ._api .retrieve_value_info (value = value )
758928 return result
759929
760-
761-
762-
763930 def retrieve_values_info (self , ** matcher_params : Any ) -> "ValuesInfo" :
764931 """Retrieve information about the matching values.
765932
@@ -995,6 +1162,8 @@ def export_values(
9951162 target_archive : Union [str , "Path" ],
9961163 values : Union [
9971164 str ,
1165+ "Value" ,
1166+ "UUID" ,
9981167 Mapping [str , Union [str , "UUID" , "Value" ]],
9991168 Iterable [Union [str , "UUID" , "Value" ]],
10001169 ],
@@ -1233,4 +1402,19 @@ def get_job_record(self, job_id: Union[str, "UUID"]) -> Union["JobRecord", None]
12331402 result : Union ["JobRecord" , None ] = self ._api .get_job_record (job_id = job_id )
12341403 return result
12351404
1405+ def retrieve_job_info (self , job_id : Union [str , "UUID" ]) -> Union ["JobInfo" , None ]:
1406+ """Retrieve the detailed job record for the specified job id.
1407+
1408+ If no job can be found, 'None' is returned.
1409+ """
1410+
1411+ result : Union ["JobInfo" , None ] = self ._api .retrieve_job_info (job_id = job_id )
1412+ return result
1413+
1414+ def retrieve_jobs_info (self , ** matcher_params : Any ) -> "JobsInfo" :
1415+ """ """
1416+
1417+ result : "JobsInfo" = self ._api .retrieve_jobs_info (** matcher_params )
1418+ return result
1419+
12361420 # END IMPORTED-ENDPOINTS
0 commit comments