0

settingsValidators: fix code style, adjust strings

Some absolute thonkers in here like two-spaces indent code. Yikes
my man.
This commit is contained in:
Nicolas F
2019-03-15 16:48:08 +01:00
parent d6ed0bd416
commit 6aaf680c8c

View File

@@ -1,29 +1,34 @@
# see settingsDefinition.py # see settingsDefinition.py
import logging
import os import os
import os.path import os.path
import rendermodes import rendermodes
import util import util
from optimizeimages import Optimizer from optimizeimages import Optimizer
from world import UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT from world import LOWER_LEFT, LOWER_RIGHT, UPPER_LEFT, UPPER_RIGHT
import logging
class ValidationException(Exception): class ValidationException(Exception):
pass pass
class Setting(object): class Setting(object):
__slots__ = ['required', 'validator', 'default'] __slots__ = ['required', 'validator', 'default']
def __init__(self, required, validator, default): def __init__(self, required, validator, default):
self.required = required self.required = required
self.validator = validator self.validator = validator
self.default = default self.default = default
def expand_path(p): def expand_path(p):
p = os.path.expanduser(p) p = os.path.expanduser(p)
p = os.path.expandvars(p) p = os.path.expandvars(p)
p = os.path.abspath(p) p = os.path.abspath(p)
return p return p
def checkBadEscape(s): def checkBadEscape(s):
# If any of these weird characters are in the path, raise an exception # If any of these weird characters are in the path, raise an exception
# instead of fixing this should help us educate our users about pathslashes # instead of fixing this should help us educate our users about pathslashes
@@ -35,36 +40,42 @@ def checkBadEscape(s):
"more info." % repr(b)) "more info." % repr(b))
for c in range(10): for c in range(10):
if chr(c) in s: if chr(c) in s:
raise ValueError("Invalid character '\\%s' in path. Please use forward slashes ('/'). Please see our docs for more info." % c) raise ValueError("Invalid character '\\%s' in path. "
"Please use forward slashes ('/'). "
"See our docs for more info." % c)
return s return s
def validateMarkers(filterlist): def validateMarkers(filterlist):
if type(filterlist) != list: if type(filterlist) != list:
raise ValidationException("Markers must specify a list of filters. This has recently changed, so check the docs.") raise ValidationException("Markers must specify a list of filters.")
for x in filterlist: for x in filterlist:
if type(x) != dict: if type(x) != dict:
raise ValidationException("Markers must specify a list of dictionaries. This has recently changed, so check the docs.") raise ValidationException("Markers must specify a list of dictionaries.")
if "name" not in x: if "name" not in x:
raise ValidationException("Must define a name") raise ValidationException("Filter must define a name.")
if "filterFunction" not in x: if "filterFunction" not in x:
raise ValidationException("Must define a filter function") raise ValidationException("Filter must define a filter function.")
if not callable(x['filterFunction']): if not callable(x['filterFunction']):
raise ValidationException("%r must be a function"% x['filterFunction']) raise ValidationException("%r must be a function." % x['filterFunction'])
return filterlist return filterlist
def validateOverlays(renderlist): def validateOverlays(renderlist):
if type(renderlist) != list: if type(renderlist) != list:
raise ValidationException("Overlay must specify a list of renders") raise ValidationException("Overlay must specify a list of renders.")
for x in renderlist: for x in renderlist:
if validateStr(x) == '': if validateStr(x) == '':
raise ValidationException("%r must be a string"% x) raise ValidationException("%r must be a string." % x)
return renderlist return renderlist
def validateWorldPath(worldpath): def validateWorldPath(worldpath):
checkBadEscape(worldpath) checkBadEscape(worldpath)
abs_path = expand_path(worldpath) abs_path = expand_path(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 '%s'. Are you sure you have the right path?" % (abs_path,)) raise ValidationException("No level.dat file in '%s'. Are you sure you have the right "
"path?" % (abs_path,))
return abs_path return abs_path
@@ -76,21 +87,23 @@ def validateRenderMode(mode):
try: try:
mode = getattr(rendermodes, mode) mode = getattr(rendermodes, mode)
except AttributeError: except AttributeError:
raise ValidationException("You must specify a valid rendermode, not '%s'. See the docs for valid rendermodes." % mode) raise ValidationException("You must specify a valid rendermode, not '%s'. "
"See the docs for valid rendermodes." % mode)
if isinstance(mode, rendermodes.RenderPrimitive): if isinstance(mode, rendermodes.RenderPrimitive):
mode = [mode] mode = [mode]
if not isinstance(mode, list): 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)
return mode return mode
def validateNorthDirection(direction): def validateNorthDirection(direction):
# normalize to integers # normalize to integers
intdir = 0 # default intdir = 0 # default
@@ -98,39 +111,49 @@ def validateNorthDirection(direction):
intdir = direction intdir = direction
elif isinstance(direction, str): elif isinstance(direction, str):
direction = direction.lower().replace("-", "").replace("_", "") direction = direction.lower().replace("-", "").replace("_", "")
if direction == "upperleft": intdir = UPPER_LEFT if direction == "upperleft":
elif direction == "upperright": intdir = UPPER_RIGHT intdir = UPPER_LEFT
elif direction == "lowerright": intdir = LOWER_RIGHT elif direction == "upperright":
elif direction == "lowerleft": intdir = LOWER_LEFT intdir = UPPER_RIGHT
elif direction == "lowerright":
intdir = LOWER_RIGHT
elif direction == "lowerleft":
intdir = LOWER_LEFT
else: else:
raise ValidationException("'%s' is not a valid north direction" % direction) raise ValidationException("'%s' is not a valid north direction." % direction)
if intdir < 0 or intdir > 3: if intdir < 0 or intdir > 3:
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 validateRerenderprob(s): def validateRerenderprob(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 rerender probability value. Should be between 0.0 and 1.0." % s) raise ValidationException("%r is not a valid rerender probability value. "
"Should be between 0.0 and 1.0." % s)
return val return val
def validateImgFormat(fmt): def validateImgFormat(fmt):
if fmt not in ("png", "jpg", "jpeg", "webp"): if fmt not in ("png", "jpg", "jpeg", "webp"):
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"
if fmt == "webp": if fmt == "webp":
try: try:
from PIL import _webp from PIL import _webp
except ImportError: except ImportError:
raise ValidationException("WebP is not supported by your PIL/Pillow installation") raise ValidationException("WebP is not supported by your PIL/Pillow installation.")
return fmt return fmt
def validateImgQuality(qual): 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): 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
@@ -139,28 +162,30 @@ def validateBGColor(color):
if color[0] != "#": if color[0] != "#":
color = "#" + color color = "#" + color
if len(color) != 7: if len(color) != 7:
raise ValidationException("%r is not a valid color. Expected HTML color syntax (i.e. #RRGGBB)" % color) raise ValidationException("%r is not a valid color. Expected HTML color syntax. "
"(i.e. #RRGGBB)" % color)
try: try:
r = int(color[1:3], 16) r = int(color[1:3], 16)
g = int(color[3:5], 16) g = int(color[3:5], 16)
b = int(color[5:7], 16) b = int(color[5:7], 16)
return (r, g, b, 0) return (r, g, b, 0)
except ValueError: except ValueError:
raise ValidationException("%r is not a valid color. Expected HTML color syntax (i.e. #RRGGBB)" % color) raise ValidationException("%r is not a valid color. Expected HTML color syntax. "
"(i.e. #RRGGBB)" % color)
elif type(color) == tuple: elif type(color) == tuple:
if len(color) != 4: if len(color) != 4:
raise ValidationException("%r is not a valid color. Expected a 4-tuple" % (color,)) raise ValidationException("%r is not a valid color. Expected a 4-tuple." % (color,))
return color return color
def validateOptImg(optimizers): def validateOptImg(optimizers):
if isinstance(optimizers, (int, long)): if isinstance(optimizers, (int, long)):
from optimizeimages import pngcrush from optimizeimages import pngcrush
logging.warning("You're using a deprecated definition of optimizeimg. "\ logging.warning("You're using a deprecated definition of optimizeimg. "
"We'll do what you say for now, but please fix this as soon as possible.") "We'll do what you say for now, but please fix this as soon as possible.")
optimizers = [pngcrush()] optimizers = [pngcrush()]
if not isinstance(optimizers, list): if not isinstance(optimizers, list):
raise ValidationException("What you passed to optimizeimg is not a list. "\ raise ValidationException("What you passed to optimizeimg is not a list. "
"Make sure you specify them like [foo()], with square brackets.") "Make sure you specify them like [foo()], with square brackets.")
if optimizers: if optimizers:
@@ -173,34 +198,38 @@ def validateOptImg(optimizers):
# Check whether the chaining is somewhat sane # Check whether the chaining is somewhat sane
if next_opt: if next_opt:
if opt.is_crusher() and not next_opt.is_crusher(): if opt.is_crusher() and not next_opt.is_crusher():
logging.warning("You're feeding a crushed output into an optimizer that does not crush. "\ logging.warning("You're feeding a crushed output into an optimizer that "
"This is most likely pointless, and wastes time.") "does not crush. This is most likely pointless, and wastes "
"time.")
return optimizers return optimizers
def validateTexturePath(path): def validateTexturePath(path):
# Expand user dir in directories strings # Expand user dir in directories strings
path = expand_path(path) path = expand_path(path)
if not os.path.exists(path): if not os.path.exists(path):
raise ValidationException("%r does not exist" % path) raise ValidationException("%r does not exist." % path)
return path return path
def validateBool(b): def validateBool(b):
return bool(b) return bool(b)
def validateFloat(f): def validateFloat(f):
return float(f) return float(f)
def validateInt(i): def validateInt(i):
return int(i) return int(i)
def validateStr(s): def validateStr(s):
return str(s) return str(s)
def validateDimension(d): def validateDimension(d):
# returns (original, argument to get_type) # returns (original, argument to get_type)
# these are provided as arguments to RegionSet.get_type() # these are provided as arguments to RegionSet.get_type()
pretty_names = { pretty_names = {
"nether": "DIM-1", "nether": "DIM-1",
@@ -208,18 +237,19 @@ def validateDimension(d):
"end": "DIM1", "end": "DIM1",
"default": 0, "default": 0,
} }
try: try:
return (d, pretty_names[d]) return (d, pretty_names[d])
except KeyError: except KeyError:
return (d, d) return (d, d)
def validateOutputDir(d): def validateOutputDir(d):
checkBadEscape(d) checkBadEscape(d)
if not d.strip(): if not d.strip():
raise ValidationException("You must specify a valid output directory") raise ValidationException("You must specify a valid output directory.")
return expand_path(d) return expand_path(d)
def validateCrop(value): def validateCrop(value):
if not isinstance(value, list): if not isinstance(value, list):
value = [value] value = [value]
@@ -227,7 +257,8 @@ def validateCrop(value):
cropZones = [] cropZones = []
for zone in value: for zone in value:
if not isinstance(zone, tuple) or len(zone) != 4: if not isinstance(zone, tuple) or len(zone) != 4:
raise ValidationException("The value for the 'crop' setting must be an array of tuples of length 4") raise ValidationException("The value for the 'crop' setting must be an array of "
"tuples of length 4.")
a, b, c, d = tuple(int(x) for x in zone) a, b, c, d = tuple(int(x) for x in zone)
if a >= c: if a >= c:
@@ -239,17 +270,20 @@ def validateCrop(value):
return cropZones return cropZones
def validateObserver(observer): def validateObserver(observer):
if all(map(lambda m: hasattr(observer, m), ['start', 'add', 'update', 'finish'])): if all(map(lambda m: hasattr(observer, m), ['start', 'add', 'update', 'finish'])):
return observer return observer
else: else:
raise ValidationException("%r does not look like an observer" % repr(observer)) raise ValidationException("%r does not look like an observer." % repr(observer))
def validateDefaultZoom(z): def validateDefaultZoom(z):
if z > 0: if z > 0:
return int(z) return int(z)
else: else:
raise ValidationException("The default zoom is set below 1") raise ValidationException("The default zoom is set below 1.")
def validateWebAssetsPath(p): def validateWebAssetsPath(p):
try: try:
@@ -257,18 +291,22 @@ def validateWebAssetsPath(p):
except ValidationException as e: except ValidationException as e:
raise ValidationException("Bad custom web assets path: %s" % e.message) raise ValidationException("Bad custom web assets path: %s" % e.message)
def validatePath(p): def validatePath(p):
checkBadEscape(p) checkBadEscape(p)
abs_path = expand_path(p) abs_path = expand_path(p)
if not os.path.exists(abs_path): if not os.path.exists(abs_path):
raise ValidationException("'%s' does not exist. Path initially given as '%s'" % (abs_path,p)) raise ValidationException("'%s' does not exist. Path initially given as '%s'"
% (abs_path, p))
def validateManualPOIs(d): def validateManualPOIs(d):
for poi in d: for poi in d:
if not 'x' in poi or not 'y' in poi or not 'z' in poi or not 'id' in poi: if 'x' not in poi or 'y' not in poi or 'z' not in poi or 'id' not in poi:
raise ValidationException("Not all POIs have x/y/z coordinates or an id: %r" % poi) raise ValidationException("Not all POIs have x/y/z coordinates or an id: %r." % poi)
return d return d
def make_dictValidator(keyvalidator, valuevalidator): def make_dictValidator(keyvalidator, valuevalidator):
"""Compose and return a dict validator -- a validator that validates each """Compose and return a dict validator -- a validator that validates each
key and value in a dictionary. key and value in a dictionary.
@@ -288,6 +326,7 @@ def make_dictValidator(keyvalidator, valuevalidator):
v.valuevalidator = valuevalidator v.valuevalidator = valuevalidator
return v return v
def make_configDictValidator(config, ignore_undefined=False): def make_configDictValidator(config, ignore_undefined=False):
"""Okay, stay with me here, this may get confusing. This function returns a """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 validator that validates a "configdict". This is a term I just made up to
@@ -326,10 +365,9 @@ def make_configDictValidator(config, ignore_undefined=False):
newdict[key] = d[key] newdict[key] = d[key]
elif match: elif match:
raise ValidationException( raise ValidationException(
"'%s' is not a configuration item. Did you mean '%s'?" "'%s' is not a configuration item. Did you mean '%s'?" % (key, match))
% (key, match))
elif not ignore_undefined: elif not ignore_undefined:
raise ValidationException("'%s' is not a configuration item" % key) raise ValidationException("'%s' is not a configuration item." % key)
else: else:
# the key is to be ignored. Copy it as-is to the `newdict` # 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 # to be returned. It shouldn't conflict, and may be used as
@@ -350,13 +388,12 @@ def make_configDictValidator(config, ignore_undefined=False):
# The user did not give us this key, there is no default, AND # The user did not give us this key, there is no default, AND
# it's required. This is an error. # it's required. This is an error.
if configkey in undefined_key_matches: if configkey in undefined_key_matches:
raise ValidationException("Key '%s' is not a valid " raise ValidationException(
"configuration item. Did you mean '%s'?" "Key '%s' is not a valid configuration item. Did you mean '%s'?"
% (undefined_key_matches[configkey], configkey)) % (undefined_key_matches[configkey], configkey))
else: else:
raise ValidationException("Required key '%s' was not " raise ValidationException("Required key '%s' was not specified. You must give "
"specified. You must give a value for this setting" "a value for this setting." % configkey)
% configkey)
return newdict return newdict
# Put these objects as attributes of the function so they can be accessed # Put these objects as attributes of the function so they can be accessed
@@ -365,11 +402,13 @@ def make_configDictValidator(config, ignore_undefined=False):
configDictValidator.ignore_undefined = ignore_undefined configDictValidator.ignore_undefined = ignore_undefined
return configDictValidator return configDictValidator
def error(errstr): def error(errstr):
def validator(_): def validator(_):
raise ValidationException(errstr) raise ValidationException(errstr)
return validator return validator
# Activestate recipe 576874 # Activestate recipe 576874
def _levenshtein(s1, s2): def _levenshtein(s1, s2):
l1 = len(s1) l1 = len(s1)
@@ -381,11 +420,14 @@ def _levenshtein(s1, s2):
for zz in range(0, l2): for zz in range(0, l2):
for sz in range(0, l1): for sz in range(0, l1):
if s1[sz] == s2[zz]: if s1[sz] == s2[zz]:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz]) matrix[zz + 1][sz + 1] = min(matrix[zz + 1][sz] + 1, matrix[zz][sz + 1] + 1,
matrix[zz][sz])
else: else:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz] + 1) matrix[zz + 1][sz + 1] = min(matrix[zz + 1][sz] + 1, matrix[zz][sz + 1] + 1,
matrix[zz][sz] + 1)
return matrix[l2][l1] return matrix[l2][l1]
def _get_closest_match(s, keys): def _get_closest_match(s, keys):
"""Returns a probable match for the given key `s` out of the possible keys in """Returns a probable match for the given key `s` out of the possible keys in
`keys`. Returns None if no matches are very close. `keys`. Returns None if no matches are very close.