Python 3.8 - Unable to update dictionary - python

Hello I have this below dictionary that I want to update
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Federated":"arn:aws:iam::111111111111:saml-provider/Test"
},
"Action":"sts:AssumeRoleWithSAML",
"Condition":{
"StringEquals":{
"SAML:aud":"https://signin.aws.amazon.com/saml"
}
}
}
]
}
Want to update it to
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Federated":[
"arn:aws:iam::111111111111:saml-provider/Test",
"arn:aws:iam::111111111111:saml-provider/Test2"
]
},
"Action":"sts:AssumeRoleWithSAML",
"Condition":{
"StringEquals":{
"SAML:aud":"https://signin.aws.amazon.com/saml"
}
}
}
]
}
i.e. add "arn:aws:iam::111111111111:saml-provider/Test2" to "Federated" and also make it a list. Below is my code
new_arn = "arn:aws:iam::111111111111:saml-provider/Test2"
my_dict = {
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Federated":[
"arn:aws:iam::111111111111:saml-provider/Test",
]
},
"Action":"sts:AssumeRoleWithSAML",
"Condition":{
"StringEquals":{
"SAML:aud":"https://signin.aws.amazon.com/saml"
}
}
}
]
}
for b in my_dict['Statement']:
updated_arn = f"['{b['Principal']['Federated']}', {new_arn}]"
b['Principal']['Federated']: updated_arn
print(my_dict)
I am bit new to python and I am not sure what am I doing wrong the dict is not getting updated. Can someone please provide some guidance on what I may be doing wrong

As folks commented, you're constructing a string that looks like a list here:
for b in my_dict['Statement']:
updated_arn = f"['{b['Principal']['Federated']}', {new_arn}]"
b['Principal']['Federated']: updated_arn
You can create a real list instead:
for b in my_dict['Statement']:
updated_arn = [b['Principal']['Federated'], new_arn]
b['Principal']['Federated'] = updated_arn
# note it's `=` not `:` here
Edit:
If Federated is sometimes a string, and sometimes already a list, you'll need to check its type and act accordingly:
for b in my_dict['Statement']:
federated = b['Principal']['Federated']
if isinstance(federated, list):
federated.append(new_arn)
# (which updates the list within the dict, no need to assign back to the dict)
else:
b['Principal']['Federated'] = [federated, new_arn]

You can append to the current value of "Federated" as follows:
for b in my_dict['Statement']:
b['Principal']['Federated'].append(new_arn)

Related

Get item in dictionary inside list from JSON - Python

I need to get the name information, inside the "object" list.
In this example I need this information (10.0.0.19)
"sourceNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911113",
"name":"**10.0.0.19**"
}
]
}
I can get any information that is not in the "objects" lists with the command example_json[['metadata']['accessPolicy']['name']
and I get the "mb-test-01" information correctly from the json, but I don't know the syntax to get the items inside the "object" list.
to create this json I use in GET request this way
example_json = requests.get(f"https://{hostname}/api/fmc_config/v1/domain/{uuid}/policy/accesspolicies/{acp_id}/accessrules?expanded=true",headers=header_acp, verify=False).json()
follow the full json.
{
"metadata":{
"ruleIndex":1,
"section":"Mandatory",
"category":"--Undefined--",
"accessPolicy":{
"type":"AccessPolicy",
"name":"mb-test-01",
"id":"005056BF-7C6E-0ed3-0000-012884914323"
},
"timestamp":1635219651530,
"domain":{
"name":"Global",
"id":"e276abec-e0f2-11e3-8169-6d9ed49b625f",
"type":"Domain"
}
},
"links":{
"self":"https://fmcrestapisandbox.cisco.com/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/accesspolicies/005056BF-7C6E-0ed3-0000-012884914323/accessrules/005056BF-7C6E-0ed3-0000-000268434442"
},
"enabled":true,
"action":"ALLOW",
"type":"AccessRule",
"id":"005056BF-7C6E-0ed3-0000-000268434442",
"sourceNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911113",
"name":"10.0.0.19"
}
]
},
"destinationNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911491",
"name":"192.168.0.39"
}
]
},
"logBegin":false,
"logEnd":false,
"variableSet":{
"name":"Default-Set",
"id":"76fa83ea-c972-11e2-8be8-8e45bb1343c0",
"type":"VariableSet"
},
"logFiles":false,
"enableSyslog":false,
"vlanTags":{
},
"sendEventsToFMC":false,
"name":"rule-1"
}
Presumably you want to retrieve all "name"s under "objects" keys so you could use a recursive function:
def get_name(d):
for k,v in d.items():
if k=='objects':
for i in v:
yield i.get('name')
elif isinstance(v, dict):
yield from get_name(v)
names = list(get_name(data))
Output:
['10.0.0.19', '192.168.0.39']

Automatically entering next JSON level using Python in a similar way to JQ in bash

I am trying to use Python to extract pricePerUnit from JSON. There are many entries, and this is just 2 of them -
{
"terms": {
"OnDemand": {
"7Y9ZZ3FXWPC86CZY": {
"7Y9ZZ3FXWPC86CZY.JRTCKXETXF": {
"offerTermCode": "JRTCKXETXF",
"sku": "7Y9ZZ3FXWPC86CZY",
"effectiveDate": "2020-11-01T00:00:00Z",
"priceDimensions": {
"7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7": {
"rateCode": "7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7",
"description": "Processed translation request in AWS GovCloud (US)",
"beginRange": "0",
"endRange": "Inf",
"unit": "Character",
"pricePerUnit": {
"USD": "0.0000150000"
},
"appliesTo": []
}
},
"termAttributes": {}
}
},
"CQNY8UFVUNQQYYV4": {
"CQNY8UFVUNQQYYV4.JRTCKXETXF": {
"offerTermCode": "JRTCKXETXF",
"sku": "CQNY8UFVUNQQYYV4",
"effectiveDate": "2020-11-01T00:00:00Z",
"priceDimensions": {
"CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7": {
"rateCode": "CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7",
"description": "$0.000015 per Character for TextTranslationJob:TextTranslationJob in EU (London)",
"beginRange": "0",
"endRange": "Inf",
"unit": "Character",
"pricePerUnit": {
"USD": "0.0000150000"
},
"appliesTo": []
}
},
"termAttributes": {}
}
}
}
}
}
The issue I run into is that the keys, which in this sample, are 7Y9ZZ3FXWPC86CZY, CQNY8UFVUNQQYYV4.JRTCKXETXF, and CQNY8UFVUNQQYYV4.JRTCKXETXF.6YS6EN2CT7 are a changing string that I cannot just type out as I am parsing the dictionary.
I have python code that works for the first level of these random keys -
with open('index.json') as json_file:
data = json.load(json_file)
json_keys=list(data['terms']['OnDemand'].keys())
#Get the region
for i in json_keys:
print((data['terms']['OnDemand'][i]))
However, this is tedious, as I would need to run the same code three times to get the other keys like 7Y9ZZ3FXWPC86CZY.JRTCKXETXF and 7Y9ZZ3FXWPC86CZY.JRTCKXETXF.6YS6EN2CT7, since the string changes with each JSON entry.
Is there a way that I can just tell python to automatically enter the next level of the JSON object, without having to parse all keys, save them, and then iterate through them? Using JQ in bash I can do this quite easily with jq -r '.terms[][][]'.
If you are really sure, that there is exactly one key-value pair on each level, you can try the following:
def descend(x, depth):
for i in range(depth):
x = next(iter(x.values()))
return x
You can use dict.values() to iterate over the values of a dict. You can also use next(iter(dict.values())) to get a first (only) element of a dict.
for demand in data['terms']['OnDemand'].values():
next_level = next(iter(demand.values()))
print(next_level)
If you expect other number of children than 1 in the second level, you can just nest the fors:
for demand in data['terms']['OnDemand'].values():
for sub_demand in demand.values()
print(sub_demand)
If you are insterested in the keys too, you can use dict.items() method to iterate over dict keys and values at the same time:
for demand_key, demand in data['terms']['OnDemand'].items():
for sub_demand_key, sub_demand in demand.items()
print(demand_key, sub_demand_key, sub_demand)

How do I return an upper field in a JSON with python?

So, I need some help returning an ID having found a certain string. My JSON looks something like this:
{
"id": "id1"
"field1": {
"subfield1": {
"subrield2": {
"subfield3": {
"subfield4": [
"string1",
"string2",
"string3"
]
}
}
}
}
"id": "id2"
"field1": {
"subfield1": {
"subrield2": {
"subfield3": {
"subfield4": [
"string4",
"string5",
"string6"
]
}
}
}
}
}
Now, I need to get the ID from a certain string, for example:
For "string5" I need to return "id2"
For "string2" I need to return "id1"
In order to find these strings I have used objectpath python module like this: json_Tree.execute('$..subfield4'))
After doing an analysis on a huge amount of strings, I need to return the ones that are meeting my criterias. I have the strings that I need (for example "string3"), but now I have to return the IDs.
Thank you!!
Note: I don't have a lot of experience with coding, I just started a few months ago to work on a project in Python and I have been stuck on this for a while
Making some assumptions about the actual structure of the data as being:
[
{
"id": "id1",
"subfield1": {
"subfield2": {
"subfield3": {
"subfield4": [
"string1",
"string2",
"string3"
]
}
}
}
}
// And so on
]
And assuming that each string1, string2 etc. is in only one id, then you can construct this mapping like so:
data: List[dict] # The json parsed as a list of dicts
string_to_id_mapping = {}
for record in data:
for string in record["subfield1"]["subfield2"]["subfield3"]["subfield4"]:
string_to_id_mapping[string] = record["id"]
assert string_to_id_mapping["string3"] == "id1"
If each string can appear in multiple ids then the following will catch all of them:
from collections import defaultdict
data: List[dict] # The json parsed as a list of dicts
string_to_id_mapping = defaultdict(set)
for record in data:
for string in record["subfield1"]["subfield2"]["subfield3"]["subfield4"]:
string_to_id_mapping[string].add(record["id"])
assert string_to_id_mapping["string3"] == {"id1"}

