Каков правильный способ «обновления» файла конфигурации, который постоянно обновляется?

#json #python-3.x #configuration #raspberry-pi4

#json #python-3.x #конфигурация #raspberry-pi4

Вопрос:

Я немного зациклен на проблеме, с которой я сталкиваюсь.

У меня есть программа на python, которая отправляет сигналы через интерфейс GPIO (Pi 4). Сигналы зависят от config.json

Макет json выглядит следующим образом:

 {
   "key1" : val1
   "key2" : val2
   "key3" : val3
}
 

Данные конфигурации передаются вызывающим абонентам в виде списков и сохраняются в виде файла конфигурации dict / json на устройстве для повторного использования, когда новая конфигурация не поступает.
Программа использует следующий фрагмент кода для чтения, редактирования и сохранения существующих или новых конфигураций:

 def check_json(self, source: str, write=False, val1=940, val2=5, val3=10):
    """check_json checks whether there's an existing config on the machine and in the same folder/location
    if it does exist, it gets returned to the caller. If it doesn't exist, a new file will be created
    with preset data"""
    if os.path.isfile(source):
        if write:
            try:
                with open(source, "r ") as json_data:  # update the existing values and save them
                    try:
                        config_data = js.load(json_data)
                        config_data["key1"] = val1
                        config_data["key2"] = val2
                        config_data["key3"] = val3
                        print(config_data)
                        json_data.seek(0)
                        json_data.truncate()
                        js.dump(config_data, json_data, indent=2)
                        json_data.flush()
                    except TypeError:
                        pass
            except TypeError:
                pass
        else:
            json_data = open(source, "r")
            dict_data = js.load(json_data)
            config_data = [dict_data["light_lvl"],
                           dict_data["on_time"], dict_data["off_time"]]
            json_data.close()
            return config_data
    # create new with presets if json config does not exist
    else:
        json_data = open(source, "w")
        dict_data = {"key1": val1,
                     "key2": on_time, "key3": val}
        js.dump(dict_data, json_data, indent=2)
        json_data.flush()
        json_data.close()
        return self.check_json(source)
 

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

 "key1" = config_data[0]
TypeError: 'NoneType' object is not subscriptable
 

Ошибка возникает, даже если json поступает с неповрежденным содержимым. Я попытался использовать несколько попыток и исключения как видимые в надежде, что он просто продолжит чтение новых данных конфигурации на новой итерации. Блоки try и except немного не помогли, и я не знаю, как еще я мог это исправить,

Любой ввод, советы / рекомендации приветствуются

Ответ №1:

Похоже, мой подход был неправильным. Я запрограммировал свое решение с идеей, что я могу просто получить доступ к своим значениям без каких-либо забот. Но это не так, поскольку файл несколько изменчив, в том смысле, что он все еще может находиться в процессе «получения».

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

class FileOps:

 def __init__(self, file_name: str):
    self.file_name = file_name
    self.config_name = "config.json"
    self.preset_config = {"key1" : val1, "key2" : val2, "key3" : val3}


def save_config(self):
    "saves the newer config file and deletes it in order to avoid clutter."
    if isfile(self.file_name):
        with open(self.config_name, "w") as file:
            js.dump(self.pass_new(), file, indent=2)
            remove(self.file_name) # delete the newly arrived config to prevent clutter


def read_config(self):
    """pass the existing config over to the caller if present. 
    Creates a preset config using the field "preset_config" if config.json doesn't exist """
    if not isfile(self.config_name):
        with open(self.config_name,"w") as file:
            js.dump(self.preset_config, file, indent=2)
            return self.preset_config # return the preset config for now
    with open(self.config_name, "r") as file:
        json_string = ""
        for line in file:
            json_string  = line
        return js.loads(json_string)


def pass_new(self): 
    """checks if a new config is present and passes the data through to the caller"""
    if isfile(self.file_name):
        with open(self.file_name, "r") as file:
            json_string = ""
            for line in file:
                json_string  = line
            return js.loads(json_string)
 

Я разделил операции чтения файлов на другой файл и класс, чтобы все было конкретным и кратким, и я просто запрограммировал его так, чтобы файл считывался построчно, а не мгновенно пытался его разобрать. Это устранило мою проблему, TypeError: 'NoneType' object is not subscriptable а также правильно передало информацию.

Класс FIleOps передается основному классу как композиционное отношение и вызывается при необходимости через простой объект.