1212INFINITY = float ('inf' )
1313
1414
15- def _make_iterencode (markers , _default , _encoder , _indent , _floatstr ,
16- _key_separator , _item_separator , _sort_keys , _skipkeys ,
17- _one_shot ,
18- ## HACK: hand-optimized bytecode; turn globals into locals
19- ValueError = ValueError ,
20- dict = dict ,
21- float = float ,
22- id = id ,
23- int = int ,
24- isinstance = isinstance ,
25- list = list ,
26- str = str ,
27- tuple = tuple ,
28- _intstr = int .__str__ ,
29- ):
15+ def _make_iterencode (
16+ markers , _default , _encoder , _indent , _floatstr ,
17+ _key_separator , _item_separator , _sort_keys , _skipkeys ,
18+ _one_shot ,
19+ ## HACK: hand-optimized bytecode; turn globals into locals
20+ ValueError = ValueError ,
21+ dict = dict ,
22+ float = float ,
23+ id = id ,
24+ int = int ,
25+ isinstance = isinstance ,
26+ list = list ,
27+ str = str ,
28+ tuple = tuple ,
29+ _intstr = int .__str__ ,
30+ ):
3031
3132 if _indent is not None and not isinstance (_indent , str ):
3233 _indent = ' ' * _indent
@@ -38,7 +39,7 @@ def _iterencode_list(lst, _current_indent_level):
3839 if markers is not None :
3940 markerid = id (lst )
4041 if markerid in markers :
41- raise ValueError (" Circular reference detected" )
42+ raise ValueError (' Circular reference detected' )
4243 markers [markerid ] = lst
4344 buf = '['
4445 if _indent is not None :
@@ -95,7 +96,7 @@ def _iterencode_dict(dct, _current_indent_level):
9596 if markers is not None :
9697 markerid = id (dct )
9798 if markerid in markers :
98- raise ValueError (" Circular reference detected" )
99+ raise ValueError (' Circular reference detected' )
99100 markers [markerid ] = dct
100101 yield '{'
101102 if _indent is not None :
@@ -131,8 +132,10 @@ def _iterencode_dict(dct, _current_indent_level):
131132 elif _skipkeys :
132133 continue
133134 else :
134- raise TypeError (f'keys must be str, int, float, bool or None, '
135- f'not { key .__class__ .__name__ } ' )
135+ raise TypeError (
136+ f'keys must be str, int, float, bool or None, '
137+ f'not { key .__class__ .__name__ } ' ,
138+ )
136139 if first :
137140 first = False
138141 else :
@@ -191,7 +194,7 @@ def _iterencode(o, _current_indent_level):
191194 if markers is not None :
192195 markerid = id (o )
193196 if markerid in markers :
194- raise ValueError (" Circular reference detected" )
197+ raise ValueError (' Circular reference detected' )
195198 markers [markerid ] = o
196199 o = _default (o )
197200 yield from _iterencode (o , _current_indent_level )
@@ -216,8 +219,10 @@ def iterencode(self, o, _one_shot=False):
216219 else :
217220 markers = None
218221
219- def floatstr (o , allow_nan = self .allow_nan ,
220- _repr = float .__repr__ , _inf = INFINITY , _neginf = - INFINITY ):
222+ def floatstr (
223+ o , allow_nan = self .allow_nan ,
224+ _repr = float .__repr__ , _inf = INFINITY , _neginf = - INFINITY ,
225+ ):
221226 # Check for specials. Note that this type of test is processor
222227 # and/or platform-specific, so do tests which don't depend on the
223228 # internals.
@@ -233,8 +238,9 @@ def floatstr(o, allow_nan=self.allow_nan,
233238
234239 if not allow_nan :
235240 raise ValueError (
236- "Out of range float values are not JSON compliant: " +
237- repr (o ))
241+ 'Out of range float values are not JSON compliant: ' +
242+ repr (o ),
243+ )
238244
239245 return text
240246
@@ -243,7 +249,8 @@ def floatstr(o, allow_nan=self.allow_nan,
243249 _iterencode = _make_iterencode (
244250 markers , self .default , _encoder , self .indent , floatstr ,
245251 self .key_separator , self .item_separator , self .sort_keys ,
246- self .skipkeys , _one_shot )
252+ self .skipkeys , _one_shot ,
253+ )
247254 return _iterencode (o , 0 )
248255
249256
@@ -253,6 +260,7 @@ def _get_pretty_format(
253260 ensure_ascii : bool = True ,
254261 sort_keys : bool = True ,
255262 top_keys : Sequence [str ] = (),
263+ sort_by_first_key : bool = False ,
256264) -> str :
257265 def pairs_first (pairs : Sequence [Tuple [str , str ]]) -> Mapping [str , str ]:
258266 before = [pair for pair in pairs if pair [0 ] in top_keys ]
@@ -261,12 +269,16 @@ def pairs_first(pairs: Sequence[Tuple[str, str]]) -> Mapping[str, str]:
261269 if sort_keys :
262270 after .sort ()
263271 return dict (before + after )
272+
273+ json_contents = json .loads (contents , object_pairs_hook = pairs_first )
274+ if sort_by_first_key :
275+ json_contents .sort (key = lambda row : list (row .values ())[0 ])
264276 json_pretty = json .dumps (
265- json . loads ( contents , object_pairs_hook = pairs_first ) ,
277+ json_contents ,
266278 indent = indent ,
267279 ensure_ascii = ensure_ascii ,
268280 cls = CustomJSONEncoder ,
269- separators = (', ' , ': ' )
281+ separators = (', ' , ': ' ),
270282 )
271283 return f'{ json_pretty } \n '
272284
@@ -337,6 +349,13 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
337349 default = [],
338350 help = 'Ordered list of keys to keep at the top of JSON hashes' ,
339351 )
352+ parser .add_argument (
353+ '--sort-by-first-key' ,
354+ dest = 'sort_by_first_key' ,
355+ action = 'store_true' ,
356+ default = False ,
357+ help = 'Sort the json by a specific key' ,
358+ )
340359 parser .add_argument ('filenames' , nargs = '*' , help = 'Filenames to fix' )
341360 args = parser .parse_args (argv )
342361
@@ -350,6 +369,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
350369 pretty_contents = _get_pretty_format (
351370 contents , args .indent , ensure_ascii = not args .no_ensure_ascii ,
352371 sort_keys = not args .no_sort_keys , top_keys = args .top_keys ,
372+ sort_by_first_key = args .sort_by_first_key ,
353373 )
354374 except ValueError :
355375 print (
0 commit comments