基于Python属性的JSON模式中的动态引用

时间:2018-07-10 09:10:34

标签: python json validation jsonschema

我在Python包中使用IoC容器,并通过使用JSON配置文件从这些容器中解析所需的对象。 (如果有人感兴趣,我正在使用dependency-injector软件包来执行此操作,尽管这与此处的问题并不相关)。

以下代码说明了如何设置容器:

from dependency_injector import containers
from dependency_injector import providers
from my_package.animals import Monkey, Giraffe, Lion

class AnimalsContainer(containers.DeclarativeContainer):
    monkey = providers.Singleton(Monkey)
    giraffe = providers.Singleton(Giraffe)
    lion = providers.Singleton(Lion)

现在让我们说我将按如下所示设置JSON配置文件:

{
"animal": "monkey" 
}

然后我可以通过以下方法解决正确的动物

import json
config = json.load(open("some/path/to/config.json", 'r'))

animal = getattr(AnimalsContainer, config["animal"])()
#...which is equivalent to just writing animal = AnimalsContainer.monkey()

现在这里只有三个有效的“动物”选项,因此我想使用jsonschema对此施加约束。为此,我可以建立一个如下所示的模式:

{
  $schema": "http://json-schema.org/draft-04/schema#",
  "title": "animals schema",
  "type": "object",
  "properties": {
    "animal" : {
      "type": "string",
      "enum": ["monkey", "lion", "giraffe"]
    }
  }
}

并使用

对其进行验证
from jsonschema import validate
schema = load_the_schema_json(path_to_schema_json) #psuedocode
validate(config, schema)

到目前为止,一切都很好。但是,我在这里面临两个问题。首先,“ AnimalsContainer”中的属性与json模式中列出的可接受属性之间没有动态链接。这意味着无论何时添加其他动物,我们都必须记住要更新架构。这很烦人,并可能导致错误。

第二,此程序包已构建为易于扩展。这意味着用户可以创建自己的“动物”实现并将其注册到AnimalsContainer,如下所示:

def register_extended_animals():
    from my_extensions.animals import Tiger
    from my_package.containers import AnimalsContainer
    from dependency_injector import containers
    from dependency_injector import providers

    AnimalsContainer.tiger = providers.Singleton(Tiger)

现在通过配置文件完全有效:

{
"animal": "tiger"
}

只要我们调用register_extended_animals(),就可以调用animal = getattr(AnimalsContainer, config["animal"])()。但是,由于“ tiger”未包含在可接受的配置输入的硬编码列表中,因此配置验证将失败。

所以,这是我的具体问题

是否可以使JSON模式动态引用AnimalsContainer类下的属性?

我可以使用以下方式获取属性:

def get_animalcontainer_attributes():
    # will return a list ["monkey", "giraffe", "lion", "tiger"]
    return [attribute for attribute in AnimalsContainer .__dict__.keys() if not attribute .startswith('_')]

def get_animals_json():
  # returns a string representation of a json property
  return json.dumps (
    {
     "animal": {
         "type": "string",
         "enum": get_animalcontainer_attributes()
       }
    }
  )

但是我对如何在JSON模式中动态引用此方法感到困惑。明确地说,我的想法将遵循以下几条原则:

{
  $schema": "http://json-schema.org/draft-04/schema#",
  "title": "animals schema",
  "type": "object",
  "properties": {"animal":  {"$ref": get_animals_json()#/animal}  -> psuedocode
}

0 个答案:

没有答案