1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-15 07:08:20 +00:00

Improve error messages

This commit is contained in:
Otto Winter 2018-12-04 20:30:16 +01:00
parent a28c879e66
commit 2f4705e2a3
No known key found for this signature in database
GPG Key ID: DB66C0BE6013F97E
2 changed files with 44 additions and 9 deletions

View File

@ -91,6 +91,9 @@ class Config(OrderedDict):
# type: (ConfigPath, basestring) -> None # type: (ConfigPath, basestring) -> None
self.domains.append((path, name)) self.domains.append((path, name))
def remove_domain(self, path, name):
self.domains.remove((path, name))
def lookup_domain(self, path): def lookup_domain(self, path):
# type: (ConfigPath) -> Optional[basestring] # type: (ConfigPath) -> Optional[basestring]
best_len = 0 best_len = 0
@ -111,7 +114,7 @@ class Config(OrderedDict):
def get_error_for_path(self, path): def get_error_for_path(self, path):
for msg, p in self.errors: for msg, p in self.errors:
if p == path: if self.nested_item_path(p) == path:
return msg return msg
return None return None
@ -124,6 +127,17 @@ class Config(OrderedDict):
return {} return {}
return data return data
def nested_item_path(self, path):
data = self
part = []
for item_index in path:
try:
data = data[item_index]
except (KeyError, IndexError, TypeError):
return part
part.append(item_index)
return part
def iter_ids(config, path=None): def iter_ids(config, path=None):
path = path or [] path = path or []
@ -252,6 +266,8 @@ def validate_config(config):
if not hasattr(component, 'PLATFORM_SCHEMA'): if not hasattr(component, 'PLATFORM_SCHEMA'):
continue continue
result.remove_domain([domain], domain)
if not isinstance(conf, list) and conf: if not isinstance(conf, list) and conf:
result[domain] = conf = [conf] result[domain] = conf = [conf]
@ -374,9 +390,17 @@ def _format_vol_invalid(ex, config, path, domain):
# type: (vol.Invalid, ConfigType, ConfigPath, basestring) -> unicode # type: (vol.Invalid, ConfigType, ConfigPath, basestring) -> unicode
message = u'' message = u''
if u'extra keys not allowed' in ex.error_message: if u'extra keys not allowed' in ex.error_message:
message += u'[{}] is an invalid option for [{}].'.format(ex.path[-1], domain) try:
paren = ex.path[-2]
except IndexError:
paren = domain
message += u'[{}] is an invalid option for [{}].'.format(ex.path[-1], paren)
elif u'required key not provided' in ex.error_message: elif u'required key not provided' in ex.error_message:
message += u"'{}' is a required option for [{}].".format(ex.path[-1], domain) try:
paren = ex.path[-2]
except IndexError:
paren = domain
message += u"'{}' is a required option for [{}].".format(ex.path[-1], paren)
else: else:
message += u'{}.'.format(humanize_error(_nested_getitem(config, path), ex)) message += u'{}.'.format(humanize_error(_nested_getitem(config, path), ex))
@ -434,6 +458,10 @@ def dump_dict(config, path, at_root=True):
if isinstance(conf, (list, tuple)): if isinstance(conf, (list, tuple)):
multiline = True multiline = True
if not conf:
ret += u'[]'
multiline = False
for i, obj in enumerate(conf): for i, obj in enumerate(conf):
path_ = path + [i] path_ = path + [i]
error = config.get_error_for_path(path_) error = config.get_error_for_path(path_)
@ -453,6 +481,10 @@ def dump_dict(config, path, at_root=True):
ret += sep + msg + u'\n' ret += sep + msg + u'\n'
elif isinstance(conf, dict): elif isinstance(conf, dict):
multiline = True multiline = True
if not conf:
ret += u'{}'
multiline = False
for k, v in conf.iteritems(): for k, v in conf.iteritems():
path_ = path + [k] path_ = path + [k]
error = config.get_error_for_path(path_) error = config.get_error_for_path(path_)
@ -475,18 +507,21 @@ def dump_dict(config, path, at_root=True):
msg = msg + u' ' + inf msg = msg + u' ' + inf
ret += st + msg + u'\n' ret += st + msg + u'\n'
elif isinstance(conf, str): elif isinstance(conf, str):
if not conf:
conf += u"''"
if len(conf) > 80: if len(conf) > 80:
ret += u'|-\n' conf = u'|-\n' + indent(conf)
conf = indent(conf)
error = config.get_error_for_path(path) error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white' col = 'bold_red' if error else 'white'
ret += color(col, unicode(conf)) ret += color(col, unicode(conf))
elif isinstance(conf, core.Lambda): elif isinstance(conf, core.Lambda):
ret += u'|-\n' conf = u'!lambda |-\n' + indent(unicode(conf.value))
conf = indent(unicode(conf.value))
error = config.get_error_for_path(path) error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white' col = 'bold_red' if error else 'white'
ret += color(col, conf) ret += color(col, conf)
elif conf is None:
pass
else: else:
error = config.get_error_for_path(path) error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white' col = 'bold_red' if error else 'white'

View File

@ -321,11 +321,11 @@ def time_period_str_unit(value):
match = re.match(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*)$", value) match = re.match(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*)$", value)
if match is None or match.group(2) not in unit_to_kwarg: if match is None:
raise vol.Invalid(u"Expected time period with unit, " raise vol.Invalid(u"Expected time period with unit, "
u"got {}".format(value)) u"got {}".format(value))
kwarg = unit_to_kwarg[one_of(*unit_to_kwarg)(match.group(2))]
kwarg = unit_to_kwarg[match.group(2)]
return TimePeriod(**{kwarg: float(match.group(1))}) return TimePeriod(**{kwarg: float(match.group(1))})