Merge pull request #36 from jammons/master

Make bot code and plugin examples PEP8 compliant
This commit is contained in:
Jeff Ammons 2016-04-15 18:03:51 -07:00
commit 134710718b
6 changed files with 69 additions and 38 deletions

View file

@ -1,8 +1,9 @@
import time import time
outputs = [] outputs = []
def canary(): def canary():
#NOTE: you must add a real channel ID for this to work # NOTE: you must add a real channel ID for this to work
outputs.append(["D12345678", "bot started: " + str(time.time())]) outputs.append(["D12345678", "bot started: " + str(time.time())])
canary() canary()

View file

@ -2,8 +2,9 @@ import time
crontable = [] crontable = []
outputs = [] outputs = []
crontable.append([5,"say_time"]) crontable.append([5, "say_time"])
def say_time(): def say_time():
#NOTE: you must add a real channel ID for this to work # NOTE: you must add a real channel ID for this to work
outputs.append(["D12345678", time.time()]) outputs.append(["D12345678", time.time()])

View file

@ -1,8 +1,9 @@
import time
crontable = [] crontable = []
outputs = [] outputs = []
def process_message(data): def process_message(data):
if data['channel'].startswith("D"): if data['channel'].startswith("D"):
outputs.append([data['channel'], "from repeat1 \"{}\" in channel {}".format(data['text'], data['channel']) ]) outputs.append([data['channel'], "from repeat1 \"{}\" in channel {}".format(
data['text'], data['channel'])]
)

View file

@ -1,3 +1,4 @@
from __future__ import print_function
import os import os
import pickle import pickle
@ -6,19 +7,21 @@ crontabs = []
tasks = {} tasks = {}
FILE="plugins/todo.data"
FILE = "plugins/todo.data"
if os.path.isfile(FILE): if os.path.isfile(FILE):
tasks = pickle.load(open(FILE, 'rb')) tasks = pickle.load(open(FILE, 'rb'))
def process_message(data): def process_message(data):
global tasks global tasks
channel = data["channel"] channel = data["channel"]
text = data["text"] text = data["text"]
#only accept tasks on DM channels # only accept tasks on DM channels
if channel.startswith("D"): if channel.startswith("D"):
if channel not in tasks.keys(): if channel not in tasks.keys():
tasks[channel] = [] tasks[channel] = []
#do command stuff # do command stuff
if text.startswith("todo"): if text.startswith("todo"):
tasks[channel].append(text[5:]) tasks[channel].append(text[5:])
outputs.append([channel, "added"]) outputs.append([channel, "added"])
@ -35,5 +38,5 @@ def process_message(data):
num = int(text.split()[1]) - 1 num = int(text.split()[1]) - 1
tasks[channel].pop(num) tasks[channel].pop(num)
if text == "show": if text == "show":
print tasks print(tasks)
pickle.dump(tasks, open(FILE,"wb")) pickle.dump(tasks, open(FILE, "wb"))

View file

