diff --git a/docs/config.rst b/docs/config.rst index 19b85b4..56a2a85 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -209,6 +209,21 @@ Render Dictonary Keys The render dictionary is a dictionary mapping configuration key strings to values. The valid configuration keys are listed below. +.. note:: + + Any of these items can be specified at the top level of the config file to + set the default for every render. For example, this line at the top of the + config file will set the world for every render to 'myworld' if no world is + specified:: + + world = 'myworld' + + Then you don't need to specify a ``world`` key in the render dictionaries:: + + render['arender'] = { + 'title': 'This render doesn't explicitly declare a world!', + } + ``world`` Specifies which world this render corresponds to. Its value should be a string from the appropriate key in the worlds dictionary. diff --git a/overviewer_core/configParser.py b/overviewer_core/configParser.py index 533f861..412e1bf 100644 --- a/overviewer_core/configParser.py +++ b/overviewer_core/configParser.py @@ -15,6 +15,7 @@ class MultiWorldParser(object): set_config_item() method. get_validated_config() validates and returns the validated config + """ def __init__(self): @@ -34,6 +35,9 @@ class MultiWorldParser(object): self._settings[settingname] = setting + # Set top level defaults. This is intended to be for container + # types, so they can initialize a config file with an empty + # container (like a dict) if setting.required and setting.default is not None: self._config_state[settingname] = setting.default @@ -45,6 +49,10 @@ class MultiWorldParser(object): internal state awating to be validated and returned upon call to get_render_settings() + Attributes defined in the file that do not match any setting are then + matched against the renderdict setting, and if it does match, is used as + the default for that setting. + """ if not os.path.exists(settings_file) and not os.path.isfile(settings_file): raise ValueError("bad settings file") @@ -60,6 +68,16 @@ class MultiWorldParser(object): logging.exception("Error parsing %s. Please check the trackback for more info" % settings_file) sys.exit(1) + # At this point, make a pass through the file to possibly set global + # render defaults + render_settings = self._settings['renders'].validator.valuevalidator.config + for key in self._config_state.iterkeys(): + if key not in self._settings: + if key in render_settings: + setting = render_settings[key] + setting.default = self._config_state[key] + + def get_validated_config(self): """Validate and return the configuration. Raises a ValidationException if there was a problem validating the config. diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 5c9e245..7882d93 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -9,11 +9,12 @@ from world import UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT class ValidationException(Exception): pass -Setting = namedtuple("Setting", [ - 'required', - 'validator', - 'default', - ]) +class Setting(object): + __slots__ = ['required', 'validator', 'default'] + def __init__(self, required, validator, default): + self.required = required + self.validator = validator + self.default = default def validateWorldPath(worldpath): abs_path = os.path.abspath(worldpath) @@ -147,6 +148,10 @@ def make_dictValidator(keyvalidator, valuevalidator): for key, value in d.iteritems(): newd[keyvalidator(key)] = valuevalidator(value) return newd + # Put these objects as attributes of the function so they can be accessed + # externally later if need be + v.keyvalidator = keyvalidator + v.valuevalidator = valuevalidator return v def make_configDictValidator(config, ignore_undefined=False): @@ -167,6 +172,7 @@ def make_configDictValidator(config, ignore_undefined=False): """ def configDictValidator(d): + newdict = {} # values are config keys that the user specified that don't match any # valid key @@ -183,16 +189,22 @@ def make_configDictValidator(config, ignore_undefined=False): # some required key that wasn't specified. (If all required # keys are specified, then this should be ignored) undefined_key_matches[match] = key + newdict[key] = d[key] elif match: raise ValidationException( "'%s' is not a configuration item. Did you mean '%s'?" % (key, match)) elif not ignore_undefined: raise ValidationException("'%s' is not a configuration item" % key) + else: + # the key is to be ignored. Copy it as-is to the `newdict` + # to be returned. It shouldn't conflict, and may be used as + # a default value for a render configdict later on. + newdict[key] = d[key] - newdict = {} # Iterate through the defined keys in the configuration (`config`), - # checking each one to see if the user specified it (in `d`) + # checking each one to see if the user specified it (in `d`). Then + # validate it and copy the result to `newdict` for configkey, configsetting in config.iteritems(): if configkey in d: # This key /was/ specified in the user's dict. Make sure it validates. @@ -213,7 +225,10 @@ def make_configDictValidator(config, ignore_undefined=False): % configkey) return newdict - + # Put these objects as attributes of the function so they can be accessed + # externally later if need be + configDictValidator.config = config + configDictValidator.ignore_undefined = ignore_undefined return configDictValidator def error(errstr):