Issues looping through dict python - python

I'm running into an issue with actually successfully looping through a boto3 result for AWS Config. From my testing, I am able to perform the loop; however, it only outputs same violation instead of each violation for the different ARNs.
I realize where the issue is at in the code as I was doing the below:
for arn in configRule.items():
acmArn = configRule['EvaluationResults'][0]['EvaluationResultIdentifier']['EvaluationResultQualifier']['ResourceId']
But, when I try and take out the [0] so it is not a specific item I get "list indices must be integers or slices, not str".
My question is if there is an actual way to get this value to be incremented, so it will be able to get the different ARNs of the violations? Sorry if this is an easy answer, still new to Python, so trying to figure all this out.
Output Example:
{
"EvaluationResults": [
{
"Annotation": "Certificate will expire on 2023-01-21T23:59:59.000Z",
"ComplianceType": "NON_COMPLIANT",
"ConfigRuleInvokedTime": "2022-01-03 18:28:54.939000+00:00",
"EvaluationResultIdentifier": {
"EvaluationResultQualifier": {
"ConfigRuleName": "acm-certificate-expiration-check",
"ResourceId": "arn:aws:acm:us-west-2:xxxx:certificate/39a95537-e5aa-46dd-bc9b-04d7b2606bd0",
"ResourceType": "AWS::ACM::Certificate"
},
"OrderingTimestamp": "2021-12-22 00:29:01+00:00"
},
"ResultRecordedTime": "2022-01-03 18:28:55.672000+00:00"
},
{
"Annotation": "Certificate will expire on 2023-01-10T23:59:59.000Z",
"ComplianceType": "NON_COMPLIANT",
"ConfigRuleInvokedTime": "2022-01-03 18:28:54.939000+00:00",
"EvaluationResultIdentifier": {
"EvaluationResultQualifier": {
"ConfigRuleName": "acm-certificate-expiration-check",
"ResourceId": "arn:aws:acm:us-west-2:xxxx:certificate/493de1e8-2bcb-42c7-96df-ce88bdeac64c",
"ResourceType": "AWS::ACM::Certificate"
},
"OrderingTimestamp": "2021-12-12 18:25:14+00:00"
},
"ResultRecordedTime": "2022-01-03 18:28:55.683000+00:00"
}
],
"ResponseMetadata": {
"HTTPHeaders": {
"content-length": "955",
"content-type": "application/x-amz-json-1.1",
"date": "Mon, 03 Jan 2022 20:13:06 GMT",
"strict-transport-security": "max-age=86400",
"x-amzn-requestid": "a6e51323-9e4c-44c7-a15a-ea0314392ab6"
},
"HTTPStatusCode": 200,
"RequestId": "a6e51323-9e4c-44c7-a15a-ea0314392ab6",
"RetryAttempts": 0
}
}

configRules.items() for your example would be a sequence containing a single tuple, ('EvaluationResults', [...]). You don't really care about that key: you hard-code it in the body. What you really want is to iterate over the dicts in the list configRule['EvaluationResults']:
for arn in configRule['EvaluationResults']:
acmArn = arn['EvaluationResultIdentifier']['EvaluationResultQualifier']['ResourceId']

So, I'm not sure if this is the correct way to do this, but for now this is how I got this to work. This allows me to add a variable there and increase it each time it performs the loop.
I'm sure there is a better way to do this, but just what I found doing some testing.
i = 0
for key, value in configRule.items():
acmArn = configRule['EvaluationResults'][i]['EvaluationResultIdentifier']['EvaluationResultQualifier']['ResourceId']
i+=1

Related

Using Atlasians Insight API to bring over AWS resources

