0

overhaul to configParser. Parsing config works now.

This commit is contained in:
Andrew Brown
2012-02-04 21:23:44 -05:00
parent ceb98c4441
commit 6d95d80a73
8 changed files with 321 additions and 245 deletions

View File

@@ -86,44 +86,6 @@ def configure_logger(loglevel=logging.INFO, verbose=False):
logger.addHandler(logger.overviewerHandler) logger.addHandler(logger.overviewerHandler)
logger.setLevel(loglevel) logger.setLevel(loglevel)
def build_fake_settings(worldpath):
"""Builds and returns a renders dict as if it was parsed from a settings
file and returned with get_render_things()
This is used for the simple command line usage with no config file
"""
from overviewer_core import settingsDefinition, rendermodes
world = {}
# Seed this render with all the defaults
for defaultname, defaultinfo in settingsDefinition.render['values'].iteritems():
if 'default' in defaultinfo:
world[defaultname] = defaultinfo['default']
# Set required items for the render. If any new required items without
# defaults are added, this will need to be updated.
worlds = {'world': worldpath}
world['worldname'] = 'world'
world['title'] = "Overviewer Render"
world['rendermode'] = rendermodes.normal
renders = {worldpath: world}
# The following is mostly a copy/paste of the code in
# MultiWorldParser.validate(). Someone make MultiWorldParser more
# extensible to avoid this!
origs = dict()
for key in world:
definition = settingsDefinition.render['values'][key]
val = definition['validator'](world[key], world = worlds)
if definition.get('save_orig', False):
origs[key + "_orig"] = world[key]
world[key] = val
world['name'] = worldpath
world.update(origs)
renders[worldpath] = world
return renders
def main(): def main():
# bootstrap the logger with defaults # bootstrap the logger with defaults
configure_logger() configure_logger()
@@ -249,42 +211,56 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
return 1 return 1
######################################################################### #########################################################################
# These two blocks of code unify config-file mode and command-line mode. # These two halfs of this if statement unify config-file mode and
# When the blocks have exited, they are expected to have set the following # command-line mode.
# vars: mw_parser = configParser.MultiWorldParser()
# destdir - the output directory
# renders - the dict heirarchy
if not options.config: if not options.config:
# No config file mode. # No config file mode.
worldpath, destdir = map(os.path.expanduser, args) worldpath, destdir = map(os.path.expanduser, args)
logging.debug("Using %r as the world directory", worldpath) logging.debug("Using %r as the world directory", worldpath)
logging.debug("Using %r as the output directory", destdir) logging.debug("Using %r as the output directory", destdir)
renders = build_fake_settings(worldpath) mw_parser.set_config_item("world", {'world': worldpath})
mw_parser.set_config_item("outputdir", destdir)
# Now for some good defaults
mw_parser.set_config_item("render", {'world': {
'worldname': 'world',
'title': 'Overviewer Render',
'rendermode': 'normal',
}})
else: else:
# Parse the config file # Parse the config file
mw_parser = configParser.MultiWorldParser(options.config) mw_parser = configParser.MultiWorldParser()
mw_parser.parse() mw_parser.parse(options.config)
try:
mw_parser.validate()
except Exception:
logging.exception("Please investigate these errors in settings.py then try running Overviewer again")
return 1
try: try:
destdir = mw_parser.outputdir config = mw_parser.get_validated_config()
except AttributeError: except Exception:
# Will get caught by the error check just below logging.exception("An error was encountered with your configuration. See the info below.")
logging.debug("Attribute error while getting the outputdir from the config file. Will error in just a sec") return 1
destdir = ""
else:
logging.debug("outputdir from parser: %r", destdir)
renders = mw_parser.get_render_things()
############################################################ ############################################################
# Final validation and creation of the destination directory # Final validation steps and creation of the destination directory
if not config['render']:
logging.error("You must specify at least one render in your config file. See the docs if you're having trouble")
return 1
for rname, render in config['render'].iteritems():
# Convert render['worldname'] to the world path, and store the original
# in render['worldname_orig']
try:
worldpath = config['world'][render['worldname']]
except KeyError:
logging.error("Render %s's world is '%s', but I could not find a corresponding entry in the worlds dictionary.",
rname, render['worldname'])
return 1
render['worldname_orig'] = render['worldname']
render['worldname'] = worldpath
destdir = config['outputdir']
if not destdir: if not destdir:
logging.error("You must specify the output directory in your config file.") logging.error("You must specify the output directory in your config file.")
logging.error("e.g. outputdir = '/path/to/outputdir'") logging.error("e.g. outputdir = '/path/to/outputdir'")
@@ -313,6 +289,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
# same for textures # same for textures
texcache = {} texcache = {}
renders = config['render']
for render_name, render in renders.iteritems(): for render_name, render in renders.iteritems():
logging.debug("Found the following render thing: %r", render) logging.debug("Found the following render thing: %r", render)
@@ -348,6 +325,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
os.mkdir(tileset_dir) os.mkdir(tileset_dir)
# only pass to the TileSet the options it really cares about # only pass to the TileSet the options it really cares about
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension"]) tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension"])
tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir) tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir)
tilesets.append(tset) tilesets.append(tset)

