Reputation: 2783
I have a weird scenario where I need to convert the string like "data["data"]["name"][0]" into a dict variable which can be used to modify the dict variable value
so
input. - "data["data"]["name"][0]"
and
output - data["data"]["name"][0]
so that I can use it modify the value of the variable.
Things that I have tried are locals() and globals() way of converting string to Variable but they seems to be failing given the string will actually be a complex dict variable.
update1:-
I was trying to get all the keys(path to keys) of a complex nested json and ended up getting that using collections and strings. so each key's path is string "data["data"]["name"][0]"
but to modify the complex json I would need to interpret this as variable and assign value.
sample code
var = "data['data']['name'][0]"
data = {"data":{"name":["test","tst2"]}}
print(data['data']['name'][0])
print(var) # this prints the string
print(eval(var)) # this prints the value of string evaluted or like get method
#how to set value using var variable
#means var should be like data['data']['name'][0]
Upvotes: 0
Views: 98
Reputation: 4378
It is not pretty, but it works :
def set_value(d, selector, val):
"""Follow the selector inside `d` to set the value of the last node."""
if not selector.startswith("data"):
raise ValueError("the query does not start with 'data'")
# start parsing the selector
parts = selector[len("data"):].split("]")
if parts[-1] != "":
raise ValueError("the query does not end with a ']'")
parts.pop() # remove the last part, we know it's empty
current_node = d
for part in parts[:-1]: # for each part but not the last
if (part.startswith("['") and part.endswith("'")) or \
(part.startswith("[\"") and part.endswith("\"")): # it's a dictionary access
key_name = part[2:-1]
current_node = current_node[key_name]
elif part[1] in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
index_val = int(part[1:])
current_node = current_node[index_val]
else:
raise ValueError(f"the query part {part[:-1]!r} is syntactically incorrect")
# then handle the last part
last_part = parts[-1]
if (last_part.startswith("['") and last_part.endswith("'")) or \
(last_part.startswith("[\"") and last_part.endswith("\"")): # it's a dictionary access
key_name = last_part[2:-1]
current_node[key_name] = val
elif last_part[1] in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
index_val = int(last_part[1:])
current_node[index_val] = val
else:
raise ValueError(f"the query part {last_part!r} is syntactically incorrect")
return d
data = {"data": {"name": ["test", "tst2"]}}
print(data) # {'data': {'name': ['test', 'tst2']}}
data = set_value(data, 'data["data"]["name"][0]', 12)
print(data) # {'data': {'name': [14, 'tst2']}}
data = set_value(data, "data['data']['name'][1]", -4)
print(data) # {'data': {'name': [12, -4]}}
data = set_value(data, "data['foo']", {'bar': [5, 6]})
print(data) # {'data': {'name': [12, -4]}, 'foo': {'bar': [5, 6]}}
data = set_value(data, "data['foo']['qux']", 'hh')
print(data) # {'data': {'name': [12, -4]}, 'foo': {'bar': [5, 6], 'qux': 'hh'}}
Upvotes: 1