Use __slots__ for core config values.

This commit is contained in:
Valentin Lorentz 2018-09-25 18:59:46 +02:00
parent fa2c11eec1
commit 1ac7812d7a
3 changed files with 70 additions and 1 deletions

View File

@ -134,6 +134,7 @@ def registerUserValue(group, name, value):
class ValidNick(registry.String):
"""Value must be a valid IRC nick."""
__slots__ = ()
def setValue(self, v):
if not ircutils.isNick(v):
self.error()
@ -142,6 +143,7 @@ class ValidNick(registry.String):
class ValidNickOrEmpty(ValidNick):
"""Value must be a valid IRC nick or empty."""
__slots__ = ()
def setValue(self, v):
if v != '' and not ircutils.isNick(v):
self.error()
@ -149,11 +151,13 @@ class ValidNickOrEmpty(ValidNick):
registry.String.setValue(self, v)
class ValidNicks(registry.SpaceSeparatedListOf):
__slots__ = ()
Value = ValidNick
class ValidNickAllowingPercentS(ValidNick):
"""Value must be a valid IRC nick, with the possible exception of a %s
in it."""
__slots__ = ()
def setValue(self, v):
# If this works, it's a valid nick, aside from the %s.
try:
@ -164,10 +168,12 @@ class ValidNickAllowingPercentS(ValidNick):
self.error()
class ValidNicksAllowingPercentS(ValidNicks):
__slots__ = ()
Value = ValidNickAllowingPercentS
class ValidChannel(registry.String):
"""Value must be a valid IRC channel name."""
__slots__ = ('channel',)
def setValue(self, v):
self.channel = v
if ',' in v:
@ -194,6 +200,7 @@ class ValidChannel(registry.String):
class ValidHostmask(registry.String):
"""Value must be a valid user hostmask."""
__slots__ = ()
def setValue(self, v):
if not ircutils.isUserHostmask(v):
self.error()
@ -219,6 +226,7 @@ registerGlobalValue(supybot, 'ident',
# bots which are migrated from Supybot or an old version of Limnoria
# (whose default value of supybot.user is the empty string).
class VersionIfEmpty(registry.String):
__slots__ = ()
def __call__(self):
ret = registry.String.__call__(self)
if not ret:
@ -231,6 +239,7 @@ registerGlobalValue(supybot, 'user',
will be generated if this is left empty.""")))
class Networks(registry.SpaceSeparatedSetOfStrings):
__slots__ = ()
List = ircutils.IrcSet
registerGlobalValue(supybot, 'networks',
@ -238,6 +247,7 @@ registerGlobalValue(supybot, 'networks',
orderAlphabetically=True))
class Servers(registry.SpaceSeparatedListOfStrings):
__slots__ = ()
def normalize(self, s):
if ':' not in s:
s += ':6667'
@ -262,6 +272,7 @@ class Servers(registry.SpaceSeparatedListOfStrings):
class SocksProxy(registry.String):
"""Value must be a valid hostname:port string."""
__slots__ = ()
def setValue(self, v):
# TODO: improve checks
if ':' not in v:
@ -273,6 +284,7 @@ class SocksProxy(registry.String):
super(SocksProxy, self).setValue(v)
class SpaceSeparatedSetOfChannels(registry.SpaceSeparatedListOf):
__slots__ = ()
sorted = True
List = ircutils.IrcSet
Value = ValidChannel
@ -313,10 +325,12 @@ class SpaceSeparatedSetOfChannels(registry.SpaceSeparatedListOf):
return None
class ValidSaslMechanism(registry.OnlySomeStrings):
__slots__ = ()
validStrings = ('ecdsa-nist256p-challenge', 'external', 'plain',
'scram-sha-256')
class SpaceSeparatedListOfSaslMechanisms(registry.SpaceSeparatedListOf):
__slots__ = ()
Value = ValidSaslMechanism
def registerNetwork(name, password='', ssl=True, sasl_username='',
@ -554,6 +568,7 @@ registerChannelValue(supybot.reply, 'showSimpleSyntax',
class ValidPrefixChars(registry.String):
"""Value must contain only ~!@#$%^&*()_-+=[{}]\\|'\";:,<.>/?"""
__slots__ = ()
def setValue(self, v):
if any([x not in '`~!@#$%^&*()_-+=[{}]\\|\'";:,<.>/?' for x in v]):
self.error()
@ -698,6 +713,7 @@ registerGroup(supybot, 'commands')
class ValidQuotes(registry.Value):
"""Value must consist solely of \", ', and ` characters."""
__slots__ = ()
def setValue(self, v):
if [c for c in v if c not in '"`\'']:
self.error()
@ -722,6 +738,7 @@ registerGlobalValue(supybot.commands.nested, 'maximum',
commands more nested than this.""")))
class ValidBrackets(registry.OnlySomeStrings):
__slots__ = ()
validStrings = ('', '[]', '<>', '{}', '()')
registerChannelValue(supybot.commands.nested, 'brackets',
@ -816,6 +833,7 @@ registerGlobalValue(supybot.drivers, 'poll',
driver should block waiting for input.""")))
class ValidDriverModule(registry.OnlySomeStrings):
__slots__ = ()
validStrings = ('default', 'Socket', 'Twisted')
registerGlobalValue(supybot.drivers, 'module',
@ -836,6 +854,7 @@ registerGlobalValue(supybot.drivers, 'maxReconnectWait',
# XXX This shouldn't make directories willy-nilly. As it is now, if it's
# configured, it'll still make the default directories, I think.
class Directory(registry.String):
__slots__ = ()
def __call__(self):
# ??? Should we perhaps always return an absolute path here?
v = super(Directory, self).__call__()
@ -857,6 +876,7 @@ class Directory(registry.String):
return os.path.join(myself, filename)
class DataFilename(registry.String):
__slots__ = ()
def __call__(self):
v = super(DataFilename, self).__call__()
dataDir = supybot.directories.data()
@ -867,6 +887,7 @@ class DataFilename(registry.String):
return v
class DataFilenameDirectory(DataFilename, Directory):
__slots__ = ()
def __call__(self):
v = DataFilename.__call__(self)
v = Directory.__call__(self)
@ -924,6 +945,7 @@ registerGlobalValue(supybot.plugins, 'alwaysLoadImportant',
# supybot.databases. For stuff relating to Supybot's databases (duh!)
###
class Databases(registry.SpaceSeparatedListOfStrings):
__slots__ = ()
def __call__(self):
v = super(Databases, self).__call__()
if not v:
@ -976,6 +998,7 @@ registerGlobalValue(supybot.databases.channels, 'filename',
# TODO This will need to do more in the future (such as making sure link.allow
# will let the link occur), but for now let's just leave it as this.
class ChannelSpecific(registry.Boolean):
__slots__ = ()
def getChannelLink(self, channel):
channelSpecific = supybot.databases.plugins.channelSpecific
channels = [channel]
@ -1029,6 +1052,7 @@ registerChannelValue(supybot.databases.plugins.channelSpecific.link, 'allow',
class CDB(registry.Boolean):
__slots__ = ()
def connect(self, filename):
from . import cdb
basename = os.path.basename(filename)
@ -1069,6 +1093,7 @@ registerGroup(supybot, 'protocols')
registerGroup(supybot.protocols, 'irc')
class Banmask(registry.SpaceSeparatedSetOfStrings):
__slots__ = ('__parent', '__dict__') # __dict__ is needed to set __doc__
validStrings = ('exact', 'nick', 'user', 'host')
def __init__(self, *args, **kwargs):
assert self.validStrings, 'There must be some valid strings. ' \
@ -1204,6 +1229,7 @@ registerGlobalValue(supybot.protocols.http, 'peekSize',
class HttpProxy(registry.String):
"""Value must be a valid hostname:port string."""
__slots__ = ()
def setValue(self, v):
proxies = {}
if v != "":
@ -1242,6 +1268,7 @@ registerGroup(supybot.servers, 'http')
class IP(registry.String):
"""Value must be a valid IP."""
__slots__ = ()
def setValue(self, v):
if v and not utils.net.isIP(v):
self.error()
@ -1249,6 +1276,7 @@ class IP(registry.String):
registry.String.setValue(self, v)
class ListOfIPs(registry.SpaceSeparatedListOfStrings):
__slots__ = ()
Value = IP
registerGlobalValue(supybot.servers.http, 'singleStack',
@ -1295,6 +1323,7 @@ registerGlobalValue(supybot, 'externalIP',
class SocketTimeout(registry.PositiveInteger):
"""Value must be an integer greater than supybot.drivers.poll and must be
greater than or equal to 1."""
__slots__ = ()
def setValue(self, v):
if v < supybot.drivers.poll() or v < 1:
self.error()

View File

@ -108,6 +108,7 @@ def unWildcardHostmask(hostmask):
_invert = invertCapability
class CapabilitySet(set):
"""A subclass of set handling basic capability stuff."""
__slots__ = ('__parent',)
def __init__(self, capabilities=()):
self.__parent = super(CapabilitySet, self)
self.__parent.__init__()
@ -155,6 +156,7 @@ class CapabilitySet(set):
antiOwner = makeAntiCapability('owner')
class UserCapabilitySet(CapabilitySet):
"""A subclass of CapabilitySet to handle the owner capability correctly."""
__slots__ = ('__parent',)
def __init__(self, *args, **kwargs):
self.__parent = super(UserCapabilitySet, self)
self.__parent.__init__(*args, **kwargs)
@ -196,6 +198,8 @@ class UserCapabilitySet(CapabilitySet):
class IrcUser(object):
"""This class holds the capabilities and authentications for a user."""
__slots__ = ('id', 'auth', 'name', 'ignore', 'secure', 'hashed',
'password', 'capabilities', 'hostmasks', 'nicks', 'gpgkeys')
def __init__(self, ignore=False, password='', name='',
capabilities=(), hostmasks=None, nicks=None,
secure=False, hashed=False):
@ -368,6 +372,8 @@ class IrcUser(object):
class IrcChannel(object):
"""This class holds the capabilities, bans, and ignores of a channel."""
__slots__ = ('defaultAllow', 'expiredBans', 'bans', 'ignores', 'silences',
'exceptions', 'capabilities', 'lobotomized')
defaultOff = ('op', 'halfop', 'voice', 'protected')
def __init__(self, bans=None, silences=None, exceptions=None, ignores=None,
capabilities=None, lobotomized=False, defaultAllow=True):
@ -491,10 +497,12 @@ class IrcChannel(object):
class Creator(object):
__slots__ = ()
def badCommand(self, command, rest, lineno):
raise ValueError('Invalid command on line %s: %s' % (lineno, command))
class IrcUserCreator(Creator):
__slots__ = ('users')
u = None
def __init__(self, users):
if self.u is None:
@ -563,6 +571,7 @@ class IrcUserCreator(Creator):
IrcUserCreator.u = None
class IrcChannelCreator(Creator):
__slots__ = ('c', 'channels', 'hadChannel')
name = None
def __init__(self, channels):
self.c = IrcChannel()
@ -611,6 +620,8 @@ class DuplicateHostmask(ValueError):
class UsersDictionary(utils.IterableMap):
"""A simple serialized-to-file User Database."""
__slots__ = ('noFlush', 'filename', 'users', '_nameCache',
'_hostmaskCache')
def __init__(self):
self.noFlush = False
self.filename = None
@ -821,6 +832,7 @@ class UsersDictionary(utils.IterableMap):
class ChannelsDictionary(utils.IterableMap):
__slots__ = ('noFlush', 'filename', 'channels')
def __init__(self):
self.noFlush = False
self.filename = None
@ -897,6 +909,7 @@ class ChannelsDictionary(utils.IterableMap):
class IgnoresDB(object):
__slots__ = ('filename', 'hostmasks')
def __init__(self):
self.filename = None
self.hostmasks = {}
@ -1145,9 +1158,11 @@ def checkCapabilities(hostmask, capabilities, requireAll=False):
###
class SpaceSeparatedListOfCapabilities(registry.SpaceSeparatedListOfStrings):
__slots__ = ()
List = CapabilitySet
class DefaultCapabilities(SpaceSeparatedListOfCapabilities):
__slots__ = ()
# We use a keyword argument trick here to prevent eval'ing of code that
# changes allowDefaultOwner from affecting this. It's not perfect, but
# it's still an improvement, raising the bar for potential crackers.

View File

@ -191,6 +191,8 @@ def join(names):
class Group(object):
"""A group; it doesn't hold a value unless handled by a subclass."""
__slots__ = ('_help', '_name', '_added', '_children', '_lastModified',
'_private', '_supplyDefault', '_orderAlphabetically', '_wasSet')
def __init__(self, help='', supplyDefault=False,
orderAlphabetically=True, private=False):
self._help = utils.str.normalizeWhitespace(help)
@ -201,7 +203,6 @@ class Group(object):
self._private = private
self._supplyDefault = supplyDefault
self._orderAlphabetically = orderAlphabetically
OriginalClass = self.__class__
self._wasSet = True
def __call__(self):
@ -326,6 +327,8 @@ class _NoValueGiven:
class Value(Group):
"""Invalid registry value. If you're getting this message, report it,
because we forgot to put a proper help string here."""
__slots__ = ('__parent', '_default', '_showDefault', '_help', '_callbacks',
'value', 'channelValue', '_opSettable')
def __init__(self, default, help, setDefault=True,
showDefault=True, **kwargs):
self.__parent = super(Value, self)
@ -421,6 +424,7 @@ class Value(Group):
class Boolean(Value):
"""Value must be either True or False (or On or Off)."""
__slots__ = ()
errormsg = _('Value must be either True or False (or On or Off), not %r.')
def set(self, s):
try:
@ -437,6 +441,7 @@ class Boolean(Value):
class Integer(Value):
"""Value must be an integer."""
__slots__ = ()
errormsg = _('Value must be an integer, not %r.')
def set(self, s):
try:
@ -446,6 +451,7 @@ class Integer(Value):
class NonNegativeInteger(Integer):
"""Value must be a non-negative integer."""
__slots__ = ()
errormsg = _('Value must be a non-negative integer, not %r.')
def setValue(self, v):
if v < 0:
@ -454,6 +460,7 @@ class NonNegativeInteger(Integer):
class PositiveInteger(NonNegativeInteger):
"""Value must be positive (non-zero) integer."""
__slots__ = ()
errormsg = _('Value must be positive (non-zero) integer, not %r.')
def setValue(self, v):
if not v:
@ -462,6 +469,7 @@ class PositiveInteger(NonNegativeInteger):
class Float(Value):
"""Value must be a floating-point number."""
__slots__ = ()
errormsg = _('Value must be a floating-point number, not %r.')
def set(self, s):
try:
@ -477,6 +485,7 @@ class Float(Value):
class PositiveFloat(Float):
"""Value must be a floating-point number greater than zero."""
__slots__ = ()
errormsg = _('Value must be a floating-point number greater than zero, '
'not %r.')
def setValue(self, v):
@ -487,6 +496,7 @@ class PositiveFloat(Float):
class Probability(Float):
"""Value must be a floating point number in the range [0, 1]."""
__slots__ = ('__parent',)
errormsg = _('Value must be a floating point number in the range [0, 1], '
'not %r.')
def __init__(self, *args, **kwargs):
@ -501,6 +511,7 @@ class Probability(Float):
class String(Value):
"""Value is not a valid Python string."""
__slots__ = ()
errormsg = _('Value should be a valid Python string, not %r.')
def set(self, s):
v = s
@ -527,6 +538,8 @@ class String(Value):
return s
class OnlySomeStrings(String):
__slots__ = ('__parent', '__dict__') # unfortunately, __dict__ is needed
# to set __doc__.
validStrings = ()
def __init__(self, *args, **kwargs):
assert self.validStrings, 'There must be some valid strings. ' \
@ -559,6 +572,7 @@ class OnlySomeStrings(String):
self.error(v)
class NormalizedString(String):
__slots__ = ('__parent')
def __init__(self, default, *args, **kwargs):
default = self.normalize(default)
self.__parent = super(NormalizedString, self)
@ -591,6 +605,7 @@ class NormalizedString(String):
return ret
class StringSurroundedBySpaces(String):
__slots__ = ()
def setValue(self, v):
if v and v.lstrip() == v:
v= ' ' + v
@ -599,6 +614,7 @@ class StringSurroundedBySpaces(String):
super(StringSurroundedBySpaces, self).setValue(v)
class StringWithSpaceOnRight(String):
__slots__ = ()
def setValue(self, v):
if v and v.rstrip() == v:
v += ' '
@ -606,6 +622,7 @@ class StringWithSpaceOnRight(String):
class Regexp(Value):
"""Value must be a valid regular expression."""
__slots__ = ('sr', 'value', '__parent')
errormsg = _('Value must be a valid regular expression, not %r.')
def __init__(self, *args, **kwargs):
kwargs['setDefault'] = False
@ -645,6 +662,7 @@ class Regexp(Value):
return self.sr
class SeparatedListOf(Value):
__slots__ = ()
List = list
Value = Value
sorted = False
@ -681,23 +699,28 @@ class SeparatedListOf(Value):
return ' '
class SpaceSeparatedListOf(SeparatedListOf):
__slots__ = ()
def splitter(self, s):
return s.split()
joiner = ' '.join
class SpaceSeparatedListOfStrings(SpaceSeparatedListOf):
__slots__ = ()
Value = String
class SpaceSeparatedSetOfStrings(SpaceSeparatedListOfStrings):
__slots__ = ()
List = set
class CommaSeparatedListOfStrings(SeparatedListOf):
__slots__ = ()
Value = String
def splitter(self, s):
return re.split(r'\s*,\s*', s)
joiner = ', '.join
class CommaSeparatedSetOfStrings(SeparatedListOf):
__slots__ = ()
List = set
Value = String
def splitter(self, s):
@ -705,6 +728,7 @@ class CommaSeparatedSetOfStrings(SeparatedListOf):
joiner = ', '.join
class TemplatedString(String):
__slots__ = ()
requiredTemplates = []
def __init__(self, *args, **kwargs):
assert self.requiredTemplates, \
@ -721,6 +745,7 @@ class TemplatedString(String):
self.error(v)
class Json(String):
__slots__ = ()
# Json-serializable data
def set(self, v):
self.setValue(json.loads(v))