Улучшение управления конфигурационным файлом в проекте, управляющем имитационными экспериментами.

Улучшение управления конфигурационным файлом

Я работаю над личным проектом более 6 месяцев, этот проект состоит из трех отдельных частей: моделирования (упаковка программного обеспечения), материалов, связанных с базой данных (сохранение смоделированных данных в базе данных) и моделирования (много машинного обучения связанные вещи)

Чтобы управлять своей конфигурацией (пути и несколько констант), я начал с помещения всех переменных в файл config.py в корне пакета (см. Ниже). Это сработало на удивление хорошо. Однако есть предостережение, я обычно работаю с симуляцией и базой данных в тандеме или с базой данных и моделированием в тандеме, дело в том, что в этой настройке у меня есть весь путь к проекту в зависимости от одного экспериментального имени, присутствующего в файле конфигурации.

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

Теперь мне нужно будет иметь возможность изменить «имя эксперимента» при запуске теста, однако мне нравится тот факт, что я могу «импортировать» весь путь и константу, просто импортировав конфигурацию как c, (тогда я могу сделать c.path .. и знать, откуда взялась переменная).

Я ищу новый способ обработки путей и переменной конфигурации в моем проекте. Я думаю о том, чтобы поместить весь файл конфигурации в класс и сделать что-то вроде c = Config (имя_эксперимента), у меня есть два вопроса, связанных с этим:

  • Это хорошая идея / хорошая практика? Есть ли лучший вариант?
  • Где мне создать объект внутри основных файлов?

Структура проекта

├── package
│   ├── __init__.py
│   ├── config.py
│   ├── simulation
│   │   ├── __init__.py
│   │   ├── core.py
│   │   └── utilities.py
│   ├── database
│   │   ├── __init__.py
│   │   ├── initialization.py
│   │   ├── insert.py
│   │   └── retrieve.py
│   └── modelization
│       ├── __init__.py
│       ├── preprocessing.py
│       └── training.py
├── tests
│   ├── test_simulation
│   │   ├── test_run_simulation.py
│   │   └── test_multiprocessing.py
│   └── test_database
│       ├── test_initialization.py
│       ├── test_insert.py
│       └── test_retrieve.py
├── databases
│   └── experiment_0
│       ├── train.db
│       └── test.db
├── FOLDER
└── experiments
    └── experiment_0
        ├── output.json
        ├── input.json
        └──  source
            └── lot_of_files_for_simulation

config.py

import socket
from pathlib import Path, PurePath

experiment_name="experiment_0"

enable_simulation = True
development_hostname="DESKTOP-VXXXX"


path_project = Path(__file__).parent.parent

path_experiments_folder = path_project.joinpath('experiments')
path_experiment_folder = path_experiments_folder.joinpath(experiment_name)
path_experiment_input_config = path_experiment_folder.joinpath('input.json')
path_experiment_output_config = path_experiment_folder.joinpath('output.json')

path_databases_folder = path_project.joinpath('databases')
path_experiment_database_folder = path_databases_folder.joinpath(experiment_name)

if socket.gethostname() != development_hostname and enable_simulation:
    run_simulation = True
    path_simulation_root_directory = PurePath('/home', 'thomas', 'FOLDER')
else:
    run_simulation = False
    path_simulation_root_directory = path_project.joinpath('FOLDER')

state = f"hostname {socket.gethostname()}, simulation {['OFF', 'ON'][run_simulation]}"

моделирование / core.py

from .. import config as c
from utilities import sub_function


def function_that_i_call_in_my_scripts(path_experiment_input_config=None):
    path = path_experiment_input_config or c.path_experiment_input_config
    sub_function(path)


class ClassThatICallInMyScripts:
    def __init__(self, path_experiment_input_config=None):
        self.path_experiment_input_config = path_experiment_input_config or c.path_experiment_input_config

    def foo(self):
        return  # do something

моделирование / utilities.py

def sub_function(path):
    print(f'do something in {path}')

идея нового config.py

import socket
from pathlib import Path, PurePath


class Config:
    def __init__(self, experiment_name, enable_simulation=True, development_hostname="DESKTOP-VXXXX"):
        self.experiment_name = experiment_name
        self.enable_simulation = enable_simulation
        self.development_hostname = development_hostname

        self.path_project = Path(__file__).parent.parent

        self.path_experiments_folder = self.path_project.joinpath('experiments')
        self.path_experiment_folder = self.path_experiments_folder.joinpath(experiment_name)
        self.path_experiment_input_config = self.path_experiment_folder.joinpath('input.json')
        self.path_experiment_output_config = self.path_experiment_folder.joinpath('output.json')

        self.path_databases_folder = self.path_project.joinpath('databases')
        self.path_experiment_database_folder = self.path_databases_folder.joinpath(experiment_name)

        if socket.gethostname() != development_hostname and enable_simulation:
            self.run_simulation = True
            self.path_simulation_root_directory = PurePath('/home', 'thomas', 'FOLDER')
        else:
            self.run_simulation = False
            self.path_simulation_root_directory = self.path_project.joinpath('FOLDER')

        self.state = f"hostname {socket.gethostname()}, simulation {['OFF', 'ON'][self.run_simulation]}"

1 ответ
1

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

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

это:

├── package
│   ├── __init__.py
│   ├── config.py
│   ├── simulation
│   │   ├── core.py
│   │   └── utilities.py

должно быть:

├── package
│   ├── __init__.py
│   ├── config
│   │   ├──production
│   │   │   └──config.py
│   │   ├──development
│   │   │   └──config.py
│   │   ├──quality
│   │   │   └──config.py
│   │   ├──local
│   │   │   └──config.py
│   │   └──configmanager.py
│   ├── simulation
│   │   ├── core.py
│   │   └── utilities.py

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

├── package
│   ├── __init__.py
│   ├── config
│   │   ├──production
│   │   │   └──config.py
│   │   ├──development
│   │   │   └──config.py
│   │   ├──quality
│   │   │   └──config.py
│   │   ├──local
│   │   │   └──config.py
│   │   ├──dbconfig
│   │   │   ├──dbconfig1.py
│   │   │   ├──dbconfig2.py
│   │   │   ├──dbconfig3.py
│   │   │   ├──dbconfig4.py
│   │   │   ├──dbconfig5.py
│   │   └──configmanager.py
│   ├── simulation
│   │   ├── core.py
│   │   └── utilities.py

На уровне структуры и развития это покажет, что существует организация данных конфигурации.

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

  • Я не совсем уверен, что понимаю первую часть вашего ответа. Можно ли показать крошечный пример, чтобы я мог лучше его понять? Хорошее предложение для приложения, которое контролирует конфигурацию, я сохраню это в моем списке задач 🙂 сейчас я только на этапе проверки концепции

    — th0mash

  • @ th0mash, я обновил диаграммы

    — Франсиско Нуньес

  • Думаю, я понимаю ваш ответ, однако для меня самой большой проблемой в настоящее время является то, что я хотел бы иметь возможность «вводить» experiment_name в моей конфигурации, чтобы иметь настраиваемые пути в зависимости от того, над каким экспериментом я работаю: / Для ассоциации с базой данных вы видите путь к папке базы данных в файле конфигурации, после этого я просто добавляю, если я в настоящее время работаю над «поездом» или «тестовая» дб. Что будет делать configmanager? объединить все файлы конфигурации?

    — th0mash

  • «configmanager» — это программа, позволяющая пользователю управлять всеми возможными конфигурациями графическим способом, и это поможет избежать пустых переменных.

    — Франсиско Нуньес

  • будет ближе всего к вводу …

    — Франсиско Нуньес

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *