我在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
}