How to get this json object in python?

so I want to get the first key element from this JSON using python 3.7 without knowing its name.
Here is the JSON:
{
"intent":[
{
"confidence":0.99313362101529,
"value":"sendmessage"
}
],
"wikipedia_search_query":[
{
"suggested":true,
"confidence":0.93804001808167,
"value":"message",
"type":"value"
}
],
"messenger_recipient":[
{
"confidence":0.93138399364195,
"value":"me",
"type":"value"
}
]
}
EDIT:
I want to compare the name of the first key like so:
if(jsonobj[0] == "wikipedia_search_query")
dosomething()
While Python 3.6+ does maintain insertion order on dictionaries, there's no guarantee that your incoming JSON will be in the order you expect. That being said, if you can guarantee the insertion order, here's a working example.
import json
js = """{
"intent":[
{
"confidence":0.99313362101529,
"value":"sendmessage"
}
],
"wikipedia_search_query":[
{
"suggested":true,
"confidence":0.93804001808167,
"value":"message",
"type":"value"
}
],
"messenger_recipient":[
{
"confidence":0.93138399364195,
"value":"me",
"type":"value"
}
]
}"""
json_data = json.loads(js)
first_key = next(iter(json_data))
first_value = json_data[next(iter(json_data))]
print(first_key)
print(first_value)
Output
intent
[{'confidence': 0.99313362101529, 'value': 'sendmessage'}]

TypeError: list indices must be integers, not dict

My json file look likes this and I'm trying to access the element syslog in a for loop.
{
"cleanup":{
"folderpath":"/home/FBML7HR/logs",
"logfilename":""
},
"preparation":{
"configuration":{
"src_configfile":"src.cfg",
"dest_configfile":"/var/home/FBML7HR/etc/vxn.cfg"
},
"executable_info1":[
{
"login_info":{
"hostname":"10.4.0.xxx",
"username":"***",
"password":"***"
}
},
{
"command":{
"folderpath":"/var/home/FBML7HR/SrcCode/vxnservers/fdchost/north/test/hostsim/",
"processname":"northhostsim",
"parameters":"-d"
}
}
],
"executable_info2":[
{
"login_info":{
"hostname":"10.4.0.xxx",
"username":"***",
"password":"***"
}
},
{
"command":{
"folderpath":"/var/home/FBML7HR/SrcCode/vxnservers/fdchost/north/build/Linux-2.6.18-194.8.1.el5/bin",
"processname":"northhost",
"parameters":"-s brazil -d"
}
}
],
"executable_info3":[
{
"login_info":{
"hostname":"10.4.0.xxx",
"username":"***",
"password":"***"
}
},
{
"command":{
"folderpath":"cd /var/home/xxx/SrcCode/vxnservers/fdchost/north/test/vxnclient_mt",
"processname":"vxnclient_north_mt",
"parameters":"0 320 205 14897 16880 60000 60000 2 2"
}
}
]
},
"execution":[
{
"test_case":{
"scriptname":"/var/home/FBML7HR/test/testcase1.sh",
"testreport":{
"syslog":"/var/log/messages",
"backupsyslog":"backuplogs1.txt",
"clientsimlog":"/var/home/FBML7HR/test/out.log",
"backupclientsimlog":"Clientlogs1.txt"
}
}
},
{
"test_case":{
"scriptname":"/var/home/FBML7HR/test/testcase2.sh",
"testreport":{
"syslog":"/var/log/messages",
"backupsyslog":"backuplogs2.txt",
"clientsimlog":"/var/home/FBML7HR/test/out.log",
"backupclientsimlog":"Clientlogs2.txt"
}
}
}
],
"verification":{
"testreport":{
"syslog":"/var/log/messages",
"backupsyslog":"backuplogs.txt",
"reportfilename":"/var/home/FBML7HR/test/out.log",
"backuplogfile":"Clientlogs.txt"
}
}
}
I do it like this:
for i in data['execution']:
cmd = data['execution'][i]['test_case']['scriptname']
But I get the error saying "TypeError: list indices must be integers, not dict".
I'm new to python (and json as well). Could anybody suggest where I'm going wrong ?
You are looping over the values in the list referenced by data['execution'], not indices.
Just use those values (dictionaries) directly:
for i in data['execution']:
cmd = i['test_case']['scriptname']
You probably want to give that a more meaningful loop name:
for entry in data['execution']:
cmd = entry['test_case']['scriptname']
you can try this, it works for me
dataArray=data['execution']
for i in range(len(dataArray)):
cmd = dataArray[i]['test_case']['scriptname']
This exactly loops by indices, so there will not be any confusion,
For me this is very simple and understandable

Categories

Resources