From 44f63992dac44a4479f3367e6006bedc893406bb Mon Sep 17 00:00:00 2001 From: Eeshan Garg Date: Sat, 22 Jul 2017 17:51:07 -0230 Subject: [PATCH] zulip_bots/run: Support importing bot modules by path. The zulip-run-bot script now supports passing in a --path-to-bot option. This allows users to specify the path to the source file for their own custom bots, the first step towards being able to support out-of-tree bots. To run an existing bot in the zulip_bots package, just passing in the name of the bot should suffice. --- zulip_bots/zulip_bots/run.py | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/zulip_bots/zulip_bots/run.py b/zulip_bots/zulip_bots/run.py index 1535341..9deee12 100755 --- a/zulip_bots/zulip_bots/run.py +++ b/zulip_bots/zulip_bots/run.py @@ -7,10 +7,29 @@ import optparse import sys from types import ModuleType from importlib import import_module +from os.path import basename, splitext + +import six from zulip_bots.lib import run_message_handler_for_bot +def import_module_from_source(path, name=None): + if name is None: + name = splitext(basename(path))[0] + + if six.PY2: + import imp + module = imp.load_source(name, path) + return module + else: + import importlib.util + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + def parse_args(): usage = ''' zulip-run-bot @@ -33,12 +52,22 @@ def parse_args(): action='store', help='(alternate config file to ~/.zuliprc)') + parser.add_option('--path-to-bot', + action='store', + help='path to the file with the bot handler class') + parser.add_option('--force', action='store_true', help='Try running the bot even if dependencies install fails.') (options, args) = parser.parse_args() - if not args: - parser.error('You must specify the name of the bot!') + + if not args and not options.path_to_bot: + error_message = """ +You must either specify the name of an existing bot or +specify a path to the file (--path-to-bot) that contains +the bot handler class. +""" + parser.error(error_message) return (options, args) @@ -46,9 +75,16 @@ def parse_args(): def main(): # type: () -> None (options, args) = parse_args() - bot_name = args[0] - lib_module = import_module('zulip_bots.bots.{bot}.{bot}'.format(bot=bot_name)) + bot_name = None + if args: + bot_name = args[0] + + if options.path_to_bot: + lib_module = import_module_from_source(options.path_to_bot, name=bot_name) + else: + lib_module = import_module('zulip_bots.bots.{bot}.{bot}'.format(bot=bot_name)) + if not options.quiet: logging.basicConfig(stream=sys.stdout, level=logging.INFO)