From 973aba6de77eb6de225bd877ad35d5ac8a16b9a4 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sat, 29 Aug 2015 09:39:33 -0700 Subject: [PATCH] Move utils' global variables to world.py --- classes.py | 3 ++- coreplugin.py | 5 ++-- main.py | 10 ++++---- plugins/commands.py | 5 ++-- plugins/relay.py | 53 ++++++++++++++++++++++--------------------- tests/test_fakeirc.py | 2 +- tests/test_relay.py | 1 - tests/test_utils.py | 14 ++++++------ utils.py | 16 +++---------- world.py | 13 ++++++++++- 10 files changed, 63 insertions(+), 59 deletions(-) diff --git a/classes.py b/classes.py index 14a0a83..dc526c8 100644 --- a/classes.py +++ b/classes.py @@ -10,6 +10,7 @@ import hashlib from log import log import utils from conf import conf +import world ### Exceptions @@ -214,7 +215,7 @@ class Irc(): hook_cmd = parsed_args.get('parse_as') or hook_cmd log.debug('Parsed args %r received from %s handler (calling hook %s)', parsed_args, command, hook_cmd) # Iterate over hooked functions, catching errors accordingly - for hook_func in utils.command_hooks[hook_cmd]: + for hook_func in world.command_hooks[hook_cmd]: try: log.debug('Calling function %s', hook_func) hook_func(self, numeric, command, parsed_args) diff --git a/coreplugin.py b/coreplugin.py index 2828cb3..c45752e 100644 --- a/coreplugin.py +++ b/coreplugin.py @@ -2,6 +2,7 @@ import utils from log import log +import world # Handle KILLs sent to the PyLink client and respawn def handle_kill(irc, source, command, args): @@ -25,7 +26,7 @@ def handle_commands(irc, source, command, args): cmd = cmd_args[0].lower() cmd_args = cmd_args[1:] try: - func = utils.bot_commands[cmd] + func = world.bot_commands[cmd] except KeyError: utils.msg(irc, source, 'Error: Unknown command %r.' % cmd) return @@ -84,7 +85,7 @@ def handle_whois(irc, source, command, args): # idle time, so we simply return 0. # <- 317 GL GL 15 1437632859 :seconds idle, signon time f(irc, server, 317, source, "%s 0 %s :seconds idle, signon time" % (nick, user.ts)) - for func in utils.whois_handlers: + for func in world.whois_handlers: # Iterate over custom plugin WHOIS handlers. They return a tuple # or list with two arguments: the numeric, and the text to send. try: diff --git a/main.py b/main.py index 5b92a4e..9c599ae 100755 --- a/main.py +++ b/main.py @@ -25,7 +25,7 @@ if __name__ == '__main__': # Import plugins first globally, because they can listen for events # that happen before the connection phase. - utils.plugins.append(coreplugin) + world.plugins.append(coreplugin) to_load = conf.conf['plugins'] plugins_folder = [os.path.join(os.getcwd(), 'plugins')] # Here, we override the module lookup and import the plugins @@ -34,7 +34,7 @@ if __name__ == '__main__': try: moduleinfo = imp.find_module(plugin, plugins_folder) pl = imp.load_source(plugin, moduleinfo[1]) - utils.plugins.append(pl) + world.plugins.append(pl) except ImportError as e: if str(e) == ('No module named %r' % plugin): log.error('Failed to load plugin %r: The plugin could not be found.', plugin) @@ -57,7 +57,7 @@ if __name__ == '__main__': log.critical('Failed to load protocol module: ImportError: %s', protoname, str(e)) sys.exit(2) else: - utils.networkobjects[network] = classes.Irc(network, proto, conf.conf) - utils.started.set() - log.info("loaded plugins: %s", utils.plugins) + world.networkobjects[network] = classes.Irc(network, proto, conf.conf) + world.started.set() + log.info("loaded plugins: %s", world.plugins) diff --git a/plugins/commands.py b/plugins/commands.py index 9032416..3609d42 100644 --- a/plugins/commands.py +++ b/plugins/commands.py @@ -6,6 +6,7 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import utils from conf import conf from log import log +import world @utils.add_cmd def status(irc, source, args): @@ -46,7 +47,7 @@ def listcommands(irc, source, args): """takes no arguments. Returns a list of available commands PyLink has to offer.""" - cmds = list(utils.bot_commands.keys()) + cmds = list(world.bot_commands.keys()) cmds.sort() utils.msg(irc, source, 'Available commands include: %s' % ', '.join(cmds)) utils.msg(irc, source, 'To see help on a specific command, type \x02help \x02.') @@ -63,7 +64,7 @@ def help(irc, source, args): listcommands(irc, source, args) return try: - func = utils.bot_commands[command] + func = world.bot_commands[command] except KeyError: utils.msg(irc, source, 'Error: Unknown command %r.' % command) return diff --git a/plugins/relay.py b/plugins/relay.py index cc60d27..6d808d0 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -13,6 +13,7 @@ from expiringdict import ExpiringDict import utils from log import log from conf import confname +import world dbname = "pylinkrelay" if confname != 'pylink': @@ -28,11 +29,11 @@ def relayWhoisHandlers(irc, target): orig = getLocalUser(irc, target) if orig: network, remoteuid = orig - remotenick = utils.networkobjects[network].users[remoteuid].nick + remotenick = world.networkobjects[network].users[remoteuid].nick return [320, "%s :is a remote user connected via PyLink Relay. Home " "network: %s; Home nick: %s" % (user.nick, network, remotenick)] -utils.whois_handlers.append(relayWhoisHandlers) +world.whois_handlers.append(relayWhoisHandlers) def normalizeNick(irc, netname, nick, separator=None, uid=''): separator = separator or irc.serverdata.get('separator') or "/" @@ -94,7 +95,7 @@ def loadDB(): db = {} def exportDB(reschedule=False): - scheduler = utils.schedulers.get('relaydb') + scheduler = world.schedulers.get('relaydb') if reschedule and scheduler: scheduler.enter(30, 1, exportDB, argument=(True,)) log.debug("Relay: exporting links database to %s", dbname) @@ -179,7 +180,7 @@ def getLocalUser(irc, user, targetirc=None): # If targetirc is given, we'll return simply the UID of the user on the # target network, if it exists. Otherwise, we'll return a tuple # with the home network name and the original user's UID. - sourceobj = utils.networkobjects.get(remoteuser[0]) + sourceobj = world.networkobjects.get(remoteuser[0]) if targetirc and sourceobj: if remoteuser[0] == targetirc.name: # The user we found's home network happens to be the one being @@ -236,7 +237,7 @@ def initializeChannel(irc, channel): remotenet, remotechan = link if remotenet == irc.name: continue - remoteirc = utils.networkobjects.get(remotenet) + remoteirc = world.networkobjects.get(remotenet) if remoteirc is None: continue rc = remoteirc.channels[remotechan] @@ -264,7 +265,7 @@ utils.add_hook(handle_join, 'JOIN') def handle_quit(irc, numeric, command, args): for netname, user in relayusers[(irc.name, numeric)].copy().items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] remoteirc.proto.quitClient(remoteirc, user, args['text']) del relayusers[(irc.name, numeric)] utils.add_hook(handle_quit, 'QUIT') @@ -278,7 +279,7 @@ utils.add_hook(handle_squit, 'SQUIT') def handle_nick(irc, numeric, command, args): for netname, user in relayusers[(irc.name, numeric)].items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] newnick = normalizeNick(remoteirc, irc.name, args['newnick'], uid=user) if remoteirc.users[user].nick != newnick: remoteirc.proto.nickClient(remoteirc, user, newnick) @@ -292,7 +293,7 @@ def handle_part(irc, numeric, command, args): return for channel in channels: for netname, user in relayusers[(irc.name, numeric)].copy().items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] remotechan = findRemoteChan(irc, remoteirc, channel) if remotechan is None: continue @@ -328,7 +329,7 @@ def handle_privmsg(irc, numeric, command, args): return if utils.isChannel(target): for netname, user in relayusers[(irc.name, numeric)].items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] real_target = findRemoteChan(irc, remoteirc, target) if not real_target: continue @@ -351,7 +352,7 @@ def handle_privmsg(irc, numeric, command, args): 'with %r in order to send messages.' % \ irc.users[target].nick, notice=True) return - remoteirc = utils.networkobjects[homenet] + remoteirc = world.networkobjects[homenet] user = getRemoteUser(irc, remoteirc, numeric, spawnIfMissing=False) if notice: remoteirc.proto.noticeClient(remoteirc, user, real_target, text) @@ -371,7 +372,7 @@ def handle_kick(irc, source, command, args): if relay is None or target == irc.pseudoclient.uid: return origuser = getLocalUser(irc, target) - for name, remoteirc in utils.networkobjects.items(): + for name, remoteirc in world.networkobjects.items(): if irc.name == name or not remoteirc.connected.is_set(): continue remotechan = findRemoteChan(irc, remoteirc, channel) @@ -462,7 +463,7 @@ def handle_chgclient(irc, source, command, args): text = args['newgecos'] if field: for netname, user in relayusers[(irc.name, target)].items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] try: remoteirc.proto.updateClient(remoteirc, user, field, text) except NotImplementedError: # IRCd doesn't support changing the field we want @@ -589,7 +590,7 @@ def getSupportedUmodes(irc, remoteirc, modes): def handle_mode(irc, numeric, command, args): target = args['target'] modes = args['modes'] - for name, remoteirc in utils.networkobjects.items(): + for name, remoteirc in world.networkobjects.items(): if irc.name == name or not remoteirc.connected.is_set(): continue if utils.isChannel(target): @@ -606,7 +607,7 @@ utils.add_hook(handle_mode, 'MODE') def handle_topic(irc, numeric, command, args): channel = args['channel'] topic = args['topic'] - for name, remoteirc in utils.networkobjects.items(): + for name, remoteirc in world.networkobjects.items(): if irc.name == name or not remoteirc.connected.is_set(): continue @@ -632,7 +633,7 @@ def handle_kill(irc, numeric, command, args): # We don't allow killing over the relay, so we must respawn the affected # client and rejoin it to its channels. del relayusers[realuser][irc.name] - remoteirc = utils.networkobjects[realuser[0]] + remoteirc = world.networkobjects[realuser[0]] for remotechan in remoteirc.channels: localchan = findRemoteChan(remoteirc, irc, remotechan) if localchan: @@ -674,7 +675,7 @@ def isRelayClient(irc, user): return False def relayJoins(irc, channel, users, ts): - for name, remoteirc in utils.networkobjects.items(): + for name, remoteirc in world.networkobjects.items(): queued_users = [] if name == irc.name or not remoteirc.connected.is_set(): # Don't relay things to their source network... @@ -708,7 +709,7 @@ def relayJoins(irc, channel, users, ts): remoteirc.proto.sjoinServer(remoteirc, remoteirc.sid, remotechan, queued_users, ts=ts) def relayPart(irc, channel, user): - for name, remoteirc in utils.networkobjects.items(): + for name, remoteirc in world.networkobjects.items(): if name == irc.name or not remoteirc.connected.is_set(): # Don't relay things to their source network... continue @@ -789,7 +790,7 @@ def destroy(irc, source, args): entry = (irc.name, channel) if entry in db: for link in db[entry]['links']: - removeChannel(utils.networkobjects.get(link[0]), link[1]) + removeChannel(world.networkobjects.get(link[0]), link[1]) removeChannel(irc, channel) del db[entry] utils.msg(irc, source, 'Done.') @@ -823,7 +824,7 @@ def link(irc, source, args): if not utils.isOper(irc, source): utils.msg(irc, source, 'Error: You must be opered in order to complete this operation.') return - if remotenet not in utils.networkobjects: + if remotenet not in world.networkobjects: utils.msg(irc, source, 'Error: No network named %r exists.' % remotenet) return localentry = findRelay((irc.name, localchan)) @@ -882,7 +883,7 @@ def delink(irc, source, args): else: for link in db[entry]['links'].copy(): if link[0] == remotenet: - removeChannel(utils.networkobjects.get(remotenet), link[1]) + removeChannel(world.networkobjects.get(remotenet), link[1]) db[entry]['links'].remove(link) else: removeChannel(irc, channel) @@ -892,8 +893,8 @@ def delink(irc, source, args): utils.msg(irc, source, 'Error: No such relay %r.' % channel) def initializeAll(irc): - log.debug('(%s) initializeAll: waiting for utils.started', irc.name) - utils.started.wait() + log.debug('(%s) initializeAll: waiting for world.started', irc.name) + world.started.wait() for chanpair, entrydata in db.items(): network, channel = chanpair initializeChannel(irc, channel) @@ -903,7 +904,7 @@ def initializeAll(irc): def main(): loadDB() - utils.schedulers['relaydb'] = scheduler = sched.scheduler() + world.schedulers['relaydb'] = scheduler = sched.scheduler() scheduler.enter(30, 1, exportDB, argument=(True,)) # Thread this because exportDB() queues itself as part of its # execution, in order to get a repeating loop. @@ -935,7 +936,7 @@ def handle_save(irc, numeric, command, args): # It's one of our relay clients; try to fix our nick to the next # available normalized nick. remotenet, remoteuser = realuser - remoteirc = utils.networkobjects[remotenet] + remoteirc = world.networkobjects[remotenet] nick = remoteirc.users[remoteuser].nick # Limit how many times we can attempt to fix our nick, to prevent # floods and such. @@ -961,7 +962,7 @@ def linked(irc, source, args): """takes no arguments. Returns a list of channels shared across the relay.""" - networks = list(utils.networkobjects.keys()) + networks = list(world.networkobjects.keys()) networks.remove(irc.name) s = 'Connected networks: \x02%s\x02 %s' % (irc.name, ' '.join(networks)) utils.msg(irc, source, s) @@ -976,7 +977,7 @@ def linked(irc, source, args): def handle_away(irc, numeric, command, args): for netname, user in relayusers[(irc.name, numeric)].items(): - remoteirc = utils.networkobjects[netname] + remoteirc = world.networkobjects[netname] remoteirc.proto.awayClient(remoteirc, user, args['text']) utils.add_hook(handle_away, 'AWAY') diff --git a/tests/test_fakeirc.py b/tests/test_fakeirc.py index 95bc800..ee241c6 100644 --- a/tests/test_fakeirc.py +++ b/tests/test_fakeirc.py @@ -9,7 +9,7 @@ import unittest # Yes, we're going to even test the testing classes. Testception? I think so. class TestFakeIRC(unittest.TestCase): def setUp(self): - self.irc = classes.FakeIRC('unittest', classes.FakeProto(), classes.testconf) + self.irc = classes.FakeIRC('unittest', classes.FakeProto()) def testFakeIRC(self): self.irc.run('this should do nothing') diff --git a/tests/test_relay.py b/tests/test_relay.py index 1cbfbc6..50fc344 100644 --- a/tests/test_relay.py +++ b/tests/test_relay.py @@ -7,7 +7,6 @@ import unittest import utils import classes import relay -import conf def dummyf(): pass diff --git a/tests/test_utils.py b/tests/test_utils.py index 795f108..8ecf82d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,7 +6,7 @@ import itertools import utils import classes -import conf +import world def dummyf(): pass @@ -26,16 +26,16 @@ class TestUtils(unittest.TestCase): utils.add_cmd(dummyf) utils.add_cmd(dummyf, 'TEST') # All command names should be automatically lowercased. - self.assertIn('dummyf', utils.bot_commands) - self.assertIn('test', utils.bot_commands) - self.assertNotIn('TEST', utils.bot_commands) + self.assertIn('dummyf', world.bot_commands) + self.assertIn('test', world.bot_commands) + self.assertNotIn('TEST', world.bot_commands) def test_add_hook(self): utils.add_hook(dummyf, 'join') - self.assertIn('JOIN', utils.command_hooks) + self.assertIn('JOIN', world.command_hooks) # Command names stored in uppercase. - self.assertNotIn('join', utils.command_hooks) - self.assertIn(dummyf, utils.command_hooks['JOIN']) + self.assertNotIn('join', world.command_hooks) + self.assertIn(dummyf, world.command_hooks['JOIN']) def testIsNick(self): self.assertFalse(utils.isNick('abcdefgh', nicklen=3)) diff --git a/utils.py b/utils.py index f3f1574..3e00eb3 100644 --- a/utils.py +++ b/utils.py @@ -1,19 +1,9 @@ import string import re -from collections import defaultdict -import threading import inspect from log import log -global bot_commands, command_hooks -# This should be a mapping of command names to functions -bot_commands = {} -command_hooks = defaultdict(list) -networkobjects = {} -schedulers = {} -plugins = [] -whois_handlers = [] -started = threading.Event() +import world # This is separate from classes.py to prevent import loops. class NotAuthenticatedError(Exception): @@ -118,12 +108,12 @@ def add_cmd(func, name=None): if name is None: name = func.__name__ name = name.lower() - bot_commands[name] = func + world.bot_commands[name] = func def add_hook(func, command): """Add a hook for command .""" command = command.upper() - command_hooks[command].append(func) + world.command_hooks[command].append(func) def toLower(irc, text): if irc.proto.casemapping == 'rfc1459': diff --git a/world.py b/world.py index e4450dc..21d9716 100644 --- a/world.py +++ b/world.py @@ -1,7 +1,18 @@ # world.py: global state variables go here +from collections import defaultdict +import threading + # Global variable to indicate whether we're being ran directly, or imported # for a testcase. testing = True - +global bot_commands, command_hooks +# This should be a mapping of command names to functions +bot_commands = {} +command_hooks = defaultdict(list) +networkobjects = {} +schedulers = {} +plugins = [] +whois_handlers = [] +started = threading.Event()