python json замена ключа переменной конфигурации на нескольких уровнях иерархии - PullRequest
0 голосов
/ 19 марта 2020

Я планирую использовать json для конфигурационного файла, и в настоящее время у меня есть такая конфигурация

{
  "settings": {
    "general": "root",
    "folder": "folder_test"
  },
  "TEST1": {
    "dataone": "xyz",
    "testing": {
      "a": "$general/$folder/test.png",
      "b": "$general/$folder/test.png"
    },
    "SOMELIST": [
      "$general/$folder/test.png",
      "$general/$folder/test.png"
    ]
  },
  "TEST2": {
    "dataone": "xyz",
    "testing": {
      "a": "$general/$folder/test.png",
      "b": "$general/$folder/test.png"
    },
    "something": {
        "test_data": {
          tester: {
            "abc": "$general/$folder/test.png",
            "zxv": "$general/$folder/test.png"
          }
        }
    }
  }
}

Моя цель состоит в том, чтобы раздел настроек заполнялся stati c path, например root и имя папки et c и оставьте остальные части конфигурации по всей иерархии конфигурации, чтобы использовать параметры в качестве переменной. Это для целей пути и папки, которые я не буду испытывать при последующем обслуживании, если root или новая папка будут изменены / добавлены.

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

пока я могу только l oop один уровень, но не уверен, как получить доступ к нескольким уровням в целом.

for k, v in config.items():
    for key in config.keys():
        if key in v:
            config[k] = v.replace("$" + key, config[key])

нашел это в другой топи c здесь в stackoverflow, но это только один уровень. Я не уверен, как построить общий, который может включать несколько уровней здесь.

1 Ответ

0 голосов
/ 19 марта 2020

Вместо того, чтобы заменять переменные для каждого элемента в отдельности, вы рассматривали просто замену переменных перед тем, как анализировать их как JSON? Это намного меньше памяти / вычислительно дорого, и это должно быть намного проще.

config = ""
with open("config.json") as f:
    config = f.read().replace("$variable", "stackoverflow")

parsed_config = your_parser(config)

Редактировать: Написал функцию рекурсивной замены. Я надеюсь, что вы можете прочитать это и извлечь уроки из этого.

import json

call_counter = 0

def replace_string(value: str, template_vars: {}) -> object:
    """
    Replaces template strings in value, by the values in template_vars. 
    """
    for template, newValue in template_vars.items():
        value = value.replace("${}".format(template), newValue)

    return value


def replace_recursive(json_obj: object, template_vars: {}) -> {}:
    """
    Recursively unpacks and replaces items in a multi-dimensional dict/list/item json object.
    """
    # For each item at this level 
    for key, value in json_obj.items():
        # If the value is a string, replace it
        if isinstance(value, str):
            json_obj[key] = replace_string(value, template_vars)        

        # If the item is a list, we need to do something for each value
        elif isinstance(value, list):
            # Enumate unpacks an index with each value
            for index, item in enumerate(value):
                # If it's a string, we can replace it 
                if isinstance(item, str):
                    value[index] = replace_string(item, template_vars)
                # If it's not, we need to do more work. 
                else:
                    value[index] = replace_recursive(item, template_vars)

        # If it's a dict, use this function again to unpack/replace the values
        else:
            json_obj[key] = replace_recursive(value, template_vars)

    return json_obj

if __name__ == "__main__":

    template_vars = {}

    # Read our file
    with open("example.json") as f:
        json = json.load(f)

    # Read our settings
    template_vars = json['settings']

    # Drop our settings block (don't if you don't want to)
    json.pop('settings')

    json = replace_recursive(json, template_vars)
    print(json)

При этом используется довольно много вызовов функций. Не проблема для этого конфига, но это может быть для другого.

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