Skip to content

Commit 230e1b3

Browse files
committed
Added max_line_length arg to data.json.write()
1 parent 47271c7 commit 230e1b3

8 files changed

Lines changed: 442 additions & 71 deletions

File tree

  • find-project-root/utils/lib/data
  • get-min-py/src/get_min_py/cli/lib/data
  • is-unicode-supported/src/is_unicode_supported/cli/lib/data
  • latin-locales/utils/lib/data
  • non-latin-locales/utils/lib/data
  • project-markers/utils/lib/data
  • remove-json-keys/src/remove_json_keys/cli/lib/data
  • translate-messages/src/translate_messages/cli/lib/data

find-project-root/utils/lib/data/json.py

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,74 @@ def read(input: Union[Path, str], encoding: str = 'utf-8') -> Any:
3535
else : return json5.loads(input_str)
3636

3737
def write(file_path: Union[Path, str], data: Any, encoding: str = 'utf-8', ensure_ascii: bool = False,
38-
style: str = 'pretty', atomic: bool =True):
38+
style: str = 'pretty', atomic: bool = True, max_line_length: int = 120) -> None:
3939
from . import file
40+
from typing import Optional, List
41+
4042
Path(file_path).parent.mkdir(parents=True, exist_ok=True)
43+
44+
def format_compact(obj: Any, indent: int = 0, padded_key: Optional[str] = None) -> List[str]:
45+
indent_spaces = ' ' * indent
46+
line_prefix = padded_key if padded_key else indent_spaces
47+
48+
if isinstance(obj, dict):
49+
50+
# Try fit whole dict in 1 line
51+
kv_pairs = [f'"{key}": {json.dumps(val, separators=(",",":"), ensure_ascii=ensure_ascii)}'
52+
for key,val in obj.items()]
53+
single_line_dict = f'{line_prefix}{{ {", ".join(kv_pairs)} }}'
54+
if len(single_line_dict) <= max_line_length:
55+
return [single_line_dict]
56+
57+
# Else split long line up
58+
lines = [line_prefix + '{']
59+
for idx, (key,val) in enumerate(obj.items()):
60+
inner_lines = format_compact(val, indent +1, f' {indent_spaces}"{key}": ')
61+
for line in inner_lines : lines.append(line)
62+
if not idx == len(obj) -1 : lines[-1] += ',' # append comma except last line
63+
lines.append(indent_spaces + '}')
64+
return lines
65+
66+
elif isinstance(obj, list):
67+
68+
# Try fit whole list in 1 line
69+
single_line_list = line_prefix + json.dumps(obj, separators=(',', ':'), ensure_ascii=ensure_ascii)
70+
if len(single_line_list) <= max_line_length:
71+
return [single_line_list]
72+
73+
# Else split long list up
74+
lines = [line_prefix + '[']
75+
if all(not isinstance(item, (dict, list)) for item in obj): # all items primitives, pack into lines
76+
list_items = [json.dumps(item, ensure_ascii=ensure_ascii) for item in obj]
77+
inner_indent = ' ' * (indent + 1)
78+
current_line_items = []
79+
for item in list_items:
80+
candidate_line = ', '.join(current_line_items + [item]) if current_line_items else item
81+
if len(inner_indent + candidate_line) + 1 <= max_line_length : current_line_items.append(item)
82+
else: # current line full, flush/start new line
83+
if current_line_items : lines.append(inner_indent + ', '.join(current_line_items) + ',')
84+
current_line_items = [item]
85+
if current_line_items: # flush last line
86+
lines.append(inner_indent + ', '.join(current_line_items))
87+
else: # mixed/complex items, format each recursively
88+
for idx, item in enumerate(obj):
89+
inner_lines = format_compact(item, indent +1)
90+
for line in inner_lines : lines.append(line)
91+
if not idx == len(obj) -1 : lines[-1] += ','
92+
lines.append(indent_spaces + ']')
93+
return lines
94+
95+
else: # primitive
96+
return [line_prefix + json.dumps(obj, ensure_ascii=ensure_ascii)]
97+
98+
# Format JSON
4199
if style == 'pretty': # single key/val spans multi-lines
42100
json_str = json.dumps(data, indent=2, ensure_ascii=ensure_ascii)
43-
elif style == 'compact': # single key/val per line
44-
lines = ['{']
45-
items = list(data.items())
46-
for idx, (key, val) in enumerate(items):
47-
line_end = ',' if idx < len(items) -1 else ''
48-
inner = f'{{ {json.dumps(val, ensure_ascii=ensure_ascii)[1:-1]} }}'
49-
lines.append(f' "{key}": {inner}{line_end}')
50-
lines.append('}')
51-
json_str = '\n'.join(lines)
101+
elif style == 'compact': # single key/val per line but honors max_line_length
102+
json_str = '\n'.join(format_compact(data))
52103
else: # minified to single line
53104
json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=ensure_ascii)
54105
json_str += '\n'
106+
107+
# Write to file
55108
getattr(file, 'atomic_write' if atomic else 'write')(file_path, json_str, encoding=encoding)

get-min-py/src/get_min_py/cli/lib/data/json.py

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,74 @@ def read(input: Union[Path, str], encoding: str = 'utf-8') -> Any:
3535
else : return json5.loads(input_str)
3636

3737
def write(file_path: Union[Path, str], data: Any, encoding: str = 'utf-8', ensure_ascii: bool = False,
38-
style: str = 'pretty', atomic: bool =True):
38+
style: str = 'pretty', atomic: bool = True, max_line_length: int = 120) -> None:
3939
from . import file
40+
from typing import Optional, List
41+
4042
Path(file_path).parent.mkdir(parents=True, exist_ok=True)
43+
44+
def format_compact(obj: Any, indent: int = 0, padded_key: Optional[str] = None) -> List[str]:
45+
indent_spaces = ' ' * indent
46+
line_prefix = padded_key if padded_key else indent_spaces
47+
48+
if isinstance(obj, dict):
49+
50+
# Try fit whole dict in 1 line
51+
kv_pairs = [f'"{key}": {json.dumps(val, separators=(",",":"), ensure_ascii=ensure_ascii)}'
52+
for key,val in obj.items()]
53+
single_line_dict = f'{line_prefix}{{ {", ".join(kv_pairs)} }}'
54+
if len(single_line_dict) <= max_line_length:
55+
return [single_line_dict]
56+
57+
# Else split long line up
58+
lines = [line_prefix + '{']
59+
for idx, (key,val) in enumerate(obj.items()):
60+
inner_lines = format_compact(val, indent +1, f' {indent_spaces}"{key}": ')
61+
for line in inner_lines : lines.append(line)
62+
if not idx == len(obj) -1 : lines[-1] += ',' # append comma except last line
63+
lines.append(indent_spaces + '}')
64+
return lines
65+
66+
elif isinstance(obj, list):
67+
68+
# Try fit whole list in 1 line
69+
single_line_list = line_prefix + json.dumps(obj, separators=(',', ':'), ensure_ascii=ensure_ascii)
70+
if len(single_line_list) <= max_line_length:
71+
return [single_line_list]
72+
73+
# Else split long list up
74+
lines = [line_prefix + '[']
75+
if all(not isinstance(item, (dict, list)) for item in obj): # all items primitives, pack into lines
76+
list_items = [json.dumps(item, ensure_ascii=ensure_ascii) for item in obj]
77+
inner_indent = ' ' * (indent + 1)
78+
current_line_items = []
79+
for item in list_items:
80+
candidate_line = ', '.join(current_line_items + [item]) if current_line_items else item
81+
if len(inner_indent + candidate_line) + 1 <= max_line_length : current_line_items.append(item)
82+
else: # current line full, flush/start new line
83+
if current_line_items : lines.append(inner_indent + ', '.join(current_line_items) + ',')
84+
current_line_items = [item]
85+
if current_line_items: # flush last line
86+
lines.append(inner_indent + ', '.join(current_line_items))
87+
else: # mixed/complex items, format each recursively
88+
for idx, item in enumerate(obj):
89+
inner_lines = format_compact(item, indent +1)
90+
for line in inner_lines : lines.append(line)
91+
if not idx == len(obj) -1 : lines[-1] += ','
92+
lines.append(indent_spaces + ']')
93+
return lines
94+
95+
else: # primitive
96+
return [line_prefix + json.dumps(obj, ensure_ascii=ensure_ascii)]
97+
98+
# Format JSON
4199
if style == 'pretty': # single key/val spans multi-lines
42100
json_str = json.dumps(data, indent=2, ensure_ascii=ensure_ascii)
43-
elif style == 'compact': # single key/val per line
44-
lines = ['{']
45-
items = list(data.items())
46-
for idx, (key, val) in enumerate(items):
47-
line_end = ',' if idx < len(items) -1 else ''
48-
inner = f'{{ {json.dumps(val, ensure_ascii=ensure_ascii)[1:-1]} }}'
49-
lines.append(f' "{key}": {inner}{line_end}')
50-
lines.append('}')
51-
json_str = '\n'.join(lines)
101+
elif style == 'compact': # single key/val per line but honors max_line_length
102+
json_str = '\n'.join(format_compact(data))
52103
else: # minified to single line
53104
json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=ensure_ascii)
54105
json_str += '\n'
106+
107+
# Write to file
55108
getattr(file, 'atomic_write' if atomic else 'write')(file_path, json_str, encoding=encoding)

