Replaced with current version of Meh
This commit is contained in:
parent
444f73b3f8
commit
894c973974
1 changed files with 59 additions and 18 deletions
|
@ -1,27 +1,38 @@
|
||||||
from imp import load_source
|
from imp import load_source
|
||||||
from os.path import isfile
|
from os.path import isfile
|
||||||
|
from marshal import dumps, loads
|
||||||
|
from types import FunctionType
|
||||||
|
|
||||||
|
|
||||||
class ValidationFailedError(Exception):
|
class OptionDuplicateError(IndexError):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
super(InputError, self).__init__("validation failed for '%s'" % name)
|
super(IndexError, self).__init__("'%s' already exists" % name)
|
||||||
|
|
||||||
|
|
||||||
class OptionNotFoundError(IndexError):
|
class OptionNotFoundError(IndexError):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
super(InputError, self).__init__("'%s' does not exist" % name)
|
super(IndexError, self).__init__("'%s' does not exist" % name)
|
||||||
|
|
||||||
|
|
||||||
|
class NameMustBeStringError(Exception):
|
||||||
|
def __init__(self):
|
||||||
|
super(Exception, self).__init__("option names have to be strings")
|
||||||
|
|
||||||
|
|
||||||
def make_value(value):
|
def make_value(value):
|
||||||
if type(value) is str:
|
if type(value) is str:
|
||||||
value = '"%s"' % value
|
value = '"%s"' % value
|
||||||
elif type(value) in (list, tuple, tuple):
|
elif type(value) in (list, tuple, dict):
|
||||||
value = str(value)
|
value = str(value)
|
||||||
|
elif type(value) is FunctionType:
|
||||||
|
value = dumps(value.__code__)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class Option:
|
class Option:
|
||||||
def __init__(self, name, default_value, validator=None, comment=""):
|
def __init__(self, name, default_value, validator=None, comment=""):
|
||||||
|
if not type(name) is str:
|
||||||
|
raise NameMustBeStringError()
|
||||||
self.name = name
|
self.name = name
|
||||||
self.default_value = default_value
|
self.default_value = default_value
|
||||||
self.validator = validator
|
self.validator = validator
|
||||||
|
@ -29,30 +40,52 @@ class Option:
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
def __init__(self, options=[]):
|
def __init__(self, options=[], validation_failed=None, override_on_error=False):
|
||||||
|
if type(options) in (list, tuple):
|
||||||
|
for option in options:
|
||||||
|
if not type(option) is Option:
|
||||||
|
raise TypeError("all options must be of type Option")
|
||||||
|
else:
|
||||||
|
raise TypeError("options must be a list or tuple containing options of type Option")
|
||||||
self.options = options
|
self.options = options
|
||||||
|
self.validation_failed = validation_failed
|
||||||
|
self.override_on_error = override_on_error
|
||||||
|
|
||||||
|
|
||||||
def read_from_file(self, file):
|
def read_from_file(self, file):
|
||||||
if isfile(file):
|
if isfile(file):
|
||||||
config = load_source("config", file)
|
config = load_source("config", file)
|
||||||
|
error = False
|
||||||
for option in self.options:
|
for option in self.options:
|
||||||
found = False
|
# Make sure all options are avaliable
|
||||||
for attr in dir(config):
|
if option.name not in dir(config):
|
||||||
if not attr.startswith("__"):
|
setattr(config, option.name, option.default_value)
|
||||||
if option.name == attr:
|
error = True
|
||||||
found = True
|
else:
|
||||||
break
|
# Make sure all validators pass
|
||||||
if not found:
|
if option.validator != None:
|
||||||
self.write_to_file(file)
|
value = getattr(config, option.name)
|
||||||
return self.read_from_file(file)
|
if not option.validator(value):
|
||||||
|
setattr(config, option.name, option.default_value)
|
||||||
|
if self.validation_failed != None:
|
||||||
|
self.validation_failed(option.name, value)
|
||||||
|
error = True
|
||||||
|
if self.override_on_error:
|
||||||
|
if error:
|
||||||
|
self.write_to_file(file)
|
||||||
return config
|
return config
|
||||||
else:
|
else:
|
||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
def add(self, option):
|
def add(self, new_option):
|
||||||
self.options.append(option)
|
if type(new_option) is Option:
|
||||||
|
for option in self.options:
|
||||||
|
if new_option.name == option.name:
|
||||||
|
raise OptionDuplicateError(option.name)
|
||||||
|
self.options.append(new_option)
|
||||||
|
else:
|
||||||
|
raise TypeError("invalid type supplied")
|
||||||
|
|
||||||
|
|
||||||
def remove(self, option):
|
def remove(self, option):
|
||||||
|
@ -67,11 +100,19 @@ class Config:
|
||||||
|
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
|
contains_function = False
|
||||||
out = ""
|
out = ""
|
||||||
for option in self.options:
|
for option in self.options:
|
||||||
out += "%s = %s %s\n" % (option.name, make_value(option.default_value), ("# %s" % option.comment) if option.comment else "")
|
value = make_value(option.default_value)
|
||||||
|
if type(option.default_value) is FunctionType:
|
||||||
|
if not contains_function:
|
||||||
|
out = "from marshal import loads; from types import FunctionType\n\n" + out
|
||||||
|
contains_function = True
|
||||||
|
value = 'FunctionType(loads(%s), globals(), "%s")' % (value, option.name)
|
||||||
|
out += "%s = %s%s\n" % (option.name, value,
|
||||||
|
(" # %s" % option.comment) if option.comment else "")
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.get()
|
return self.get()
|
Reference in a new issue