From 05ca843d313d98a1e3b11303f4351acc3b4c678f Mon Sep 17 00:00:00 2001 From: Quentin Nerden Date: Mon, 10 Aug 2015 12:00:00 +0200 Subject: [PATCH 1/6] running pycharm code instpector and pycharm reformat code --- rtmbot.py | 63 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/rtmbot.py b/rtmbot.py index 3bd4184..59964a1 100755 --- a/rtmbot.py +++ b/rtmbot.py @@ -1,11 +1,11 @@ #!/usr/bin/env python import sys + sys.dont_write_bytecode = True import glob import yaml -import json import os import sys import time @@ -14,20 +14,24 @@ from argparse import ArgumentParser from slackclient import SlackClient + def dbg(debug_string): if debug: logging.info(debug_string) + class RtmBot(object): def __init__(self, token): self.last_ping = 0 self.token = token self.bot_plugins = [] self.slack_client = None + def connect(self): """Convenience method that creates Server instance""" self.slack_client = SlackClient(self.token) self.slack_client.rtm_connect() + def start(self): self.connect() self.load_plugins() @@ -38,12 +42,14 @@ class RtmBot(object): self.output() self.autoping() time.sleep(.1) + def autoping(self): - #hardcode the interval to 3 seconds + # hardcode the interval to 3 seconds now = int(time.time()) if now > self.last_ping + 3: self.slack_client.server.ping() self.last_ping = now + def input(self, data): if "type" in data: function_name = "process_" + data["type"] @@ -51,35 +57,39 @@ class RtmBot(object): for plugin in self.bot_plugins: plugin.register_jobs() plugin.do(function_name, data) + def output(self): for plugin in self.bot_plugins: limiter = False for output in plugin.do_output(): channel = self.slack_client.server.channels.find(output[0]) - if channel != None and output[1] != None: - if limiter == True: + if channel is not None and output[1] is not None: + if limiter: time.sleep(.1) - limiter = False - message = output[1].encode('ascii','ignore') - channel.send_message("{}".format(message)) - limiter = True + limiter = True # TODO: check goal: no sleep for 1st channel, sleep of all after ? + # TODO: find out how to safely encode stuff if needed :( + # message = output[1].encode('utf-8','ignore') + channel.send_message(output[1]) # message + + def crons(self): for plugin in self.bot_plugins: plugin.do_jobs() + 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, directory+'/plugins/') - for plugin in glob.glob(directory+'/plugins/*.py') + glob.glob(directory+'/plugins/*/*.py'): + sys.path.insert(0, directory + '/plugins/') + for plugin in glob.glob(directory + '/plugins/*.py') + glob.glob(directory + '/plugins/*/*.py'): logging.info(plugin) name = plugin.split('/')[-1][:-3] -# try: + # try: self.bot_plugins.append(Plugin(name)) -# except: -# print "error loading plugin %s" % name + # except: + # print "error loading plugin %s" % name class Plugin(object): - def __init__(self, name, plugin_config={}): + def __init__(self, name): self.name = name self.jobs = [] self.module = __import__(name) @@ -90,32 +100,36 @@ class Plugin(object): self.module.config = config[name] if 'setup' in dir(self.module): self.module.setup() + def register_jobs(self): if 'crontable' in dir(self.module): 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) self.module.crontable = [] else: self.module.crontable = [] + def do(self, function_name, data): 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: try: - eval("self.module."+function_name)(data) + eval("self.module." + function_name)(data, bot, config) except: dbg("problem in module {} {}".format(function_name, data)) else: - eval("self.module."+function_name)(data) + eval("self.module." + function_name)(data, bot, config) if "catch_all" in dir(self.module): try: self.module.catch_all(data) except: dbg("problem in catch all") + def do_jobs(self): for job in self.jobs: job.check() + def do_output(self): output = [] while True: @@ -129,15 +143,19 @@ class Plugin(object): self.module.outputs = [] return output + class Job(object): def __init__(self, interval, function): self.function = function self.interval = interval self.lastrun = 0 + def __str__(self): return "{} {} {}".format(self.function, self.interval, self.lastrun) + def __repr__(self): return self.__str__() + def check(self): if self.lastrun + self.interval < time.time(): if not debug: @@ -150,6 +168,7 @@ class Job(object): self.lastrun = time.time() pass + class UnknownChannel(Exception): pass @@ -182,8 +201,8 @@ if __name__ == "__main__": directory = os.path.dirname(sys.argv[0]) if not directory.startswith('/'): directory = os.path.abspath("{}/{}".format(os.getcwd(), - directory - )) + directory + )) config = yaml.load(file(args.config or 'rtmbot.conf', 'r')) debug = config["DEBUG"] @@ -195,7 +214,7 @@ if __name__ == "__main__": if config.has_key("DAEMON"): if config["DAEMON"]: import daemon + with daemon.DaemonContext(): main_loop() main_loop() - From aff0446b8f34202d8b2da4d05d977aa9719502b1 Mon Sep 17 00:00:00 2001 From: Quentin Nerden Date: Fri, 14 Aug 2015 11:35:06 +0200 Subject: [PATCH 2/6] adding deamon to requirements. It is needed in rtmbot.py --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index d740102..ca595ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ python-daemon pyyaml websocket-client slackclient +deamon From 6052333c6482d7629c92776bd3b870fac30daaf2 Mon Sep 17 00:00:00 2001 From: Jeff Ammons Date: Fri, 15 Apr 2016 12:40:27 -0700 Subject: [PATCH 3/6] Removing non-PEP8 changes to clean up PR --- requirements.txt | 1 - rtmbot.py | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index ca595ee..d740102 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,3 @@ python-daemon pyyaml websocket-client slackclient -deamon diff --git a/rtmbot.py b/rtmbot.py index 59964a1..65c2668 100755 --- a/rtmbot.py +++ b/rtmbot.py @@ -7,7 +7,6 @@ sys.dont_write_bytecode = True import glob import yaml import os -import sys import time import logging from argparse import ArgumentParser @@ -66,6 +65,9 @@ class RtmBot(object): if channel is not None and output[1] is not None: if limiter: time.sleep(.1) + limiter = False + message = output[1].encode('ascii','ignore') + channel.send_message("{}".format(message)) limiter = True # TODO: check goal: no sleep for 1st channel, sleep of all after ? # TODO: find out how to safely encode stuff if needed :( # message = output[1].encode('utf-8','ignore') @@ -89,7 +91,9 @@ class RtmBot(object): # print "error loading plugin %s" % name class Plugin(object): - def __init__(self, name): + def __init__(self, name, plugin_config=None): + if plugin_config is None: + plugin_config = {} #TODO: is this necessary? self.name = name self.jobs = [] self.module = __import__(name) @@ -115,11 +119,11 @@ class Plugin(object): # this makes the plugin fail with stack trace in debug mode if not debug: try: - eval("self.module." + function_name)(data, bot, config) + eval("self.module." + function_name)(data) except: dbg("problem in module {} {}".format(function_name, data)) else: - eval("self.module." + function_name)(data, bot, config) + eval("self.module." + function_name)(data) if "catch_all" in dir(self.module): try: self.module.catch_all(data) From 25ce082eacfdd70d6e99799cdb3b27ca37443bcf Mon Sep 17 00:00:00 2001 From: Jeff Ammons Date: Fri, 15 Apr 2016 14:03:20 -0700 Subject: [PATCH 4/6] Fix PEP8 compliance in example plugins and rtmbot --- doc/example-plugins/canary.py | 3 ++- doc/example-plugins/counter.py | 5 +++-- doc/example-plugins/repeat.py | 7 ++++--- doc/example-plugins/todo.py | 10 ++++++---- rtmbot.py | 28 +++++++++++++++++----------- tox.ini | 2 +- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/doc/example-plugins/canary.py b/doc/example-plugins/canary.py index 2c76784..b2cea10 100644 --- a/doc/example-plugins/canary.py +++ b/doc/example-plugins/canary.py @@ -1,8 +1,9 @@ import time outputs = [] + 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())]) canary() diff --git a/doc/example-plugins/counter.py b/doc/example-plugins/counter.py index 84e9012..00fac1a 100644 --- a/doc/example-plugins/counter.py +++ b/doc/example-plugins/counter.py @@ -2,8 +2,9 @@ import time crontable = [] outputs = [] -crontable.append([5,"say_time"]) +crontable.append([5, "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()]) diff --git a/doc/example-plugins/repeat.py b/doc/example-plugins/repeat.py index 54bc581..3106457 100644 --- a/doc/example-plugins/repeat.py +++ b/doc/example-plugins/repeat.py @@ -1,8 +1,9 @@ -import time crontable = [] outputs = [] + def process_message(data): 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'])] + ) diff --git a/doc/example-plugins/todo.py b/doc/example-plugins/todo.py index 616be49..4437840 100644 --- a/doc/example-plugins/todo.py +++ b/doc/example-plugins/todo.py @@ -6,19 +6,21 @@ crontabs = [] tasks = {} -FILE="plugins/todo.data" + +FILE = "plugins/todo.data" if os.path.isfile(FILE): tasks = pickle.load(open(FILE, 'rb')) + def process_message(data): global tasks channel = data["channel"] text = data["text"] - #only accept tasks on DM channels + # only accept tasks on DM channels if channel.startswith("D"): if channel not in tasks.keys(): tasks[channel] = [] - #do command stuff + # do command stuff if text.startswith("todo"): tasks[channel].append(text[5:]) outputs.append([channel, "added"]) @@ -36,4 +38,4 @@ def process_message(data): tasks[channel].pop(num) if text == "show": print tasks - pickle.dump(tasks, open(FILE,"wb")) + pickle.dump(tasks, open(FILE, "wb")) diff --git a/rtmbot.py b/rtmbot.py index 65c2668..c23156a 100755 --- a/rtmbot.py +++ b/rtmbot.py @@ -1,18 +1,17 @@ #!/usr/bin/env python - import sys - -sys.dont_write_bytecode = True - import glob import yaml import os import time import logging + from argparse import ArgumentParser from slackclient import SlackClient +sys.dont_write_bytecode = True + def dbg(debug_string): if debug: @@ -66,14 +65,14 @@ class RtmBot(object): if limiter: time.sleep(.1) limiter = False - message = output[1].encode('ascii','ignore') + message = output[1].encode('ascii', 'ignore') channel.send_message("{}".format(message)) - limiter = True # TODO: check goal: no sleep for 1st channel, sleep of all after ? + limiter = True + # TODO: check goal: no sleep for 1st channel, sleep of all after ? # TODO: find out how to safely encode stuff if needed :( # message = output[1].encode('utf-8','ignore') channel.send_message(output[1]) # message - def crons(self): for plugin in self.bot_plugins: plugin.do_jobs() @@ -82,7 +81,8 @@ class RtmBot(object): for plugin in glob.glob(directory + '/plugins/*'): sys.path.insert(0, plugin) 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) name = plugin.split('/')[-1][:-3] # try: @@ -90,10 +90,12 @@ class RtmBot(object): # except: # print "error loading plugin %s" % name + class Plugin(object): + def __init__(self, name, plugin_config=None): if plugin_config is None: - plugin_config = {} #TODO: is this necessary? + plugin_config = {} # TODO: is this necessary? self.name = name self.jobs = [] self.module = __import__(name) @@ -179,7 +181,11 @@ class UnknownChannel(Exception): def main_loop(): 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) try: bot.start() @@ -215,7 +221,7 @@ if __name__ == "__main__": files_currently_downloading = [] job_hash = {} - if config.has_key("DAEMON"): + if 'DAEMON' in config: if config["DAEMON"]: import daemon diff --git a/tox.ini b/tox.ini index 0c59058..d8924e4 100644 --- a/tox.ini +++ b/tox.ini @@ -20,4 +20,4 @@ basepython = [testenv:flake8] basepython=python deps=flake8 -commands=flake8 {toxinidir}/rtmbot.py {toxinidir}/example-plugins \ No newline at end of file +commands=flake8 {toxinidir}/rtmbot.py {toxinidir}/doc/example-plugins \ No newline at end of file From 5898a379976bfa6bcd8a291229e7d0d800bea03c Mon Sep 17 00:00:00 2001 From: Jeff Ammons Date: Fri, 15 Apr 2016 14:32:19 -0700 Subject: [PATCH 5/6] Remove spurious change unrelated to PEP8 --- rtmbot.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rtmbot.py b/rtmbot.py index c23156a..4b77249 100755 --- a/rtmbot.py +++ b/rtmbot.py @@ -68,10 +68,6 @@ class RtmBot(object): message = output[1].encode('ascii', 'ignore') channel.send_message("{}".format(message)) limiter = True - # TODO: check goal: no sleep for 1st channel, sleep of all after ? - # TODO: find out how to safely encode stuff if needed :( - # message = output[1].encode('utf-8','ignore') - channel.send_message(output[1]) # message def crons(self): for plugin in self.bot_plugins: @@ -95,7 +91,7 @@ class Plugin(object): def __init__(self, name, plugin_config=None): if plugin_config is None: - plugin_config = {} # TODO: is this necessary? + plugin_config = {} # TODO: is this variable necessary? self.name = name self.jobs = [] self.module = __import__(name) From aa710d2d4ef4cd032253db513321657b7826c947 Mon Sep 17 00:00:00 2001 From: Jeff Ammons Date: Fri, 15 Apr 2016 14:49:38 -0700 Subject: [PATCH 6/6] Fix Python3 linting --- doc/example-plugins/todo.py | 3 ++- rtmbot.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/example-plugins/todo.py b/doc/example-plugins/todo.py index 4437840..cd1db8d 100644 --- a/doc/example-plugins/todo.py +++ b/doc/example-plugins/todo.py @@ -1,3 +1,4 @@ +from __future__ import print_function import os import pickle @@ -37,5 +38,5 @@ def process_message(data): num = int(text.split()[1]) - 1 tasks[channel].pop(num) if text == "show": - print tasks + print(tasks) pickle.dump(tasks, open(FILE, "wb")) diff --git a/rtmbot.py b/rtmbot.py index 4b77249..a275cc5 100755 --- a/rtmbot.py +++ b/rtmbot.py @@ -210,7 +210,7 @@ if __name__ == "__main__": directory )) - config = yaml.load(file(args.config or 'rtmbot.conf', 'r')) + config = yaml.load(open(args.config or 'rtmbot.conf', 'r')) debug = config["DEBUG"] bot = RtmBot(config["SLACK_TOKEN"]) site_plugins = []