Python, How to zip and restructure complex data set - python

I am a new python user, and I have just been getting familiar with restructuring data with the zip function, however I am now faced with a challenging data set that i have to restructure. I have 3 json responses that I have to merge from my end, the data sets are identical in design and would have the same length, they just differ from environments they ran on.
Let 3 files be the same values for brevity: qa.json | dev.json | prod.json
Note: This outer object is array/list of object, I just put one object for brevity
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"status": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"status": "passed"
}
},
{
"name": "map should display",
"result": {
"status": "passed"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"status": "passed"
}
]
What I want to achieve:
Note: i want to merge them in one set with different environments reflecting the status
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"qa": "passed",
"prod": "passed",
"dev": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"qa": "passed",
"prod": "passed",
"dev": "passed"
}
},
{
"name": "map should display",
"result": {
"qa": "passed",
"prod": "passed",
"dev": "passed"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"qa": "passed",
"prod": "passed",
"dev": "passed"
}
]
What i have done so far:
I come from a javascript background so i im still getting familiar with python logic
import json
with open('qa.json') as data_file:
qa = json.load(data_file)
with open('dev.json') as data_file:
dev = json.load(data_file)
with open('prod.json') as data_file:
prod = json.load(data_file)
json_list = [{SOME STRUCT} for q, d, p in zip(qa, dev, prod)]

I don't have a lot of time so I'm posting what I believe is a working solution to your problem even if it's slightly messy. If I have time I'll edit it.
Code
import json
data = """
[
{
"elements": [{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [{
"name": "a valid user name and password",
"result": {
"status": "passed"
}
}, {
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"status": "passed"
}
}, {
"name": "map should display",
"result": {
"status": "passed"
}
}]
}],
"keyword": "Feature",
"name": "login",
"status": "passed"
},
{
"elements": [{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [{
"name": "a valid user name and password",
"result": {
"status": "passed"
}
}, {
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"status": "failed"
}
}, {
"name": "map should display",
"result": {
"status": "passed"
}
}]
}],
"keyword": "Feature",
"name": "login",
"status": "passed"
}
]
"""
def get_result(envData, objIndex, elementIndex, stepIndex):
return envData[objIndex]['elements'][elementIndex]['steps'][stepIndex]['result']['status']
def set_combined_results(combinedData, objIndex, elementIndex, stepIndex, results):
resultNode = combinedData[objIndex]['elements'][elementIndex]['steps'][stepIndex]['result']
resultNode.update({ 'qa': results[0], 'prod': results[1], 'dev': results[2] })
if __name__ == '__main__':
qAData = json.loads(data)
prodData = json.loads(data)
devData = json.loads(data)
combinedData = json.loads(data)
for objIndex, obj in enumerate(combinedData):
for elementIndex, element in enumerate(obj['elements']):
for stepIndex, _ in enumerate(element['steps']):
qAResult = get_result(qAData, objIndex, elementIndex, stepIndex)
prodResult = get_result(prodData, objIndex, elementIndex, stepIndex)
devResult = get_result(devData, objIndex, elementIndex, stepIndex)
combinedResults = (qAResult, prodResult, devResult)
set_combined_results(combinedData, objIndex, elementIndex, stepIndex, combinedResults)
qAAggregateResult = qAData[objIndex]['status']
prodAggregateResult = prodData[objIndex]['status']
devAggregateResult = devData[objIndex]['status']
del combinedData[objIndex]['status']
combinedData[objIndex]['qa'] = qAAggregateResult
combinedData[objIndex]['prod'] = prodAggregateResult
combinedData[objIndex]['dev'] = devAggregateResult
print(json.dumps(combinedData, indent=True))
Output
[
{
"keyword": "Feature",
"name": "login",
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"result": {
"qa": "passed",
"status": "passed",
"dev": "passed",
"prod": "passed"
},
"name": "a valid user name and password"
},
{
"result": {
"qa": "passed",
"status": "passed",
"dev": "passed",
"prod": "passed"
},
"name": "a valid user clicking on the login button after typing in user name and password"
},
{
"result": {
"qa": "passed",
"status": "passed",
"dev": "passed",
"prod": "passed"
},
"name": "map should display"
}
]
}
],
"dev": "passed",
"prod": "passed",
"qa": "passed"
},
{
"keyword": "Feature",
"name": "login",
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"result": {
"qa": "passed",
"status": "passed",
"dev": "passed",
"prod": "passed"
},
"name": "a valid user name and password"
},
{
"result": {
"qa": "failed",
"status": "failed",
"dev": "failed",
"prod": "failed"
},
"name": "a valid user clicking on the login button after typing in user name and password"
},
{
"result": {
"qa": "passed",
"status": "passed",
"dev": "passed",
"prod": "passed"
},
"name": "map should display"
}
]
}
],
"dev": "failed",
"prod": "failed",
"qa": "failed"
}
]

