Я использую Cerberus для проверки некоторых файлов YAML, которые могут выглядеть следующим образом:
fleet.yml
fleet_city: "New York"
vehicles:
vehicle_1:
car:
# License plate required for car
license_plate: "ABC123"
cargo: 10
vehicle_2:
# All vehicle types can have optional remarks block
remarks:
active: true
car:
license_plate: "XYZ789"
# Cargo is optional
# Vehicle names (dict keys) are arbitrary
cool_ride:
remarks:
active: false
boat:
# Required
seaworthy: true
# not required
sails: 3
Общая структура такова, что есть некоторые значения для всего файла, например fleet_city
, а затем блок с именем vehicles
. Последний представляет собой словарь с названиями транспортных средств в качестве ключей. У каждого типа автомобиля есть своя схема, хотя все они словари. Я придумал эту схему, чтобы формализовать это:
schema.yml
fleet_city:
type: string
vehicles:
type: dict
keysrules:
# Vehicle name constraints
type: string
regex: '[A-Za-z\d_]+'
valuesrules:
type: dict
schema:
# Optional remarks block
remarks:
type: dict
# Car schema
car:
schema:
license_plate:
type: string
required: true
cargo:
type: integer
required: false
# Boat schema
boat:
schema:
seaworthy:
type: boolean
required: true
propulsion:
type: dict
schema:
sails:
type: integer
required: false
Что я могу проверить с помощью:
import yaml
from cerberus import Validator
with open('schema.yml') as f:
schema = yaml.safe_load(f)
v = Validator(schema)
with open('fleet.yml') as f:
fleet = yaml.safe_load(f)
print(v.validate(fleet))
print(v.errors)
Что правильно возвращает True
. Однако предполагается, что во входных данных каждое транспортное средство должно иметь один тип (либо один блок car
, либо один блок boat
, но не оба). Это правило не отражено в схеме выше. Я попытался добавить это так:
schema2.yml
fleet_city:
type: string
vehicles:
type: dict
keysrules:
# Vehicle name constraints
type: string
regex: '[A-Za-z\d_]+'
valuesrules:
type: dict
schema:
# Optional remarks block
remarks:
type: dict
oneof_schema:
# Car schema
- car:
schema:
license_plate:
type: string
required: true
cargo:
type: integer
required: false
# Boat schema
- boat:
schema:
seaworthy:
type: boolean
required: true
propulsion:
type: dict
schema:
sails:
type: integer
required: false
Насколько я могу судить, я следовал синтаксису , приведенному в документации. , но schema2.yml
вызывает:
cerberus.schema.SchemaError: {'vehicles': [{'valuesrules': [{'schema': ['no definitions validate', {'anyof definition 0': [{'oneof': ['must be of dict type']}], 'anyof definition 1': [{'oneof': [{'schema': ['no definitions validate', 'no definitions validate', {'anyof definition 0': [{'car': ['null value not allowed'], 'schema': [{'cargo': ['unknown rule'], 'license_plate': ['unknown rule'], 'propulsion': ['unknown rule'], 'seaworthy': ['unknown rule']}], 'boat': ['null value not allowed']}], 'anyof definition 1': [{'car': ['unknown rule'], 'boat': ['unknown rule']}]}]}], 'remarks': ['unknown rule']}]}]}]}]}
Что на самом деле не помогает.
Одним из способов решения проблемы является использование excludes
для car
в boat
и наоборот, но этот подход развалится, если у нас будет не только два типа транспортных средств, а их много.
В чем проблема в моем schema2.yml
и как я могу ее исправить?