From 44f63992dac44a4479f3367e6006bedc893406bb Mon Sep 17 00:00:00 2001
From: Eeshan Garg <jerryguitarist@gmail.com>
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 1535341d..9deee125 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 <bot_name>
@@ -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)