Разрешить одну из указанных схем - PullRequest
1 голос
/ 08 мая 2020

Я использую 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 и как я могу ее исправить?

...