mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	
		
			
	
	
		
			123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import json | ||
|  | 
 | ||
|  | from functools import reduce | ||
|  | 
 | ||
|  | INDENT = '  ' | ||
|  | 
 | ||
|  | class CollapseList(list): | ||
|  |     pass | ||
|  | class CollapseDict(dict): | ||
|  |     pass | ||
|  | class AlignedDict(dict): | ||
|  |     def __init__(self, src_dict, depth): | ||
|  |         self.depth = depth - 1 | ||
|  |         super().__init__(src_dict) | ||
|  | class SortedDict(dict): | ||
|  |     pass | ||
|  | 
 | ||
|  | 
 | ||
|  | def is_scalar(value): | ||
|  |     return not is_list(value) and not is_dict(value) | ||
|  | 
 | ||
|  | 
 | ||
|  | def is_list(value): | ||
|  |     return isinstance(value, list) or isinstance(value, tuple) | ||
|  | 
 | ||
|  | 
 | ||
|  | def is_dict(value): | ||
|  |     return isinstance(value, dict) | ||
|  | 
 | ||
|  | 
 | ||
|  | def dump_scalar(obj, ensure_ascii=False): | ||
|  |     return json.dumps(obj, ensure_ascii=ensure_ascii) | ||
|  | 
 | ||
|  | 
 | ||
|  | def dump_list(obj, current_indent='', ensure_ascii=False): | ||
|  |     entries = [dump_obj(value, current_indent + INDENT, ensure_ascii=ensure_ascii) for value in obj] | ||
|  | 
 | ||
|  |     if len(entries) == 0: | ||
|  |         return '[]' | ||
|  | 
 | ||
|  |     if isinstance(obj, CollapseList): | ||
|  |         values_format = '{value}' | ||
|  |         output_format = '[{values}]' | ||
|  |         join_format   = ', ' | ||
|  |     else: | ||
|  |         values_format = '{indent}{value}' | ||
|  |         output_format = '[\n{values}\n{indent}]' | ||
|  |         join_format   = ',\n' | ||
|  | 
 | ||
|  |     output = output_format.format( | ||
|  |         indent=current_indent, | ||
|  |         values=join_format.join([values_format.format( | ||
|  |             value=entry, | ||
|  |             indent=current_indent + INDENT | ||
|  |         ) for entry in entries]) | ||
|  |     ) | ||
|  | 
 | ||
|  |     return output | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_keys(obj, depth): | ||
|  |     if depth == 0: | ||
|  |         yield from obj.keys() | ||
|  |     else: | ||
|  |         for value in obj.values(): | ||
|  |             yield from get_keys(value, depth - 1) | ||
|  | 
 | ||
|  | 
 | ||
|  | def dump_dict(obj, current_indent='', sub_width=None, ensure_ascii=False): | ||
|  |     entries = [] | ||
|  | 
 | ||
|  |     key_width = None | ||
|  |     if sub_width is not None: | ||
|  |         sub_width = (sub_width[0]-1, sub_width[1]) | ||
|  |         if sub_width[0] == 0: | ||
|  |             key_width = sub_width[1] | ||
|  | 
 | ||
|  |     if isinstance(obj, AlignedDict): | ||
|  |         sub_keys = get_keys(obj, obj.depth) | ||
|  |         sub_width = (obj.depth, reduce(lambda acc, entry: max(acc, len(entry)), sub_keys, 0)) | ||
|  | 
 | ||
|  |     for key, value in obj.items():         | ||
|  |         entries.append((dump_scalar(str(key), ensure_ascii), dump_obj(value, current_indent + INDENT, sub_width, ensure_ascii))) | ||
|  | 
 | ||
|  |     if key_width is None: | ||
|  |         key_width = reduce(lambda acc, entry: max(acc, len(entry[0])), entries, 0) | ||
|  | 
 | ||
|  |     if len(entries) == 0: | ||
|  |         return '{}' | ||
|  | 
 | ||
|  |     if isinstance(obj, SortedDict): | ||
|  |         entries.sort(key=lambda item: item[0]) | ||
|  | 
 | ||
|  |     if isinstance(obj, CollapseDict): | ||
|  |         values_format = '{key} {value}' | ||
|  |         output_format = '{{{values}}}' | ||
|  |         join_format   = ', ' | ||
|  |     else: | ||
|  |         values_format = '{indent}{key:{padding}}{value}' | ||
|  |         output_format = '{{\n{values}\n{indent}}}' | ||
|  |         join_format   = ',\n' | ||
|  | 
 | ||
|  |     output = output_format.format( | ||
|  |         indent=current_indent, | ||
|  |         values=join_format.join([values_format.format( | ||
|  |             key='{key}:'.format(key=key),  | ||
|  |             value=value, | ||
|  |             indent=current_indent + INDENT, | ||
|  |             padding=key_width + 2, | ||
|  |         ) for (key, value) in entries]) | ||
|  |     ) | ||
|  | 
 | ||
|  |     return output | ||
|  | 
 | ||
|  | 
 | ||
|  | def dump_obj(obj, current_indent='', sub_width=None, ensure_ascii=False): | ||
|  |     if is_list(obj): | ||
|  |         return dump_list(obj, current_indent, ensure_ascii) | ||
|  |     elif is_dict(obj): | ||
|  |         return dump_dict(obj, current_indent, sub_width, ensure_ascii) | ||
|  |     else: | ||
|  |         return dump_scalar(obj, ensure_ascii) |