def rpn(self, irc, msg, args): """<rpn math expression> Returns the value of an RPN expression. """ stack = [] for arg in args: try: x = complex(arg) if x == abs(x): x = abs(x) stack.append(x) except ValueError: # Not a float. if arg in SAFE_ENV: f = SAFE_ENV[arg] if callable(f): called = False arguments = [] while not called and stack: arguments.append(stack.pop()) try: stack.append(f(*arguments)) called = True except TypeError: pass if not called: irc.error(_('Not enough arguments for %s') % arg) return else: stack.append(f) elif arg in self._rpnEnv: self._rpnEnv[arg](stack) else: arg2 = stack.pop() arg1 = stack.pop() s = '%s%s%s' % (arg1, arg, arg2) try: stack.append(safe_eval(s, allow_ints=False)) except SyntaxError: irc.error( format(_('%q is not a defined function.'), arg)) return if len(stack) == 1: irc.reply(str(self._complexToString(complex(stack[0])))) else: s = ', '.join(map(self._complexToString, list(map(complex, stack)))) irc.reply(_('Stack: [%s]') % s)
def rank(self, irc, msg, args, channel, expr): """[<channel>] <stat expression> Returns the ranking of users according to the given stat expression. Valid variables in the stat expression include 'msgs', 'chars', 'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits', 'kicks', 'kicked', 'topics', and 'modes'. Any simple mathematical expression involving those variables is permitted. """ if channel != '#': # Skip this check if databases.plugins.channelspecific is False. if msg.nick not in irc.state.channels[channel].users: irc.error( format('You must be in %s to use this command.', channel)) return expr = expr.lower() users = [] for ((c, id), stats) in self.db.items(): if ircutils.strEqual(c, channel) and \ (id == 0 or ircdb.users.hasUser(id)): e = {} for attr in stats._values: e[attr] = float(getattr(stats, attr)) try: v = safe_eval(expr, allow_ints=True, variables=e) except ZeroDivisionError: v = float('inf') except NameError as e: irc.errorInvalid(_('stat variable'), str(e)) except InvalidNode as e: irc.error(_('Invalid syntax: %s') % e.args[0], Raise=True) except Exception as e: irc.error(utils.exnToString(e), Raise=True) else: v = float(v) if id == 0: users.append((v, irc.nick)) else: users.append((v, ircdb.users.getUser(id).name)) users.sort() users.reverse() s = utils.str.commaAndify([ '#%s %s (%.3g)' % (i + 1, u, v) for (i, (v, u)) in enumerate(users) ]) irc.reply(s)
def icalc(self, irc, msg, args, text): """<math expression> This is the same as the calc command except that it allows integer math, and can thus cause the bot to suck up CPU. Hence it requires the 'trusted' capability to use. """ try: self.log.info('evaluating %q from %s', text, msg.prefix) x = safe_eval(text, allow_ints=True) irc.reply(str(x)) except OverflowError: maxFloat = math.ldexp(0.9999999999999999, 1024) irc.error(_('The answer exceeded %s or so.') % maxFloat) except InvalidNode as e: irc.error(_('Invalid syntax: %s') % e.args[0]) except NameError as e: irc.error(_('%s is not a defined function.') % str(e).split()[1]) except Exception as e: irc.error(utils.exnToString(e))
def calc(self, irc, msg, args, text): """<math expression> Returns the value of the evaluated <math expression>. The syntax is Python syntax; the type of arithmetic is floating point. Floating point arithmetic is used in order to prevent a user from being able to crash to the bot with something like '10**10**10**10'. One consequence is that large values such as '10**24' might not be exact. """ try: self.log.info('evaluating %q from %s', text, msg.prefix) x = complex(safe_eval(text, allow_ints=False)) irc.reply(self._complexToString(x)) except OverflowError: maxFloat = math.ldexp(0.9999999999999999, 1024) irc.error(_('The answer exceeded %s or so.') % maxFloat) except InvalidNode as e: irc.error(_('Invalid syntax: %s') % e.args[0]) except NameError as e: irc.error(_('%s is not a defined function.') % e.args[0]) except MemoryError: irc.error(_('Memory error (too much recursion?)')) except Exception as e: irc.error(str(e))