is-unicode-supported/src/is_unicode_supported/cli/lib/data/json.py

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,74 @@ def read(input: Union[Path, str], encoding: str = 'utf-8') -> Any:
3535
else : return json5.loads(input_str)
3636

3737
def write(file_path: Union[Path, str], data: Any, encoding: str = 'utf-8', ensure_ascii: bool = False,
38-
style: str = 'pretty', atomic: bool =True):
38+
style: str = 'pretty', atomic: bool = True, max_line_length: int = 120) -> None:
3939
from . import file
40+
from typing import Optional, List
41+
4042
Path(file_path).parent.mkdir(parents=True, exist_ok=True)
43+
44+
def format_compact(obj: Any, indent: int = 0, padded_key: Optional[str] = None) -> List[str]:
45+
indent_spaces = ' ' * indent
46+
line_prefix = padded_key if padded_key else indent_spaces
47+
48+
if isinstance(obj, dict):
49+
50+
# Try fit whole dict in 1 line
51+
kv_pairs = [f'"{key}": {json.dumps(val, separators=(",",":"), ensure_ascii=ensure_ascii)}'
52+
for key,val in obj.items()]
53+
single_line_dict = f'{line_prefix}{{ {", ".join(kv_pairs)} }}'
54+
if len(single_line_dict) <= max_line_length:
55+
return [single_line_dict]
56+
57+
# Else split long line up
58+
lines = [line_prefix + '{']
59+
for idx, (key,val) in enumerate(obj.items()):
60+
inner_lines = format_compact(val, indent +1, f' {indent_spaces}"{key}": ')
61+
for line in inner_lines : lines.append(line)
62+
if not idx == len(obj) -1 : lines[-1] += ',' # append comma except last line
63+
lines.append(indent_spaces + '}')
64+
return lines
65+
66+
elif isinstance(obj, list):
67+
68+
# Try fit whole list in 1 line
69+
single_line_list = line_prefix + json.dumps(obj, separators=(',', ':'), ensure_ascii=ensure_ascii)
70+
if len(single_line_list) <= max_line_length:
71+
return [single_line_list]
72+
73+
# Else split long list up
74+
lines = [line_prefix + '[']
75+
if all(not isinstance(item, (dict, list)) for item in obj): # all items primitives, pack into lines
76+
list_items = [json.dumps(item, ensure_ascii=ensure_ascii) for item in obj]
77+
inner_indent = ' ' * (indent + 1)
78+
current_line_items = []
79+
for item in list_items:
80+
candidate_line = ', '.join(current_line_items + [item]) if current_line_items else item
81+
if len(inner_indent + candidate_line) + 1 <= max_line_length : current_line_items.append(item)
82+
else: # current line full, flush/start new line
83+
if current_line_items : lines.append(inner_indent + ', '.join(current_line_items) + ',')
84+
current_line_items = [item]
85+
if current_line_items: # flush last line
86+
lines.append(inner_indent + ', '.join(current_line_items))
87+
else: # mixed/complex items, format each recursively
88+
for idx, item in enumerate(obj):
89+
inner_lines = format_compact(item, indent +1)
90+
for line in inner_lines : lines.append(line)
91+
if not idx == len(obj) -1 : lines[-1] += ','
92+
lines.append(indent_spaces + ']')
93+
return lines
94+
95+
else: # primitive
96+
return [line_prefix + json.dumps(obj, ensure_ascii=ensure_ascii)]
97+
98+
# Format JSON
4199
if style == 'pretty': # single key/val spans multi-lines
42100
json_str = json.dumps(data, indent=2, ensure_ascii=ensure_ascii)
43-
elif style == 'compact': # single key/val per line
44-
lines = ['{']
45-
items = list(data.items())
46-
for idx, (key, val) in enumerate(items):
47-
line_end = ',' if idx < len(items) -1 else ''
48-
inner = f'{{ {json.dumps(val, ensure_ascii=ensure_ascii)[1:-1]} }}'
49-
lines.append(f' "{key}": {inner}{line_end}')
50-
lines.append('}')
51-
json_str = '\n'.join(lines)
101+
elif style == 'compact': # single key/val per line but honors max_line_length
102+
json_str = '\n'.join(format_compact(data))
52103
else: # minified to single line
53104
json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=ensure_ascii)
54105
json_str += '\n'
106+
107+
# Write to file
55108
getattr(file, 'atomic_write' if atomic else 'write')(file_path, json_str, encoding=encoding)

latin-locales/utils/lib/data/json.py

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,74 @@ def read(input: Union[Path, str], encoding: str = 'utf-8') -> Any:
3535
else : return json5.loads(input_str)
3636

3737
def write(file_path: Union[Path, str], data: Any, encoding: str = 'utf-8', ensure_ascii: bool = False,
38-
style: str = 'pretty', atomic: bool =True):
38+
style: str = 'pretty', atomic: bool = True, max_line_length: int = 120) -> None:
3939
from . import file
40+
from typing import Optional, List
41+
4042
Path(file_path).parent.mkdir(parents=True, exist_ok=True)
43+
44+
def format_compact(obj: Any, indent: int = 0, padded_key: Optional[str] = None) -> List[str]:
45+
indent_spaces = ' ' * indent
46+
line_prefix = padded_key if padded_key else indent_spaces
47+
48+
if isinstance(obj, dict):
49+
50+
# Try fit whole dict in 1 line
51+
kv_pairs = [f'"{key}": {json.dumps(val, separators=(",",":"), ensure_ascii=ensure_ascii)}'
52+
for key,val in obj.items()]
53+
single_line_dict = f'{line_prefix}{{ {", ".join(kv_pairs)} }}'
54+
if len(single_line_dict) <= max_line_length:
55+
return [single_line_dict]
56+
57+
# Else split long line up
58+
lines = [line_prefix + '{']
59+
for idx, (key,val) in enumerate(obj.items()):
60+
inner_lines = format_compact(val, indent +1, f' {indent_spaces}"{key}": ')
61+
for line in inner_lines : lines.append(line)
62+
if not idx == len(obj) -1 : lines[-1] += ',' # append comma except last line
63+
lines.append(indent_spaces + '}')
64+
return lines
65+
66+
elif isinstance(obj, list):
67+
68+
# Try fit whole list in 1 line
69+
single_line_list = line_prefix + json.dumps(obj, separators=(',', ':'), ensure_ascii=ensure_ascii)
70+
if len(single_line_list) <= max_line_length:
71+
return [single_line_list]
72+
73+
# Else split long list up
74+
lines = [line_prefix + '[']
75+
if all(not isinstance(item, (dict, list)) for item in obj): # all items primitives, pack into lines
76+
list_items = [json.dumps(item, ensure_ascii=ensure_ascii) for item in obj]
77+
inner_indent = ' ' * (indent + 1)
78+
current_line_items = []
79+
for item in list_items:
80+
candidate_line = ', '.join(current_line_items + [item]) if current_line_items else item
81+
if len(inner_indent + candidate_line) + 1 <= max_line_length : current_line_items.append(item)
82+
else: # current line full, flush/start new line
83+
if current_line_items : lines.append(inner_indent + ', '.join(current_line_items) + ',')
84+
current_line_items = [item]
85+
if current_line_items: # flush last line
86+
lines.append(inner_indent + ', '.join(current_line_items))
87+
else: # mixed/complex items, format each recursively
88+
for idx, item in enumerate(obj):
89+
inner_lines = format_compact(item, indent +1)
90+
for line in inner_lines : lines.append(line)
91+
if not idx == len(obj) -1 : lines[-1] += ','
92+
lines.append(indent_spaces + ']')
93+
return lines
94+
95+
else: # primitive
96+
return [line_prefix + json.dumps(obj, ensure_ascii=ensure_ascii)]
97+
98+
# Format JSON
4199
if style == 'pretty': # single key/val spans multi-lines
42100
json_str = json.dumps(data, indent=2, ensure_ascii=ensure_ascii)
43-
elif style == 'compact': # single key/val per line
44-
lines = ['{']
45-
items = list(data.items())
46-
for idx, (key, val) in enumerate(items):
47-
line_end = ',' if idx < len(items) -1 else ''
48-
inner = f'{{ {json.dumps(val, ensure_ascii=ensure_ascii)[1:-1]} }}'
49-
lines.append(f' "{key}": {inner}{line_end}')
50-
lines.append('}')
51-
json_str = '\n'.join(lines)
101+
elif style == 'compact': # single key/val per line but honors max_line_length
102+
json_str = '\n'.join(format_compact(data))
52103
else: # minified to single line
53104
json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=ensure_ascii)
54105
json_str += '\n'
106+
107+
# Write to file
55108
getattr(file, 'atomic_write' if atomic else 'write')(file_path, json_str, encoding=encoding)

0 commit comments

Comments
 (0)