View File

@@ -4,103 +4,72 @@ import os.path
import logging import logging
import settingsDefinition import settingsDefinition
import settingsValidators
class MultiWorldParser(object): class MultiWorldParser(object):
"""A class that is used to parse a settings.py file. It should replace """A class that is used to parse a settings.py file.
ConfigOptionParser class above."""
This class's job is to compile and validate the configuration settings for
a set of renders. It can read in configuration from the given file with the
parse() method, and one can set configuration options directly with the
set_config_item() method.
def __init__(self, settings): get_validated_config() validates and returns the validated config
"""Settings is a path to a settings.py file""" """
if not os.path.exists(settings) and not os.path.isfile(settings):
def __init__(self):
"""Initialize this parser object"""
# This maps config names to their values
self._config_state = {}
# Scan the settings definition and build the config state heirarchy.
# Also go ahead and set default values for non-required settings.
# This maps setting names to their values as given in
# settingsDefinition.py
self._settings = {}
for settingname in settingsDefinition.__all__:
setting = getattr(settingsDefinition, settingname)
assert isinstance(setting, settingsValidators.Setting)
self._settings[settingname] = setting
if not setting.required:
self._config_state[settingname] = setting.default
def set_config_item(self, itemname, itemvalue):
self._config_state[itemname] = itemvalue
def parse(self, settings_file):
"""Reads in the named file and parses it, storing the results in an
internal state awating to be validated and returned upon call to
get_render_settings()
"""
if not os.path.exists(settings_file) and not os.path.isfile(settings_file):
raise ValueError("bad settings file") raise ValueError("bad settings file")
self.settings_file = settings # The global environment should be the rendermode module, so the config
# file has access to those resources.
def parse(self):
# settingsDefinition.py defines what types of things you can put in a configfile
# anything in settingsDefinitino that is a dict with a "type" key is a definiton
defDicts = [x for x in dir(settingsDefinition) if type(getattr(settingsDefinition,x)) == dict and getattr(settingsDefinition,x).has_key("type") and x != "__builtins__"]
glob = dict()
for name in defDicts:
d = getattr(settingsDefinition, name)
glob[name] = d['type']()
import rendermodes import rendermodes
loc=dict()
for thing in dir(rendermodes):
thething = getattr(rendermodes, thing)
if isinstance(thething, type) and issubclass(thething, rendermodes.RenderPrimitive):
loc[thing] = thething
try: try:
execfile(self.settings_file, glob, loc) execfile(settings_file, rendermodes.__dict__, self._config_state)
# delete the builtins, we don't need it
del glob['__builtins__']
except NameError, ex: except NameError, ex:
import traceback logging.exception("Error parsing %s. Please check the trackback for more info" % settings_file)
traceback.print_exc()
logging.error("Error parsing %s. Please check the trackback above" % self.settings_file)
sys.exit(1) sys.exit(1)
except SyntaxError, ex: except SyntaxError, ex:
import traceback logging.exception("Error parsing %s. Please check the trackback for more info" % self.settings_file)
traceback.print_exc()
tb = sys.exc_info()[2]
#print tb.tb_frame.f_code.co_filename
logging.error("Error parsing %s. Please check the trackback above" % self.settings_file)
sys.exit(1) sys.exit(1)
for name in defDicts: def get_validated_config(self):
setattr(self, name, glob[name]) """Validate and return the configuration"""
del glob[name] # Okay, this is okay, isn't it? We're going to create the validation
# routine right here, right now. I hope this works!
validator = settingsValidators.make_configdictvalidator(self._settings)
# seed with the Overviewer defaults, then update with the user defaults # Woah. What just happened? No. WAIT, WHAT ARE YOU...
self.defaults = dict() validated_config = validator(self._config_state)
for name in defDicts: # WHAT HAVE YOU DONE?
d = getattr(settingsDefinition, name) return validated_config
if d['type'] == dict and d['valuetype'] == dict: # WHAT HAVE YOU DOOOOOOOOOOONE????
for key in d['values']:
option = d['values'][key]
if option.has_key("default"):
self.defaults[key] = option["default"]
self.defaults.update(glob)
def validate(self):
origs = dict()
for worldname in self.render:
world = dict()
world.update(self.defaults)
world.update(self.render[worldname])
for key in world:
if key not in settingsDefinition.render['values']:
logging.warning("%r is not a known setting", key)
continue
definition = settingsDefinition.render['values'][key]
try:
val = definition['validator'](world[key], world = self.world)
if definition.get('save_orig', False):
origs[key + "_orig"] = world[key]
world[key] = val
except Exception as e:
logging.error("Error validating '%s' option in render definition for '%s':", key, worldname)
logging.error(e)
raise e
world['name'] = worldname
world.update(origs)
self.render[worldname] = world
def get_render_things(self):
return self.render

View File

@@ -1,54 +1,73 @@
# This file defines all of the things than can # This file describes the format of the config file. Each item defined in this
# appear in a settings.py file, as well as the # module is expected to appear in the same format in a settings file. The only
# function that can validate them # difference is, instead of actual values for the settings, one is to use a
# Setting object. Here is its signature:
# the validator should raise an exception if there # Setting(required, validator, default)
# is a problem parsing or validating the value.
# it should return the value to use (which gives
# the validator an oppertunity to cleanup/normalize/
# whaterver)
# if a setting is not required, the validator is # required is a boolean indicating the user is required to provide this
# expected to return the default option # setting. In this case, default is unused and can be set to anything (None is
# a good choice).
# validator is a callable that takes the provided value and returns a
# cleaned/normalized value to use. It should raise an exception if there is a
# problem parsing or validating the value given.
# default is used instead of the user-provided value in the event that required
# is false. It is passed into the validator just the same. If default is None
# and required is False, then that value is skipped entirely and will not
# appear in the resulting parsed options.
# The signature for validators is validator(value_given). Remember that the
# default is passed in as value_given in the event that required is False and
# default is not None.
# This file doesn't specify the format or even the type of the setting values,
# that is up to the validators used.
from settingsValidators import * from settingsValidators import *
# note that all defaults go thought the validator # This is the export list for this module. It defines which items defined in
render = { # this module are recognized by the config parser. Don't forget to update this
"type": dict, # if you add new items!
"valuetype": dict, __all__ = ['render', 'world', 'outputdir']
"values": {
"worldname": dict(required=True, validator=validateWorldPath, save_orig=True), # render is a dictionary mapping names to dicts describing the configuration
"dimension": dict(required=False, validator=validateDimension, default="default"), # for that render. It is therefore set to a settings object with a dict
"title": dict(required=True, validator=validateStr), # validator configured to validate keys as strings and values as... values are
"rendermode": dict(required=False, validator=validateRenderMode), # set to validate as a "configdict", which is a dict mapping a set of strings
"northdirection": dict(required=False, validator=validateNorthDirection, default=0), # to some value. the make_configdictvalidator function creates a validator to
"renderrange": dict(required=False, validator=validateRenderRange), # use here configured with the given set of keys and Setting objects with their
"forcerender": dict(required=False, validator=validateBool), # respective validators.
"stochasticrender": dict(required=False, validator=validateStochastic),
"imgformat": dict(required=False, validator=validateImgFormat, default="png"), # Perhaps unintuitively, this is set to required=False. Of course, if no
"imgquality": dict(required=False, validator=validateImgQuality), # renders are specified, this is an error. However, this is caught later on in
"bgcolor": dict(required=False, validator=validateBGColor, default="1a1a1a"), # the code, and it also lets an empty dict get defined beforehand for the
"optimizeimg": dict(required=False, validator=validateOptImg, default=0), # config file.
"nomarkers": dict(required=False, validator=validateBool), render = Setting(required=False, default={},
"texturepath": dict(required=False, validator=validateTexturePath), validator=dictValidator(validateStr, make_configdictvalidator(
"renderchecks": dict(required=False, validator=validateInt, default=0), {
"rerenderprob": dict(required=False, validator=validateFloat, default=0), "worldname": Setting(required=True, validator=validateStr, default=None),
} "dimension": Setting(required=False, validator=validateDimension, default="default"),
"title": Setting(required=True, validator=validateStr, default=None),
"rendermode": Setting(required=False, validator=validateRenderMode, default=None),
"northdirection": Setting(required=False, validator=validateNorthDirection, default=0),
"renderrange": Setting(required=False, validator=validateRenderRange, default=None),
"forcerender": Setting(required=False, validator=validateBool, default=None),
"stochasticrender": Setting(required=False, validator=validateStochastic, default=None),
"imgformat": Setting(required=False, validator=validateImgFormat, default="png"),
"imgquality": Setting(required=False, validator=validateImgQuality, default=None),
"bgcolor": Setting(required=False, validator=validateBGColor, default="1a1a1a"),
"optimizeimg": Setting(required=False, validator=validateOptImg, default=0),
"nomarkers": Setting(required=False, validator=validateBool, default=None),
"texturepath": Setting(required=False, validator=validateTexturePath, default=None),
"renderchecks": Setting(required=False, validator=validateInt, default=0),
"rerenderprob": Setting(required=False, validator=validateFloat, default=0),
} }
)))
world = { # The world dict, mapping world names to world paths
"type": dict, world = Setting(required=False, validator=dictValidator(validateStr, validateWorldPath), default={})
"valuetype": str,
"value": dict(validator=validateStr)
}
outputdir = {
"type": str,
"value": dict(validator=validateOutputDir)
}
#defines the values for each member of the world dict
#world = dict(require
outputdir = Setting(required=True, validator=validateOutputDir, default=None)

