可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a some.yaml
file with the below contents.
init_config: {} instances: - host: username: password:
The yaml file should be parsed and updated as below.
init_config: {} instances: - host: 1.2.3.4 username: Username password: Password
How do I parse the values and update them appropriately?
回答1:
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: # update with IP username: # update with user name password: # update with password
and run:
import ruamel.yaml file_name = 'input.yml' from ruamel.yaml.util import load_yaml_guess_indent config, ind, bsi = 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' ruamel.yaml.round_trip_dump(config, open('output.yml', 'w'), indent=ind, block_seq_indent=bsi)
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 more traditional load, and set the indent values yourself:
config = ruamel.yaml.load(open(file_name), ruamel.yaml.RoundTripLoader) ind = 6 bsi = 4
回答2:
This is how i can read from the above file i mentioned, parse and update as needed.
import yaml fname = "some.yaml" stream = open(fname, 'r') data = yaml.load(stream) data['instances'][0]['host'] = '1.2.3.4' data['instances'][0]['username'] = 'Username' data['instances'][0]['password'] = 'Password' with open(fname, 'w') as yaml_file: yaml_file.write( yaml.dump(data, default_flow_style=False))
回答3:
I don't know if you need YAML. Aside from using the YAML tag, it seems that you have no interest in the YAML document. So why not using Jinja2 or some template language?
from jinja2 import Template tmpl = Template(u'''\ init_config: {} instances: - host: {{ IP }} username: {{ username }} password: {{ password }} ''') print tmpl.render( IP=u"1.2.3.4", username=u"Username", password=u"Password" )
I don't know if it is a good idea, but if you only need to obtain a file with some fields changed, you don't need to actually parse the YAML document and can benefit from a Template language directly.
Bonus: Use case
I have worked with very complex YAML documents, for which there are tags unknown
... propertiesIDs: { 1, 2, 3, 4 } globalID: !myapplication.InterfaceID &primitiveID replication: !myapplication.replication beginDate: 2012-09-10T20:00:03 endDate: 2020-09-10T20:00:04 replicant_uuid: ? 17169504-B6AB-11E4-8437-36E258BB2172 ? 206B5842-B6AB-11E4-AAC3-36E258BB2172 ...
Performing a valid parse of this document is difficult and time-consuming. I only need to populate some values, and the YAML is sent to a third-party application. So instead of parsing the YAML or trying to generate a valid document directly using pyyaml, is simpler (more time-efficient, less bug-prone) to generate it directly through templates. Moreover, template languages can easily be used with loops to populate dynamically sized fields.
回答4:
Here's how i generate docker-crane templates for dev, production, stage, etc...
- mkdir crane_templates
- touch crane_templates/init.py
- Add template content with nano crane_templates/some.yaml
- Nano crane_gen.py
--- crane_gen.py ---
#!/usr/bin/env python from jinja2 import Environment, PackageLoader env = Environment(loader=PackageLoader('crane_templates', './')) tmpl = env.get_template('crane.yaml.tmpl') result = tmpl.render( IP=u"1.2.3.4", username=u"Username", password=u"Password" )
5. python crane_gen.py > result.yaml
Answer inspired by @MariusSiuram
回答5:
Here are sample using PyYaml
. As I understand you have something like template in yaml
format, and you have to substitute places in angle brackets with actual values.
import yaml s = """ init_config: {} instances: - host: username: password: """ dict_obj = yaml.load(s) # loads string in internal data structure - dict dict_obj['instances'][0]['host'] = 'localhost' # change values print yaml.dump(dict_obj) # dumps dict to yaml format back