2017-02-09 5 views
1

Я экспериментирую с написанием механизма переменных конфигурации, который принимает файл YAML (содержащий переменные конфигурации AWS) в качестве входных данных и преобразует их в JSON, чтобы он мог быть загружен в API k/v HTTP (например, Consul). Функция, с которой я столкнулся, позволит разработчику «включить» наборы ключей (обозначенные символом подчеркивания, которые опущены в конечной полезной нагрузке) в последующих ключах. Образец выглядит следующим образом:Как я могу переписать через словарь и динамически обновлять значения, чтобы впоследствии их можно было называть?

# Region 
us-east-1: 
    # Any key preceded by an underscore (_) is considered a "tag group" and will not be uploaded to Consul KV unless explicitly included. 
    _taggroup1: 
    key1: value1 
    key2: value2 
    key3: value3 
    _taggroup2: 
    key4: value1 
    key5: value2 
    key6: value3 

    dev: 
    _include: us-east-1/_taggroup1 
    qa: 
    _include: 
     - us-east-1/_taggroup1 
     - us-east-1/_taggroup2 
    key6: baz 
    prod: 
    _include: 
     - us-east-1/_taggroup1 
     - us-east-1/_taggroup2 

us-west-1: 
    _taggroup1: 
    key1: value1 
    key2: value2 
    key3: value3 
    _taggroup2: 
    key4: value1 
    key5: value2 
    key6: value3 

    dev: 
    _include: 
     - us-west-1/_taggroup1 
    qa: 
    _include: 
     - us-west-1/_taggroup1 
     - us-west-1/_taggroup2 
    key2: foo 
    prod: 
    _include: 
     - us-west-1/_taggroup1 
     - us-west-1/_taggroup2 
    key4: foo 
    key5: bar 
    key1: undef 

    us-west-1a: 
    qa: 
     _include: us-west-1/qa 
    prod: 
     _include: us-west-1/prod 

    us-west-1b: 
    _include: us-west-1/us-west-1a 

Как вы можете видеть, что я пытаюсь структурировать конфигурационный файл, который позволяет разработчикам группировать переменные и subsquently включать/переопределить их, если они пожелают.

Код я написал для этого эксперимента, до сих пор, по существу, ваша стандартная функция рекурсии с добавлением специфичных для данного применения:

# parse_input is a separate function that converts a YAML stream into 
# an OrderedDict 
original_dict = parse_input(stream1) 

def print_dict(input_dict): 

    new_dict = collections.OrderedDict() 

    for key, value in input_dict.iteritems(): 
     if key.startswith('_'): 
      if key == '_include': 
       if isinstance(value, list): 
        for item in value: 
         x = dpath.util.get(original_dict, item) 
         for k, v in x.iteritems(): 
          new_dict[k] = v 
       else: 
        x = dpath.util.get(original_dict, value) 
        for k, v in x.iteritems(): 
         new_dict[k] = v 
      else: 
       continue 
      continue 
     elif isinstance(value, dict): 
      new_dict[key] = print_dict(value) 
     else: 
      new_dict[key] = value 
    return new_dict 

Выход так далеко, что я достиг как таковой:

{ 
    "us-east-1": { 
     "dev": { 
      "key1": "value1", 
      "key2": "value2", 
      "key3": "value3" 
     }, 
     "qa": { 
      "key1": "value1", 
      "key2": "value2", 
      "key3": "value3", 
      "key4": "value1", 
      "key5": "value2", 
      "key6": "baz" 
     }, 
     "prod": { 
      "key1": "value1", 
      "key2": "value2", 
      "key3": "value3", 
      "key4": "value1", 
      "key5": "value2", 
      "key6": "value3" 
     } 
    }, 
    "us-west-1": { 
     "dev": { 
      "key1": "value1", 
      "key2": "value2", 
      "key3": "value3" 
     }, 
     "qa": { 
      "key1": "value1", 
      "key2": "foo", 
      "key3": "value3", 
      "key4": "value1", 
      "key5": "value2", 
      "key6": "value3" 
     }, 
     "prod": { 
      "key1": "undef", 
      "key2": "value2", 
      "key3": "value3", 
      "key4": "foo", 
      "key5": "bar", 
      "key6": "value3" 
     }, 
     "us-west-1a": { 
      "qa": { 
       "_include": [ 
        "us-west-1/_taggroup1", 
        "us-west-1/_taggroup2" 
       ], 
       "key2": "foo" 
      }, 
      "prod": { 
       "_include": [ 
        "us-west-1/_taggroup1", 
        "us-west-1/_taggroup2" 
       ], 
       "key4": "foo", 
       "key5": "bar", 
       "key1": "undef" 
      } 
     }, 
     "us-west-1b": { 
      "qa": { 
       "_include": "us-west-1/qa" 
      }, 
      "prod": { 
       "_include": "us-west-1/prod" 
      } 
     } 
    } 
} 

