Лучшая практика для хранения файла конфигурации в python

У меня есть скрипт Python, в котором у меня есть файл конфигурации, который выглядит так:

PROD = 'production'
DEV = 'dev'
ENVIRONMENT = None

и у меня есть функция, которая получает желаемую среду из аргумента команды и устанавливает ее так:

if sys.argv[1] in [config.PROD, config.DEV]:
    config.ENVIRONMENT = sys.argv[1]

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

Итак, мой вопрос: какова наилучшая практика в этом случае


person Ofrine    schedule 29.11.2017    source источник


Ответы (1)


Я не уверен, что именно лучше всего, но мне нравится использовать файлы JSON. Я использую следующий класс в качестве уровня абстракции для взаимодействия с файлом конфигурации (свойств). Вы можете создать один файл JSONPropertiesFile и передать его в свое приложение.

import json
from collections import OrderedDict
import os
from stat import * # ST_SIZE etc
from datetime import datetime
from copy import deepcopy


class JSONPropertiesFileError(Exception):
    pass


class JSONPropertiesFile(object):

    def __init__(self, file_path, default={}):
        self.file_path = file_path
        self._default_properties = default
        self._validate_file_path(file_path)

    def _validate_file_path(self, file_path):
        if not file_path.endswith(".json"):
            raise JSONPropertiesFileError(f"Must be a JSON file: {file_path}")
        if not os.path.exists(file_path):
            self.set(self._default_properties)

    def set(self, properties):
        new_properties = deepcopy(self._default_properties)
        new_properties.update(properties)
        with open(self.file_path, 'w') as file:
            json.dump(new_properties, file, indent=4)


    def get(self):
        properties = deepcopy(self._default_properties)
        with open(self.file_path) as file:
            properties.update(json.load(file, object_pairs_hook=OrderedDict))
        return properties

    def get_file_info(self):
        st = os.stat(self.file_path)
        res = {
            'size':st[ST_SIZE],
            'size_str':str(round(st[ST_SIZE]/1000,2)) + ' KB',
            'last_mod': datetime.fromtimestamp(st[ST_MTIME]).strftime("%Y-%m-%d")
         }
         return res

В вашем случае вы можете использовать его следующим образом:

file_path = "path/to/your/config/file"
default_properties = {
    'PROD': 'production',
    'DEV': 'dev',
    'ENVIRONMENT': ""
} 
config_file = JSONPropertiesFile(file_path, default_properties)
config = config_file.get() 
print(config["PROD"])
config["PROD"] = "something else"
config_file.set(config) #  save new config
person J. Darnell    schedule 29.11.2017
comment
Спасибо за ваш ответ, но я думаю, что это решение немного излишне и не будет выглядеть красиво. В моем (нерабочем) решении, чтобы получить доступ к ENV, вы вызываете config.ENV, и все готово. В вашем случае вам нужно вызвать JSONPropertiesFile.get()['ENV'], и, хотя он очень надежен, я считаю, что он некрасив (а также требует чтения/записи из/в файл) - person Ofrine; 30.11.2017
comment
Я понимаю, что это перебор. Мое решение можно превратить во что-то, что позволит вам делать на нем .ENV, хотя это только усложнит его. Вы хотите загрузить его из файловой системы один раз, а затем больше ничего не делать с файловой системой? - person J. Darnell; 30.11.2017