Проверка схемы словаря Python с помощью Dynamic "находится в" Ограничении - PullRequest
0 голосов
/ 15 марта 2019

Я ищу решение для проверки словаря с одним ограничением, являющимся ограничением is in, где значения, считающиеся допустимыми, берутся из самого словаря, который проверяется.

Например, представьте следующее псевдо-schema

{
    "notions" : [ string ],
    "category" : [ is in notions ]
}

Для полной ясности я также устно выражаю ограничения этой псевдошхемы.Вот ограничения, которые я хочу проверить: d словарь для проверки:

  1. set(d.keys()) == {"notions", "categories"}
  2. isinstance(d["notions"], list)
  3. isinstance(notion, str) for notion in d["notions"]
  4. isinstance(d["category"], list)
  5. element is in d["notion"] for element in d["category"]

Не спрашивайте, имеет ли эта конкретная структура данных какой-либо смысл.Это не.Я просто придумал, чтобы создать минимальный пример для моей проблемы.Моя фактическая словарная схема намного сложнее и будет содержать несколько ссылок на значения из dict.Вот почему я хотел бы избежать определения и проверки ограничений вручную и предпочел бы решение на основе схемы.

Я изучил некоторые библиотеки проверки схемы, но я не нашел нигде включенной этой функции,Есть ли решение, основанное на некоторых библиотеках, возможно, с небольшой настройкой?Я бы предпочел не изобретать колесо во второй раз.

Ответы [ 2 ]

1 голос
/ 15 марта 2019

В общем случае валидаторы схемы стараются избегать ввода данных в валидатор.Например, стандарт JSON-схемы - это , обсуждающий добавление $data доступа в схемах , но (пока) не реализовавший эту идею (хотя они несколько используютслучаи для этого ).

Общее возражение состоит в том, что из-за того, что привязка схемы проверки к проверяемым данным затрудняет проверку без контекста (что упрощает реализацию и делает проверку параллельно)намного проще), и это делает статический анализ схем намного сложнее (так как схема изменяется с данными во время выполнения).

Тем не менее, проект Colander может делать то, что вы хотите,поскольку это позволяет вам тривиально определять валидаторы в коде Python.

Например:

import colander

class Foo(colander.MappingSchema):
    @colander.instantiate()
    class notions(colander.SequenceSchema):
        notion = colander.SchemaNode(colander.String())

    @colander.instantiate()
    class category(colander.SequenceSchema):
        cat = colander.SchemaNode(colander.String())

    def validator(self, node, cstruct):
        """Validate that all category values are listed in notions"""
        notions = set(cstruct['notions'])
        if not notions.issuperset(cstruct['category']):
            raise colander.Invalid(
                node['category'], 
                "All categories must be listed in notions"
            )

Обратите внимание, что валидатор определен на уровне, где определены и notions, и categoryв, поскольку валидатор имеет доступ только к «локальному» разделу проверяемых данных (все проверки дочерних узлов уже проведены).Если вы определили валидатор только для category, то вы не сможете получить доступ к списку notions, и вы можете рассчитывать на список notions, который уже был проверен.Валидатор вызывает исключение Invalid, и первым аргументом является узел схемы category, который прямо возлагает вину на значения в этом списке.

Схема Коландера проверяется при десериализации;Вы можете увидеть ввод метода Schema.deserialize() в виде непроверенных данных ( сериализация дуршлаг ) и вывод в виде данных, готовых для приложения ( appdata ), проверенных и очищенных.Это потому, что Colander также поместит значения по умолчанию на место, если они отсутствуют, может создавать кортежи, наборы, значения datetime и т. Д., А также поддерживает подготовку данных (очистку HTML и т. Д.) При обработке их со схемой.

С некоторым демонстрационным вводом приведенная выше схема проверяет и возвращает проверенную структуру в случае успеха:

>>> schema = Foo()
>>> schema.deserialize({'notions': [], 'category': []})
{'notions': [], 'category': []}
>>> schema.deserialize({'notions': ['foo', 'bar'], 'category': []})
{'notions': ['foo', 'bar'], 'category': []}
>>> schema.deserialize({'notions': ['foo', 'bar'], 'category': ['foo']})
{'notions': ['foo', 'bar'], 'category': ['foo']}
>>> schema.deserialize({'notions': ['foo', 'bar'], 'category': ['foo', 'spam']})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../site-packages/colander/__init__.py", line 2381, in deserialize
    self.validator(self, appstruct)
  File "<string>", line 17, in validator
colander.Invalid: {'category': 'All categories must be listed in notions'}
0 голосов
/ 15 марта 2019

Ваш словарь настолько сложен, что вы все делаете неправильно.Подумайте о создании классов и сохраните объект этого класса в словаре.Эти классы также могут содержать другие объекты других классов.Таким образом вы избежите вложения словарей.Создайте функции внутри классов для проверки их данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...