简体   繁体   中英

How to check if a key exists in a multiple level dictionary and if a key has a particular values?(Python)

I have a dictionary r_dict and I want to check the every keys in the r_dict['paths'] that the key security inside every endpoint (for example /pet/{petId}/uploadImage ) exists and inside the security, the values contains words read or write and append the result in the dictionary

result = {} as result[end_point_name] = 'secure' if key security is present and words read or write is present

ELSE

result[end_point_name] ='unsecure'

The following is a dictionary r_dict

r_dict = {"paths": {
"/pet/{petId}/uploadImage": {
"post": {
"tags": [
"pet"
],
"summary": "uploads an image",
"description": "",
"operationId": "uploadFile",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to update",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "additionalMetadata",
"in": "formData",
"description": "Additional data to pass to server",
"required": false,
"type": "string"
},
{
"name": "file",
"in": "formData",
"description": "file to upload",
"required": false,
"type": "file"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/ApiResponse"
}
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"put": {
"tags": [
"pet"
],
"summary": "Update an existing pet",
"description": "",
"operationId": "updatePet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
},
"405": {
"description": "Validation exception"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"name": "status",
"in": "query",
"description": "Status values that need to be considered for filter",
"required": true,
"type": "array",
"items": {
"type": "string",
"enum": [
"available",
"pending",
"sold"
],
"default": "available"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
} }

path "/pet" in r_dict has more than one http method unlike other paths, so have built the script to accomodate more than 1 http method in a path

result = {}
paths = r_dict['paths']
for path in paths:
    path_val = paths[path]
    methods = path_val.keys()
    for val in methods:
        key = f'{path}[{val}]'
        method_data = path_val[val]
        sec = method_data.get('security', None)
        if sec and len(sec) > 0:
            sec_tag = sec[0]
            petstore_data = sec_tag['petstore_auth']
            if any(item for item in petstore_data if 'read' in item or 'write' in item):
                result[key] = 'secure'
            else:
                result[key] = 'unsecure'
        else:
            result[key] = 'unsecure'

print(result)

this prints the below results for r_dict, as you can see the method names are also mentioned with paths:

{
    '/pet/{petId}/uploadImage[post]': 'secure',
    '/pet[post]': 'secure',
    '/pet[put]': 'secure',
    '/pet/findByStatus[get]': 'secure'
}

More type of methods are possible for a path ( GET , POST , PUT etc...) so these methods should be handled differently (I guess). I have written a solution which handles that different methods and the missing security attributes.

You can change this line end_point_with_method = "{} -> {}".format(method.upper(), end_point) if you want to change the keys in the result dict. BUT if you use only the path as key then the different methods won't be separated.

Code:

result = {}

for end_point, methods in r_dict["paths"].items():
    for method, data in methods.items():
        end_point_with_method = "{} -> {}".format(method.upper(), end_point)
        if "security" in data:
            for auths in [item["petstore_auth"] for item in data["security"]]:
                for auth in auths:
                    if "write" in auth or "read" in auth:
                        result[end_point_with_method] = "secure"
            if end_point_with_method not in result:
                result[end_point_with_method] = "unsecure"
        else:
            result[end_point_with_method] = "unsecure"

for path, secure in result.items():
    print("{} -> {}".format(path, secure))

Output:

>>> python3 test.py 
POST -> /pet/{petId}/uploadImage -> secure
POST -> /pet -> secure
PUT -> /pet -> secure
GET -> /pet/findByStatus -> secure

If I change the data in PUT method of /pet path to:

"security": [{"petstore_auth": ["X:pets", "Y:pets"]}]

The output is:

>>> python3 test.py 
POST -> /pet/{petId}/uploadImage -> secure
POST -> /pet -> secure
PUT -> /pet -> unsecure
GET -> /pet/findByStatus -> secure

If I remove the security member competelly from PUT method of /pet path then output is:

>>> python3 test.py 
POST -> /pet/{petId}/uploadImage -> secure
POST -> /pet -> secure
PUT -> /pet -> unsecure
GET -> /pet/findByStatus -> secure

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM