dvarfe's picture
sync with github version
0705c62
Raw
History Blame Contribute Delete
2.78 kB
import argparse
import yaml
from dotmap import DotMap
from functools import reduce
from operator import getitem
from distutils.util import strtobool
from pathlib import Path
import re
PROJECT_ROOT = Path(__file__).absolute().parents[1].absolute()
def parse_config(config_file_path: str) -> DotMap:
"""Parse the YAML configuration file"""
with open(config_file_path, 'r') as file:
config = yaml.safe_load(file)
return DotMap(config, _dynamic=False)
def parse_command_line_args(config: DotMap) -> DotMap:
"""Parse the command-line arguments"""
parser = argparse.ArgumentParser()
# Automatically add command-line arguments based on the config structure
def add_arguments(section, prefix=''):
for key, value in section.items():
full_key = f'{prefix}.{key}' if prefix else key
if isinstance(value, dict):
add_arguments(value, prefix=full_key)
else:
# Check if the value is a list
if isinstance(value, list):
# Convert list to comma-separated string
parser.add_argument(f'--{full_key}', default=value, type=type(value[0]), nargs='+', help=f'Value for {full_key}')
else:
if type(value) == bool:
parser.add_argument(f'--{full_key}', default=value, type=strtobool, help=f'Value for {full_key}')
else:
parser.add_argument(f'--{full_key}', default=value, type=type(value), help=f'Value for {full_key}')
add_arguments(config)
args, _ = parser.parse_known_args()
args = DotMap(vars(args), _dynamic=False)
return args
def merge_configs(config: DotMap, args: DotMap) -> DotMap:
"""Merge the command-line arguments into the config. The command-line arguments take precedence over the config file
:rtype: object
"""
keys_to_modify = []
def update_config(config, key, value):
*keys, last_key = key.split('.')
reduce(getitem, keys, config)[last_key] = value
# Recursively merge command-line parameters into the config
def get_updates(section, args, prefix=''):
for key, value in section.items():
full_key = f'{prefix}.{key}' if prefix else key
if isinstance(value, dict):
get_updates(value, args, prefix=full_key)
elif getattr(args, full_key, None) or getattr(args, full_key, None) != getattr(section, key, None):
keys_to_modify.append((full_key, getattr(args, full_key)))
get_updates(config, args)
for key, value in keys_to_modify:
update_config(config, key, value)
return config