33
44import builtins
55import html
6- import json
76import sys
87import unicodedata
98from argparse import Namespace
@@ -95,7 +94,7 @@ def print_output_format(
9594 data : Optional [Any ] = None ,
9695 hidden_data : Optional [Any ] = None ,
9796 show_headers : bool = False ,
98- # print_callback : bool = True ,
97+ show_key_value_list : bool = False ,
9998) -> None :
10099 """Create a FabricCLIOutput instance and print it depends on the format.
101100
@@ -105,6 +104,7 @@ def print_output_format(
105104 data: Optional data to include in output
106105 hidden_data: Optional hidden data to include in output
107106 show_headers: Whether to show headers in the output (default: False)
107+ show_key_value_list: Whether to show output in key-value list format (default: False)
108108
109109 Returns:
110110 FabricCLIOutput: Configured output instance ready for printing
@@ -121,6 +121,7 @@ def print_output_format(
121121 data = data ,
122122 hidden_data = hidden_data ,
123123 show_headers = show_headers ,
124+ show_key_value_list = show_key_value_list ,
124125 )
125126
126127 # Get format from output or config
@@ -355,6 +356,8 @@ def _print_output_format_result_text(output: FabricCLIOutput) -> None:
355356 ):
356357 data_keys = output .result .get_data_keys () if output_result .data else []
357358 print_entries_unix_style (output_result .data , data_keys , header = show_headers )
359+ elif output .show_key_value_list :
360+ _print_entries_key_value_list_style (output_result .data )
358361 else :
359362 _print_raw_data (output_result .data )
360363
@@ -486,3 +489,76 @@ def _get_visual_length(string: str) -> int:
486489 else :
487490 length += 1
488491 return length
492+
493+
494+ def _print_entries_key_value_list_style (entries : Any ) -> None :
495+ """Print entries in a key-value list format with formatted keys.
496+
497+ Args:
498+ entries: Dictionary or list of dictionaries to print
499+
500+ Example output:
501+ Logged In: true
502+ Account: johndoe@example.com
503+ """
504+ if isinstance (entries , dict ):
505+ _entries = [entries ]
506+ elif isinstance (entries , list ):
507+ if not entries :
508+ return
509+ _entries = entries
510+ else :
511+ raise FabricCLIError (
512+ ErrorMessages .Common .invalid_entries_format (),
513+ fab_constant .ERROR_INVALID_ENTRIES_FORMAT ,
514+ )
515+
516+ for i , entry in enumerate (_entries ):
517+ for key , value in entry .items ():
518+ pretty_key = _format_key_to_convert_to_title_case (key )
519+ print_grey (f"{ pretty_key } : { value } " , to_stderr = False )
520+ if i < len (_entries ) - 1 :
521+ print_grey ("" , to_stderr = False ) # Empty line between entries
522+
523+
524+ def _format_key_to_convert_to_title_case (key : str ) -> str :
525+ """Convert a snake_case key to a Title Case name.
526+
527+ Args:
528+ key: The key to format in snake_case format (e.g. 'user_id', 'account_name')
529+
530+ Returns:
531+ str: Formatted to title case name (e.g. 'User ID', 'Account Name')
532+
533+ Raises:
534+ ValueError: If the key is not in the expected underscore-separated format
535+ """
536+ # Allow letters, numbers, and underscores only
537+ if not key .replace ('_' , '' ).replace (' ' , '' ).isalnum ():
538+ raise ValueError (f"Invalid key format: '{ key } '. Only underscore-separated words are allowed." )
539+
540+ # Check for invalid patterns (camelCase, spaces mixed with underscores, etc.)
541+ if ' ' in key and '_' in key :
542+ raise ValueError (f"Invalid key format: '{ key } '. Only underscore-separated words are allowed." )
543+
544+ # Check for camelCase pattern (uppercase letters not at the start)
545+ if any (char .isupper () for char in key [1 :]) and '_' not in key :
546+ raise ValueError (f"Invalid key format: '{ key } '. Only underscore-separated words are allowed." )
547+
548+ pretty = key .replace ('_' , ' ' ).title ().strip ()
549+
550+ return _check_special_cases (pretty )
551+
552+
553+ def _check_special_cases (pretty : str ) -> str :
554+ """Check for special cases and replace them with the correct value."""
555+ # Here add special cases for specific keys that need to be formatted differently
556+ special_cases = {
557+ "Id" : "ID" ,
558+ "Powerbi" : "PowerBI" ,
559+ }
560+
561+ for case_key , case_value in special_cases .items ():
562+ pretty = pretty .replace (case_key .title (), case_value )
563+
564+ return pretty
0 commit comments