I want to use the following syntax for substituting environment variables into settings, like {env [key]}

>>> person = {'first':'Reuven', 'last':'Lerner'} >>> "Your name is {p[first]}.".format(p=person) 

Settings I read from a text file in which JSON is saved

 if (self.settings is None) and os.path.exists(self.settings_file): with open(self.settings_file, 'r', encoding='utf8') as f: file_content = f.read() file_content_env = file_content.format(env=environment) self.settings = json.loads(file_content_env) 

but it falls with an error.

 file_content_env = file_content.format(env=environment) KeyError: '\n "Type"' 

How to load settings correctly? Or maybe someone pokes a better solution?

Added an example that crash

 environment = { "date": time.strftime("%Y%m%d"), "datetime": time.strftime("%Y%m%d_%H%M"), "workdir": os.path.dirname("") } file_content = """[ { "Type": "test", "Name": "Task from {env[datetime]}", "Path": "{env[workdir]}\\test" } ]""" file_content_env = file_content.format(env=environment) 
  • Instead of creating json text using formatting, it’s better to manipulate the data as a regular dictionary (download json beforehand if necessary) and write down the necessary data directly by key into the dictionary, and you can convert it back to json if necessary. Example: settings = json.load(f); settings["Path"] = ... settings = json.load(f); settings["Path"] = ... - jfs
  • I did not catch the better and how it should look in my case. json serves as a file with settings. It is assumed that the config is all in one place, without climbing into the code, but the plain text lacks flexibility, therefore for some typical things (time stamp, some service paths) it is supposed to introduce variables by analogy with environment variables in ordinary shell scripts. At the output, JSON is not needed, it is needed at the input, so that it can be conveniently edited with highlight in any normal editor and validated immediately. Further, the parameters obtained from json are used by the necessary modules. - QuAzI
  • I didn’t want to spread my hands on the code with a hundred replace after reading the config, when it would seem there is a list with "environment variables" and there is a config that can be processed as plain_text. - QuAzI
  • If json is only at the input, then it is even simpler: step # 1: load json: settings = json.load(f) Step # 2 make changes from environment: settings["Path"] = environment["workdir"] / "test" (used pathlib for convenience). Everything. - jfs
  • environment ["workdir"] / "test" - is a hardcode, here the user will not fit in and will not change as he needs. Again, each parameter will have to be attracted by the ears with your hands (and there may be a lot of parameters) - QuAzI

1 answer 1

You have a problem because of curly braces. In order for format ignore braces, you must repeat them twice: {{ and }}

 import os import time import json import datetime environment = { "date": time.strftime("%Y%m%d"), "datetime": time.strftime("%Y%m%d_%H%M"), "workdir": os.path.dirname("") } file_content = """[ {{ "Type": "test", "Name": "Task from {datetime}", "Path": "{workdir}\\test" }} ]""" file_content_env = file_content.format(**environment) print(file_content_env) 

If you need a valid json and you need string substitutions, you will have to do it in a loop:

 import os import time import json environment = { "date": time.strftime("%Y%m%d"), "datetime": time.strftime("%Y%m%d_%H%M"), "workdir": os.path.dirname("") } file_content = """[ { "Type": "test", "Name": "Task from {datetime}", "Path": "{workdir}\\test" } ]""" js = json.loads(file_content) for key in js[0]: js[0][key] = js[0][key].format(**environment) print(js) 
  • I wanted something like that, but it crashes when processing multi-line content - QuAzI
  • Hard to say, you did not give an example of what you transmit. There can be a lot of reasons for crash, one of the reasons is that you don’t transfer the dictionary in format. - Avernial
  • Added to the end of the main post an example - QuAzI
  • You have a problem because of curly braces. format finds the first braces, and tries to substitute the value there. But in the first brackets is the wrong field for the substitution. - Avernial
  • Corrected the answer. - Avernial