I'm very new to this API. I've been able to figure out everything in this link up until step 3 ([api docs][1]). I have a sample payload of what we want to import, but I have no idea what the schema/mapping should be. The example provided [here][2], for a hard drive does not make sense to me at all. I've even tried sending the exact payload/mapping from that example and get hit with a 409 error. Any help would be great.
Example of what I want to bring in:
{
"ARN": "arn:aws:codedeploy:ca-central-1:030375219570:deploymentconfig:CodeDeployDefault.LambdaCanary10Percent10Minutes",
"availabilityZone": "Not Applicable",
"awsAccountId": "030375219570",
"awsRegion": "ca-central-1",
"configuration": {
"computePlatform": "Lambda",
"deploymentConfigId": "00000000-0000-0000-0000-000000000008",
"deploymentConfigName": "CodeDeployDefault.LambdaCanary10Percent10Minutes",
"trafficRoutingConfig": {
"timeBasedCanary": {
"canaryInterval": 10,
"canaryPercentage": 10
},
"type": "TimeBasedCanary"
}
},
"configurationItemCaptureTime": "2022-02-09T20:42:23.445Z",
"configurationItemStatus": "ResourceDiscovered",
"configurationItemVersion": "1.3",
"configurationStateId": 1644439343445,
"configurationStateMd5Hash": "",
"relatedEvents": [],
"relationships": [],
"resourceId": "00000000-0000-0000-0000-000000000008",
"resourceName": "CodeDeployDefault.LambdaCanary10Percent10Minutes",
"resourceType": "AWS::CodeDeploy::DeploymentConfig",
"supplementaryConfiguration": {},
"tags": {}
}
If anyone knows how the mapping/schema would look for something like the above, I'm all ears.
thanks
[1]: https://developer.atlassian.com/cloud/assets/imports/workflow/
[2]: https://developer.atlassian.com/cloud/assets/imports/schema-and-mapping/?utm_source=%2Fcloud%2Finsight%2Fimports%2Fschema-and-mapping%2F&utm_medium=301#external-imports-schema-and-mapping

Is it possible to retreive object_story_spec for an ad creative which was not created with that object_story_spec? [Python Facebook API]

