I need to convert json to given hcl structure. There is this code:
user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }
double_q = '"'
result = f"""
users = [
{''.join([
f'''{{
name = {double_q}{ d['name'] }{double_q},
pass = {double_q}{ d['pass'] }{double_q},
permissions = [
{''.join([f"{{ access = {double_q}{ d['permissions'][index]['access'] }{double_q}, role = {double_q}{ d['permissions'][index]['role'] }{double_q} }}," for index in range(len(d['permissions'])) ])}
]
}},
''' for d in user_dicts['users']
])}
]"""
print(result)
which returns the following line:
users = [
{
name = "test1",
pass = "password1",
permissions = [
{ access = "yes", role = "admin" },{ access = "yes", role = "user" },
]
},
{
name = "test2",
pass = "password2",
permissions = [
{ access = "yes", role = "admin" },
]
},
]
What needs to be done so that there is a new line between the dictionaries in permissions while maintaining the number of spaces? That is:
users = [
{
name = "test1",
pass = "password1",
permissions = [
{ access = "yes", role = "admin" },
{ access = "yes", role = "user" },
]
},
{
name = "test2",
pass = "password2",
permissions = [
{ access = "yes", role = "admin" },
]
},
]
I tried adding f-string to new_line variable:
user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }
double_q = '"'
new_line = '\n'
result = f"""
users = [
{''.join([
f'''{{
name = {double_q}{ d['name'] }{double_q},
pass = {double_q}{ d['pass'] }{double_q},
permissions = [
{f'{new_line}'.join([f"{{ access = {double_q}{ d['permissions'][index]['access'] }{double_q}, role = {double_q}{ d['permissions'][index]['role'] }{double_q} }}," for index in range(len(d['permissions'])) ])}
]
}},
''' for d in user_dicts['users']
])}
]"""
print(result)
But the next line becomes from the beginning of the line:
users = [
{
name = "test1",
pass = "password1",
permissions = [
{ access = "yes", role = "admin" },
{ access = "yes", role = "user" },
]
},
{
name = "test2",
pass = "password2",
permissions = [
{ access = "yes", role = "admin" },
]
},
]
You were on the right track, using the new_line
variable together with str.join()
. To maintain the number of spaces, just include them in new_line
:
new_line = ' \n'
You may want to start using a templating engine, like Jinja.
Pros
Cons
Your example, implemented with Jinja
To run the following code, you need to install the jinja2
package
import jinja2
user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }
template_str = """
users = [
{% for user in users %}
{
name = "{{ user['name'] }}",
pass = "{{ user['pass'] }}",
permissions = [
{% for p in user['permissions'] %}
{ access = "{{ p['access'] }}", role = "{{ p['role'] }}" },
{% endfor %}
]
},
{% endfor %}
]
""".strip()
template = jinja2.Template(template_str, trim_blocks=True, lstrip_blocks=True)
users = template.render(user_dicts).replace("'", '"')
The template string template_str
is basically your desired output, plus some special tokens ({% for ... %}
, {% endfor %}
, {{ ... }}
). These tokens tell the engine how to "fill in the blanks".