Package gozerbot :: Module persistconfig
[hide private]
[frames] | no frames]

Source Code for Module gozerbot.persistconfig

  1  # gozerbot/persistconfig.py 
  2  # 
  3  # 
  4   
  5  """ allow data to be pickled to disk .. creating the persisted object 
  6      restores data 
  7       
  8  usage: 
  9      !plug-cfg                   ->      shows list of all config 
 10      !plug-cfg key value         ->      sets value to key 
 11      !plug-cfg key               ->      shows list of key 
 12      !plug-cfg key add value     ->      adds value to list 
 13      !plug-cfg key remove value  ->      removes value from list 
 14      !plug-cfg key clear         ->      clears entire list 
 15      !plug-cfgsave               ->      force save configuration to disk 
 16       
 17  todo: 
 18      - plugin api (more work needed?) 
 19       
 20  """ 
 21   
 22  __copyright__ = 'this file is in the public domain' 
 23  __author__ = 'Bas van Oostveen' 
 24   
 25  from gozerbot.generic import rlog, calledfrom 
 26  from gozerbot.persist import Persist 
 27  from gozerbot.commands import cmnds, Command 
 28  from gozerbot.examples import examples 
 29  from gozerbot.datadir import datadir 
 30  import sys, os, types, time 
 31   