I have a set of ad creatives that I retreive through the Facebook Business Python SDK. I need these specifically to retreive the outbound URL when someone clicks on the ad: AdCreative['object_story_spec']['video_data']['call_to_action']['value']['link'].
I use the following call:
adcreatives = set.get_ad_creatives(fields=[
AdCreative.Field.id,
AdCreative.Field.name,
AdCreative.Field.object_story_spec,
AdCreative.Field.effective_object_story_id ,
])
Where set is an ad set.
For some cases, the result looks like this (with actual data removed), which is expected:
<AdCreative> {
"body": "[<BODY>]",
"effective_object_story_id": "[<EFFECTIVE_OBJECT_STORY_ID>]",
"id": "[<ID>]",
"name": "[<NAME>]",
"object_story_spec": {
"instagram_actor_id": "[<INSTAGRAM_ACTOR_ID>]",
"page_id": "[<PAGE_ID>]",
"video_data": {
"call_to_action": {
"type": "[<TYPE>]",
"value": {
"link": "[<LINK>]", <== This is what I need
"link_format": "[<LINK_FORMAT>]"
}
},
"image_hash": "[<IMAGE_HASH>]",
"image_url": "[<IMAGE_URL>]",
"message": "[<MESSAGE>]",
"video_id": "[<VIDEO_ID>]"
}
}
}
While sometimes results look like this:
<AdCreative> {
"effective_object_story_id": "[<EFFECTIVE_OBJECT_STORY_ID>]",
"id": "[<ID>]",
"name": "[<NAME>]",
"object_story_spec": {
"instagram_actor_id": "[<INSTAGRAM_ACTOR_ID>]",
"page_id": "[<PAGE_ID>]"
}
}
According to this earlier question: Can't get AdCreative ObjectStorySpec this is due to the fact that the object_story_spec is not populated if it is linked to a creative, instead of created along with the creative.
However, the video_data (and as such, the link), should be saved somewhere. Is there a way to retreive this? Maybe through effective_object_story_id?
The documentation page for object_story_spec (https://developers.facebook.com/docs/marketing-api/reference/ad-creative-object-story-spec/v12.0) does not have the information I am looking for.

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 to properly parse embedded value from JSON

I'm having trouble parsing this json for a particular key:
sample.json:
{
"AccessToken": {
"ABCD": {
"credential_type": "AccessToken",
"secret": "abcdefghijklmnopqrstuxwxyz",
"home_account_id": "4dafe035-ff2",
"environment": "login.microsoftonline.com",
"client_id": "f16f9f797",
"target": "Directory.Read.All User.Read profile openid email",
"realm": "56c621fa50f2",
"token_type": "Bearer",
"cached_at": "1599671717",
"expires_on": "1599675316",
"extended_expires_on": "1599675316"
}
},
"Account": {
"EFGH": {
"home_account_id": "f977-41eb-8241613.56c62bbe-8598-4b85-9e51-1ca753fa50f2",
"environment": "login.microsoftonline.com",
"realm": "56c62bbe8598",
"local_account_id": "4dafe0353-304e48a51613",
"username": "foo#mail.com",
"authority_type": "MS"
}
},
"IdToken": {
"WXYZ": {
"credential_type": "IdToken",
"secret": "abcdefghijklmnopqrstuxwxyz",
"home_account_id": "4dafe035-ff2",
"environment": "login.microsoftonline.com",
"realm": "56c6a753fa50f2",
"client_id": "f169aaf9f797"
}
}
}
The goal is to parse and print the "secret" from the "IdToken" section.
abcdefghijklmnopqrstuxwxyz
So far, I can print the entire "IdToken" section, but I just want the secret.
import json
with open('sample.json') as json_file:
data = json.load(json_file)
print(data['IdToken'])
print(data['IdToken'][0]['secret']) #Tried this. Doesnot work
You need to do
print(data['IdToken']['WXYZ']['secret'])
When you do data['IdToken'][0], it takes the first element from data['IdToken'] if data['IdToken'] was an array. But here, data['IdToken'] is a dict. To get an element from a dict, you need to use the dict key inside square brackets.
EDIT: (If you don't know the exact key, but only know the position)
JSON doesn't guarantee the order of elements in a map/dict. So, unless you are sure that the items in the dict will appear in a particular order, don't use this solution. But anyways, here is how you do it - you can do print(data['IdToken'][list(data['IdToken'].keys())[0]]['secret']). Also make sure to use OrderedDict while parsing JSON. Check out this answer for that - https://stackoverflow.com/a/47111106/1421222.
If you want to index on the nested dict of data you should just use its keys and append it on the list where you index on it with an index of [0] to get the first key which is dict to and get the secret
Example
print(data['IdToken'][[*(data['IdToken'].keys())][0]]['secret'])
and the above method will get the key of IdToken and if you don't know it

Getting KeyError when parsing JSON in Python for following response

TL;DR:
Confused on how to parse following JSON response and get the value of [status of 12345 of dynamicValue_GGG of payload] in this case.
Full question:
I get the following as (sanitized) response upon hitting a REST API via Python code below:
response = requests.request("POST", url, data=payload,
headers=headers).json()
{
"payload": {
"name": "asdasdasdasd",
"dynamicValue_GGG": {
"12345": {
"model": "asad",
"status": "active",
"subModel1": {
"dynamicValue_67890": {
"model": "qwerty",
"status": "active"
},
"subModel2": {
"dynamicValue_33445": {
"model": "gghjjj",
"status": "active"
},
"subModel3": {
"dynamicValue_66778": {
"model": "tyutyu",
"status": "active"
}
}
}
},
"date": "2016-02-04"
},
"design": "asdasdWWWsaasdasQ"
}
If I do a type(response['payload']), it gives me 'dict'.
Now, I'm trying to parse the response above and fetch certain keys and values out of it. The problem is that I'm not able to iterate through using "index" and rather have to specify the "key", but then the response has certain "keys" that are dynamically generated and sent over. For instance, the keys called "dynamicValue_GGG", "dynamicValue_66778" etc are not static unlike the "status" key.
I can successfully parse by mentioning like:
print response['payload']['dynamicValue_GGG']['12345'][status]
in which case I get the expected output = 'active'.
However, since I have no control on 'dynamicValue_GGG', it would work only if I can specify something like this instead:
print response['payload'][0][0][status]
But the above line gives me error: " KeyError: 0 " when the python code is executed.
Is there someway in which I can use the power of both keys as well as index together in this case?
The order of values in a dictionary in Python are random, so you cannot use indexing. You'll have to iterate over all elements, potentially recursive, and test to see if it's the thing you're looking for. For example:
def find_submodels(your_dict):
for item_key, item_values in your_dict.items():
if 'status' in item_values:
print item_key, item_values['status']
if type(item_values) == dict:
find_submodels(item_values)
find_submodels(your_dict)
Which would output:
12345 active
dynamicValue_67890 active
dynamicValue_66778 active
dynamicValue_33445 active

Categories

Resources