Как видите, я оказываюсь на полпути. Моя проблема заключается в том, что в моем первоначальном эксперименте я получал благоприятные результаты, ссылаясь на переменную original_dict в функции при ссылке на набор include (с помощью dpath для возврата ключей). Это быстро превращается в проблему, так как функция рекурсирует глубже (т. Е. AZ-специфические переменные в этом случае), так как я не знаю, как динамически обновлять ключи в исходном dict или иначе отслеживать изменения, поэтому функция будет вводить ключ с _include ключами и не может их повторно оценить.

Как устранить в зависимости от ссылки на оригинальный словарь и скорее динамически отслеживать изменения, чтобы ключи _include были должным образом оценены глубже в дереве?

ответ

1

Я думаю, что этот код исправляет проблему, с которой вы столкнулись. Ключевым изменением является восстановление до print_dict с результатом dpath. Я также рухнул некоторый избыточный код.

Код:

import yaml 
import collections 
import json 
import dpath 

with open('data.yml', 'rb') as f: 
    original_dict = yaml.load(f) 

def print_dict(input_dict): 

    new_dict = collections.OrderedDict() 

    for key, value in input_dict.iteritems(): 
     if key.startswith('_'): 
      if key == '_include': 
       if not isinstance(value, list): 
        value = [value] 
       for item in value: 
        x = print_dict(dpath.util.get(original_dict, item)) 
        for k, v in x.iteritems(): 
         new_dict[k] = v 
     elif isinstance(value, dict): 
      new_dict[key] = print_dict(value) 
     else: 
      new_dict[key] = value 
    return new_dict 

print(json.dumps(print_dict(original_dict), indent=2)) 

Выход:

{ 
    "us-east-1": { 
    "qa": { 
     "key3": "value3", 
     "key2": "value2", 
     "key1": "value1", 
     "key6": "baz", 
     "key5": "value2", 
     "key4": "value1" 
    }, 
    "prod": { 
     "key3": "value3", 
     "key2": "value2", 
     "key1": "value1", 
     "key6": "value3", 
     "key5": "value2", 
     "key4": "value1" 
    }, 
    "dev": { 
     "key3": "value3", 
     "key2": "value2", 
     "key1": "value1" 
    } 
    }, 
    "us-west-1": { 
    "qa": { 
     "key2": "value2", 
     "key3": "value3", 
     "key1": "value1", 
     "key6": "value3", 
     "key5": "value2", 
     "key4": "value1" 
    }, 
    "us-west-1b": { 
     "qa": { 
     "key2": "value2", 
     "key3": "value3", 
     "key1": "value1", 
     "key6": "value3", 
     "key5": "value2", 
     "key4": "value1" 
     }, 
     "prod": { 
     "key1": "value1", 
     "key3": "value3", 
     "key2": "value2", 
     "key6": "value3", 
     "key5": "bar", 
     "key4": "foo" 
     } 
    }, 
    "prod": { 
     "key1": "value1", 
     "key3": "value3", 
     "key2": "value2", 
     "key6": "value3", 
     "key5": "bar", 
     "key4": "foo" 
    }, 
    "us-west-1a": { 
     "qa": { 
     "key2": "value2", 
     "key3": "value3", 
     "key1": "value1", 
     "key6": "value3", 
     "key5": "value2", 
     "key4": "value1" 
     }, 
     "prod": { 
     "key1": "value1", 
     "key3": "value3", 
     "key2": "value2", 
     "key6": "value3", 
     "key5": "bar", 
     "key4": "foo" 
     } 
    }, 
    "dev": { 
     "key3": "value3", 
     "key2": "value2", 
     "key1": "value1" 
    } 
    } 
} 
+1

Это, кажется, работает! Спасибо, я (очевидно) еще не пробовал! :) – asdoylejr

 Смежные вопросы

  • Нет связанных вопросов^_^