If you are using 2.6+, you can use do this:
print json.dumps(jsonStr, sort_keys=True, indent=2, separators=(',', ': '))
http://docs.python.org/2/library/json.html
Answer from onetwopunch on Stack OverflowIf you are using 2.6+, you can use do this:
print json.dumps(jsonStr, sort_keys=True, indent=2, separators=(',', ': '))
http://docs.python.org/2/library/json.html
For Python as well as JSON, the order within a dict bears no meaning. Use lists instead of dicts if you mind.
If you only want to order the JSON output (that is, prefer {1:0, 2:0} over {2:0, 1:0}, even if they are equivalent), you can use the collections.OrderedDict which will remember the order the items were inserted.
Format String Syntax section says:
Format strings contain “replacement fields” surrounded by curly braces
{}. Anything that is not contained in braces is considered literal text, which is copied unchanged to the output. If you need to include a brace character in the literal text, it can be escaped by doubling:{{and}}.
So if you want to use .format method, you need to escape all JSON curly braces in your template string:
>>> '{{"fvAp": {{"attributes": {{"name": {}}}}}}}'.format('"app-name"')
'{"fvAp": {"attributes": {"name": "app-name"}}}'
That looks really bad.
There's a better way to do that with string.Template:
>>> from string import Template
>>> t = Template('{"fvAp": {"attributes": {"name": "${name}"}}')
>>> t.substitute(name='StackOverflow')
'{"fvAp": {"attributes": {"name": "StackOverflow"}}'
Though I suggest abandoning the idea of generating configs this way altogether and using a factory function and json.dumps instead:
>>> import json
>>> def make_config(name):
... return {'fvAp': {'attributes': {'name': name}}}
>>> app_config = make_config('StackOverflow')
>>> json.dumps(app_config)
'{"fvAp": {"attributes": {"name": "StackOverflow"}}}'
Looks like you are trying to substitute dynamic values within a json file with their runtime counterparts.
You can use PLACEHOLDER in this scenario.
Construct your json using PLACEHOLDER values where you would like to substitute them with dynamic values.
For example:
{
"services": [{
"name": "service_a",
"config": {
"dynamic_value_1": "PLACEHOLDER",
"dynamic_value_2": "PLACEHOLDER"
}
},
{
"name": "service_b",
"config": {
"dynamic_value_1": "PLACEHOLDER",
"dynamic_value_2": "PLACEHOLDER"
}
}
]
}
You can then read the json file and perform an update by passing a dictionary of values you want to substitute.
def dynamic_values() -> Dict:
"""
Provides a map of placeholder values with their dynamic counterparts
"""
return {
"service_a": {
"dynamic_value_1": service_a_method_1(),
"dynamic_value_2": service_a_method_2(),
},
"service_b": {
"dynamic_value_1": service_b_method_1(),
"dynamic_value_2": service_b_method_1(),
},
}
def load_dynamic_values(dynamic_values) -> List:
"""
Overrides placeholder values in json file with dynamic values at runtime
"""
with open(file_name, "r") as f:
data = json.load(f)
services = data["services"]
for s in services:
override = dynamic_values.get(s["name"], None)
if override:
s["config"].update(override)
return services
How to format json string in Python - Stack Overflow
python - String format a JSON string gives KeyError - Stack Overflow
Formatting JSON in Python - Stack Overflow
formatting json output in Python
Are there online platforms for string to JSON file Python conversions?
How can one revert a JSON string back to its Python form?
How do you differentiate between creating a JSON string and saving it as a file in Python?
Hi,
I would like to read json into Python code, and then output processed json. In order to get started with this, I have written very basic Python, and am attempting to read in very basic json I found online.
The input json is:
{
"firstName": "John",
"lastName": "Doe",
"hobbies": ["biking", "coding", "rapping"],
"age": 35,
"children": [
{
"firstName": "hector",
"age": 6
},
{
"firstName": "cassandra",
"age": 8
}
]
}The code is:
import json
if __name__ == '__main__':
print( "start" )
# read and load input json
json_input_filename = "input.json"
json_input = open( json_input_filename )
json_input_dict = json.load( json_input )
# write output json
json_output_filename = "output.json"
with open( json_output_filename, 'w' ) as json_output:
json.dump( json_string, json_output )
print( f"end" )and the output is:
"{\"firstName\": \"John\", \"lastName\": \"Doe\", \"hobbies\": [\"biking\", \"coding\", \"rapping\"], \"age\": 35, \"children\": [{\"firstName\": \"hector\", \"age\": 6}, {\"firstName\": \"cassandra\", \"age\": 8}]}"What can I do in order to preserve something resembling the original formatting? I'm going to load this output into some other code in order to process it further.
Thank you very much
Don't try to manipulate the data as an encoded string. Decode the JSON before trying to apply the formatting.
import json
json_data = '{"key1":"{0}","key2":"{1}"}'
format_args = ["value1", "value2"]
data = json.loads(json_data)
formatted_data = {key: value.format(*format_args) for key, value in data.items()}
You can then re-encode the formatted data as JSON if need be.
If you are building these strings yourself or have control over them, have a different format be sent, or build the value as a dictionary and use json.dumps.
However, if you really need to do this, if it's guaranteed that the substitution values will be in the format {X}, then you can escape the string with this kludge:
import re
s = '{"key1":{0}, "key2":{1}}'
begin = re.compile(r'{(?!\d)')
end = re.compile(r'(?<!\d)}')
escaped = end.sub('}}', begin.sub('{{', s))
print(escaped.format(1, 2))
results in
{"key1":1, "key2":2}
Note that this is not the best solution. Considering you have control of the strings, you should be escaping them in some other way. Maybe use the % syntax instead of str.format?
You need to double the outer braces; otherwise Python thinks { "File".. is a reference too:
output_format = '{{ "File": "{filename}", "Success": {success}, "ErrorMessage": "{error_msg}", "LogIdentifier": "{log_identifier}" }}'
Result:
>>> print output_format.format(filename='My_file_name',
... success=True,
... error_msg='',
... log_identifier='123')
{ "File": "My_file_name", "Success": True, "ErrorMessage": "", "LogIdentifier": "123" }
If, indicentally, you are producing JSON output, you'd be better off using the json module:
>>> import json
>>> print json.dumps({'File': 'My_file_name',
... 'Success': True,
... 'ErrorMessage': '',
... 'LogIdentifier': '123'})
{"LogIdentifier": "123", "ErrorMessage": "", "Success": true, "File": "My_file_name"}
Note the lowercase true in the output, as required by the JSON standard.
As mentioned by Tudor in a comment to another answer, the Template class was the solution that worked best for me. I'm dealing with nested dictionaries or list of dictionaries and handling those were not as straightforward.
Using Template though the solution is quite simple.
I start with a dictionary that is converted into a string. I then replace all instances of { with ${ which is the Template identifier to substitute a placeholder.
The key point of getting this to work is using the Template method safe_substitute. It will replace all valid placeholders like ${user_id} but ignore any invalid ones that are part of the dictionary structure, like ${'name': 'John', ....
After the substitution is done I remove any leftovers $ and convert the string back to a dictionary.
In the code bellow, resolve_placeholders returns a dictionary where each key matches a placeholder in the payload string and the value is substituted by the Template class.
from string import Template
.
.
.
payload = json.dumps(payload)
payload = payload.replace('{', '${')
replace_values = self.resolve_placeholders(payload)
if replace_values:
string_template = Template(payload)
payload = string_template.safe_substitute(replace_values)
payload = payload.replace('${', '{')
payload = json.loads(payload)
json.dumps(obj, indent=2) is better than pprint because:
- It is faster with the same load methodology.
- It has the same or similar simplicity.
- The output will produce valid JSON, whereas
pprintwill not.
pprint_vs_dumps.py
import cProfile
import json
import pprint
from urllib.request import urlopen
def custom_pretty_print():
url_to_read = "https://www.cbcmusic.ca/Component/Playlog/GetPlaylog?stationId=96&date=2018-11-05"
with urlopen(url_to_read) as resp:
pretty_json = json.dumps(json.load(resp), indent=2)
print(f'Pretty: {pretty_json}')
def pprint_json():
url_to_read = "https://www.cbcmusic.ca/Component/Playlog/GetPlaylog?stationId=96&date=2018-11-05"
with urlopen(url_to_read) as resp:
info = json.load(resp)
pprint.pprint(info)
cProfile.run('custom_pretty_print()')
>>> 71027 function calls (42309 primitive calls) in 0.084 seconds
cProfile.run('pprint_json()')
>>>164241 function calls (140121 primitive calls) in 0.208 seconds
Thanks @tobias_k for pointing out my errors along the way.
I think for a true JSON object print, it's probably as good as it gets. timeit(number=10000) for the following took about 5.659214497s:
import json
d = {
'breakfast': [
'spam', 'spam', 'eggs',
{
'another': 'level',
'nested': [
{'a':'b'},
{'c':'d'}
]
}
],
'foo': True,
'bar': None
}
s = json.dumps(d)
q = json.dumps(json.loads(s), indent=2)
print(q)
I tried with pprint, but it actually wouldn't print the pure JSON string unless it's converted to a Python dict, which loses your true, null and false etc valid JSON as mentioned in the other answer. As well it doesn't retain the order in which the items appeared, so it's not great if order is important for readability.
Just for fun I whipped up the following function:
def pretty_json_for_savages(j, indentor=' '):
ind_lvl = 0
temp = ''
for i, c in enumerate(j):
if c in '{[':
print(indentor*ind_lvl + temp.strip() + c)
ind_lvl += 1
temp = ''
elif c in '}]':
print(indentor*ind_lvl + temp.strip() + '\n' + indentor*(ind_lvl-1) + c, end='')
ind_lvl -= 1
temp = ''
elif c in ',':
print(indentor*(0 if j[i-1] in '{}[]' else ind_lvl) + temp.strip() + c)
temp = ''
else:
temp += c
print('')
# {
# "breakfast":[
# "spam",
# "spam",
# "eggs",
# {
# "another": "level",
# "nested":[
# {
# "a": "b"
# },
# {
# "c": "d"
# }
# ]
# }
# ],
# "foo": true,
# "bar": null
# }
It prints pretty alright, and unsurprisingly it took a whooping 16.701202023s to run in timeit(number=10000), which is 3 times as much as a json.dumps(json.loads()) would get you. It's probably not worthwhile to build your own function to achieve this unless you spend some time to optimize it, and with the lack of a builtin for the same, it's probably best you stick with your gun since your efforts will most likely give diminishing returns.