if any(x not in ('level', 'format') for x in obj['logging']):
raise InvalidConfig('Unknown key found in log section')
if 'level' in obj['logging'] and obj['logging']['level'] not in ('DEBUG', 'INFO', 'WARNING', 'ERROR'):
raise InvalidConfig('Invalid log level')
if 'format' in obj['logging']:
if not isinstance(obj['logging']['format'], str):
raise InvalidConfig('Invalid log format')
try:
#TODO: Replace with logging.Formatter's validate option (3.8+); this test does not cover everything that could be wrong (e.g. invalid format spec or conversion)
# This counts the number of replacement fields. Formatter.parse yields tuples whose second value is the field name; if it's None, there is no field (e.g. literal text).
assert sum(1 for x in string.Formatter().parse(obj['logging']['format']) if x[1] is not None) > 0
except (ValueError, AssertionError) as e:
raise InvalidConfig('Invalid log format: parsing failed') from e
if 'irc' in obj:
if any(x not in ('host', 'port', 'ssl', 'nick', 'real', 'certfile', 'certkeyfile') for x in obj['irc']):
raise InvalidConfig('Unknown key found in irc section')