YAML can represent a string as a scalar in multiple ways: plain (without quotes), single quoted, double quoted, with literal or folded style. Your value for the key sshkey
is a plain scalar.
YAML also wants to be readable, and long lines are not very readable. So there are rules how to wrap long lines forced by wide scalars. Your plain scalar that is the value for sshkey
is wrapped. That means there is a newline in the YAML document, but there is no newline in the scalar string it represents, and on reading the YAML document, that newline gets "unfolded".
You can see this by running the following with your yamldict
definition:
with open('tmp.yaml', 'w') as fp:
yaml.safe_dump(yamldict, fp)
with open('tmp.yaml') as fp:
data = yaml.safe_load(fp)
assert '\n' in data['users'][0]['sshkey']
this will throw an error, as there is no newline in the re-loaded ssh-key.
So your program is fine, but the thing you have been doing wrong is that you did not read the YAML specification, in particular the part on line folding.
Now this particular folding doesn't really make things more readable as there are not enough spaces in the ssh-key. So you might as well increase the line width and get everything on one line. You can do that with PyYAML , but I recommend you use ruamel.yaml
for that, which support the newer YAML 1.2 standard, allows seperate indent values for mappings and sequences and has many PyYAML issues fixed (disclaimer: I am the author of that package):
import sys
from ruamel.yaml import YAML
yaml = YAML()
yaml.width = 1024
# yaml.indent(sequence=4, offset=2) # uncomment to indent the sequences "-"
yamldict = { "users": [] }
yamldict["users"].append({
"username": "user",
"name": "user",
"sshkey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHV/xbvOHuPq6WbBhtmjUWKYPrqQlkILf8b/I6V9dZVBPzmhRZFCAf/gWny0hmZ95bVRED4iCSTCtN3Lq2VZiZ/kwBO7Y9E4vr1wVQYrr4IIwEhdaifZmWFLlwOXbt76dxJQs2xS9Z5ZQjEzZBFZqgYu42QbSi7tKBNSaLadOWbB3sq0IOzCZeSgrELlZIuUy7u1RbcS4w2Y29S3XLrbi2yVdVbPW8B9PfsG1n4q2/XR7w3gqhP6c8ibO4jYpADLZuHZvuoVpjKINO4kSdrwUfD8rl3MBIAD/Nu9sy0bIiKdSONQohxcsjMevxPOijjz4EiI1Ad4U6dDJrFlT0asYH user@email.com"
})
yaml.dump(yamldict, sys.stdout)
this dumps as:
users:
- username: user
name: user
sshkey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHV/xbvOHuPq6WbBhtmjUWKYPrqQlkILf8b/I6V9dZVBPzmhRZFCAf/gWny0hmZ95bVRED4iCSTCtN3Lq2VZiZ/kwBO7Y9E4vr1wVQYrr4IIwEhdaifZmWFLlwOXbt76dxJQs2xS9Z5ZQjEzZBFZqgYu42QbSi7tKBNSaLadOWbB3sq0IOzCZeSgrELlZIuUy7u1RbcS4w2Y29S3XLrbi2yVdVbPW8B9PfsG1n4q2/XR7w3gqhP6c8ibO4jYpADLZuHZvuoVpjKINO4kSdrwUfD8rl3MBIAD/Nu9sy0bIiKdSONQohxcsjMevxPOijjz4EiI1Ad4U6dDJrFlT0asYH user@email.com
The other thing you can do is dump that key as a literal style scalar. For that you need to include an import: from ruamel.yaml.scalarstring import PreservedScalarString
and then somewhere define the key as preserved scalar string after reading in the data from MySQL. In your example you could e.g. do:
for m in yamldict['users']:
m['sshkey'] = PreservedScalarString(m['sshkey'])
assuming you remove the yaml.width = 1024
, and include yaml.indent(sequence=4, offset=2)
this will then dump as:
users:
- username: user
name: user
sshkey: |-
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHV/xbvOHuPq6WbBhtmjUWKYPrqQlkILf8b/I6V9dZVBPzmhRZFCAf/gWny0hmZ95bVRED4iCSTCtN3Lq2VZiZ/kwBO7Y9E4vr1wVQYrr4IIwEhdaifZmWFLlwOXbt76dxJQs2xS9Z5ZQjEzZBFZqgYu42QbSi7tKBNSaLadOWbB3sq0IOzCZeSgrELlZIuUy7u1RbcS4w2Y29S3XLrbi2yVdVbPW8B9PfsG1n4q2/XR7w3gqhP6c8ibO4jYpADLZuHZvuoVpjKINO4kSdrwUfD8rl3MBIAD/Nu9sy0bIiKdSONQohxcsjMevxPOijjz4EiI1Ad4U6dDJrFlT0asYH user@email.com
Where |-
indicates a literal style block scalar.
If you need to stick with PyYAML, then use safe_dump(yamldict, ..., width=1024)
, however there is no easy way there to dump the key as literal style block scalar, nor to indent only the sequences).