Skip to content

Instantly share code, notes, and snippets.

@aryzhov
Last active January 26, 2024 11:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aryzhov/d92991528cc7a996711a220b37903756 to your computer and use it in GitHub Desktop.
Save aryzhov/d92991528cc7a996711a220b37903756 to your computer and use it in GitHub Desktop.
YAML array extention in Python
CoreTeam: &CoreTeam
Characters:
- Mario
- Luigi
ExtendedTeam: &ExtendedTeam
<<: *CoreTeam
Characters+:
- Princess Peach
- Yoshi
- Toad
Games:
SuperMario:
<<: *CoreTeam
Characters+:
- Peach
Mario Cart 6:
<<: *ExtendedTeam
Characters++:
- Donkey Kong
Mario Cart 7:
<<: *ExtendedTeam
Characters++:
- Donkey Kong
- Metal Mario
#!/usr/bin/env python3
import yaml
from yaml_utils import execute_merge_notation
import json
with open("example.yaml") as f:
data = yaml.load(f)
print("--- Before --- ")
print(json.dumps(data, indent=4))
execute_merge_notation(data)
print("--- After --- ")
print(json.dumps(data, indent=4))
--- Before ---
{
"CoreTeam": {
"Characters": [
"Mario",
"Luigi"
]
},
"Games": {
"SuperMario": {
"Characters": [
"Mario",
"Luigi"
],
"Characters+": [
"Peach"
]
},
"Mario Cart 7": {
"Characters": [
"Mario",
"Luigi"
],
"Characters+": [
"Princess Peach",
"Yoshi",
"Toad"
],
"Characters++": [
"Donkey Kong",
"Metal Mario"
]
},
"Mario Cart 6": {
"Characters": [
"Mario",
"Luigi"
],
"Characters+": [
"Princess Peach",
"Yoshi",
"Toad"
],
"Characters++": [
"Donkey Kong"
]
}
},
"ExtendedTeam": {
"Characters": [
"Mario",
"Luigi"
],
"Characters+": [
"Princess Peach",
"Yoshi",
"Toad"
]
}
}
--- After ---
{
"CoreTeam": {
"Characters": [
"Mario",
"Luigi"
]
},
"Games": {
"SuperMario": {
"Characters": [
"Mario",
"Luigi",
"Peach"
]
},
"Mario Cart 7": {
"Characters": [
"Mario",
"Luigi",
"Princess Peach",
"Yoshi",
"Toad",
"Donkey Kong",
"Metal Mario"
]
},
"Mario Cart 6": {
"Characters": [
"Mario",
"Luigi",
"Princess Peach",
"Yoshi",
"Toad",
"Donkey Kong"
]
}
},
"ExtendedTeam": {
"Characters": [
"Mario",
"Luigi",
"Princess Peach",
"Yoshi",
"Toad"
]
}
}
'''
YAML has a missing feature: ability to extend lists. This is a Python implementation that allows extending the lists,
as well as the maps of the elements referenced by an alias.
'''
def _trailing_plus_count(s):
for i in range(0, len(s)):
if s[-i-1] != '+':
return i
return len(s)
def _extend_list_or_dict(json, json2, key, merge_lists=True):
if type(json) == dict and type(json2) == dict:
for k2, v2 in json2.items():
json[k2] = v2
return json
elif merge_lists and type(json) == list and type(json2) == list:
json.extend(json2)
return json
return json2
def execute_merge_notation(json):
if type(json) == dict:
to_merge = None
for k in json.keys():
if type(k) == str and _trailing_plus_count(k) > 0:
if not to_merge:
to_merge = [k]
else:
to_merge.append(k)
if to_merge:
for k2 in sorted(to_merge, key=_trailing_plus_count):
v2 = json[k2]
k = k2[0: len(k2) - _trailing_plus_count(k2)]
if len(k) > 0:
if k in json:
v = json[k]
json[k] = _extend_list_or_dict(v, v2, k)
else:
json[k] = v2
json.pop(k2)
for v in json.values():
if type(v) in (list, dict):
execute_merge_notation(v)
elif type(json) == list:
for item in json:
execute_merge_notation(item)
@aryzhov
Copy link
Author

aryzhov commented Jan 18, 2017

@mbd-dbc-dk
Copy link

This does not work as intended, at least not with yaml.load(f, Loader=yaml.FullLoader)

Output has tons of duplicates -- seems references are overwritten, which means that additions to list elements pollute the original lists.

@mbd-dbc-dk
Copy link

Changing the _extend_list_or_dict function works for me:

def _extend_list_or_dict(json, json2, key, merge_lists=True):
    if type(json) == dict and type(json2) == dict:
        for k2, v2 in json2.items():
           json[k2] = v2
        return json
    elif merge_lists and type(json) == list and type(json2) == list:
        res = []
        res.extend(json)
        res.extend(json2)
        #json.extend(json2)
        #return json
        return res
    return json2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment