I am using Marshmallow for serialization and de-serialization of JSON strings. From the Marshmallow API Docs (https://marshmallow.readthedocs.io/en/3.0/api_reference.html), it looks like you have specify a list of fields (and, unless using Meta
) their data type. For example:
Marital_Status=Fields.Str()
Employer=Fields.Str()
ContactInfo(data) #where ContactInfo is a class not shown here
However, I already have a JSON schema that specifies the fields and the data types. For example:
the_template_schema={
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"properties": {
"Marital_Status": {
"$id": "#/properties/Marital_Status",
"type": "string",
"title": "The Marital_status Schema",
"default": "",
"examples": [
"Married"
],
"pattern": "^(.*)$"
}
"Employer": {
"$id": "#/properties/Employer",
"type": "string",
"title": "The Employer Schema",
"default": "",
"examples": [
"Roivant"
],
"pattern": "^(.*)$"
}
}
}
My Question
I want to specify to Marshmallow the fields, based on the schema data provided. Something like:
fields.magicmethod(the_template_schema)
ContactInfo(data)
Is this possible? If so, how?
In marshmallow, the schema should be specified as a class in your Python code (see example here: https://marshmallow.readthedocs.io/en/3.0/quickstart.html#declaring-schemas).
For your case, it might look something like
from marshmallow import Schema, fields
class ContactInfoSchema(Schema):
Marital_Status=Fields.Str()
Employer=Fields.Str()
Do you need to use marshmallow? If your schema already exists in the json-schema format, you can load your objects using json.load
and validate against the schema using the jsonschema
module.
https://medium.com/python-pandemonium/json-the-python-way-91aac95d4041
https://python-jsonschema.readthedocs.io/en/latest/
You could write your own converter that will take a JSON Schema and create a dynamic marshmallow schema from it.
Here's an example ( it's not JSONSchema but something simpler ).
from marshmallow import Schema, fields
from functools import partial
def validator(valid_values, input):
if input in valid_values:
return True
return False
def get_type(param_type):
if param_type == "String":
return fields.String
if param_type == "Boolean":
return fields.Boolean
def gen_schema(cls_name, params):
fields = {}
for p in params:
field_type = get_type(p["type"])
if p.get("valid_values"):
fields[p["name"]] = field_type(validate=partial(validator, p["valid_values"]))
else:
fields[p["name"]] = field_type()
schema = type(cls_name, (Schema,), fields)
return schema
class ParameterSchema(Schema):
name = fields.String(required=True)
description = fields.String(required=False)
required = fields.Bool(default=False)
type = fields.String(required=True)
valid_values = fields.List(fields.String, required=False)
p = [
{"name": "filename",
"description": "Should be a filename",
"required": True,
"type": "String",
"valid_values": ["hello.txt", "foo.py", "bar.png"]
},
{"name": "SomeBool",
"description": "Just a bool",
"required": True,
"type": "Boolean",
},
{"name": "NotRequiredBool",
"description": "Another bool thats not required",
"required": False,
"type": "Boolean"
}
]
req1 = {"filename": "foo.py", "SomeBool": False}
req2 = {"filename": "hi.txt", "SomeBool": True, "NotRequiredBool": False}
schema = ParameterSchema()
params1 = schema.load(p, many=True)
dynamic_schema = gen_schema("D1", params1.data)()
dynamic_res1 = dynamic_schema.load(req1)
dynamic_res2 = dynamic_schema.load(req2)
print(dynamic_res1)
print(dynamic_res2)
Running this prints:
UnmarshalResult(data={'filename': 'foo.py', 'SomeBool': False}, errors={})
UnmarshalResult(data={'NotRequiredBool': False, 'SomeBool': True}, errors={'filename': ['Invalid value.']})
You'd just have to change gen_schema
to accept a valid JSONSchema instead of the simple one I made up here.
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With