bots: Move all bots and the bots API to separate package.
1
.gitignore
vendored
|
@ -10,7 +10,6 @@ dist
|
|||
build
|
||||
eggs
|
||||
parts
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import provision
|
||||
from types import ModuleType
|
||||
|
||||
our_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, our_dir)
|
||||
|
||||
from bot_lib import run_message_handler_for_bot
|
||||
|
||||
def validate_path(bots_fn):
|
||||
# type: (str) -> None
|
||||
bots_fn = os.path.realpath(bots_fn)
|
||||
if not os.path.dirname(bots_fn).startswith(os.path.normpath(os.path.join(our_dir, "../bots"))):
|
||||
print('Sorry, we will only import code from api/bots.')
|
||||
sys.exit(1)
|
||||
|
||||
if not bots_fn.endswith('.py'):
|
||||
print('Please use a .py extension for library files.')
|
||||
sys.exit(1)
|
||||
|
||||
def get_lib_module(bots_fn):
|
||||
# type: (str) -> ModuleType
|
||||
base_bots_fn = os.path.basename(os.path.splitext(bots_fn)[0])
|
||||
sys.path.insert(1, os.path.dirname(bots_fn))
|
||||
module_name = base_bots_fn
|
||||
module = importlib.import_module(module_name)
|
||||
return module
|
||||
|
||||
def run():
|
||||
# type: () -> None
|
||||
usage = '''
|
||||
./run.py <lib file>
|
||||
Example: ./run.py lib/followup.py
|
||||
(This program loads bot-related code from the
|
||||
library code and then runs a message loop,
|
||||
feeding messages to the library code to handle.)
|
||||
Please make sure you have a current ~/.zuliprc
|
||||
file with the credentials you want to use for
|
||||
this bot.
|
||||
See lib/readme.md for more context.
|
||||
'''
|
||||
|
||||
parser = optparse.OptionParser(usage=usage)
|
||||
parser.add_option('--quiet', '-q',
|
||||
action='store_true',
|
||||
help='Turn off logging output.')
|
||||
parser.add_option('--config-file',
|
||||
action='store',
|
||||
help='(alternate config file to ~/.zuliprc)')
|
||||
parser.add_option('--provision',
|
||||
action='store_true',
|
||||
help='Install dependencies for the bot')
|
||||
parser.add_option('--force',
|
||||
action='store_true',
|
||||
help='Try running the bot even if dependencies install fails.')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if len(args) == 0:
|
||||
print('You must specify a library!')
|
||||
sys.exit(1)
|
||||
bots_fn = args[0]
|
||||
|
||||
validate_path(bots_fn)
|
||||
if options.provision:
|
||||
print("Provisioning")
|
||||
provision.provision_bot(os.path.dirname(bots_fn), options.force)
|
||||
lib_module = get_lib_module(bots_fn)
|
||||
if not options.quiet:
|
||||
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
||||
|
||||
run_message_handler_for_bot(
|
||||
lib_module=lib_module,
|
||||
config_file=options.config_file,
|
||||
quiet=options.quiet
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
|
@ -17,11 +17,11 @@ def dir_join(dir1, dir2):
|
|||
|
||||
if __name__ == '__main__':
|
||||
|
||||
bots_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
root_dir = dir_join(bots_dir, '..')
|
||||
bots_test_dir = dir_join(bots_dir, '../bots')
|
||||
tools_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
bots_dir = os.path.join(tools_dir, '..', 'zulip_bots', 'zulip_bots')
|
||||
bots_test_dir = dir_join(bots_dir, 'bots')
|
||||
|
||||
sys.path.insert(0, root_dir)
|
||||
sys.path.insert(0, bots_dir)
|
||||
sys.path.insert(0, bots_test_dir)
|
||||
|
||||
btd = bots_test_dir
|
||||
|
@ -57,7 +57,7 @@ if __name__ == '__main__':
|
|||
sys.path.insert(0, dep_path)
|
||||
try:
|
||||
suites.append(loader.discover(start_dir = dir_join(bots_test_dir, bot_to_test),
|
||||
top_level_dir = root_dir))
|
||||
top_level_dir = bots_dir))
|
||||
except ImportError:
|
||||
logging.error("Bot %s requires __init__.py to be added" % (bot_to_test))
|
||||
failed = True
|
5
zulip_bots/MANIFEST.in
Normal file
|
@ -0,0 +1,5 @@
|
|||
include zulip_bots/bots/giphy/fixtures/test_1.json
|
||||
include zulip_bots/bots/github_detail/fixtures/test_404.json
|
||||
include zulip_bots/bots/github_detail/fixtures/test_issue.json
|
||||
include zulip_bots/bots/github_detail/fixtures/test_pull.json
|
||||
|
|
@ -24,13 +24,17 @@ to messages in any of the following settings:
|
|||
account specific authentication, for example: a gmail bot that lets
|
||||
one send emails directly through Zulip.
|
||||
|
||||
## Installing
|
||||
|
||||
To install the bots and bots API, run:
|
||||
|
||||
python setup.py install
|
||||
|
||||
## Running bots
|
||||
|
||||
Here is an example of running the "follow-up" bot from
|
||||
inside a Zulip repo (and in your remote instance):
|
||||
Here is an example of running the "follow-up" bot:
|
||||
|
||||
cd ~/zulip/api
|
||||
bots_api/run.py bots/followup/followup.py --config-file ~/.zuliprc-prod
|
||||
zulip-run-bot followup --config-file ~/.zuliprc-prod
|
||||
|
||||
Once the bot code starts running, you will see a
|
||||
message explaining how to use the bot, as well as
|
78
zulip_bots/setup.py
Executable file
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
# We should be installable with either setuptools or distutils.
|
||||
package_info = dict(
|
||||
name='zulip_bots',
|
||||
version='0.3.1',
|
||||
description='Zulip\'s Bot framework',
|
||||
author='Zulip Open Source Project',
|
||||
author_email='zulip-devel@googlegroups.com',
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Web Environment',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Topic :: Communications :: Chat',
|
||||
],
|
||||
url='https://www.zulip.org/',
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'zulip-run-bot=zulip_bots.run:main',
|
||||
],
|
||||
},
|
||||
include_package_data=True,
|
||||
) # type: Dict[str, Any]
|
||||
|
||||
setuptools_info = dict(
|
||||
install_requires=[
|
||||
'zulip>=0.3.1',
|
||||
'mock>=2.0.0',
|
||||
'html2text', # for bots/define
|
||||
'PyDictionary', # for bots/thesaurus
|
||||
],
|
||||
)
|
||||
|
||||
try:
|
||||
from setuptools import setup, find_packages
|
||||
package_info.update(setuptools_info)
|
||||
package_info['packages'] = find_packages()
|
||||
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
from distutils.version import LooseVersion
|
||||
from importlib import import_module
|
||||
|
||||
# Manual dependency check
|
||||
def check_dependency_manually(module_name, version=None):
|
||||
try:
|
||||
module = import_module(module_name)
|
||||
if version is not None:
|
||||
assert(LooseVersion(module.__version__) >= LooseVersion(version))
|
||||
except (ImportError, AssertionError):
|
||||
if version is not None:
|
||||
print("{name}>={version} is not installed.".format(
|
||||
req=req, version=version), file=sys.stderr)
|
||||
else:
|
||||
print("{name} is not installed.".format(name=module_name), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
check_dependency_manually('zulip', '0.3.1')
|
||||
check_dependency_manually('mock', '2.0.0')
|
||||
check_dependency_manually('html2text')
|
||||
check_dependency_manually('PyDictionary')
|
||||
|
||||
# Include all submodules under bots/
|
||||
package_list = ['zulip_bots']
|
||||
dirs = os.listdir('zulip_bots/bots/')
|
||||
for dir_name in dirs:
|
||||
if os.path.isdir(os.path.join('zulip_bots/bots/', dir_name)):
|
||||
package_list.append('zulip_bots.bots.' + dir_name)
|
||||
package_info['packages'] = package_list
|
||||
|
||||
|
||||
setup(**package_info)
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
@ -5,11 +5,10 @@ from __future__ import division
|
|||
|
||||
import copy
|
||||
import importlib
|
||||
import sys
|
||||
from math import log10, floor
|
||||
|
||||
import utils
|
||||
import re
|
||||
from zulip_bots.bots.converter import utils
|
||||
|
||||
def is_float(value):
|
||||
try:
|
2
bots/converter/test_converter.py → zulip_bots/zulip_bots/bots/converter/test_converter.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestConverterBot(BotTestCase):
|
||||
bot_name = "converter"
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
2
bots/define/test_define.py → zulip_bots/zulip_bots/bots/define/test_define.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestDefineBot(BotTestCase):
|
||||
bot_name = "define"
|
Before Width: | Height: | Size: 287 KiB After Width: | Height: | Size: 287 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 180 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
2
bots/encrypt/test_encrypt.py → zulip_bots/zulip_bots/bots/encrypt/test_encrypt.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestEncryptBot(BotTestCase):
|
||||
bot_name = "encrypt"
|
2
bots/followup/test_followup.py → zulip_bots/zulip_bots/bots/followup/test_followup.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestFollowUpBot(BotTestCase):
|
||||
bot_name = "followup"
|
2
bots/giphy/test_giphy.py → zulip_bots/zulip_bots/bots/giphy/test_giphy.py
Normal file → Executable file
|
@ -5,7 +5,7 @@ from __future__ import print_function
|
|||
|
||||
import json
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestGiphyBot(BotTestCase):
|
||||
bot_name = "giphy"
|
|
@ -27,7 +27,7 @@ Here is an example of running the `git_hub_comment` bot from
|
|||
inside a Zulip repo:
|
||||
|
||||
`cd ~/zulip/api`
|
||||
`bots_api/run.py bots/git_hub_comment/git_hub_comment.py --config-file ~/.zuliprc-prod`
|
||||
`zulip-run-bot git_hub_comment --config-file ~/.zuliprc-prod`
|
||||
|
||||
Once the bot code starts running, you will see a
|
||||
message explaining how to use the bot, as well as
|
||||
|
@ -49,5 +49,3 @@ page to create a user-owned bot.
|
|||
email=someuser@example.com
|
||||
key=<your api key>
|
||||
site=https://zulip.somewhere.com
|
||||
|
||||
|
9
bots/github_detail/test_github_detail.py → zulip_bots/zulip_bots/bots/github_detail/test_github_detail.py
Normal file → Executable file
|
@ -3,16 +3,9 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
our_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.normpath(os.path.join(our_dir)))
|
||||
# For dev setups, we can find the API in the repo itself.
|
||||
if os.path.exists(os.path.join(our_dir, '..')):
|
||||
sys.path.insert(0, '..')
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestGithubDetailBot(BotTestCase):
|
||||
bot_name = "github_detail"
|
2
bots/helloworld/test_helloworld.py → zulip_bots/zulip_bots/bots/helloworld/test_helloworld.py
Normal file → Executable file
|
@ -5,7 +5,7 @@ from __future__ import print_function
|
|||
|
||||
from six.moves import zip
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestHelloWorldBot(BotTestCase):
|
||||
bot_name = "helloworld"
|
2
bots/help/test_help.py → zulip_bots/zulip_bots/bots/help/test_help.py
Normal file → Executable file
|
@ -5,7 +5,7 @@ from __future__ import print_function
|
|||
|
||||
from six.moves import zip
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestHelpBot(BotTestCase):
|
||||
bot_name = "help"
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 9 KiB After Width: | Height: | Size: 9 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
@ -1,6 +1,5 @@
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from random import choice
|
||||
|
||||
|
@ -12,9 +11,6 @@ except ImportError:
|
|||
Please: pip install chatterbot""")
|
||||
|
||||
BOTS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(os.path.dirname(BOTS_DIR))
|
||||
sys.path.insert(0, os.path.dirname(BOTS_DIR))
|
||||
|
||||
JOKES_PATH = os.path.join(BOTS_DIR, 'assets/var/jokes.json')
|
||||
DATABASE_PATH = os.path.join(BOTS_DIR, 'assets/var/database.db')
|
||||
DIRECTORY_PATH = os.path.join(BOTS_DIR, 'assets')
|
2
bots/thesaurus/test_thesaurus.py → zulip_bots/zulip_bots/bots/thesaurus/test_thesaurus.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestThesaurusBot(BotTestCase):
|
||||
bot_name = "thesaurus"
|
2
bots/virtual_fs/test_virtual_fs.py → zulip_bots/zulip_bots/bots/virtual_fs/test_virtual_fs.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
from bots_test_lib import BotTestCase
|
||||
from zulip_bots.test_lib import BotTestCase
|
||||
|
||||
class TestVirtualFsBot(BotTestCase):
|
||||
bot_name = "virtual_fs"
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |