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.