3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-23 19:19:31 +01:00
PyLink/conf.py

103 lines
3.7 KiB
Python

"""
conf.py - PyLink configuration core.
This module is used to access the complete configuration for the current
PyLink instance. It will load the config on first import, taking the
configuration file name from the first command-line argument, but defaulting
to 'config.yml' if this isn't given.
If world.testing is set to True, it will return a preset testing configuration
instead.
This module also provides simple checks for validating and loading YAML-format
configurations from arbitrary files.
"""
import yaml
import sys
from collections import defaultdict
from . import world
global testconf
testconf = {'bot':
{
'nick': 'PyLink',
'user': 'pylink',
'realname': 'PyLink Service Client',
'serverdesc': 'PyLink unit tests'
},
'logging':
{
# Suppress logging in the test output for the most part.
'stdout': 'CRITICAL'
},
'servers':
# Wildcard defaultdict! This means that
# any network name you try will work and return
# this basic template:
defaultdict(lambda: {
'ip': '0.0.0.0',
'port': 7000,
'recvpass': "abcd",
'sendpass': "chucknorris",
'protocol': "null",
'hostname': "pylink.unittest",
'sid': "9PY",
'channels': ["#pylink"],
'maxnicklen': 20,
'sidrange': '8##'
})
}
def validateConf(conf):
"""Validates a parsed configuration dict."""
assert type(conf) == dict, "Invalid configuration given: should be type dict, not %s." % type(conf).__name__
for section in ('bot', 'servers', 'login', 'logging'):
assert conf.get(section), "Missing %r section in config." % section
for netname, serverblock in conf['servers'].items():
for section in ('ip', 'port', 'recvpass', 'sendpass', 'hostname',
'sid', 'sidrange', 'protocol', 'maxnicklen'):
assert serverblock.get(section), "Missing %r in server block for %r." % (section, netname)
assert type(serverblock.get('channels')) == list, "'channels' option in " \
"server block for %s must be a list, not %s." % (netname, type(serverblock['channels']).__name__)
assert type(conf['login'].get('password')) == type(conf['login'].get('user')) == str and \
conf['login']['password'] != "changeme", "You have not set the login details correctly!"
return conf
def loadConf(fname, errors_fatal=True):
"""Loads a PyLink configuration file from the filename given."""
with open(fname, 'r') as f:
try:
conf = yaml.load(f)
except Exception as e:
print('ERROR: Failed to load config from %r: %s: %s' % (fname, type(e).__name__, e))
if errors_fatal:
sys.exit(4)
raise
else:
return conf
if world.testing:
conf = testconf
confname = 'testconf'
fname = None
else:
try:
# Get the config name from the command line, falling back to config.yml
# if not given.
fname = sys.argv[1]
confname = fname.split('.', 1)[0]
except IndexError:
# confname is used for logging and PID writing, so that each
# instance uses its own files. fname is the actual name of the file
# we load.
confname = 'pylink'
fname = 'config.yml'
conf = validateConf(loadConf(fname))