Added ability to define an IRC command with a function decorator instead of a manifest entry

Sun, 16 Aug 2015 23:30:11 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 16 Aug 2015 23:30:11 +0300
changeset 154
df862cca1773
parent 153
497b7290977d
child 155
5a9b5065f53f

Added ability to define an IRC command with a function decorator instead of a manifest entry

hgdb.py file | annotate | diff | comparison | revisions
mod_util.py file | annotate | diff | comparison | revisions
modulecore.py file | annotate | diff | comparison | revisions
utility.py file | annotate | diff | comparison | revisions
--- a/hgdb.py	Sun Aug 16 19:27:14 2015 +0300
+++ b/hgdb.py	Sun Aug 16 23:30:11 2015 +0300
@@ -101,8 +101,8 @@
 		''', (node + '%',))
 
 		names = cursor.fetchall()
-		names = set (zip (*names)[0]) if names else set()
-		return [hgpoll.RepositoriesByName[name] for name in names]
+		names = list (zip (*names))[0] if names else []
+		return [hgpoll.RepositoriesByName[name] for name in set (names)]
 
 	def find_commit_by_dateversion (self, dateversion):
 		cursor = self.db.execute ('''
--- a/mod_util.py	Sun Aug 16 19:27:14 2015 +0300
+++ b/mod_util.py	Sun Aug 16 23:30:11 2015 +0300
@@ -30,8 +30,7 @@
 import math
 import json
 import re
-from modulecore import command_error
-import modulecore as ModuleCore
+import modulecore
 import utility
 import calc
 import urllib.parse
@@ -108,21 +107,14 @@
 			'args': '<link>',
 			'level': 'normal'
 		},
-
-		{
-			'name': 'py',
-			'description': 'Evaluates python',
-			'args': '<command...>',
-			'level': 'normal'
-		}
 	]
 }
 
-def cmd_convert (bot, args, reply, **rest):
+def cmd_convert (bot, args, reply, error, **rest):
 	try:
 		value = float (args['value'])
 	except Exception as e:
-		command_error (str (e))
+		error (str (e))
 
 	valuetype = args['valuetype']
 	
@@ -148,10 +140,10 @@
 		reply ('%s degrees celsius, %s degrees fahrenheit' % (celvalue, fahrvalue))
 		return
 	
