gameboy_worlds.utils.parameter_handling
1import os 2import yaml 3import sys 4from gameboy_worlds.utils.fundamental import get_logger, check_optional_installs 5 6 7def load_yaml(yaml_path: str) -> dict: 8 """ 9 Loads a yaml file and returns the contents as a dictionary. 10 Args: 11 yaml_path (str): Path to the yaml file. 12 Returns: 13 dict: Contents of the yaml file. 14 """ 15 with open(yaml_path, "r") as f: 16 return yaml.load(f, Loader=yaml.FullLoader) 17 18 19def compute_secondary_parameters(params: dict): 20 """ 21 Computes secondary parameters based on the primary parameters. 22 This sets up the directory structure for the project, including data, model, tmp, sync, and log directories. 23 It also initializes the logger and adds it to the parameters dictionary. 24 25 Args: 26 params (dict): Primary parameters dictionary. 27 """ 28 params["rom_data_dir"] = os.path.join(params["storage_dir"], "rom_data") 29 params["log_dir"] = os.path.join(params["storage_dir"], "logs") 30 params["tmp_dir"] = os.path.join(params["storage_dir"], "tmp") 31 for dirname in ["rom_data_dir", "log_dir", "tmp_dir"]: 32 if not os.path.exists(params[dirname]): 33 os.makedirs(params[dirname]) 34 if "log_file" not in params: 35 log_file = os.path.join(params["log_dir"], "log.txt") 36 params["log_file"] = log_file 37 else: 38 # check if log_file is a child of log_dir, but handle silly // vs / cases 39 log_dir_str = params["log_dir"].replace("//", "/") 40 log_file_str = params["log_file"].replace("//", "/") 41 if not log_file_str.startswith(log_dir_str): 42 log_file = os.path.join(params["log_dir"], params["log_file"]) 43 params["log_file"] = log_file 44 logger = get_logger(filename=params["log_file"]) 45 params["logger"] = logger 46 # convert all rom_data_paths to absolute paths 47 for key in params: 48 if key.endswith("_rom_data_path"): 49 relative_addition = params[key] 50 if os.path.isabs(relative_addition) or relative_addition.strip() == "": 51 logger.error( 52 f"{key} should be a relative path, as it will get joined with rom_data_dir {params['rom_data_dir']}. However, the entered value {relative_addition} seems to be an absolute path." 53 ) 54 sys.exit(1) 55 params[key] = os.path.abspath( 56 os.path.join(params["rom_data_dir"], relative_addition) 57 ) 58 59 60def load_parameters(parameters: dict = None) -> dict: 61 """ 62 Loads the parameters for the project from configs/private_vars.yaml and any other yaml files in the configs directory. 63 64 That is, unless a non None parameters dictionary is passed through, in which case we assume all is good and just return it. 65 66 Args: 67 parameters (dict, optional): If provided, this dictionary is returned as the parameters. 68 If None, parameters are loaded from the config files. Defaults to None. 69 70 Returns: 71 dict: Parameters dictionary. 72 """ 73 if parameters is not None: 74 if ( 75 "logger" not in parameters 76 ): # this is a flag that secondary parameters need to be computed 77 compute_secondary_parameters(parameters) 78 return parameters 79 essential_keys = ["storage_dir"] 80 project_root = os.path.dirname( 81 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 82 ) 83 params = {"project_root": project_root} 84 logger = get_logger() 85 config_files = os.listdir(os.path.join(project_root, "configs")) 86 87 def error(msg): 88 logger.error(msg) 89 sys.exit(1) 90 91 if "private_vars.yaml" not in config_files: 92 error("Please create private_vars.yaml in the configs directory") 93 for file in config_files: 94 if file.endswith(".yaml"): 95 configs = None 96 while configs is None: 97 configs = load_yaml(os.path.join(project_root, "configs", file)) 98 for key in configs: 99 if key in params: 100 error( 101 f"{key} is present in multiple config files. At least one of which is {file}. Please remove the duplicate" 102 ) 103 params.update(configs) 104 else: 105 pass 106 107 for key in params: 108 if params[key] == "PLACEHOLDER": 109 error( 110 f"{key} is currently the placeholder value in private_vars.yaml. Please set it" 111 ) 112 for essential_key in essential_keys: 113 if essential_key not in params: 114 error(f"Please set {essential_key} in one of the config yamls") 115 # check if there are any .py files in storage_dir, if so, log error 116 if os.path.exists(params["storage_dir"]): 117 if any([f.endswith(".py") for f in os.listdir(params["storage_dir"])]): 118 logger.warning( 119 f"There are .py files in the storage_dir {params['storage_dir']}. It is recommended to set a path which has nothing else inside it to avoid issues." 120 ) 121 else: 122 full_path = os.path.abspath(params["storage_dir"]) 123 if params["storage_dir"] == "storage": 124 logger.warning( 125 f"Using default storage directory '{full_path}'. This may cause issues if your project root directory has limited space. To change the storage directory, modify the 'storage_dir' parameter in your config files and run this method again." 126 ) 127 os.makedirs(full_path) 128 logger.info( 129 f"Created storage directory {full_path}. You will find a {full_path}/rom_data/ directory inside it, which is where you must place your downloaded ROM (.gb or .gbc) files." 130 ) 131 # For every path, see if it looks relative, and if so, make it absolute based on project_root 132 for key in params: 133 if isinstance(params[key], str): 134 try_path = os.path.join(project_root, params[key]) 135 if os.path.exists(try_path): 136 params[key] = os.path.abspath(try_path) 137 compute_secondary_parameters(params) 138 return params
def
load_yaml(yaml_path: str) -> dict:
8def load_yaml(yaml_path: str) -> dict: 9 """ 10 Loads a yaml file and returns the contents as a dictionary. 11 Args: 12 yaml_path (str): Path to the yaml file. 13 Returns: 14 dict: Contents of the yaml file. 15 """ 16 with open(yaml_path, "r") as f: 17 return yaml.load(f, Loader=yaml.FullLoader)
Loads a yaml file and returns the contents as a dictionary.
Arguments:
- yaml_path (str): Path to the yaml file.
Returns:
dict: Contents of the yaml file.
def
compute_secondary_parameters(params: dict):
20def compute_secondary_parameters(params: dict): 21 """ 22 Computes secondary parameters based on the primary parameters. 23 This sets up the directory structure for the project, including data, model, tmp, sync, and log directories. 24 It also initializes the logger and adds it to the parameters dictionary. 25 26 Args: 27 params (dict): Primary parameters dictionary. 28 """ 29 params["rom_data_dir"] = os.path.join(params["storage_dir"], "rom_data") 30 params["log_dir"] = os.path.join(params["storage_dir"], "logs") 31 params["tmp_dir"] = os.path.join(params["storage_dir"], "tmp") 32 for dirname in ["rom_data_dir", "log_dir", "tmp_dir"]: 33 if not os.path.exists(params[dirname]): 34 os.makedirs(params[dirname]) 35 if "log_file" not in params: 36 log_file = os.path.join(params["log_dir"], "log.txt") 37 params["log_file"] = log_file 38 else: 39 # check if log_file is a child of log_dir, but handle silly // vs / cases 40 log_dir_str = params["log_dir"].replace("//", "/") 41 log_file_str = params["log_file"].replace("//", "/") 42 if not log_file_str.startswith(log_dir_str): 43 log_file = os.path.join(params["log_dir"], params["log_file"]) 44 params["log_file"] = log_file 45 logger = get_logger(filename=params["log_file"]) 46 params["logger"] = logger 47 # convert all rom_data_paths to absolute paths 48 for key in params: 49 if key.endswith("_rom_data_path"): 50 relative_addition = params[key] 51 if os.path.isabs(relative_addition) or relative_addition.strip() == "": 52 logger.error( 53 f"{key} should be a relative path, as it will get joined with rom_data_dir {params['rom_data_dir']}. However, the entered value {relative_addition} seems to be an absolute path." 54 ) 55 sys.exit(1) 56 params[key] = os.path.abspath( 57 os.path.join(params["rom_data_dir"], relative_addition) 58 )
Computes secondary parameters based on the primary parameters. This sets up the directory structure for the project, including data, model, tmp, sync, and log directories. It also initializes the logger and adds it to the parameters dictionary.
Arguments:
- params (dict): Primary parameters dictionary.
def
load_parameters(parameters: dict = None) -> dict:
61def load_parameters(parameters: dict = None) -> dict: 62 """ 63 Loads the parameters for the project from configs/private_vars.yaml and any other yaml files in the configs directory. 64 65 That is, unless a non None parameters dictionary is passed through, in which case we assume all is good and just return it. 66 67 Args: 68 parameters (dict, optional): If provided, this dictionary is returned as the parameters. 69 If None, parameters are loaded from the config files. Defaults to None. 70 71 Returns: 72 dict: Parameters dictionary. 73 """ 74 if parameters is not None: 75 if ( 76 "logger" not in parameters 77 ): # this is a flag that secondary parameters need to be computed 78 compute_secondary_parameters(parameters) 79 return parameters 80 essential_keys = ["storage_dir"] 81 project_root = os.path.dirname( 82 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 83 ) 84 params = {"project_root": project_root} 85 logger = get_logger() 86 config_files = os.listdir(os.path.join(project_root, "configs")) 87 88 def error(msg): 89 logger.error(msg) 90 sys.exit(1) 91 92 if "private_vars.yaml" not in config_files: 93 error("Please create private_vars.yaml in the configs directory") 94 for file in config_files: 95 if file.endswith(".yaml"): 96 configs = None 97 while configs is None: 98 configs = load_yaml(os.path.join(project_root, "configs", file)) 99 for key in configs: 100 if key in params: 101 error( 102 f"{key} is present in multiple config files. At least one of which is {file}. Please remove the duplicate" 103 ) 104 params.update(configs) 105 else: 106 pass 107 108 for key in params: 109 if params[key] == "PLACEHOLDER": 110 error( 111 f"{key} is currently the placeholder value in private_vars.yaml. Please set it" 112 ) 113 for essential_key in essential_keys: 114 if essential_key not in params: 115 error(f"Please set {essential_key} in one of the config yamls") 116 # check if there are any .py files in storage_dir, if so, log error 117 if os.path.exists(params["storage_dir"]): 118 if any([f.endswith(".py") for f in os.listdir(params["storage_dir"])]): 119 logger.warning( 120 f"There are .py files in the storage_dir {params['storage_dir']}. It is recommended to set a path which has nothing else inside it to avoid issues." 121 ) 122 else: 123 full_path = os.path.abspath(params["storage_dir"]) 124 if params["storage_dir"] == "storage": 125 logger.warning( 126 f"Using default storage directory '{full_path}'. This may cause issues if your project root directory has limited space. To change the storage directory, modify the 'storage_dir' parameter in your config files and run this method again." 127 ) 128 os.makedirs(full_path) 129 logger.info( 130 f"Created storage directory {full_path}. You will find a {full_path}/rom_data/ directory inside it, which is where you must place your downloaded ROM (.gb or .gbc) files." 131 ) 132 # For every path, see if it looks relative, and if so, make it absolute based on project_root 133 for key in params: 134 if isinstance(params[key], str): 135 try_path = os.path.join(project_root, params[key]) 136 if os.path.exists(try_path): 137 params[key] = os.path.abspath(try_path) 138 compute_secondary_parameters(params) 139 return params
Loads the parameters for the project from configs/private_vars.yaml and any other yaml files in the configs directory.
That is, unless a non None parameters dictionary is passed through, in which case we assume all is good and just return it.
Arguments:
- parameters (dict, optional): If provided, this dictionary is returned as the parameters. If None, parameters are loaded from the config files. Defaults to None.
Returns:
dict: Parameters dictionary.