This is a recursive merge implementation. It will merge arbitrary types of Python objects, such that anything but dicts must be equal when merged.
For dicts, it will allow merging if the same keys are associated with mergable values in those where the key is present. Any dict keys equalling the parameter fieldname will be suffixed with an index before merging:
from copy import deepcopy
from itertools import chain
def merge(field_name, *objs):
# Make sure all objs are of same type
types = list(set(map(type, objs)))
if not len(set(map(type, objs))) == 1:
raise Exception('Cannot merge objects of different types: {types}'.format(types=types))
first = objs[0]
# for any random objects, make sure they are equal!
if not isinstance(first, (list, tuple, dict)):
if not len(set(objs)) == 1:
raise Exception("Cannot merge non-equal objects that aren't dicts: {objs}".format(objs=objs))
return deepcopy(first)
# for lists, tuples: zip 'em and merge the zipped elements
if isinstance(first, (list, tuple)):
return [merge(field_name, *zipped) for zipped in zip(*objs)]
# dicts
result_dict = {}
keys = list(set(chain.from_iterable(d.keys() for d in objs)))
try:
keys.remove(field_name)
except ValueError:
pass
for k in keys:
# merge values from all dicts where key is present
result_dict[k] = merge(field_name, *(d[k] for d in objs if k in d))
for i, d in enumerate(objs):
if field_name in d:
result_dict['{f}_{i}'.format(f=field_name, i=i)] = d[field_name]
return result_dict
This can now be used on dev, qa, prod that are dicts of the structure given by th OP:
>>> from pprint import pprint
>>> pprint(merge('status', qa, dev, prod))
[{'elements': [{'keyword': 'Scenario',
'name': 'valid user can login site',
'steps': [{'name': 'a valid user name and password',
'result': {'status_0': 'passed',
'status_1': 'passed',
'status_2': 'passed'}},
{'name': 'a valid user clicking on the login button after typing in user name and password',
'result': {'status_0': 'passed',
'status_1': 'passed',
'status_2': 'passed'}},
{'name': 'map should display',
'result': {'status_0': 'passed',
'status_1': 'passed',
'status_2': 'passed'}}]}],
'keyword': 'Feature',
'name': 'login',
'status_0': 'passed',
'status_1': 'passed',
'status_2': 'passed'}]
This is, of course, not fully generic, e.g. it only "deep" merges sequences when they are lists or tuples, but it should be decent enough for data structures loaded from json. I hope it helps you find a solution.

