This was the question given to me:
Implement a function to query json_schema
The goal of this exercise is to implement a function that allows you to query the type of a keypath in a JSON schema.
This function will accept a valid JSON schema as dict, a key_path (eg:
foo.bar.baz
) and return the type of the property.Note:
- There are only two fields in the schema you have to pay attention to:
properties
anddefinitions
.- If the dictionary associated with the field has a field named
$ref
it means that it's referring to another schema stored under the top- level schema. You have follow the link to get to the actual definition.- For the sake of this exercise you can assume that all values for
$ref
will start with#/<key_path>
.- You should see a schema and some assert statements under "Test" section. You should NOT have to change anything under the "Test" section. If you can get our code to pass the tests, then it means your function works as expected.
- Feel free to use whatever libraries you need to use except any libraries that actually allow you to query the JSON schema.
I followed it by doing this:
import json
import copy
schema = json.loads('''{
"$id": "https://example.com/nested-schema.json",
"title": "nested-schema",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"EmploymentInformation",
"EmployeePartyID",
"Age"
],
"properties": {
"EmployeePartyID": {
"type": "string",
"minLength": 1,
"maxLength": 3
},
"EmploymentInformation": {
"$ref": "#/definitions/EmploymentInformation"
},
"Age": {
"type": "integer",
"minimum": 16,
"maximum": 80
}
},
"definitions": {
"EmploymentInformation": {
"type": "object",
"required": [
"OriginalHireDate"
],
"properties": {
"OriginalHireDate": {
"type": "string",
"format": "date"
},
"Beneficiary": {
"$ref": "#/definitions/DependantInformation"
}
}
},
"DependantInformation": {
"type": "object",
"required": [
"Name"
],
"properties": {
"Name": {
"type": "string",
"minLength": 5
}
}
}
},
"description": "nested-schema"
}''')
def resolve_ref(ref, modified_schema):
ref_path = ref["$ref"].split("/")[1:]
ref_obj = modified_schema
for node in ref_path:
ref_obj = ref_obj[node]
resolve_refs(ref_obj, modified_schema)
return ref_obj
def resolve_refs(json_schema, modified_schema=None):
if modified_schema is None:
modified_schema = json_schema
for k, v in json_schema.items():
if isinstance(v, dict) and "$ref" in v:
json_schema[k] = resolve_ref(v, modified_schema)
elif isinstance(v, dict):
resolve_refs(json_schema[k], modified_schema)
def get_type(key_path, json_schema):
"""
Recursively gets the type if it exists.
:param key_path:
:param json_schema:
:return:
"""
if 'properties' in json_schema:
if key_path[0] in json_schema['properties']:
return get_type(key_path[1:], json_schema['properties'][key_path[0]])
else:
return json_schema.get('type', None)
else:
return json_schema.get('type', None)
completed_schema = dict()
def get_complete_schema(json_schema):
"""
Takes the schema and solves the refs, stores in a dict so that it is computed only once.
:param json_schema:
:return modified schema:
"""
schema_str = json.dumps(json_schema, sort_keys=True)
if not completed_schema.get(schema_str):
modified_schema = copy.deepcopy(json_schema)
resolve_refs(modified_schema)
completed_schema[schema_str] = modified_schema
else:
modified_schema = completed_schema[schema_str]
return modified_schema
def get_type_for_key_path(json_schema: dict, key_path: str) -> str:
modified_schema = get_complete_schema(json_schema)
key_path_list = key_path.split('.')
key_path_type = get_type(key_path_list, modified_schema)
return key_path_type
assert (get_type_for_key_path(schema, "Age") == "integer")
assert (get_type_for_key_path(schema, "EmploymentInformation.OriginalHireDate") == "string")
assert (get_type_for_key_path(schema, "EmploymentInformation.Beneficiary.Name") == "string")
assert (get_type_for_key_path(schema, "foo.bar") == None)
Would my code be good enough for a Senior Python Engineer?
Note, they gave me the schema and the test conditions.