32 -class Option(object):
33
34 - def __init__(self, value, desc, perm, example, name, exposed):
35 assert isinstance(name, str), "Option.self.name must be a string" 36 self.value = value 37 self.desc = desc 38 self.perm = perm 39 self.example = example 40 self.name = name.lower() 41 self.exposed = exposed
42
43 - def __casattr__(self, name, val):
44 # Update option if needed 45 if not hasattr(self, name): 46 setattr(self, name, val) 47 return True 48 else: 49 #if val and getattr(self, name)!=val: # old style 50 if val != None and type(getattr(self, name)) != type(val): 51 setattr(self, name, val) 52 return True 53 return False
54
55 - def check(self, key, plugname, value, desc, perm, example, name, exposed):
56 upd = False 57 # maybe checking value is too much here 58 if self.__casattr__("value", value): upd = True 59 if self.__casattr__("example", example): upd = True 60 if self.__casattr__("name", name): upd = True 61 if self.__casattr__("perm", perm): upd = True 62 if self.__casattr__("exposed", exposed): upd = True 63 if self.name == None: 64 self.name = "%s-cfg-%s" % (plugname, str(key)) 65 upd = True 66 return upd
67
68 - def __lt__(self, other):
69 return self.value < other
70
71 - def __le__(self, other):
72 return self.value <= other
73
74 - def __eq__(self, other):
75 return self.value == other
76
77 - def __ne__(self, other):
78 return self.value != other
79
80 - def __gt__(self, other):
81 return self.value >= other
82
83 - def __ge__(self, other):
84 return self.value >= other
85
86 -class LazyValueDict(object):
87 88 """ emulates the normal Persist.data (key, value) dict """ 89
90 - def __init__(self, cfg):
91 self.__cfg = cfg
92
93 - def __len__(self):
94 return len(self.__persistData)
95
96 - def __getitem__(self, key):
97 return self.__cfg.data[key].value
98
99 - def __setitem__(self, key, value):
100 if not self.__cfg.data.has_key(key) or not \ 101 isinstance(self.__cfg.data[key], Option): 102 name = "%s-cfg-%s" % (self.__cfg.plugname, str(key)) 103 self.__cfg.define(value, "", 'OPER', "", name, exposed=False) 104 self.__cfg.set(key, value)
105
106 - def __delitem__(self, key):
107 raise Exception("Direct deletion not supported, use \ 108 persistConfig.undefine()")
109
110 - def __iter__(self):
111 return self.__cfg.data.__iter__()
112
113 - def iterkeys(self):
114 return self.__iter__()
115
116 - def __contains__(self, item):
117 return self.__cfg.data.has_key(item)
118
119 -class PersistConfigError(Exception): pass
120
121 -class PersistConfig(Persist):
122 123 """ persist plugin configuration and create default handlers """ 124
125 - def __init__(self):
126 self.__basename__ = self.__class__.__name__ 127 self.plugname = calledfrom(sys._getframe()) 128 Persist.__init__(self, os.path.join(datadir, "%s-config" % \ 129 self.plugname), {}) 130 self.__callbacks = {} 131 cmndname = "%s-cfg" % self.plugname 132 rlog(-3, 'persistconfig', 'added command %s (%s)' % (cmndname, \ 133 self.plugname)) 134 cmnds[cmndname] = Command(self.cmnd_cfg, 'OPER', self.plugname, \ 135 threaded=True) 136 examples.add(cmndname, "plugin configuration", cmndname) 137 cmndnamesave = cmndname + "save" 138 cmnds[cmndnamesave] = Command(self.cmnd_cfgsave, 'OPER', \ 139 self.plugname, threaded=True) 140 examples.add(cmndnamesave, "save plugin configuration", cmndnamesave)
141
142 - def __getattribute__(self, name):
143 # make sure the attribute data is not called from Persist or 144 # PersistConfig returning a persist compatible (key, value) dict 145 # instead of the rich persistconfig 146 cf = calledfrom(sys._getframe()) 147 ## (key, option(value, ...)) is only for persistconfig internal usage. 148 if name == "data" and cf != "persistconfig" and cf != "persist" and \ 149 cf != self.__basename__: 150 # intercept data block, return a clean dict with lazy binding 151 # to option.value 152 return LazyValueDict(self) 153 return super(PersistConfig, self).__getattribute__(name)
154
155 - def handle_callback(self, event, key, value=None):
156 if self.__callbacks.has_key((key, event)): 157 cb, extra_data = self.__callbacks[(key, event)] 158 if callable(cb): 159 cb(key, value, event, extra_data) 160 else: 161 rlog(5, 'persistconfig', 'invalid callback for %s %s' % (key, \ 162 event)) 163 del self.__callbacks[(key, event)]
164 165 ### cmnds 166
167 - def show_cfg(self, bot, ievent):
168 s = [] 169 for key, option in sorted(self.data.items()): 170 if not isinstance(option, Option): 171 rlog(5, 'persistconfig', 'Option %s is not a valid option' % \ 172 key) 173 continue 174 if not option.exposed: 175 continue 176 v = option.value 177 if type(v) in [str, unicode]: 178 v = '"'+v+'"' 179 v = str(v) 180 s.append("%s=%s" % (key, v)) 181 ievent.reply("options: " + ' .. '.join(s))
182
183 - def cmnd_cfgsave(self, bot, ievent):
184 self.save() 185 ievent.reply("config saved")
186
187 - def cmnd_cfg_edit(self, bot, ievent, args, key, option):
188 if type(option.value) == types.ListType: 189 if args[0].startswith("[") and args[-1].endswith("]"): 190 values = [] 191 for v in ' '.join(args)[1:-1].replace(", ", ",").split(","): 192 if v[0]=='"' and v[-1]=='"': 193 # string 194 v = v.replace('"', '') 195 elif v[0]=="'" and v[-1]=="'": 196 # string 197 v = v.replace("'", "") 198 elif '.' in v: 199 # float 200 try: 201 v = float(v) 202 except ValueError: 203 ievent.reply("invalid long literal: %s" % v) 204 return 205 else: 206 # int 207 try: 208 v = int(v) 209 except ValueError: 210 ievent.reply("invalid int literal: %s" % v) 211 return 212 values.append(v) 213 self.set(key, values) 214 ievent.reply("%s set %s" % (key, values)) 215 return 216 command = args[0] 217 value = ' '.join(args[1:]) 218 if command == "clear": 219 self.clear(key) 220 ievent.reply("list empty") 221 elif command == "add": 222 self.append(key, value) 223 ievent.reply("%s added %s" % (key, value)) 224 elif command == "remove" or command == "del": 225 try: 226 self.remove(key, value) 227 ievent.reply("%s removed" % str(value)) 228 except ValueError: 229 ievent.reply("%s is not in list" % str(value)) 230 else: 231 ievent.reply("invalid command") 232 return 233 else: 234 value = ' '.join(args) 235 try: 236 value = type(option.value)(value) 237 except: 238 pass 239 if type(value) == type(option.value): 240 self.set(key, value) 241 ievent.reply("%s set" % key) 242 elif type(value) == types.LongType and \ 243 type(option.value) == types.IntType: 244 # allow upscaling from int to long 245 self.set(key, value) 246 ievent.reply("%s set" % key) 247 else: 248 ievent.reply("value %s (%s) is not of the same type as %s \ 249 (%s)" % (value, type(value), option.value, type(option.value)))
250
251 - def cmnd_cfg(self, bot, ievent):
252 if not ievent.args: 253 self.show_cfg(bot, ievent) 254 return 255 argc = len(ievent.args) 256 key = ievent.args[0] 257 try: 258 option = self.data[key] 259 except KeyError: 260 ievent.reply("%s option %s not found" % (self.plugname, key)) 261 return 262 if not isinstance(option, Option): 263 rlog(5, 'persistconfig', 'Option %s is not a valid option' % key) 264 return 265 if not option.exposed: 266 return 267 if argc == 1: 268 ievent.reply(str(option.value)) 269 return 270 self.cmnd_cfg_edit(bot, ievent, ievent.args[1:], key, option)
271
272 - def generic_cmnd(self, key):
273 def func(bot, ievent): 274 try: 275 option = self.data[key] 276 except KeyError: 277 ievent.reply("%s not found" % key) 278 # need return ? 279 if not isinstance(option, Option): 280 rlog(5, 'persistconfig', 'Option %s is not a valid option' % \ 281 key) 282 return 283 if ievent.args: 284 value = ' '.join(ievent.args) 285 try: 286 value = type(option.value)(value) 287 except: 288 pass 289 self.cmnd_cfg_edit(bot, ievent, ievent.args, key, option) 290 else: 291 ievent.reply(str(option.value))
292 return func
293 294 ### plugin api 295
296 - def define(self, key, value=None, desc="plugin option", perm='OPER', \ 297 example="", name=None, exposed=True):
298 if name: 299 name = name.lower() 300 if not self.data.has_key(key): 301 if name == None: 302 name = "%s-cfg-%s" % (self.plugname, str(key)) 303 option = Option(value, desc, perm, example, name, exposed) 304 self.data[key] = option 305 self.save() 306 else: 307 option = self.data[key] 308 # if unpickled option is not of class Option recreate the option 309 # also if the type of value has changed recreate the option 310 # exception if value got upgraded from int to long, then nothing 311 # has to be changed 312 if not isinstance(option, Option): 313