Because each object in the list is a dict you can use dict.update mehthod to update a dict.
f.e.
a = [{'one': 1}, {'three': 3}]
b = [{'one': 1}, {'two': 2}] # {'one': 1} is duplicate with same value
c = [{'a': 'aaa'}, {'two': 22}] # {'two': 22} is duplicate with different value
for x, y, z in zip(a, b, c):
x.update(y)
x.update(z)
Now x would be [{'a': 'aaa', 'one': 1}, {'three': 3, 'two': 22}]
For those json files you mentioned, it would be;
import json
from pprint import pprint
qa = '''
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"qa": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"qa": "passed"
}
},
{
"name": "map should display",
"result": {
"qa": "passed"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"qa": "passed"
}
]
'''
dev = '''
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"dev": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"dev": "passed"
}
},
{
"name": "map should display",
"result": {
"dev": "passed"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"dev": "passed"
}
]
'''
prod = '''
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"prod": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"prod": "passed"
}
},
{
"name": "map should display",
"result": {
"prod": "passed"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"prod": "passed"
}
]
'''
qa = json.loads(qa)
dev = json.loads(dev)
prod = json.loads(prod)
for q, p, d in zip(qa, dev, prod):
# update all keys but 'elements'
q.update({k: v for k, v in p.items() if k != 'elements'})
q.update({k: v for k, v in d.items() if k != 'elements'})
# update the three 'result' dict
for i in range(3):
q['elements'][0]['steps'][i]['result'].update(p['elements'][0]['steps'][i]['result'])
q['elements'][0]['steps'][i]['result'].update(d['elements'][0]['steps'][i]['result'])
pprint(qa)
Output;
[{'dev': 'passed',
'elements': [{'keyword': 'Scenario',
'name': 'valid user can login site',
'steps': [{'name': 'a valid user name and password',
'result': {'dev': 'passed',
'prod': 'passed',
'qa': 'passed'}},
{'name': 'a valid user clicking on the login button '
'after typing in user name and password',
'result': {'dev': 'passed',
'prod': 'passed',
'qa': 'passed'}},
{'name': 'map should display',
'result': {'dev': 'passed',
'prod': 'passed',
'qa': 'passed'}}]}],
'keyword': 'Feature',
'name': 'login',
'prod': 'passed',
'qa': 'passed'}]

Related

How to extract data from complex JSON object?

I am trying to extract data from the json file I got from a get request.
{
"data": [
{
"type": "Projects",
"id": "102777c7-50a7-592d-1b65-621d5850a5bb",
"attributes": {
"name": "Hydroelectric Project Updated from Postman",
"projectid": "001"
},
"relationships": {
"Accounts": "Account1"
"Notes": "Note1"
}
},
{
"type": "Projects",
"id": "102c7131-d797-c085-d248-621d5820494f",
"attributes": {
"name": "Ana Hydroelectric Project",
"projectid": "002"
},
"relationships": {
"Accounts": "Account1"
"Notes": "Note1"
}
},
{
"type": "Projects",
"id": "1041f300-5acf-4bd9-2ec4-621d58bbe6bc",
"attributes": {
"name": "Methane Capture Project",
"projectid": "003"
},
"relationships": {
"Accounts": "Account1"
"Notes": "Note1"
}
}
]
}
I have an empty dictionary that stores projectid as Key.
projectids = {
001:"",
002:"",
003:"",
004:"",
}
I was looking for a way to find "projectid" inside "attributes" and the corresponding value for "id" and populate the dictionary projectids with the key(['attributes']['projectid']) and values(id):
{
"001": "102777c7-50a7-592d-1b65-621d5850a5bb",
"002": "102c7131-d797-c085-d248-621d5820494f",
"003": "1041f300-5acf-4bd9-2ec4-621d58bbe6bc",
"004": ""
}
You can try this, assuming data is your variable for the response from the GET request
# this solution will populate for all project ids
projectids = {}
for item in data['data']:
projectids[item['attributes']['projectid']] = item['id']
Output:
{
'001': '102777c7-50a7-592d-1b65-621d5850a5bb',
'002': '102c7131-d797-c085-d248-621d5820494f',
'003': '1041f300-5acf-4bd9-2ec4-621d58bbe6bc'
}
if you're trying to match with already existing projectids in a dict then try
# this solution will search for only pre-specified project ids
projectids = {
"001": "",
"002": "",
"003": "",
"004": "",
}
for idx in projectids.keys():
# find the index of matching dict from data['data']
# will return None if match is not found
matching_index = next((i for i, item in enumerate(data['data']) if
item["attributes"]["projectid"] == idx), None)
if matching_index is not None:
projectids[idx] = data['data'][matching_index]['id']
If data is your input data from the question, then:
projectids = {f"{i:>03}": "" for i in range(1, 5)}
out = {
**projectids,
**{d["attributes"]["projectid"]: d["id"] for d in data["data"]},
}
print(out)
Prints:
{
"001": "102777c7-50a7-592d-1b65-621d5850a5bb",
"002": "102c7131-d797-c085-d248-621d5820494f",
"003": "1041f300-5acf-4bd9-2ec4-621d58bbe6bc",
"004": "",
}
Simply try this:
json_data = {
"data": [
{
"type": "Projects",
"id": "102777c7-50a7-592d-1b65-621d5850a5bb",
"attributes": {
"name": "Hydroelectric Project Updated from Postman",
"projectid": "001"
},
"relationships": {
"Accounts": "Account1",
"Notes": "Note1"
}
},
{
"type": "Projects",
"id": "102c7131-d797-c085-d248-621d5820494f",
"attributes": {
"name": "Ana Hydroelectric Project",
"projectid": "002"
},
"relationships": {
"Accounts": "Account1",
"Notes": "Note1"
}
},
{
"type": "Projects",
"id": "1041f300-5acf-4bd9-2ec4-621d58bbe6bc",
"attributes": {
"name": "Methane Capture Project",
"projectid": "003"
},
"relationships": {
"Accounts": "Account1",
"Notes": "Note1"
}
}
]
}
Just asumme the above json data and try the following code:
project_ids = {item['attributes']['projectid']:item['id'] for item in json_data['data']}
expected output:
{'001': '102777c7-50a7-592d-1b65-621d5850a5bb',
'002': '102c7131-d797-c085-d248-621d5820494f',
'003': '1041f300-5acf-4bd9-2ec4-621d58bbe6bc'}

Merge Json with same key value pairs

