From 2da1486d8e493432be7d1170f26d5764db1b3076 Mon Sep 17 00:00:00 2001 From: novirium Date: Mon, 23 Dec 2019 10:45:46 +0800 Subject: [PATCH] Fix naming from old scheme. Closes #4 --- configspec.py | 144 +++++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/configspec.py b/configspec.py index d29f9f7..d72159c 100644 --- a/configspec.py +++ b/configspec.py @@ -1,6 +1,6 @@ """ Configuration management module. Enables configuration to be validated against -requirement definitions before being loaded and used. +requirement specifications before being loaded and used. Compatible with both raw config data structures and TOML files, config data must start with a root dict containing named "config bundles". These are intended to @@ -41,7 +41,7 @@ import toml from abc import ABC, abstractmethod from copy import deepcopy -from .freezedry import freezedryable, rehydrate +from preserve import preservable, restore class InvalidConfigError(Exception): @@ -51,7 +51,7 @@ class InvalidConfigError(Exception): # map directly to Dictionaries (Tables), and Lists (Arrays) -class _ConfigDefinition(ABC): +class _ValueSpecification(ABC): def __init__(self, default=None, optional=False, helptext=""): self.default = default self.optional = optional @@ -60,14 +60,14 @@ class _ConfigDefinition(ABC): @abstractmethod def validate(self, value): """ - Checks the supplied value to confirm that it complies with this ConfigDefinition. + Checks the supplied value to confirm that it complies with this specification. Raises InvalidConfigError on failure. """ pass -@freezedryable -class BoolDef(_ConfigDefinition): +@preservable +class BoolSpec(_ValueSpecification): def __init__(self, default=None, optional=False, helptext=""): super().__init__(default, optional, helptext) @@ -76,8 +76,8 @@ class BoolDef(_ConfigDefinition): raise InvalidConfigError("Config value must be a boolean") -@freezedryable -class IntDef(_ConfigDefinition): +@preservable +class IntSpec(_ValueSpecification): def __init__(self, default=None, minval=None, maxval=None, optional=False, helptext=""): super().__init__(default, optional, helptext) @@ -95,8 +95,8 @@ class IntDef(_ConfigDefinition): str(self.maxval)) -@freezedryable -class StringDef(_ConfigDefinition): +@preservable +class StringSpec(_ValueSpecification): def __init__(self, default="", minlength=None, maxlength=None, optional=False, helptext=""): super().__init__(default, optional, helptext) @@ -114,53 +114,53 @@ class StringDef(_ConfigDefinition): str(self.maxlength)) -@freezedryable -class DictDef(_ConfigDefinition): +@preservable +class DictSpec(_ValueSpecification): def __init__(self, default=None, optional=False, helptext=""): super().__init__(default, optional, helptext) - self.def_dict = {} + self.spec_dict = {} - def add_def(self, name, newdef): - if not isinstance(newdef, _ConfigDefinition): - raise TypeError("Config definiton must be an instance of a " - "ConfigDefinition subclass") + def add_spec(self, name, newspec): + if not isinstance(newspec, _ValueSpecification): + raise TypeError("Config specification must be an instance of a " + "_ValueSpecification subclass") if not isinstance(name, str): - raise TypeError("Config definition name must be a string") - self.def_dict[name] = newdef - return newdef + raise TypeError("Config specification name must be a string") + self.spec_dict[name] = newspec + return newspec def validate(self, value_dict): """ - Checks the supplied value to confirm that it complies with this ConfigDefinition. + Checks the supplied value to confirm that it complies with this specification. Raises InvalidConfigError on failure. This *can* modify the supplied value dict, inserting defaults for any child - ConfigDefinitions that are marked as optional. + config specifications that are marked as optional. """ - def_set = set(self.def_dict.keys()) + spec_set = set(self.spec_dict.keys()) value_set = set(value_dict.keys()) - for missing_key in def_set - value_set: - if not self.def_dict[missing_key].optional: + for missing_key in spec_set - value_set: + if not self.spec_dict[missing_key].optional: raise InvalidConfigError("Dict must contain key: " + missing_key) else: - value_dict[missing_key] = self.def_dict[missing_key].default + value_dict[missing_key] = self.spec_dict[missing_key].default - for extra_key in value_set - def_set: + for extra_key in value_set - spec_set: raise InvalidConfigError("Dict contains unknown key: " + extra_key) for key, value in value_dict.items(): try: - self.def_dict[key].validate(value) + self.spec_dict[key].validate(value) except InvalidConfigError as e: e.args = ("Key: " + key,) + e.args raise def get_template(self, include_optional=False): """ - Return a config dict with the minimum structure required for this ConfigDefinition. + Return a config dict with the minimum structure required for this specification. Default values will be included, though not all required fields will necessarily have defaults that successfully validate. @@ -169,21 +169,21 @@ class DictDef(_ConfigDefinition): required ones Returns: Dict containing the structure that should be passed back in (with values) to comply - with this ConfigDefinition. + with this config specification. """ template = {} - for key, confdef in self.def_dict.items(): - if confdef.optional and (not include_optional): + for key, confspec in self.spec_dict.items(): + if confspec.optional and (not include_optional): continue - if hasattr(confdef, "get_template"): - template[key] = confdef.get_template(include_optional) + if hasattr(confspec, "get_template"): + template[key] = confspec.get_template(include_optional) else: - template[key] = confdef.default + template[key] = confspec.default return template -class _ListDefMixin(): +class _ListSpecMixin(): def validate(self, value_list): if not isinstance(value_list, list): raise InvalidConfigError("Config item must be a list") @@ -201,35 +201,35 @@ class _ListDefMixin(): return [self.default] -@freezedryable -class BoolListDef(_ListDefMixin, BoolDef): +@preservable +class BoolListSpec(_ListSpecMixin, BoolSpec): pass -@freezedryable -class IntListDef(_ListDefMixin, IntDef): +@preservable +class IntListSpec(_ListSpecMixin, IntSpec): pass -@freezedryable -class StringListDef(_ListDefMixin, StringDef): +@preservable +class StringListSpec(_ListSpecMixin, StringSpec): pass -@freezedryable -class DictListDef(_ListDefMixin, DictDef): +@preservable +class DictListSpec(_ListSpecMixin, DictSpec): pass -@freezedryable -class ConfDefinition(DictDef): +@preservable +class ConfigSpecification(DictSpec): pass class ConfigManager(): def __init__(self): self.root_config = {} - self.confdefs = {} + self.confspecs = {} self.frozen_config = {} @staticmethod @@ -297,32 +297,32 @@ class ConfigManager(): frozen_value[names[-1]] = target_field[names[-1]] - def add_confdef(self, bundle_name, confdef): + def add_confspec(self, bundle_name, confspec): """ - Stores a ConfigDefinition for future use when validating the corresponding config bundle + Stores a ConfigSpecification for future use when validating the corresponding config bundle Args: - bundle_name (str) : The name to store the config definition under. - confdef (ConfigDefinition): The populated ConfigDefinition to store. + bundle_name (str) : The name to store the config specification under. + confspec (ConfigSpecification): The populated ConfigSpecification to store. """ - self.confdefs[bundle_name] = confdef + self.confspecs[bundle_name] = confspec - def add_confdefs(self, confdefs): + def add_confspecs(self, confspecs): """ - Stores multiple ConfigDefinitions at once for future use when validating the corresponding + Stores multiple ConfigSpecifications at once for future use when validating the corresponding config bundles Args: - confdefs : A dict of populated ConfigDefinitions to store, using their keys as names. + confspecs : A dict of populated ConfigSpecifications to store, using their keys as names. """ - self.confdefs.update(confdefs) + self.confspecs.update(confspecs) - def list_missing_confdefs(self): + def list_missing_confspecs(self): """ - Returns a list of config bundle names that do not have a corresponding ConfigDefinition + Returns a list of config bundle names that do not have a corresponding ConfigSpecification stored in the ConfigManager. """ - return list(self.root_config.keys() - self.confdefs.keys()) + return list(self.root_config.keys() - self.confspecs.keys()) def _overlay(self, src, dest): for key in src: @@ -333,31 +333,31 @@ class ConfigManager(): # Otherwise it's either an existing value to be replaced or needs to be added. dest[key] = src[key] - def get_config_bundle(self, bundle_name, conf_def=None): + def get_config_bundle(self, bundle_name, conf_spec=None): """ Get a config bundle called ``bundle_name`` and validate - it against the corresponding config definition stored in the ConfigManager. - If ``conf_def`` is supplied, it gets used instead. Returns a validated + it against the corresponding config specification stored in the ConfigManager. + If ``conf_spec`` is supplied, it gets used instead. Returns a copy of the validated config bundle dict. Note that as part of validation, optional keys that are missing will be - filled in with their default values (see ``DictDef``). This function will copy + filled in with their default values (see ``DictSpec``). This function will copy the config bundle *after* validation, and so config loaded in the ConfManager will be modified, but future ConfigManager manipulations won't change the returned config bundle. Args: config_name: (str) Name of the config dict to find. - conf_def: (ConfDefinition) Optional config definition to validate against. + conf_spec: (ConfigSpecification) Optional config specification to validate against. """ - if not isinstance(conf_def, ConfDefinition): - conf_def = self.confdefs[bundle_name] + if not isinstance(conf_spec, ConfigSpecification): + conf_spec = self.confspecs[bundle_name] if bundle_name not in self.root_config: raise InvalidConfigError( "Config must contain dict: " + bundle_name) try: - conf_def.validate(self.root_config[bundle_name]) + conf_spec.validate(self.root_config[bundle_name]) except InvalidConfigError as e: e.args = ("Bundle: " + bundle_name,) + e.args raise @@ -366,11 +366,11 @@ class ConfigManager(): def get_config_bundles(self, bundle_names): """ Get multiple config bundles from the root dict at once, validating each one with the - corresponding confdef stored in the ConfigManager. See ``get_config_bundle`` + corresponding ConfigSpecification stored in the ConfigManager. See ``get_config_bundle`` Args: bundle_names: A list of config bundle names to get. If dictionary is supplied, uses - the values as ConfigDefinitions rather than looking up a stored one in the + the values as ConfigSpecifications rather than looking up a stored one in the ConfigManager. Returns: @@ -378,8 +378,8 @@ class ConfigManager(): """ config_values = {} if isinstance(bundle_names, dict): - for name, conf_def in bundle_names.items(): - config_values[name] = self.get_config_bundle(name, conf_def) + for name, conf_spec in bundle_names.items(): + config_values[name] = self.get_config_bundle(name, conf_spec) else: for name in bundle_names: config_values[name] = self.get_config_bundle(name) @@ -419,4 +419,4 @@ def update_toml_message(filepath, message): def gen_comment(string): - return '\n# shepherd_message: ' + '\n# '.join(string.replace('#', '').splitlines()) + '\n' + return '\n# config-spec_message: ' + '\n# '.join(string.replace('#', '').splitlines()) + '\n'