View File

@@ -1,6 +1,7 @@
# see settingsDefinition.py # see settingsDefinition.py
import os import os
import os.path import os.path
from collections import namedtuple
import rendermodes import rendermodes
from world import UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT from world import UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
@@ -8,20 +9,34 @@ from world import UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
class ValidationException(Exception): class ValidationException(Exception):
pass pass
def validateWorldPath(name, **kwargs): Setting = namedtuple("Setting", [
world = kwargs.get('world', dict()) 'required',
if name not in world.keys(): 'validator',
raise ValidationException("bad world name") 'default',
abs_path = os.path.abspath(world[name]) ])
def validateWorldPath(worldpath):
abs_path = os.path.abspath(worldpath)
if not os.path.exists(os.path.join(abs_path, "level.dat")): if not os.path.exists(os.path.join(abs_path, "level.dat")):
raise ValidationException("No level.dat file in %r. Check the path for world %r" % (abs_path, name)) raise ValidationException("No level.dat file in %r. Are you sure you have the right path?" % (abs_path,))
return abs_path return abs_path
def validateRenderMode(mode, **kwargs): def validateRenderMode(mode):
# make sure that mode is a list of things that are all rendermode primative # make sure that mode is a list of things that are all rendermode primative
if type(mode) != list: if isinstance(mode, str):
# Try and find an item named "mode" in the rendermodes module
try:
mode = getattr(rendermodes, mode)
except AttributeError:
raise ValidationException("You must specify a valid rendermode, not '%s'. See the docs for valid rendermodes." % mode)
if isinstance(mode, rendermodes.RenderPrimitive):
mode = [mode]
if not isinstance(mode, list):
raise ValidationException("%r is not a valid list of rendermodes. It should be a list"% mode) raise ValidationException("%r is not a valid list of rendermodes. It should be a list"% mode)
for m in mode: for m in mode:
if not isinstance(m, rendermodes.RenderPrimitive): if not isinstance(m, rendermodes.RenderPrimitive):
raise ValidationException("%r is not a valid rendermode primitive." % m) raise ValidationException("%r is not a valid rendermode primitive." % m)
@@ -29,7 +44,7 @@ def validateRenderMode(mode, **kwargs):
return mode return mode
def validateNorthDirection(direction, **kwargs): def validateNorthDirection(direction):
# normalize to integers # normalize to integers
intdir = 0 #default intdir = 0 #default
if type(direction) == int: if type(direction) == int:
@@ -43,28 +58,28 @@ def validateNorthDirection(direction, **kwargs):
raise ValidationException("%r is not a valid north direction" % direction) raise ValidationException("%r is not a valid north direction" % direction)
return intdir return intdir
def validateRenderRange(r, **kwargs): def validateRenderRange(r):
raise NotImplementedError("render range") raise NotImplementedError("render range")
def validateStochastic(s, **kwargs): def validateStochastic(s):
val = float(s) val = float(s)
if val < 0 or val > 1: if val < 0 or val > 1:
raise ValidationException("%r is not a valid stochastic value. Should be between 0.0 and 1.0" % s) raise ValidationException("%r is not a valid stochastic value. Should be between 0.0 and 1.0" % s)
return val return val
def validateImgFormat(fmt, **kwargs): def validateImgFormat(fmt):
if fmt not in ("png", "jpg", "jpeg"): if fmt not in ("png", "jpg", "jpeg"):
raise ValidationException("%r is not a valid image format" % fmt) raise ValidationException("%r is not a valid image format" % fmt)
if fmt == "jpeg": fmt = "jpg" if fmt == "jpeg": fmt = "jpg"
return fmt return fmt
def validateImgQuality(qual, **kwargs): def validateImgQuality(qual):
intqual = int(qual) intqual = int(qual)
if (intqual < 0 or intqual > 100): if (intqual < 0 or intqual > 100):
raise ValidationException("%r is not a valid image quality" % intqual) raise ValidationException("%r is not a valid image quality" % intqual)
return intqual return intqual
def validateBGColor(color, **kwargs): def validateBGColor(color):
"""BG color must be an HTML color, with an option leading # (hash symbol) """BG color must be an HTML color, with an option leading # (hash symbol)
returns an (r,b,g) 3-tuple returns an (r,b,g) 3-tuple
""" """
@@ -86,32 +101,80 @@ def validateBGColor(color, **kwargs):
return color return color
def validateOptImg(opt, **kwargs): def validateOptImg(opt):
return bool(opt) return bool(opt)
def validateTexturePath(path, **kwargs): def validateTexturePath(path):
# Expand user dir in directories strings # Expand user dir in directories strings
path = os.path.expanduser(path) path = os.path.expanduser(path)
# TODO assert this path exists? # TODO assert this path exists?
return path return path
def validateBool(b, **kwargs): def validateBool(b):
return bool(b) return bool(b)
def validateFloat(f, **kwargs): def validateFloat(f):
return float(f) return float(f)
def validateInt(i, **kwargs): def validateInt(i):
return int(i) return int(i)
def validateStr(s, **kwargs): def validateStr(s):
return str(s) return str(s)
def validateDimension(d, **kwargs): def validateDimension(d):
if d in ["nether", "overworld", "end", "default"]: if d in ["nether", "overworld", "end", "default"]:
return d return d
raise ValidationException("%r is not a valid dimension" % d) raise ValidationException("%r is not a valid dimension" % d)
def validateOutputDir(d, **kwargs): def validateOutputDir(d):
return os.path.abs(d) if not d.strip():
raise ValidationException("You must specify a valid output directory")
return os.path.abspath(d)
def dictValidator(keyvalidator, valuevalidator):
"""Compose a dict validator by validating each key/value combination with
the given key validator and value validator
"""
def v(d):
newd = {}
for key, value in d.iteritems():
newd[keyvalidator(key)] = valuevalidator(value)
return newd
return v
def make_configdictvalidator(config):
"""Okay, stay with me here, this may get confusing. This function returns a
validator that validates a "configdict". This is a term I just made up to
refer to a dict where keys are strings and values are something. The
argument to /this/ function is a dictionary mapping those key names to
Setting objects. When the validator validates, it calls all the appropriate
validators to validate each item in the configdict.
I hope that makes sense.
"""
def configDictValidator(d):
newdict = {}
for configkey, configsetting in config.iteritems():
if configkey in d:
# This key /was/ specified in the user's dict. Make sure it validates.
newdict[configkey] = configsetting.validator(d[configkey])
else:
# The user did not give us this key. If it's required, send up
# an error. Otherwise, just return the default.
if configsetting.required:
raise ValidationException("Required key '%s' was not specified" % configkey)
elif configsetting.default is not None:
newdict[configkey] = configsetting.validator(configsetting.default)
# Now that all the defined keys have been accounted for, check to make
# sure any unauthorized keys were not specified.
for key in d.iterkeys():
if key not in config:
raise ValidationException("'%s' is not a configuration item" % key)
return newdict
return configDictValidator

View File

@@ -1,14 +1,17 @@
world['test'] = "test/data/settings/test_world" world['test'] = "test/data/settings/test_world"
worldname = 'test'
rendermode = "normal" render["myworld"] = {
"title": "myworld title",
render["world"] = { "worldname": "test",
"rendermode": "normal", "rendermode": normal,
"northdirection": ["upper-left"], "northdirection": "upper-left",
} }
render["otherworld"] = { render["otherworld"] = {
"rendermode": "foo", "title": "otherworld title",
"worldname": "test",
"rendermode": normal,
"bgcolor": "#ffffff" "bgcolor": "#ffffff"
} }
outputdir = "/tmp/fictional/outputdir"

View File

@@ -1,8 +0,0 @@
bgcolor="#000000"
world['test'] = "test/data/settings/test_world"
render["world"] = {
"worldname": "test",
"bgcolor":"ffff"
}

View File

@@ -2,6 +2,9 @@ world['test'] = "test/data/settings/test_world"
render["world"] = { render["world"] = {
"worldname": "test", "worldname": "test",
"title": "myworld title",
"rendermode": "bad_rendermode", "rendermode": "bad_rendermode",
"northdirection": ["upper-left"], "northdirection": "upper-left",
} }
outputdir = "/tmp/fictional/outputdir"