I got a resultant json from an API in the following format
[{
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Name": "Kiran"
}
}, {
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Age": "24"
}
},
{
"Uid": "196f5865-e9fe-4847-86ae-97d0bf57b816",
"Id": "84909ecb-c92e-48a7-bcaa-d478bf3a9220",
"Details": {
"Name": "Shreyas"
}
}
]
since the Uid and Id are same for multiple entires, can I club them togeather with Details key being the comma seperate key,value pair? Something like mentioned below
[{
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Name": "Kiran",
"Age": "24"
}
},
{
"Uid": "196f5865-e9fe-4847-86ae-97d0bf57b816",
"Id": "84909ecb-c92e-48a7-bcaa-d478bf3a9220",
"Details": {
"Name": "Shreyas"
}
}]
Please Guide me on this for the approach to be followed. Thanks
What you need is the dictionary function update(). Here's an example:
A = [{
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Name": "Kiran"
}
}, {
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Age": "24"
}
},
{
"Uid": "196f5865-e9fe-4847-86ae-97d0bf57b816",
"Id": "84909ecb-c92e-48a7-bcaa-d478bf3a9220",
"Details": {
"Name": "Shreyas"
}
}
]
B = []
def find(uid, id_):
for i, d in enumerate(B):
if d['Uid'] == uid and d['Id'] == id_:
return i
return -1
for d in A:
if (i := find(d['Uid'], d['Id'])) < 0:
B.append(d)
else:
B[i]['Details'].update(d['Details'])
print(B)
Prettyfied output:
[
{
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Name": "Kiran",
"Age": "24"
}
},
{
"Uid": "196f5865-e9fe-4847-86ae-97d0bf57b816",
"Id": "84909ecb-c92e-48a7-bcaa-d478bf3a9220",
"Details": {
"Name": "Shreyas"
}
}
]
Note:
This could be very inefficient if your API response contains very large numbers of dictionaries. You might need a completely different approach
You should iterate over the list and merge with accumulator with (Uid, Id) as key:
from typing import Dict, List
l = [{
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Name": "Kiran"
}
}, {
"Uid": "40cc6103-1cf0-4735-b882-d14d32018e58",
"Id": "9e1a0057-4570-4a6e-8ff5-88b2facbaf4e",
"Details": {
"Age": "24"
}
},
{
"Uid": "196f5865-e9fe-4847-86ae-97d0bf57b816",
"Id": "84909ecb-c92e-48a7-bcaa-d478bf3a9220",
"Details": {
"Name": "Shreyas"
}
}
]
def mergeItem(it: Dict, acc: Dict) -> Dict:
uid = it["Uid"]
id = it["Id"]
if (uid, id) in acc:
acc[(uid, id)] = {"Uid": uid, "Id": id, "Details": {**acc[(uid, id)]["Details"], **it["Details"]}}
else:
acc[(uid, id)] = {"Uid": uid, "Id": id, "Details": it["Details"]}
return acc
def mergeList(a:List) -> Dict:
acc = {}
for v in a:
acc = mergeItem(v, acc)
return acc
print(list(mergeList(l).values()))
# [
# {
# 'Uid': '40cc6103-1cf0-4735-b882-d14d32018e58',
# 'Id': '9e1a0057-4570-4a6e-8ff5-88b2facbaf4e',
# 'Details': {'Name': 'Kiran', 'Age': '24'}},
# {
# 'Uid': '196f5865-e9fe-4847-86ae-97d0bf57b816',
# 'Id': '84909ecb-c92e-48a7-bcaa-d478bf3a9220',
# 'Details': {'Name': 'Shreyas'}
# }
# ]

glom assign based on data