@ -1,33 +1,35 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys import sys
sys.dont_write_bytecode = True
import glob import glob
import yaml import yaml
import json
import os import os
import sys
import time import time
import logging import logging
from argparse import ArgumentParser from argparse import ArgumentParser
from slackclient import SlackClient from slackclient import SlackClient
sys.dont_write_bytecode = True
def dbg(debug_string): def dbg(debug_string):
if debug: if debug:
logging.info(debug_string) logging.info(debug_string)
class RtmBot(object): class RtmBot(object):
def __init__(self, token): def __init__(self, token):
self.last_ping = 0 self.last_ping = 0
self.token = token self.token = token
self.bot_plugins = [] self.bot_plugins = []
self.slack_client = None self.slack_client = None
def connect(self): def connect(self):
"""Convenience method that creates Server instance""" """Convenience method that creates Server instance"""
self.slack_client = SlackClient(self.token) self.slack_client = SlackClient(self.token)
self.slack_client.rtm_connect() self.slack_client.rtm_connect()
def start(self): def start(self):
self.connect() self.connect()
self.load_plugins() self.load_plugins()
@ -38,12 +40,14 @@ class RtmBot(object):
self.output() self.output()
self.autoping() self.autoping()
time.sleep(.1) time.sleep(.1)
def autoping(self): def autoping(self):
#hardcode the interval to 3 seconds # hardcode the interval to 3 seconds
now = int(time.time()) now = int(time.time())
if now > self.last_ping + 3: if now > self.last_ping + 3:
self.slack_client.server.ping() self.slack_client.server.ping()
self.last_ping = now self.last_ping = now
def input(self, data): def input(self, data):
if "type" in data: if "type" in data:
function_name = "process_" + data["type"] function_name = "process_" + data["type"]
@ -51,35 +55,43 @@ class RtmBot(object):
for plugin in self.bot_plugins: for plugin in self.bot_plugins:
plugin.register_jobs() plugin.register_jobs()
plugin.do(function_name, data) plugin.do(function_name, data)
def output(self): def output(self):
for plugin in self.bot_plugins: for plugin in self.bot_plugins:
limiter = False limiter = False
for output in plugin.do_output(): for output in plugin.do_output():
channel = self.slack_client.server.channels.find(output[0]) channel = self.slack_client.server.channels.find(output[0])
if channel != None and output[1] != None: if channel is not None and output[1] is not None:
if limiter == True: if limiter:
time.sleep(.1) time.sleep(.1)
limiter = False limiter = False
message = output[1].encode('ascii','ignore') message = output[1].encode('ascii', 'ignore')
channel.send_message("{}".format(message)) channel.send_message("{}".format(message))
limiter = True limiter = True
def crons(self): def crons(self):
for plugin in self.bot_plugins: for plugin in self.bot_plugins:
plugin.do_jobs() plugin.do_jobs()
def load_plugins(self): def load_plugins(self):
for plugin in glob.glob(directory+'/plugins/*'): for plugin in glob.glob(directory + '/plugins/*'):
sys.path.insert(0, plugin) sys.path.insert(0, plugin)
sys.path.insert(0, directory+'/plugins/') sys.path.insert(0, directory + '/plugins/')
for plugin in glob.glob(directory+'/plugins/*.py') + glob.glob(directory+'/plugins/*/*.py'): for plugin in glob.glob(directory + '/plugins/*.py') + \
glob.glob(directory + '/plugins/*/*.py'):
logging.info(plugin) logging.info(plugin)
name = plugin.split('/')[-1][:-3] name = plugin.split('/')[-1][:-3]
# try: # try:
self.bot_plugins.append(Plugin(name)) self.bot_plugins.append(Plugin(name))
# except: # except:
# print "error loading plugin %s" % name # print "error loading plugin %s" % name
class Plugin(object): class Plugin(object):
def __init__(self, name, plugin_config={}):
def __init__(self, name, plugin_config=None):
if plugin_config is None:
plugin_config = {} # TODO: is this variable necessary?
self.name = name self.name = name
self.jobs = [] self.jobs = []
self.module = __import__(name) self.module = __import__(name)
@ -90,32 +102,36 @@ class Plugin(object):
self.module.config = config[name] self.module.config = config[name]
if 'setup' in dir(self.module): if 'setup' in dir(self.module):
self.module.setup() self.module.setup()
def register_jobs(self): def register_jobs(self):
if 'crontable' in dir(self.module): if 'crontable' in dir(self.module):
for interval, function in self.module.crontable: for interval, function in self.module.crontable:
self.jobs.append(Job(interval, eval("self.module."+function))) self.jobs.append(Job(interval, eval("self.module." + function)))
logging.info(self.module.crontable) logging.info(self.module.crontable)
self.module.crontable = [] self.module.crontable = []
else: else:
self.module.crontable = [] self.module.crontable = []
def do(self, function_name, data): def do(self, function_name, data):
if function_name in dir(self.module): if function_name in dir(self.module):
#this makes the plugin fail with stack trace in debug mode # this makes the plugin fail with stack trace in debug mode
if not debug: if not debug:
try: try:
eval("self.module."+function_name)(data) eval("self.module." + function_name)(data)
except: except:
dbg("problem in module {} {}".format(function_name, data)) dbg("problem in module {} {}".format(function_name, data))
else: else:
eval("self.module."+function_name)(data) eval("self.module." + function_name)(data)
if "catch_all" in dir(self.module): if "catch_all" in dir(self.module):
try: try:
self.module.catch_all(data) self.module.catch_all(data)
except: except:
dbg("problem in catch all") dbg("problem in catch all")
def do_jobs(self): def do_jobs(self):
for job in self.jobs: for job in self.jobs:
job.check() job.check()
def do_output(self): def do_output(self):
output = [] output = []
while True: while True:
@ -129,15 +145,19 @@ class Plugin(object):
self.module.outputs = [] self.module.outputs = []
return output return output
class Job(object): class Job(object):
def __init__(self, interval, function): def __init__(self, interval, function):
self.function = function self.function = function
self.interval = interval self.interval = interval
self.lastrun = 0 self.lastrun = 0
def __str__(self): def __str__(self):
return "{} {} {}".format(self.function, self.interval, self.lastrun) return "{} {} {}".format(self.function, self.interval, self.lastrun)
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
def check(self): def check(self):
if self.lastrun + self.interval < time.time(): if self.lastrun + self.interval < time.time():
if not debug: if not debug:
@ -150,13 +170,18 @@ class Job(object):
self.lastrun = time.time() self.lastrun = time.time()
pass pass
class UnknownChannel(Exception): class UnknownChannel(Exception):
pass pass
def main_loop(): def main_loop():
if "LOGFILE" in config: if "LOGFILE" in config:
logging.basicConfig(filename=config["LOGFILE"], level=logging.INFO, format='%(asctime)s %(message)s') logging.basicConfig(
filename=config["LOGFILE"],
level=logging.INFO,
format='%(asctime)s %(message)s'
)
logging.info(directory) logging.info(directory)
try: try:
bot.start() bot.start()
@ -182,20 +207,20 @@ if __name__ == "__main__":
directory = os.path.dirname(sys.argv[0]) directory = os.path.dirname(sys.argv[0])
if not directory.startswith('/'): if not directory.startswith('/'):
directory = os.path.abspath("{}/{}".format(os.getcwd(), directory = os.path.abspath("{}/{}".format(os.getcwd(),
directory directory
)) ))
config = yaml.load(file(args.config or 'rtmbot.conf', 'r')) config = yaml.load(open(args.config or 'rtmbot.conf', 'r'))
debug = config["DEBUG"] debug = config["DEBUG"]
bot = RtmBot(config["SLACK_TOKEN"]) bot = RtmBot(config["SLACK_TOKEN"])
site_plugins = [] site_plugins = []
files_currently_downloading = [] files_currently_downloading = []
job_hash = {} job_hash = {}
if config.has_key("DAEMON"): if 'DAEMON' in config:
if config["DAEMON"]: if config["DAEMON"]:
import daemon import daemon
with daemon.DaemonContext(): with daemon.DaemonContext():
main_loop() main_loop()
main_loop() main_loop()

View file

@ -20,4 +20,4 @@ basepython =
[testenv:flake8] [testenv:flake8]
basepython=python basepython=python
deps=flake8 deps=flake8
commands=flake8 {toxinidir}/rtmbot.py {toxinidir}/example-plugins commands=flake8 {toxinidir}/rtmbot.py {toxinidir}/doc/example-plugins