mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 13:19:24 +01:00
Refactored registry to remove the Group/Value distinction.
This commit is contained in:
parent
18ce33a61d
commit
9bf4f35a51
@ -95,10 +95,10 @@ def loadPluginClass(irc, module):
|
||||
irc.addCallback(callback)
|
||||
|
||||
conf.registerGroup(conf.supybot, 'commands')
|
||||
conf.registerGroup(conf.supybot.commands, 'defaultPlugins',
|
||||
registry.GroupWithDefault(registry.String('(Unused)', """Determines what
|
||||
commands have default plugins set, and which plugins are set to be the
|
||||
default for each of those commands.""")))
|
||||
conf.registerGlobalValue(conf.supybot.commands, 'defaultPlugins',
|
||||
registry.String('(Unused)', """Determines what commands have default
|
||||
plugins set, and which plugins are set to be the default for each of
|
||||
those commands."""))
|
||||
conf.registerGlobalValue(conf.supybot.commands.defaultPlugins,
|
||||
'list', registry.String('Misc', ''))
|
||||
conf.registerGlobalValue(conf.supybot.commands.defaultPlugins,
|
||||
|
39
src/conf.py
39
src/conf.py
@ -57,21 +57,20 @@ supybot = registry.Group()
|
||||
supybot.setName('supybot')
|
||||
|
||||
def registerPlugin(name, currentValue=None):
|
||||
supybot.plugins.registerGroup(
|
||||
name,
|
||||
registry.GroupWithValue(registry.Boolean(False, """Determines whether
|
||||
this plugin is loaded by default.""")))
|
||||
supybot.plugins.register(name, registry.Boolean(False, """Determines
|
||||
whether this plugin is loaded by default."""))
|
||||
if currentValue is not None:
|
||||
supybot.plugins.getChild(name).setValue(currentValue)
|
||||
supybot.plugins.get(name).setValue(currentValue)
|
||||
|
||||
def registerChannelValue(group, name, value):
|
||||
group.registerGroup(name, registry.GroupWithDefault(value))
|
||||
value.supplyDefault = True
|
||||
group.register(name, value)
|
||||
|
||||
def registerGlobalValue(group, name, value):
|
||||
group.registerGroup(name, registry.GroupWithValue(value))
|
||||
group.register(name, value)
|
||||
|
||||
def registerGroup(group, name, Group=None):
|
||||
group.registerGroup(name, Group)
|
||||
def registerGroup(Group, name, group=None):
|
||||
Group.register(name, group)
|
||||
|
||||
class ValidNick(registry.String):
|
||||
def setValue(self, v):
|
||||
@ -98,13 +97,13 @@ supybot.register('ident', ValidNick('supybot',
|
||||
supybot.register('user', registry.String('supybot', """Determines the user
|
||||
the bot sends to the server."""))
|
||||
|
||||
supybot.register('password', registry.String('', """Determines the password to
|
||||
be sent to the server if it requires one."""))
|
||||
|
||||
# TODO: Make this check for validity.
|
||||
supybot.register('server', registry.String('irc.freenode.net', """Determines
|
||||
what server the bot connects to."""))
|
||||
|
||||
supybot.register('password', registry.String('', """Determines the password to
|
||||
be sent to the server if it requires one."""))
|
||||
|
||||
class SpaceSeparatedListOfChannels(registry.SeparatedListOf):
|
||||
Value = ValidChannel
|
||||
def splitter(self, s):
|
||||
@ -114,9 +113,9 @@ class SpaceSeparatedListOfChannels(registry.SeparatedListOf):
|
||||
supybot.register('channels', SpaceSeparatedListOfChannels(['#supybot'], """
|
||||
Determines what channels the bot will join when it connects to the server."""))
|
||||
|
||||
supybot.registerGroup('databases')
|
||||
supybot.databases.registerGroup('users')
|
||||
supybot.databases.registerGroup('channels')
|
||||
supybot.register('databases')
|
||||
supybot.databases.register('users')
|
||||
supybot.databases.register('channels')
|
||||
supybot.databases.users.register('filename', registry.String('users.conf', """
|
||||
Determines what filename will be used for the users database. This file will
|
||||
go into the directory specified by the supybot.directories.conf
|
||||
@ -126,7 +125,7 @@ supybot.databases.channels.register('filename',registry.String('channels.conf',
|
||||
will go into the directory specified by the supybot.directories.conf
|
||||
variable."""))
|
||||
|
||||
supybot.registerGroup('directories')
|
||||
supybot.register('directories')
|
||||
supybot.directories.register('conf', registry.String('conf', """
|
||||
Determines what directory configuration data is put into."""))
|
||||
supybot.directories.register('data', registry.String('data', """
|
||||
@ -175,7 +174,7 @@ bytes."""))
|
||||
###
|
||||
# Reply/error tweaking.
|
||||
###
|
||||
supybot.registerGroup('reply')
|
||||
supybot.register('reply')
|
||||
supybot.reply.register('oneToOne', registry.Boolean(True, """Determines whether
|
||||
the bot will send multi-message replies in a single messsage or in multiple
|
||||
messages. For safety purposes (so the bot can't possibly flood) it will
|
||||
@ -261,7 +260,7 @@ why these default to what they do."""))
|
||||
###
|
||||
# Replies
|
||||
###
|
||||
supybot.registerGroup('replies')
|
||||
supybot.register('replies')
|
||||
|
||||
registerChannelValue(supybot.replies, 'error',
|
||||
registry.NormalizedString("""An error has occurred and has been logged.
|
||||
@ -379,7 +378,7 @@ there are no prefix characters set, it just uses its nick."""))
|
||||
###
|
||||
# Driver stuff.
|
||||
###
|
||||
supybot.registerGroup('drivers')
|
||||
supybot.register('drivers')
|
||||
supybot.drivers.register('poll', registry.Float(1.0, """Determines the default
|
||||
length of time a driver should block waiting for input."""))
|
||||
|
||||
@ -407,7 +406,7 @@ you to integrate with asyncore-based applications. twistedDrivers is very
|
||||
stable and simple, and if you've got Twisted installed, is probably your best
|
||||
bet."""))
|
||||
|
||||
supybot.registerGroup('plugins') # This will be used by plugins, but not here.
|
||||
supybot.register('plugins') # This will be used by plugins, but not here.
|
||||
|
||||
###############################
|
||||
###############################
|
||||
|
@ -193,7 +193,7 @@ class LogLevel(registry.Value):
|
||||
conf.supybot.directories.register('log', registry.String('logs', """Determines
|
||||
what directory the bot will store its logfiles in."""))
|
||||
|
||||
conf.supybot.registerGroup('log')
|
||||
conf.supybot.register('log')
|
||||
conf.supybot.log.register('level', LogLevel(logging.INFO,
|
||||
"""Determines what the minimum priority level logged will be. Valid values are
|
||||
DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of increasing
|
||||
@ -207,9 +207,9 @@ Determines whether highly detailed tracebacks will be logged. While more
|
||||
informative (and thus more useful for debugging) they also take a significantly
|
||||
greater amount of space in the logs. Hopefully, however, such uncaught
|
||||
exceptions aren't very common."""))
|
||||
conf.supybot.log.registerGroup('stdout',
|
||||
registry.GroupWithValue(registry.Boolean(True, """Determines whether the bot
|
||||
will log to stdout.""")))
|
||||
conf.supybot.log.register('stdout',
|
||||
registry.Boolean(True, """Determines whether the bot will log to
|
||||
stdout."""))
|
||||
|
||||
class BooleanRequiredFalseOnWindows(registry.Boolean):
|
||||
def set(self, s):
|
||||
|
277
src/registry.py
277
src/registry.py
@ -93,12 +93,114 @@ def close(registry, filename, annotated=True):
|
||||
fd.close()
|
||||
|
||||
|
||||
class Value(object):
|
||||
def __init__(self, default, help):
|
||||
class Group(object):
|
||||
def __init__(self, supplyDefault=False):
|
||||
self.name = 'unset'
|
||||
self.added = []
|
||||
self.children = {}
|
||||
self.originals = {}
|
||||
self._lastModified = 0
|
||||
self.supplyDefault = supplyDefault
|
||||
OriginalClass = self.__class__
|
||||
class X(OriginalClass):
|
||||
"""This class exists to differentiate those values that have
|
||||
been changed from their default from those that haven't."""
|
||||
def set(self, *args):
|
||||
self.__class__ = OriginalClass
|
||||
self.set(*args)
|
||||
def setValue(self, *args):
|
||||
self.__class__ = OriginalClass
|
||||
self.setValue(*args)
|
||||
self.X = X
|
||||
|
||||
def __nonExistentEntry(self, attr):
|
||||
s = '%s is not a valid entry in %s' % (attr, self.name)
|
||||
raise NonExistentRegistryEntry, s
|
||||
|
||||
def __normalizeAttr(self, attr):
|
||||
return attr.lower()
|
||||
|
||||
def __makeChild(self, attr, s):
|
||||
v = self.__class__(self.default, self.help)
|
||||
v.set(s)
|
||||
v.__class__ = self.X
|
||||
v.supplyDefault = False
|
||||
self.register(attr, v)
|
||||
return v
|
||||
|
||||
def __getattr__(self, attr):
|
||||
original = attr
|
||||
attr = self.__normalizeAttr(attr)
|
||||
if attr in self.children:
|
||||
return self.children[attr]
|
||||
elif self.supplyDefault:
|
||||
return self.__makeChild(original, str(self))
|
||||
else:
|
||||
self.__nonExistentEntry(original)
|
||||
|
||||
def get(self, attr):
|
||||
# Not getattr(self, attr) because some nodes might have groups that
|
||||
# are named the same as their methods.
|
||||
return self.__getattr__(attr)
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
if name in _cache and self._lastModified < _lastModified:
|
||||
self.set(_cache[name.lower()])
|
||||
if self.supplyDefault:
|
||||
for (k, v) in _cache.iteritems():
|
||||
if k.startswith(self.name):
|
||||
(_, group) = rsplit(k, '.', 1)
|
||||
self.__makeChild(group, v)
|
||||
|
||||
def register(self, name, node=None):
|
||||
original = name
|
||||
name = self.__normalizeAttr(name)
|
||||
if node is None:
|
||||
node = Group()
|
||||
if name not in self.children: # XXX Is this right?
|
||||
self.children[name] = node
|
||||
self.added.append(original)
|
||||
self.originals[name] = original
|
||||
fullname = '%s.%s' % (self.name, original)
|
||||
node.setName(fullname)
|
||||
|
||||
def unregister(self, name):
|
||||
original = name
|
||||
name = self.__normalizeAttr(name)
|
||||
try:
|
||||
del self.children[name]
|
||||
self.added.remove(original)
|
||||
except KeyError:
|
||||
self.__nonExistentEntry(original)
|
||||
|
||||
def getValues(self, getChildren=False, fullNames=True):
|
||||
L = []
|
||||
for name in map(self.__normalizeAttr, self.added):
|
||||
node = self.children[name]
|
||||
if hasattr(node, 'value'):
|
||||
if node.__class__ is not self.X:
|
||||
L.append((node.name, node))
|
||||
if getChildren:
|
||||
L.extend(node.getValues(getChildren, fullNames))
|
||||
if not fullNames:
|
||||
L = [(rsplit(s, '.', 1)[1], node) for (s, node) in L]
|
||||
return L
|
||||
|
||||
|
||||
class Value(Group):
|
||||
def __init__(self, default, help, **kwargs):
|
||||
Group.__init__(self, **kwargs)
|
||||
self.default = default
|
||||
self.help = utils.normalizeWhitespace(help.strip())
|
||||
self.setValue(default)
|
||||
|
||||
def setName(self, *args):
|
||||
if self.name == 'unset':
|
||||
self._lastModified = 0
|
||||
Group.setName(self, *args)
|
||||
self._lastModified = time.time()
|
||||
|
||||
def set(self, s):
|
||||
"""Override this with a function to convert a string to whatever type
|
||||
you want, and call self.setValue to set the value."""
|
||||
@ -118,8 +220,9 @@ class Value(object):
|
||||
|
||||
# This is simply prettier than naming this function get(self)
|
||||
def __call__(self):
|
||||
# TODO: Check _lastModified to see if stuff needs to be reloaded from
|
||||
# the _cache.
|
||||
if _lastModified > self._lastModified:
|
||||
if self.name in _cache:
|
||||
self.set(_cache[self.name.lower()])
|
||||
return self.value
|
||||
|
||||
class Boolean(Value):
|
||||
@ -274,157 +377,9 @@ class CommaSeparatedListOfStrings(SeparatedListOf):
|
||||
class CommaSeparatedSetOfStrings(CommaSeparatedListOfStrings):
|
||||
List = sets.Set
|
||||
|
||||
class Group(object):
|
||||
def __init__(self):
|
||||
self.name = 'unset'
|
||||
self.values = {}
|
||||
self.children = {}
|
||||
self.originals = {}
|
||||
|
||||
def __nonExistentEntry(self, attr):
|
||||
s = '%s is not a valid entry in %s' % (attr, self.name)
|
||||
raise NonExistentRegistryEntry, s
|
||||
|
||||
def __getattr__(self, attr):
|
||||
original = attr
|
||||
attr = attr.lower()
|
||||
if attr in self.values:
|
||||
return self.values[attr]
|
||||
elif attr in self.children:
|
||||
return self.children[attr]
|
||||
else:
|
||||
self.__nonExistentEntry(original)
|
||||
|
||||
def get(self, attr):
|
||||
return self.__getattr__(attr)
|
||||
|
||||
def getChild(self, attr):
|
||||
return self.children[attr.lower()]
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def register(self, name, value):
|
||||
original = name
|
||||
name = name.lower()
|
||||
self.values[name] = value
|
||||
self.originals[name] = original
|
||||
if _cache:
|
||||
fullname = '%s.%s' % (self.name, name)
|
||||
if fullname in _cache:
|
||||
value.set(_cache[fullname])
|
||||
|
||||
def registerGroup(self, name, group=None):
|
||||
original = name
|
||||
name = name.lower()
|
||||
if name in self.children:
|
||||
return # Ignore redundant group inserts.
|
||||
if group is None:
|
||||
group = Group()
|
||||
self.children[name] = group
|
||||
self.originals[name] = original
|
||||
fullname = '%s.%s' % (self.name, name)
|
||||
group.setName(fullname)
|
||||
if _cache and fullname in _cache:
|
||||
group.set(_cache[fullname])
|
||||
|
||||
def getValues(self, getChildren=False, fullNames=True):
|
||||
L = []
|
||||
items = self.values.items()
|
||||
# If getChildren=True, the group will insert itself into its getValues.
|
||||
if not getChildren:
|
||||
for (name, child) in self.children.items():
|
||||
if hasattr(child, 'value'):
|
||||
items.append((name, child))
|
||||
utils.sortBy(lambda (k, _): (k.lower(), len(k), k), items)
|
||||
for (name, value) in items:
|
||||
if fullNames:
|
||||
name = '%s.%s' % (self.getName(), self.originals[name])
|
||||
else:
|
||||
name = self.originals[name]
|
||||
L.append((name, value))
|
||||
if getChildren:
|
||||
items = self.children.items()
|
||||
utils.sortBy(lambda (k, _): (k.lower(), len(k), k), items)
|
||||
for (_, child) in items:
|
||||
L.extend(child.getValues(getChildren, fullNames))
|
||||
return L
|
||||
|
||||
|
||||
class GroupWithValue(Group):
|
||||
def __init__(self, value):
|
||||
Group.__init__(self)
|
||||
self.value = value
|
||||
self.help = value.help
|
||||
self.default = value.default
|
||||
|
||||
def set(self, s):
|
||||
self.value.set(s)
|
||||
|
||||
def setValue(self, v):
|
||||
self.value.setValue(v)
|
||||
|
||||
def __call__(self):
|
||||
return self.value()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
def getValues(self, getChildren=False, fullNames=True):
|
||||
L = Group.getValues(self, getChildren, fullNames)
|
||||
if getChildren:
|
||||
L.insert(0, (self.getName(), self))
|
||||
return L
|
||||
|
||||
|
||||
class GroupWithDefault(GroupWithValue):
|
||||
def __init__(self, value):
|
||||
class X(value.__class__):
|
||||
"""This class exists to differentiate those values that have been
|
||||
changed from their default to those that haven't."""
|
||||
def set(self, *args):
|
||||
self.__class__ = value.__class__
|
||||
self.set(*args)
|
||||
def setValue(self, *args):
|
||||
self.__class__ = value.__class__
|
||||
self.setValue(*args)
|
||||
self.X = X
|
||||
GroupWithValue.__init__(self, value)
|
||||
|
||||
def __makeChild(self, attr, s):
|
||||
#print '***', attr, ':', repr(s)
|
||||
v = copy.copy(self.value)
|
||||
v.set(s)
|
||||
v.__class__ = self.X
|
||||
self.register(attr, v)
|
||||
return v
|
||||
|
||||
def __getattr__(self, attr):
|
||||
try:
|
||||
v = GroupWithValue.__getattr__(self, attr)
|
||||
if v.__class__ is self.X:
|
||||
raise NonExistentRegistryEntry
|
||||
except NonExistentRegistryEntry:
|
||||
v = self.__makeChild(attr, str(self))
|
||||
return v
|
||||
|
||||
def setName(self, name):
|
||||
GroupWithValue.setName(self, name)
|
||||
for (k, v) in _cache.iteritems():
|
||||
if k.startswith(self.name):
|
||||
(_, group) = rsplit(k, '.', 1)
|
||||
self.__makeChild(group, v)
|
||||
|
||||
def getValues(self, getChildren=False, fullNames=True):
|
||||
L = GroupWithValue.getValues(self, getChildren, fullNames)
|
||||
L = [v for v in L if v[1].__class__ is not self.X]
|
||||
return L
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#if 1:
|
||||
import sys
|
||||
sys.setrecursionlimit(40)
|
||||
supybot = Group()
|
||||
@ -432,20 +387,18 @@ if __name__ == '__main__':
|
||||
supybot.register('throttleTime', Float(1, """Determines the minimum
|
||||
number of seconds the bot will wait between sending messages to the server.
|
||||
"""))
|
||||
supybot.registerGroup('plugins')
|
||||
supybot.plugins.registerGroup('topic')
|
||||
supybot.plugins.topic.registerGroup('separator',
|
||||
GroupWithDefault(StringSurroundedBySpaces(' || ',
|
||||
'Determines what separator the bot uses to separate topic entries.')))
|
||||
supybot.register('plugins')
|
||||
supybot.plugins.register('topic')
|
||||
supybot.plugins.topic.register('separator',
|
||||
StringSurroundedBySpaces(' || ', """Determines what separator the bot
|
||||
uses to separate topic entries.""", supplyDefault=True))
|
||||
supybot.plugins.topic.separator.get('#supybot').set(' |||| ')
|
||||
supybot.plugins.topic.separator.set(' <> ')
|
||||
|
||||
supybot.throttleTime.set(10)
|
||||
|
||||
supybot.registerGroup('log')
|
||||
supybot.log.registerGroup('stdout',
|
||||
GroupWithValue(Boolean(False,
|
||||
"""Help for stdout.""")))
|
||||
supybot.register('log')
|
||||
supybot.log.register('stdout', Boolean(False, """Help for stdout."""))
|
||||
supybot.log.stdout.register('colorized', Boolean(False,
|
||||
'Help colorized'))
|
||||
supybot.log.stdout.setValue(True)
|
||||
|
Loading…
Reference in New Issue
Block a user