There're some modules that might help you get rid of the structure you're complaining about like marshmallow or voluptous and since you didn't added the reinventing-the wheel tag I guess that's perfectly okay.
For the sake of example, I'll refer to the former one because IMO it better fits our purpose (and is also probably clearer).
From the docs:
Marshmallow is an ORM/ODM/framework-agnostic library for converting
complex datatypes, such as objects, to and from native Python
datatypes.
In short, marshmallow schemas can be used to:
- Validate input data.
- Deserialize input data to app-level objects.
- Serialize app-level objects to primitive Python types. The serialized objects can then be rendered to standard formats such as
JSON for use in an HTTP API.
First of, you'll need to define your Schema:
class DataSchema(Schema):
name = fields.String(required=True)
tags = fields.List(fields.String(), required=True)
In the above, name
and tags
are the keys of our dictionaries. In our class I've specified each key type (str
and list
). They're also mandatory, so I added required=True
.
Next, to validate our top-level list, we need to instantiate our list item schema with many=True
argument and then just load the data we need:
data, errors = DataSchema(many=True).load([
{'name': 'Frank', 'tags': ['dog', 'cat']},
{'name': 'Manfred', 'tags': ['dog', 'chicken']}
])
Printing the above:
print(data)
print(errors)
Will have the following output:
[{'name': 'Frank', 'tags': ['dog', 'cat']}, {'name': 'Manfred', 'tags': ['dog', 'chicken']}]
{}
Now, if we try to pass an invalid data to our dict, the errors
will warn us about this. For example, passing a str
instead of a list in our tags
key will result in:
[{'name': 'Frank'}, {'name': 'Manfred', 'tags': ['dog', 'chicken']}]
{0: {'tags': ['Not a valid list.']}}
Full code:
from marshmallow import Schema, fields
class DataSchema(Schema):
name = fields.String(required=True)
tags = fields.List(fields.String(), required=True)
data, errors = DataSchema(many=True).load([
{'name': 'Frank', 'tags': ['dog', 'cat']},
{'name': 'Manfred', 'tags': ['dog', 'chicken']}
])
Now, IDK if the above will be valid for all the test-cases (e.g it might allow you to pass an empty list), but it should give you a good overview of what you can achieve with this module.