J'ai un dictionnaire avec informations de configuration:
my_conf = {
'version': 1,
'info': {
'conf_one': 2.5,
'conf_two': 'foo',
'conf_three': False,
'optional_conf': 'bar'
}
}
Je veux vérifier si le dictionnaire suit la structure dont j'ai besoin.
Je cherche quelque chose comme ça:
conf_structure = {
'version': int,
'info': {
'conf_one': float,
'conf_two': str,
'conf_three': bool
}
}
is_ok = check_structure(conf_structure, my_conf)
Existe-t-il une solution à ce problème ou une bibliothèque qui pourrait faciliter la mise en œuvre de check_structure
?
Sans utiliser les bibliothèques, vous pouvez également définir une fonction récursive simple comme celle-ci:
def check_structure(struct, conf):
if isinstance(struct, dict) and isinstance(conf, dict):
# struct is a dict of types or other dicts
return all(k in conf and check_structure(struct[k], conf[k]) for k in struct)
if isinstance(struct, list) and isinstance(conf, list):
# struct is list in the form [type or dict]
return all(check_structure(struct[0], c) for c in conf)
Elif isinstance(struct, type):
# struct is the type of conf
return isinstance(conf, struct)
else:
# struct is neither a dict, nor list, not type
return False
Cela suppose que la configuration peut avoir des clés qui ne sont pas dans votre structure, comme dans votre exemple.
Mise à jour: la nouvelle version prend également en charge les listes, par exemple. comme 'foo': [{'bar': int}]
Vous pouvez utiliser schema
( PyPi Link )
schema est une bibliothèque de validation des structures de données Python, telles que celles obtenues à partir de fichiers de configuration, de formulaires, de services externes ou d'analyses de ligne de commande, converties de JSON/YAML (ou quelque chose d'autre) en types de données Python.
from schema import Schema, And, Use, Optional, SchemaError
def check(conf_schema, conf):
try:
conf_schema.validate(conf)
return True
except SchemaError:
return False
conf_schema = Schema({
'version': And(Use(int)),
'info': {
'conf_one': And(Use(float)),
'conf_two': And(Use(str)),
'conf_three': And(Use(bool)),
Optional('optional_conf'): And(Use(str))
}
})
conf = {
'version': 1,
'info': {
'conf_one': 2.5,
'conf_two': 'foo',
'conf_three': False,
'optional_conf': 'bar'
}
}
print(check(conf_schema, conf))
@tobias_k m'a battu (probablement en termes de temps et de qualité), mais voici une autre fonction récursive pour la tâche qui pourrait être un peu plus facile à suivre pour vous (et moi):
def check_dict(my_dict, check_against):
for k, v in check_against.items():
if isinstance(v, dict):
return check_dict(my_dict[k], v)
else:
if not isinstance(my_dict[k], v):
return False
return True
La nature des dictionnaires, s'ils sont utilisés en python et non exportés au format JSON, est que l'ordre du dictionnaire n'a pas besoin d'être défini. Au lieu de cela, la recherche de clés renvoie des valeurs (d'où un dictionnaire).
Dans les deux cas, ces fonctions doivent vous fournir ce que vous recherchez pour le niveau d'imbrication présent dans les échantillons que vous avez fournis.
#assuming identical order of keys is required
def check_structure(conf_structure,my_conf):
if my_conf.keys() != conf_structure.keys():
return False
for key in my_conf.keys():
if type(my_conf[key]) == dict:
if my_conf[key].keys() != conf_structure[key].keys():
return False
return True
#assuming identical order of keys is not required
def check_structure(conf_structure,my_conf):
if sorted(my_conf.keys()) != sorted(conf_structure.keys()):
return False
for key in my_conf.keys():
if type(my_conf[key]) != dict:
return False
else:
if sorted(my_conf[key].keys()) != sorted(conf_structure[key].keys()):
return False
return True
Cette solution devrait évidemment être changée si le niveau d’imbrication était supérieur (c’est-à-dire configuré pour évaluer la similarité de la structure des dictionnaires qui ont certaines valeurs en tant que dictionnaires, mais pas les dictionnaires où certaines valeurs, ces derniers dictionnaires sont également des dictionnaires).
Vous pouvez construire une structure en utilisant la récursivité:
def get_type(value):
if isinstance(value, dict):
return {key: get_type(value[key]) for key in value}
else:
return str(type(value))
Et comparez ensuite la structure requise avec votre dictionnaire:
get_type(current_conf) == get_type(required_conf)
Exemple:
required_conf = {
'version': 1,
'info': {
'conf_one': 2.5,
'conf_two': 'foo',
'conf_three': False,
'optional_conf': 'bar'
}
}
get_type(required_conf)
{'info': {'conf_two': "<type 'str'>", 'conf_one': "<type 'float'>", 'optional_conf': "<type 'str'>", 'conf_three': "<type 'bool'>"}, 'version': "<type 'int'>"}