In the following code, I am trying to mask personal information based on data. I have two scenarioes. In scenario 1, I want to update when type = 'FirstName', update or assign valueString value to "Masked". In scenario 2, I want to update when type matches the pattern "first****Name", update or assign valueString value to "Masked". I was wondering if anyone have suggestions for writing glom assign statements to solve the above cases.
Example Json String
{
"id": "985babac-9999-8888-8887",
"entity": [
{
"what": {
"reference": "4lincoln-123-11eb-bc1a-732f"
},
"detail": [
{
"type": "uuid",
"valueString": "4obama-f199-77eb-bc1a-555555704d2f"
},
{
"type": "firstName",
"valueString": "John"
},
{
"type": "userName",
"valueString": "Johns"
},
{
"type": "middleInitial",
"valueString": "S"
},
{
"type": "lastName",
"valueString": "Trump"
},
{
"type": "first-4fa999-f1999-Name",
"valueString": "John"
},
{
"type": "birth-4fa999-f1999-Date",
"valueString": "2010-01-01"
}
]
}
]
}
Updated output should look like the following
{
"id": "985babac-9999-8888-8887",
"entity": [
{
"what": {
"reference": "4lincoln-123-11eb-bc1a-732f"
},
"detail": [
{
"type": "uuid",
"valueString": "4obama-f199-77eb-bc1a-555555704d2f"
},
{
"type": "firstName",
"valueString": "Masked"
},
{
"type": "userName",
"valueString": "Johns"
},
{
"type": "middleInitial",
"valueString": "S"
},
{
"type": "lastName",
"valueString": "Trump"
},
{
"type": "first-4fa999-f1999-Name",
"valueString": "Masked"
},
{
"type": "birth-4fa999-f1999-Date",
"valueString": "2010-01-01"
}
]
}
]
}
I came up with the following solution. I was wondering if this can be done in one glom call instead of calling multiple times?
import json
import logging
import sys
import time
import re
from glom import glom, assign, Coalesce, SKIP, Spec, Path, Call, T, Iter, Inspect
LOGGING_FORMAT = '%(asctime)s - [%(filename)s:%(name)s:%(lineno)d] - %(levelname)s - %(message)s'
LOGLEVEL = logging.INFO
logging.basicConfig(level=LOGLEVEL,format=LOGGING_FORMAT)
logger = logging.getLogger(__name__)
start_time = time.time()
target = {
"id": "985babac-9999-8888-8887",
"entity": [
{
"what": {
"reference": "4lincoln-123-11eb-bc1a-732f"
},
"detail": [
{
"type": "uuid",
"valueString": "4obama-f199-77eb-bc1a-555555704d2f"
},
{
"type": "firstName",
"valueString": "John"
},
{
"type": "userName",
"valueString": "Johns"
},
{
"type": "middleInitial",
"valueString": "S"
},
{
"type": "lastName",
"valueString": "Trump"
},
{
"type": "first-4fa999-f1999-Name",
"valueString": "John"
},
{
"type": "birth-4fa999-f1999-Date",
"valueString": "2010-01-01"
}
]
}
]
}
# def myupdate(x):
# for count, item in enumerate(x):
# myspec = 'entity.0.detail.{}.valueString'.format(count)
# if item == 'firstName':
# _ = assign(target,myspec,'Masked')
piiRegex = re.compile(r'^first.*Name$|^last.*Name$|^middle.*Initial$|^birth.*Date$')
def myupdate(x):
for count, item in enumerate(x):
myspec = 'entity.0.detail.{}.valueString'.format(count)
mo = piiRegex.search(item)
if mo:
_ = assign(target,myspec,'Masked')
spec = {'result': ('entity.0.detail', ['type'], myupdate)}
xyz = glom(target, spec)
print(xyz)
print(target)
logger.info("Program completed in --- %s seconds ---" % (time.time() - start_time))
===============
Result:
{'result': None}
{'id': '985babac-9999-8888-8887', 'entity': [{'what': {'reference': '4lincoln-123-11eb-bc1a-732f'}, 'detail': [{'type': 'uuid', 'valueString': '4obama-f199-77eb-bc1a-555555704d2f'}, {'type': 'firstName', 'valueString': 'Masked'}, {'type': 'userName', 'valueString': 'Johns'}, {'type': 'middleInitial', 'valueString': 'Masked'}, {'type': 'lastName', 'valueString': 'Masked'}, {'type': 'first-4fa999-f1999-Name', 'valueString': 'Masked'}, {'type': 'birth-4fa999-f1999-Date', 'valueString': 'Masked'}]}]}

How to get this json specific word from this array