-	command_error ('unknown valuetype %s, expected one of: degrees, radians (angle conversion), ' +
+	error ('unknown valuetype %s, expected one of: degrees, radians (angle conversion), ' +
 		'celsius, fahrenheit (temperature conversion)' % valuetype)
 
-def cmd_ud (bot, args, reply, **rest):
+def cmd_ud (bot, args, reply, error, **rest):
 	try:
 		url = 'http://api.urbandictionary.com/v0/define?term=%s' % (args['term'].replace (' ', '%20'))
 		response = utility.read_url (url)
@@ -161,7 +153,7 @@
 		or len(data['list']) == 0 \
 		or not 'word' in data['list'][0] \
 		or not 'definition' in data['list'][0]:
-			command_error ("couldn't find a definition of \002%s\002" % args['term'])
+			error ("couldn't find a definition of \002%s\002" % args['term'])
 		
 		word = data['list'][0]['word']
 		definition = data['list'][0]['definition'].replace ('\r', ' ').replace ('\n', ' ').replace ('  ', ' ')
@@ -169,10 +161,10 @@
 		down = data['list'][0]['thumbs_down']
 		reply ("\002%s\002: %s\0033 %d\003 up,\0035 %d\003 down" % (word, definition, up, down))
 	except Exception as e:
-		command_error ('Urban dictionary lookup failed: %s' % e)
+		error ('Urban dictionary lookup failed: %s' % e)
 
 def cmd_commands (bot, reply, ident, host, **rest):
-	commandlist = ModuleCore.get_available_commands (ident, host)
+	commandlist = modulecore.get_available_commands (ident, host)
 	partitioned=[]
 
 	while len (commandlist) > 0:
@@ -182,27 +174,17 @@
 	for part in partitioned:
 		reply ('\002Available commands\002: %s' % (", ".join (part)))
 
-def cmd_help (bot, reply, ident, host, args, **rest):
-	cmd = ModuleCore.get_command_by_name (args['command'])
+def cmd_help (bot, reply, ident, host, args, error, **rest):
+	cmd = modulecore.get_command_by_name (args['command'])
 
 	if not cmd:
-		command_error ('unknown command \'%s\'' % args['command'])
+		error ('unknown command \'%s\'' % args['command'])
 
-	if not ModuleCore.is_available (cmd, ident, host):
-		command_error ('you may not use %s' % cmd['name'])
+	if not modulecore.is_available (cmd, ident, host):
+		error ('you may not use %s' % cmd['name'])
 
 	reply ('%s %s: %s' % (cmd['name'], cmd['args'], cmd['description']))
 
-def mathsubstitute (expr, token, value):
-	rex = re.compile (r'^(.*)\b' + token + r'\b(.*)$')
-	match = rex.match (expr)
-
-	while match:
-		expr = match.group(1) + str (value) + match.group(2)
-		match = rex.match (expr)
-
-	return expr
-
 def cmd_calcfunctions (bot, reply, **rest):
 	reply ('Available functions for .calc: %s' % \
 		', '.join (sorted ([name for name, data in calc.Functions.items()])))
@@ -211,20 +193,26 @@
 	reply (calc.Calculator().calc (args['expression']))
 
 def cmd_more (commandObject, **rest):
-	ModuleCore.print_responses (commandObject)
+	modulecore.print_responses (commandObject)
 
 def cmd_yes (**k):
-	ModuleCore.confirm (k, True)
+	modulecore.confirm (k, True)
 
 def cmd_no (**k):
-	ModuleCore.confirm (k, False)
+	modulecore.confirm (k, False)
 
 def cmd_bitly (reply, args, **k):
 	reply ('Result: %s' % utility.shorten_link (args['link']))
 
-def cmd_py (reply, args, **rest):
+@modulecore.irc_command (args='<command...>')
+def py (reply, args, **rest):
+	''' Evaluates the given Python string using appspot.com '''
 	url = 'http://eval.appspot.com/eval?statement=' + urllib.parse.quote (args['command'])
-	result = utility.read_url (url).splitlines()
+	result = utility.read_url (url, timeout=15).splitlines()
+
+	if not result:
+		reply ('No output.')
+		return
 
 	# \x0f is the 'reset colors' code, prepended to all reply lines to prevent other bots from
 	# reacting to this .py call.
--- a/modulecore.py	Sun Aug 16 19:27:14 2015 +0300
+++ b/modulecore.py	Sun Aug 16 23:30:11 2015 +0300
@@ -30,6 +30,7 @@
 import os
 import re
 import time
+import sys
 from configfile import Config
 
 Modules = {}
@@ -63,24 +64,7 @@
 		Modules[fn] = module
 
 		for cmd in module.ModuleData['commands']:
-			if cmd['args'] == None:
-				cmd['args'] = ''
-
-			cmd['module'] = module
-			cmd['regex'] = make_regex (cmd['args'])
-			cmd['argnames'] = []
-			Commands[cmd['name']] = cmd
-
-			for argname in cmd['args'].split (' '):
-				argname = argname[1:-1]
-
-				if argname[-3:] == '...':
-					argname = argname[0:-3]
-
-				if argname == '':
-					continue
-
-				cmd['argnames'].append (argname)
+			install_command (cmd, module)
 
 		if 'hooks' in module.ModuleData:
 			for key, hooks in module.ModuleData['hooks'].items():
@@ -96,6 +80,28 @@
 	print ('''Loaded %d commands and %d hooks in %d modules''' %
 		(len (Commands), numHooks, len (Modules)))
 
+def install_command (cmd, module):
+	if cmd['args'] == None:
+		cmd['args'] = ''
+
+	Modules[module.__name__] = module
+	cmd['module'] = module
+	cmd['regex'] = make_regex (cmd['args'])
+	cmd['argnames'] = []
+
+	for argname in cmd['args'].split (' '):
+		argname = argname[1:-1]
+
+		if argname[-3:] == '...':
+			argname = argname[0:-3]
+
+		if argname == '':
+			continue
+
+		cmd['argnames'].append (argname)
+
+	Commands[cmd['name']] = cmd
+
 #
 # command_error (message)
 #
@@ -181,8 +187,8 @@
 	global g_lastConfirm
 	global g_confirmCommand
 
-	if 'function' in commandObject:
-		func = commandObject['function']
+	if 'function' in commandObject['info']:
+		func = commandObject['info']['function']
 	else:
 		cmdname = commandObject['cmdname']
 
@@ -379,3 +385,22 @@
 		regex += r'\s*'
 
 	return '^[^ ]+%s$' % regex
+
+def irc_command (**command):
+	def result (fn):
+		command['name'] = fn.__name__
+		command['description'] = fn.__doc__
+		command['function'] = fn
+
+		if command['description'] == None:
+			command['description'] = ''
+	
+		if 'level' not in command:
+			command['level'] = 'normal'
+
+		if 'args' not in command:
+			command['args'] = None
+
+		install_command (command, sys.modules[fn.__module__])
+		return fn
+	return result
\ No newline at end of file
--- a/utility.py	Sun Aug 16 19:27:14 2015 +0300
+++ b/utility.py	Sun Aug 16 23:30:11 2015 +0300
@@ -51,8 +51,13 @@
 
 	return link
 
-def read_url (url):
-	data = urllib.request.urlopen (urllib.request.Request (url)).read()
+def read_url (url, timeout=None):
+	args = [urllib.request.Request (url), None]
+
+	if timeout:
+		args += [timeout]
+
+	data = urllib.request.urlopen (*args).read()
 	return data.decode ('utf-8')
 
 def make_progress_bar (p, barLength, colored=True):

mercurial