Source code for abcclassroom.config

"""
abc-classroom.config
====================

"""

import pprint
from pathlib import Path
from ruamel.yaml import YAML
import ruamel.yaml.composer


[docs]def get_config(configpath=None): """Attempts to read a config file at the provided path (or at "config.yml" if no path provided). Throws FileNotFoundError if no config file found, and RuntimeError if there is a problem reading the file. Returns ------- ruamel.yaml.comments.CommentedMap Yaml object that contains the contents of the config file. """ yaml = YAML() try: if configpath is None: configpath = Path("config.yml") else: configpath = Path(configpath, "config.yml") with open(configpath) as f: config = yaml.load(f) return config except ruamel.yaml.composer.ComposerError: raise RuntimeError( "Error reading config.yml. This can happen if the config " "contains an unquoted *. Try adding quotes around any wildcards " "in the config, e.g. '*.csv'. See " "https://abc-classroom.readthedocs.io/en/latest/get-started/configuration.html " # noqa "for details." ) except FileNotFoundError: c = configpath.resolve() raise FileNotFoundError( "Oops! I can't seem to find a config.yml file at {}. " "Are you in the top-level directory for the course? If you don't " "have a course directory and config file " "setup yet, you can create one using abc-quickstart" ".\n".format(c) )
[docs]def write_config(config, configpath=None): yaml = YAML() if configpath is None: configpath = Path("config.yml") else: configpath = Path(configpath, "config.yml") with open(configpath, "w") as f: yaml.dump(config, f)
# TODO: allow for nested gets, e.g. config[a][b]
[docs]def get_config_option(config, option, required=True): """ Get an option (value of key) from provided config dictionary. If the key does not exist, exit with KeyError (required=True) or return None (required=False). """ try: value = config[option] return value except KeyError: if required: raise KeyError( "Oops! I couldn't find the required option in the " "config file. Check your config file to ensure the the {} " "option is populated".format(option) ) else: return None
[docs]def set_config_option( config, option, value, append_value=False, configpath=None ): """ Sets a config option. If option already exists and append_value is False, replaces existing value. If option exists and append_value is true, adds new value to list of existing values. Will not add a duplicate value. Writes the new config (overwriting the existing file) and returns new config dict. """ existing_value = get_config_option(config, option, required=False) if append_value and existing_value is not None: if isinstance(existing_value, list): existing_value.append(value) value = existing_value else: value = [existing_value, value] # eliminate duplicates value = list(set(value)) config[option] = value print("Writing modified config at {}".format(configpath)) write_config(config, configpath) return config