Colander для сопоставления переменных, но значения - массивы
Как определить схему в дуршлаге для JSON следующей формы?
{
'data' : {
'key_1' : [123, 567],
'key_2' : ['abc','def'],
'frank_underwood' : [666.66, 333.333],
... etc ...
}
}
Ключами внутри "данных" может быть любая строка, а значения - массивы.
В настоящее время у меня есть следующее, но на самом деле оно не создает ограничений на типы значений, которые может иметь сопоставление.
class Query(colander.MappingSchema):
data = colander.SchemaNode(
colander.Mapping(unknown='preserve'),
missing={}
)
Каков правильный способ описания этого?
Ответы
Ответ 1
Возможным решением является использование настраиваемого валидатора.
Вот полный рабочий пример настраиваемого валидатора, который проверяет, являются ли все значения произвольного отображения типично типизированными массивами.
import colander
def values_are_singularly_typed_arrays(node, mapping):
for val in mapping.values():
if not isinstance(val, list):
raise colander.Invalid(node, "one or more value(s) is not a list")
if not len(set(map(type, val))) == 1:
raise colander.Invalid(node, "one or more value(s) is a list with mixed types")
class MySchema(colander.MappingSchema):
data = colander.SchemaNode(
colander.Mapping(unknown='preserve'),
validator=values_are_singularly_typed_arrays
)
def main():
valid_data = {
'data' : {
'numbers' : [1,2,3],
'reals' : [1.2,3.4,5.6],
}
}
not_list = {
'data' : {
'numbers' : [1,2,3],
'error_here' : 123
}
}
mixed_type = {
'data' : {
'numbers' : [1,2,3],
'error_here' : [123, 'for the watch']
}
}
schema = MySchema()
schema.deserialize(valid_data)
try:
schema.deserialize(not_list)
except colander.Invalid as e:
print(e.asdict())
try:
schema.deserialize(mixed_type)
except colander.Invalid as e:
print(e.asdict())
if __name__ == '__main__':
main()
Ответ 2
Я не знаю о дуршлаге, но вы можете использовать Spyne.
class Data(ComplexModel):
key_1 = Array(Integer)
key_2 = Array(Unicode)
frank_underwood = Array(Double)
class Wrapper(ComplexModel):
data = Data
Полный рабочий пример: https://gist.github.com/plq/3081280856ed1c0515de
Документы модели Spyne: http://spyne.io/docs/2.10/manual/03_types.html
Однако получается, что не то, что вам нужно. Если вам нужен более свободный словарь, тогда вам нужно использовать специальный тип:
class DictOfUniformArray(AnyDict):
@staticmethod # yes staticmethod
def validate_native(cls, inst):
for k, v in inst.items():
if not isinstance(k, six.string_types):
raise ValidationError(type(k), "Invalid key type %r")
if not isinstance(v, list):
raise ValidationError(type(v), "Invalid value type %r")
# log_repr prevents too much data going in the logs.
if not len(set(map(type, v))) == 1:
raise ValidationError(log_repr(v),
"List %s is not uniform")
return True
class Wrapper(ComplexModel):
data = DictOfUniformArray
Полный рабочий ресурс: https://github.com/arskom/spyne/blob/spyne-2.12.5-beta/examples/custom_type.py
Ответ 3
Здесь я нашел другой способ.
from colander import SchemaType, Invalid
import json
class JsonType(SchemaType):
...
def deserialize(self, node, cstruct):
if not cstruct: return null
try:
result = json.loads(cstruct, encoding=self.encoding)
except Exception as e:
raise Invalid(node,"Not json ...")
return result
Как создать атрибут типа "агностик" SchemaNode в дуршлаге