Given some json
[
{
"default_value": "True",
"feature_name": "feature_1",
"active_on": "remote_1,remote_2,remote_3,remote_4,remote_5,remote_6,remote_7"
},
{
"feature_name": "special_super_duper_feature_wooooooooot",
"active_on": "remote_2"
}
]
how do I truncate values longer than, say, 20 chars:
[
{
"default_value": "True",
"feature_name": "feature_1",
"active_on": "remote_1,remote_2..."
},
{
"feature_name": "special_super_dup...",
"active_on": "remote_2"
}
]
as generically as possible?
EDIT: Here's a more generic example to fit:
[
{
"a": {"b": "c"},
"d": "e"
},
{
"a": [{"b": "dugin-walrus-blowing-up-the-view-and-ruining-page-frame"}]
}
]
The endgame here is to make "pretty-print" for arbitrary json. I'm wondering whether there's a nice way to do that using only standard library.
Here's my take on it:
import collections
...
def truncate_strings(obj: collections.abc.Iterable, truncate: int, suffix: str = "...") -> int:
"""
@param obj: generic iterable - object to truncate. Implemented for dicts and lists.
Extensible by adding new types to isinstance.
@param truncate: int - total str length to be set. value 0 to disable.
@param suffix: str [Optional] - the truncation string suffix
@returns count: int - number of strings truncated
"""
if not truncate or not obj or isinstance(obj, str):
return 0
count = 0
if isinstance(obj, dict):
for key_ in obj.keys():
if not key_:
return 0
if isinstance(obj.get(key_), str):
if len(obj[key_]) > truncate - len(suffix):
count += 1
obj[key_] = obj[key_][:truncate - len(suffix)] + suffix
else:
count += truncate_strings(key_, truncate, suffix)
elif isinstance(obj, collections.abc.Iterable):
for item in obj:
count += truncate_strings(item, truncate, suffix)
return count
Note this func is recursive on iterables, so a long list will kill your call stack. Should work on reasonable size jsons though (tested on 1k items json array)