I have this json and I would like to get only the Name from every array. How do I write it in python,
Currently, I have this li = [item.get(data_new[0]'id') for item in data_new]
where data_new is my json data.
[
{
"id": "1687fbfa-8936-4b77-a7bc-123f9f276c49",
"attributes": [
{
"name": "status",
"value": "rejected",
"scope": "identity"
},
{
"name": "created_ts",
"value": "2020-06-25T16:22:07.578Z",
"scope": "system"
},
{
"name": "updated_ts",
"value": "2020-07-08T12:43:09.361Z",
"scope": "system"
},
{
"name": "artifact_name",
"value": "release-v10",
"scope": "inventory"
},
{
"name": "device_type",
"value": "proddemo-device",
"scope": "inventory"
},
],
"updated_ts": "2020-07-08T12:43:09.361Z"
},
{
"id": "0bf2a1fe-6004-473f-88b7-aab061972115",
"attributes": [
{
"name": "status",
"value": "rejected",
"scope": "identity"
},
{
"name": "created_ts",
"value": "2020-07-01T16:23:00.631Z",
"scope": "system"
},
{
"name": "updated_ts",
"value": "2020-07-08T17:41:16.45Z",
"scope": "system"
},
{
"name": "artifact_name",
"value": "Module_logs_v7",
"scope": "inventory"
},
{
"name": "cpu_model",
"value": "ARMv8 Processor",
"scope": "inventory"
},
{
"name": "device_type",
"value": "device",
"scope": "inventory"
},
{
"name": "hostname",
"value": "device004",
"scope": "inventory"
},
{
"name": "ipv4_br-d6eae8b3a339",
"value": "172.0.0.1/18",
"scope": "inventory"
}
],
"updated_ts": "2020-07-08T12:43:09.361Z"
}
]
This is the output snippet from my API and from this output I want to retrieve the value of the device whose name is hostname, as you can see that is the second last entry from this code where "name": "hostname"
So, I want to retrieve the value for that particular json only where the name will be "hostname", how can I do that.
Please guide me through.
a = [{'id': '291ae0e5956c69c2267489213df4459d19ed48a806603def19d417d004a4b67e',
'attributes': [{'name': 'ip_addr',
'value': '1.2.3.4',
'descriptionName': 'IP address'},
{'name': 'ports', 'value': ['8080', '8081'], 'description': 'Open ports'}],
'updated_ts': '2016-10-03T16:58:51.639Z'},
{'id': '76f40e5956c699e327489213df4459d1923e1a806603def19d417d004a4a3ef',
'attributes': [{'name': 'mac',
'value': '00:01:02:03:04:05',
'descriptionName': 'MAC address'}],
'updated_ts': '2016-10-04T18:24:21.432Z'}]
descriptionName = []
for i in a:
for j in i["attributes"]:
for k in j:
if k == "descriptionName":
descriptionName.append(j[k])
One liner:
[j["descriptionName"] for j in i["attributes"] for i in a if "descriptionName" in j ]
Output:
['IP address', 'MAC address']
Update 1:
To get all names
One liner code -
[j["name"] for j in i["attributes"] for i in a if "name" in j.keys()]
Output:
['status',
'status',
'created_ts',
'created_ts',
'updated_ts',
'updated_ts',
'artifact_name',
'artifact_name',
'cpu_model',
'cpu_model',
'device_type',
'device_type',
'hostname',
'hostname',
'ipv4_br-d6eae8b3a339',
'ipv4_br-d6eae8b3a339']
To get value for which name is "hostname"
[j["value"] for j in i["attributes"] for i in a if "name" in j.keys() and j["name"] == "hostname"]
Output:
['device004', 'device004']

Python how to insert objects in nested lists

How do I insert an object in nested lists. I get json response that doesn't return a a certain object for certain a condition
data.json
Note: in 'steps' list, the 3rd index did not return result
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"status": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"status": "passed"
}
},
{
"name": "map should display"
}
]
}
],
"keyword": "Feature",
"name": "login",
"status": "passed"
}
]
What I want to achieve:
I want to insert a 'result' object if it is absent
[
{
"elements": [
{
"keyword": "Scenario",
"name": "valid user can login site",
"steps": [
{
"name": "a valid user name and password",
"result": {
"status": "passed"
}
},
{
"name": "a valid user clicking on the login button after typing in user name and password",
"result": {
"status": "passed"
}
},
{
"name": "map should display"
"result": {
"status": "skipped"
}
}
]
}
],
"keyword": "Feature",
"name": "login",
"status": "passed"
}
]
What i've done so far (pseudo):
with open('data.json') as data_file:
data = json.load(data_file)
#nested for loops??
#if x.has_key('result') == False
#insert result object
The following should word for you:
for step in data[0]['elements'][0]['steps']:
if 'result' not in step:
step['result'] = {"status": "skipped"}
More generic solution:
for d in data:
for element in d['elements']:
for step in element['steps']:
if 'result' not in step:
step['result'] = {"status": "skipped"}

Categories