0

I need to dynamically rename keys starting with '@' to key without '@' wherever it comes in nested dict. Sample Input dict:

{
    '@personal_infonmation':{
        'name' : {
            '@first_name': 'Ashutosh',
            '@last_name' : 'Gupta'
        },
        'address':[{'@city': 'Mumbai'}, {'@city': 'Delhi'}]
    }
}

Output

{
'personal_infonmation':{
    'name' : {
        'first_name': 'Ashutosh',
        'last_name' : 'Gupta'
    },
    'address':[{'city': 'Mumbai'}, {'city': 'Delhi'}]
}}

Solution Tried but not working fine in all cases:

def rename_keys(data):
    for k, v in data.items():
        if isinstance(v, dict):
            rename_keys(v)
        if isinstance(v, list):
            [rename_keys(row) for row in v]
        if k[0] == '@':
            data[k[1:]] = v
            data.pop(k)

Failed case:

{'@contentUrl': 'contentUrl', '@createdAt': '2020-06-11T09:08:13Z', '@defaultViewId': 'defaultViewId', '@encryptExtracts': 'false', '@id': 'id', '@name': 'Login', '@showTabs': 'true', '@size': '1', '@updatedAt': '2020-07-20T06:41:34Z', '@webpageUrl': 'webpageUrl', 'dataAccelerationConfig': {'@accelerationEnabled': 'false'}, 'owner': {'@id': 'id', '@name': 'name'}, 'project': {'@id': 'id', '@name': 'name'}, 'tags': {'tag': {'@label': 'label'}}, 'views': {'view': [{'@contentUrl': 'contentUrl', '@createdAt': '2020-06-11T09:08:13Z', '@id': 'id', '@name': 'name', '@updatedAt': '2020-07-20T06:41:34Z', '@viewUrlName': 'Sheet1', 'tags': {'tag': {'@label': 'label'}}}, {'@contentUrl': 'contentUrl', '@createdAt': '2020-06-11T09:08:13Z', '@id': 'id', '@name': 'name', '@updatedAt': 'updatedAt', '@viewUrlName': 'viewUrlName', 'tags': {'tag': {'@label': 'label'}}}]}}
Ashutosh gupta
  • 447
  • 4
  • 16

1 Answers1

2

The issue is that you are modifying the dictionary while you are iterating over it, a small demo of this is here:

data = {i: str(i) for i in range(8)}

for k,v in data.items():
    if k%3 != 0:
        del data[k]
        data[k+10] = "hello"
print(data)

the data should only have keys that are divisible by 3 left, but 5 shows up incorrectly, the solution is to make a copy of the .items() so that it is preserved while iterating so your loop would look like this:

for k,v in list(data.items()):

And that should fix the issue.

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59