View File

@@ -3,32 +3,81 @@ import unittest
from overviewer_core import configParser from overviewer_core import configParser
from overviewer_core.settingsValidators import ValidationException from overviewer_core.settingsValidators import ValidationException
from overviewer_core import world
from overviewer_core import rendermodes
class SettingsTest(unittest.TestCase): class SettingsTest(unittest.TestCase):
def setUp(self):
self.s = configParser.MultiWorldParser()
def test_missing(self): def test_missing(self):
"Validates that a non-existant settings.py causes an exception" "Validates that a non-existant settings.py causes an exception"
self.assertRaises(ValueError, configParser.MultiWorldParser, "doesnotexist.py") self.assertRaises(ValueError, self.s.parse, "doesnotexist.py")
def test_existing_file(self): def test_existing_file(self):
s = configParser.MultiWorldParser("test/data/settings/settings_test_1.py") self.s.parse("test/data/settings/settings_test_1.py")
s.parse() things = self.s.get_validated_config()
s.validate() # no exceptions so far. that's a good thing
things = s.get_render_things()
# no exceptions so far. that's good # Test the default
self.assertEquals(things['world']['bgcolor'], (26,26,26,0)) self.assertEquals(things['render']['myworld']['bgcolor'], (26,26,26,0))
self.assertEquals(things['otherworld']['bgcolor'], (255,255,255,0))
# Test a non-default
self.assertEquals(things['render']['otherworld']['bgcolor'], (255,255,255,0))
self.assertEquals(things['render']['myworld']['northdirection'],
world.UPPER_LEFT)
def test_rendermode_validation(self): def test_rendermode_validation(self):
s = configParser.MultiWorldParser("test/data/settings/settings_test_rendermode.py") self.s.parse("test/data/settings/settings_test_rendermode.py")
s.parse()
self.assertRaises(ValidationException,s.validate) self.assertRaises(ValidationException,self.s.get_validated_config)
def test_bgcolor_validation(self): def test_manual(self):
s = configParser.MultiWorldParser("test/data/settings/settings_test_bgcolor.py") """Tests that manually setting the config parser works, you don't have
s.parse() to do it from a file
"""
fromfile = configParser.MultiWorldParser()
fromfile.parse("test/data/settings/settings_test_1.py")
self.assertRaises(ValidationException, s.validate) self.s.set_config_item("world", {
'test': "test/data/settings/test_world",
})
self.s.set_config_item("render", {
"myworld": {
"title": "myworld title",
"worldname": "test",
"rendermode": rendermodes.normal,
"northdirection": "upper-left",
},
"otherworld": {
"title": "otherworld title",
"worldname": "test",
"rendermode": rendermodes.normal,
"bgcolor": "#ffffff"
},
})
self.s.set_config_item("outputdir", "/tmp/fictional/outputdir")
self.assertEquals(fromfile.get_validated_config(), self.s.get_validated_config())
def test_rendermode_string(self):
self.s.set_config_item("world", {
'test': "test/data/settings/test_world",
})
self.s.set_config_item("outputdir", "/tmp/fictional/outputdir")
self.s.set_config_item("render", {
"myworld": {
"title": "myworld title",
"worldname": "test",
"rendermode": "normal",
"northdirection": "upper-left",
},
})
p = self.s.get_validated_config()
self.assertEquals(p['render']['myworld']['rendermode'], rendermodes.normal)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()