I have JSON like this.
{
"currentdatetime": "11",
"syncinterval_seconds": 4,
"public_keys": [
{
"system": "aa",
"pubkey": "aa"
}
],
"users": [
{
"username": "user",
"user_id": "user",
"realname": "user_10",
"emailaddress": "test#gmail.com",
"accountenabled": false,
"mustchangepassword": false,
"passwordhash": "$E6gi",
"accesslevel": [
"WORKER"
],
"expiration": "2022-11-02T16:21:52",
"site_specific": false,
"symkey": "aaaa",
"privatekey": "aaa"
},
]
}
and I created a dictionary like this which maps usernames to their respective access level
user_access = {
"user": "WORKER",
"user2": "ADMIN",
"user3": "WORKER",
"user4": "GENERAL"
}
I am trying to verify in my API response json that the defined user has the correct access level.
I wrote a function like this
def LoadUserList(apijson)
for user_result in apijson[USERS]:
username = user_result[USER_NAME]
accesslevel = user_result[accesslevel]
if (user_result[USER_NAME] == 'user' AND user_result[accesslevel] == 'WORKER')
print "success"
else
print "not matching"
But the above code is not working as expected. I don't know how to compare the values in the JSON with the values in the dictionary. How do I fix my code so that it prints "success" for each user in the JSON that has a matching accesslevel value in the user_access dictionary?
Dictionaries in python have 2 ways of accessing values by some key.
via hard bracket indexers - apijson["users"]
via .get - apijson.get("users")
Note that both are case-sensitive and both are using quotes to pass the values as strings rather than variable names. USERS = "users"; apijson[USERS] would be fine as well but USERS would need to first be defined.
Additionally -
We love colons in python so def LoadUserList(apijson): and if <>:/else:
The keywords or/and are case-sensitive so your example AND -> and
Your example json structure has users[0].accesslevel as an array so your (corrected) user_result["accesslevel"] == 'WORKER' won't evaluate to True since user_result["accesslevel"] = ["WORKER"]
So with some corrections,
def LoadUserList(apijson):
for user_result in apijson["users"]:
username = user_result["username"]
accesslevel = user_result["accesslevel"]
user_accesslevel = user_access.get(username) # "WORKER"
if (username == 'user' and user_accesslevel in accesslevel):
print("success")
else:
print("not matching")
Assuming apijson is a dict, e.g., generated by applying json.loads() on API result:
def LoadUserList(apijson)
for user in apijson['users']:
username, accesslevel = user['username'], user['accesslevel']
if user_access.get(username) in accesslevel:
print(username, "success")
else
print(username, "not matching")
Related
I a trying to expose an API (if that's the correct way to say it). I am using Quart, a python library made out of Flask and this is what my code looks like:
async def capture_post_request(request_json):
for item in request_json:
callbackidd = item['callbackid']
print(callbackidd)
#app.route('/start_work/', methods=['POST'])
async def start_work():
content_type = request.headers.get('content-type')
if (content_type == 'application/json'):
request_json = await request.get_json()
loop = asyncio.get_event_loop()
loop.create_task(capture_post_request(request_json))
body = "Async Job Started"
return body
else:
return 'Content-Type not supported!'
My schema looks like that:
[
{
"callbackid": "dd",
"itemid": "234r",
"input": [
{
"type": "thistype",
"uri": "www.uri.com"
}
],
"destination": {
"type": "thattype",
"uri": "www.urino2.com"
}
},
{
"statusCode": "202"
}
]
So far what I am getting is this error:
line 11, in capture_post_request
callbackidd = item['callbackid']
KeyError: 'callbackid'
I've tried so many stackoverflow posts to see how to iterate through my list of dicts but nothing worked. At one point in my start_work function I was using the get_data(as_text=True) method but still no results. In fact with the last method (or attr) I got:
TypeError: string indices must be integers
Any help on how to access those values is greatly appreciated. Cheers.
Your schema indicates there are two items in the request_json. The first indeed has the callbackid, the 2nd only has statusCode.
Debugging this should be easy:
async def capture_post_request(request_json):
for item in request_json:
print(item)
callbackidd = item.get('callbackid')
print(callbackidd) # will be None in case of the 2nd 'item'
This will print two dicts:
{
"callbackid": "dd",
"itemid": "234r",
"input": [
{
"type": "thistype",
"uri": "www.uri.com"
}
],
"destination": {
"type": "thattype",
"uri": "www.urino2.com"
}
}
And the 2nd, the cause of your KeyError:
{
"statusCode": "202"
}
I included the 'fix' of sorts already:
callbackidd = item.get('callbackid')
This will default to None if the key isn't in the dict.
Hopefully this will get you further!
Edit
How to work with only the dict containing your key? There are two options.
First, using filter. Something like this:
def has_callbackid(dict_to_test):
return 'callbackid' in dict_to_test
list_with_only_list_callbackid_items = list(filter(has_callbackid, request_json))
# Still a list at this point! With dicts which have the `callbackid` key
Filter accepts some arguments:
Function to call to determine if the value being tested should be filtered out or not.
The iterable you want to filter
Could also use a 'lambda function', but it's a bit evil. But serves the purpose just as well:
list_with_only_list_callbackid_items = list(filter(lambda x: 'callbackid' in x, request_json))
# Still a list at this point! With dict(s) which have the `callbackid` key
Option 2, simply loop over the result and only grab the one you want to use.
found_item = None # default
for item in request_json:
if 'callbackid' in item:
found_item = item
break # found what we're looking for, stop now
# Do stuff with the found_item from this point.
I want to get user id in payment_intent.payment_failed event and client_refrence_id isn't in request data in payment_failed event from stripe. I tried metadata={'user_id': user_id} but this too isn't showing in request data. Also tried this subscription_data.metadata = {"metadata": {"bar": "BAR", }}, but it is showing syntax error "SyntaxError: expression cannot contain assignment, perhaps you meant "=="? and even if I do this (==) it says SyntaxError: positional argument follows keyword argument
Here is my code:
checkout_session = stripe.checkout.Session.create(
client_reference_id=user_id,
# metadata={'user_id': user_id},
subscription_data.metadata = {"metadata": {"bar": "BAR", }},
success_url="success_url",
cancel_url="cancel_url",
payment_method_types=["card"],
mode="subscription",
line_items=[
{
"price": price_id,
"quantity": 1,
}
],
)
Here's my webhook code
def webhook_received(self):
payload = request.data
endpoint_secret = 'my_secret_key'
sig_header = request.headers.get('stripe-signature')
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
data = event['data']
except:
pass
event_type = event['type']
if event_type == 'checkout.session.completed':
self.handle_checkout_session(data)
elif event_type == 'payment_intent.payment_failed':
self.saving_failed_subscription_data(data)
return "success"
In order to pass the metadata through to the subscription in when creating the checkout session in Python, you need to use nested dictionaries instead of dot notation. So in your case you would revise the creation of the checkout session like so:
checkout_session = stripe.checkout.Session.create(
client_reference_id=user_id,
# metadata={'user_id': user_id},
# subscription_data.metadata = {"metadata": {"bar": "BAR", }}, <-- won't work
# This should work to get data to invoice/subscription
subscription_data = {
"metadata": {"user_id": user_id}
},
# This will get the metadata on to the related payment_intent
payment_intent_data={
"metadata": {"user_id": user_id}
},
success_url="success_url",
cancel_url="cancel_url",
payment_method_types=["card"],
mode="subscription",
line_items=[
{
"price": price_id,
"quantity": 1,
}
],
)
This approach of using dictionaries is required in Python to post data for any of the nested attributes that the Stripe APIs allow you to manipulate.
The Create a Session docs have a pretty long list of configurable parameters that it is worth reviewing, now that you've got the syntax for how to append nested data.
I continue to get this KeyError even though the key "name" obviously exists. I've attempted a couple methods to iterate through an array of dictionaries in Python with no luck. Any help is appreciated.
import re
from flask import Flask, json, request
from werkzeug.user_agent import UserAgent
app = Flask(__name__)
users = [
{"name:": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]
#/GET a user by ID
#app.route('/users/<string:name>')
def get_user_by_name(name):
#check to see if the user exists
for user in users:
if user['name'] == 'name':
return json.jsonify(users)
return json.jsonify({"message: " "user not found.."})
Error at line
if user['name'] == 'name':
KeyError: 'name'
It's because there is an extra colon "name:":.
What I think you mean is "name":.
And probably you mean return json.jsonify({"message:" "user not found.."}) instead of return json.jsonify({"message": "user not found.."}).
And if user['name'] == name: instead of if user['name'] == 'name':.
Your problem is when you create your users list, you have an extra colon in in the name key, it should be:
users = [
{"name": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]
The problem is not only the extra colon but also how you access the data in the list because, in list indices, you can only use integers or slices, not strings. Moreover, when you check the username, it should be a variable and not a string, otherwise, it will never pass through.
So it should be:
from flask import Flask, json, request
app = Flask(__name__)
users = [
{"name": "bitley",
"age": 5000,
"items": [
{"name:": "toyota"},
{"name": "camry"}
]
}
]
#app.route('/users/<string:name>')
def get_user_by_name(name):
#check to see if the user exists
for user in users:
if users[0]['name'] == name:
return json.jsonify(users)
return json.jsonify({"message: " "user not found.."})
This is an example of a JSON database that I will work with in my Python code.
{
"name1": {
"file": "abc"
"delimiter": "n"
},
"name2": {
"file": "def"
"delimiter": "n"
}
}
Pretend that a user of my code presses a GUI button that is supposed to change the name of "name1" to whatever the user typed into a textbox.
How do I change "name1" to a custom string without manually copying and pasting the entire JSON database into my actual code? I want the code to load the JSON database and change the name by itself.
Load the JSON object into a dict. Grab the name1 entry. Create a new entry with the desired key and the same value. Delete the original entry. Dump the dict back to your JSON file.
This is likely not the best way to perform the task. Use sed on Linux or its Windows equivalent (depending on your loaded apps) to make the simple stream-edit change.
If I understand clearly the task. Here is an example:
import json
user_input = input('Name: ')
db = json.load(open("db.json"))
db[user_input] = db.pop('name1')
json.dump(db, open("db.json", 'w'))
You can use the object_hook parameter that json.loads() accepts to detect JSON objects (dictionaries) that have an entry associated with the old key and re-associate its value with new key they're encountered.
This can be implement as a function as shown follows:
import json
def replace_key(json_repr, old_key, new_key):
def decode_dict(a_dict):
try:
entry = a_dict.pop(old_key)
except KeyError:
pass # Old key not present - no change needed.
else:
a_dict[new_key] = entry
return a_dict
return json.loads(json_repr, object_hook=decode_dict)
data = '''{
"name1": {
"file": "abc",
"delimiter": "n"
},
"name2": {
"file": "def",
"delimiter": "n"
}
}
'''
new_data = replace_key(data, 'name1', 'custom string')
print(json.dumps(new_data, indent=4))
Output:
{
"name2": {
"file": "def",
"delimiter": "n"
},
"custom string": {
"file": "abc",
"delimiter": "n"
}
}
I got the basic idea from #Mike Brennan's answer to another JSON-related question How to get string objects instead of Unicode from JSON?
What am I missing when trying to parse this JSON output with Python? The JSON looks like this:
{
"start": 0,
"terms": [
"process_name:egagent.exe"
],
"highlights": [],
"total_results": 448,
"filtered": {},
"facets": {},
"results": [
{
"username": "SYSTEM",
"alert_type": "test"
},
{
"username": "SYSTEM2",
"alert_type": "test"
}
]
}
The Python I'm trying to use to access this is simple. I want to grab username, but everything I try throws an error. When it doesn't throw an error, I seem to get the letter of each one. So, if I do:
apirequest = requests.get(requesturl, headers=headers, verify=False)
readable = json.loads(apirequest.content)
#print readable
for i in readable:
print (i[0])
I get s, t, h, t, f, f, r, which are the first letters of each item. If I try i[1], I get the second letter of each item. When I try by name, say, i["start"], I get an error saying the string indices must be integers. I'm pretty confused and I am new to Python, but I haven't found anything on this yet. Please help! I just want to access the username fields, which is why I am trying to do the for loop. Thanks in advance!
Try this:
for i in readable["results"]:
print i["username"]
Load your json string:
import json
s = """
{
"start": 0,
"terms": [
"process_name:egagent.exe"
],
"highlights": [],
"total_results": 448,
"filtered": {},
"facets": {},
"results": [
{
"username": "SYSTEM",
"alert_type": "test"
},
{
"username": "SYSTEM2",
"alert_type": "test"
}
]
}
"""
And print username for every result:
print [res['username'] for res in json.loads(s)['results']]
Output:
[u'SYSTEM', u'SYSTEM2']
for i in readable will iterate i through each key in the readable dictionary. If you then print i[0], you are printing the first character of each key.
Given that you want the values associated with the "username" key in the entries of the list which is associated with the "results" key, you can get them like this:
for result in readable["results"]:
print (result["username"])
If readable is your JSON object (dict), you can access elements like you'd in every map, using their keys.
readable["results"][0]["username"]
Should give you "SYSTEM" string as result.
To print every username, do:
for result in readable["results"]:
print(result["username"])
If your JSON is a str object, you have to deserialize it with json.loads(readable) first.