The ruamel.yaml package was specifically enhanced (by me starting from PyYAML) to do this kind of round-trip, programmatic, updating.
If you start with (please note I removed the extra initial spaces):
init_config: {}
instances:
- host: <IP> # update with IP
username: <username> # update with user name
password: <password> # update with password
and run:
import ruamel.yaml
file_name = 'input.yaml'
config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(open(file_name))
instances = config['instances']
instances[0]['host'] = '1.2.3.4'
instances[0]['username'] = 'Username'
instances[0]['password'] = 'Password'
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=ind, sequence=ind, offset=bsi)
with open('output.yaml', 'w') as fp:
yaml.dump(config, fp)
The output will be:
init_config: {}
instances:
- host: 1.2.3.4 # update with IP
username: Username # update with user name
password: Password # update with password
The ordering of mapping keys (host
, username
and password
), the style and the comments are preserved without any further specific action.
Instead of having the indent and block sequence indent guessed, you can do a manual traditional load, and set the indent values yourself:
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=6, sequence=4)
with open(file_name) as fp:
config = yaml.load(fp)
If you look at the history of this answer, you can see how to do this with a more limited, PyYAML like, API.