From a7d8b67c2288f5b48a40daf02686c0aebfb6dfce Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Wed, 15 Nov 2017 23:02:29 +0000 Subject: [PATCH 1/8] Add config loader from config file in addition to the environment variable With this config we load configuration variables from a config file and from the environment. If a variable is in both (config and env) the env variable is used. This makes easy to quick change a particular variable between restarts (the debug level e.g.). --- config.ini | 7 +++++++ limbo/limbo.py | 16 ++-------------- requirements.txt | 1 + test/test_config.py | 27 +++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 config.ini create mode 100644 test/test_config.py diff --git a/config.ini b/config.ini new file mode 100644 index 00000000..b954f9c1 --- /dev/null +++ b/config.ini @@ -0,0 +1,7 @@ +[DEFAULT] + +SLACK_TOKEN = token + +[BOT] + +logfile = logfile.log \ No newline at end of file diff --git a/limbo/limbo.py b/limbo/limbo.py index 2f0e35d1..b7ea0f2a 100644 --- a/limbo/limbo.py +++ b/limbo/limbo.py @@ -15,6 +15,7 @@ from .slack import SlackClient, SlackConnectionError, SlackLoginError from .server import LimboServer from .fakeserver import FakeServer +from .config import Config CURDIR = os.path.abspath(os.path.dirname(__file__)) DIR = functools.partial(os.path.join, CURDIR) @@ -151,19 +152,6 @@ def handle_event(event, server): if handler: return handler(event, server) -def getif(config, name, envvar): - if envvar in os.environ: - config[name] = os.environ.get(envvar) - -def init_config(): - config = {} - getif(config, "token", "SLACK_TOKEN") - getif(config, "loglevel", "LIMBO_LOGLEVEL") - getif(config, "logfile", "LIMBO_LOGFILE") - getif(config, "logformat", "LIMBO_LOGFORMAT") - getif(config, "plugins", "LIMBO_PLUGINS") - - return config def loop(server, test_loop=None): """Run the main loop @@ -282,7 +270,7 @@ def encode(str_, codec='utf8'): return str_.encode(codec) def main(args): - config = init_config() + config = Config() if args.test: init_log(config) return repl(FakeServer(), args) diff --git a/requirements.txt b/requirements.txt index 444231f7..a0fb834e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,3 +35,4 @@ virtualenv==15.1.0 webencodings==0.5.1 websocket-client==0.44.0 wrapt==1.10.10 +configparser==3.5.0 diff --git a/test/test_config.py b/test/test_config.py new file mode 100644 index 00000000..f50b15f4 --- /dev/null +++ b/test/test_config.py @@ -0,0 +1,27 @@ +# -*- coding: UTF-8 -*- +import os + +DIR = os.path.dirname(os.path.realpath(__file__)) +PARENT = os.path.split(DIR)[0] + +from limbo.config import Config + + +def test_config(): + # test wrong config location + os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" + try: + config = Config() + assert False + except IOError: + assert True + + # know a correct config location + os.environ["LIMBO_CONFIG_LOCATION"] = "../config.ini" + config = Config() + assert config["SLACK_TOKEN"] == "token" + + # test non existing setting + result = config.get("weather", "weather_token") + assert not result + From 8777370be3d8137be7426912d685e6f58e1c4e1b Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Wed, 15 Nov 2017 23:40:59 +0000 Subject: [PATCH 2/8] Add missing file from last commit with the config definition --- .gitignore | 3 ++- limbo/config.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 limbo/config.py diff --git a/.gitignore b/.gitignore index d2f5d943..6b2d07c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .env venv/ *.pyc -config.py +./config.py *.config.py limbo.sqlite3 limbo.egg-info @@ -17,3 +17,4 @@ slask.egg-info/ .vagrant .python-version .cache +.idea \ No newline at end of file diff --git a/limbo/config.py b/limbo/config.py new file mode 100644 index 00000000..006c94e9 --- /dev/null +++ b/limbo/config.py @@ -0,0 +1,45 @@ +import os +from backports import configparser as confparser + + +class Config: + env_config = {} + file_config = None # type: confparser.ConfigParser + + def __init__(self): + self.load_env_config() + self.load_config_file() + + def load_config_file(self): + self.file_config = confparser.ConfigParser() + config_file = self.env_config.get("config_location", "config.ini") + # check if config exists + import os + if not os.path.exists(config_file): + raise IOError("File for configuration not found") + self.file_config.read(config_file) + + def load_env_config(self): + config = {} + self._getif(config, "token", "SLACK_TOKEN") + self._getif(config, "loglevel", "LIMBO_LOGLEVEL") + self._getif(config, "logfile", "LIMBO_LOGFILE") + self._getif(config, "logformat", "LIMBO_LOGFORMAT") + self._getif(config, "plugins", "LIMBO_PLUGINS") + self._getif(config, "config_location", "LIMBO_CONFIG_LOCATION") + self.env_config = config + + def _getif(self, config, name, envvar): + if envvar in os.environ: + config[name] = os.environ.get(envvar) + + def get(self, plugin_name, item_name): + if plugin_name and plugin_name + "_" + item_name in self.env_config.keys(): + return self.env_config[plugin_name + "_" + item_name] + try: + return self.file_config.get(plugin_name, item_name) + except confparser.NoSectionError: + return None # in case of not finding it anywhere + + def __getitem__(self, item): + return self.get("BOT", item) From 9b5669bd3873d9fd41572a586ad87e4763d7494c Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Thu, 16 Nov 2017 00:26:33 +0000 Subject: [PATCH 3/8] Fix config calling in some cases --- limbo/config.py | 11 ++++++++--- test/test_cmd.py | 2 ++ test/test_config.py | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/limbo/config.py b/limbo/config.py index 006c94e9..a96cc372 100644 --- a/limbo/config.py +++ b/limbo/config.py @@ -33,13 +33,18 @@ def _getif(self, config, name, envvar): if envvar in os.environ: config[name] = os.environ.get(envvar) - def get(self, plugin_name, item_name): - if plugin_name and plugin_name + "_" + item_name in self.env_config.keys(): + def get_by_section(self, plugin_name, item_name): + if plugin_name and plugin_name + "_" + str(item_name) in self.env_config.keys(): return self.env_config[plugin_name + "_" + item_name] try: return self.file_config.get(plugin_name, item_name) - except confparser.NoSectionError: + except confparser.Error: return None # in case of not finding it anywhere + def get(self, *args): + if len(args) > 1: + return self.get_by_section(args[0], args[1]) + return self.get_by_section("BOT", args[0]) + def __getitem__(self, item): return self.get("BOT", item) diff --git a/test/test_cmd.py b/test/test_cmd.py index 95e48fa8..68a9b314 100644 --- a/test/test_cmd.py +++ b/test/test_cmd.py @@ -6,6 +6,8 @@ DIR = os.path.dirname(os.path.realpath(__file__)) TESTPLUGINS = os.path.join(DIR, "plugins") +os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" + # http://stackoverflow.com/a/13160748/42559 def sh(cmd): diff --git a/test/test_config.py b/test/test_config.py index f50b15f4..926035c9 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -9,7 +9,7 @@ def test_config(): # test wrong config location - os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" + os.environ["LIMBO_CONFIG_LOCATION"] = "config_non_existent.ini" try: config = Config() assert False @@ -17,7 +17,7 @@ def test_config(): assert True # know a correct config location - os.environ["LIMBO_CONFIG_LOCATION"] = "../config.ini" + os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" config = Config() assert config["SLACK_TOKEN"] == "token" From 58c5140863976f644705258c8a48fa61622ab0fb Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Sat, 18 Nov 2017 17:58:19 +0000 Subject: [PATCH 4/8] Requested fixes and changes --- limbo/config.py | 11 ++++++----- requirements.txt | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/limbo/config.py b/limbo/config.py index a96cc372..aac7b407 100644 --- a/limbo/config.py +++ b/limbo/config.py @@ -1,22 +1,23 @@ +import logging import os from backports import configparser as confparser -class Config: - env_config = {} - file_config = None # type: confparser.ConfigParser +class Config(object): def __init__(self): self.load_env_config() self.load_config_file() + self.env_config = {} + self.file_config = None # type: confparser.ConfigParser def load_config_file(self): self.file_config = confparser.ConfigParser() config_file = self.env_config.get("config_location", "config.ini") # check if config exists - import os if not os.path.exists(config_file): - raise IOError("File for configuration not found") + logger = logging.getLogger(__name__) + logger.warning("File for configuration not found") self.file_config.read(config_file) def load_env_config(self): diff --git a/requirements.txt b/requirements.txt index a0fb834e..444231f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,4 +35,3 @@ virtualenv==15.1.0 webencodings==0.5.1 websocket-client==0.44.0 wrapt==1.10.10 -configparser==3.5.0 From 2f2439056a24eb71deb474643600ede6a524d08f Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Sat, 18 Nov 2017 18:05:08 +0000 Subject: [PATCH 5/8] Fix to support non existence of config file --- limbo/config.py | 5 ++++- test/test_config.py | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/limbo/config.py b/limbo/config.py index aac7b407..b9426420 100644 --- a/limbo/config.py +++ b/limbo/config.py @@ -18,7 +18,8 @@ def load_config_file(self): if not os.path.exists(config_file): logger = logging.getLogger(__name__) logger.warning("File for configuration not found") - self.file_config.read(config_file) + else: + self.file_config.read(config_file) def load_env_config(self): config = {} @@ -37,6 +38,8 @@ def _getif(self, config, name, envvar): def get_by_section(self, plugin_name, item_name): if plugin_name and plugin_name + "_" + str(item_name) in self.env_config.keys(): return self.env_config[plugin_name + "_" + item_name] + if not self.file_config: + return None try: return self.file_config.get(plugin_name, item_name) except confparser.Error: diff --git a/test/test_config.py b/test/test_config.py index 926035c9..823f959d 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -10,11 +10,8 @@ def test_config(): # test wrong config location os.environ["LIMBO_CONFIG_LOCATION"] = "config_non_existent.ini" - try: - config = Config() - assert False - except IOError: - assert True + config = Config() + assert config.file_config is None # know a correct config location os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" From 8789708c3f7665d38457413ccad0ee6e35d02ab7 Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Sat, 18 Nov 2017 18:17:13 +0000 Subject: [PATCH 6/8] Wrong order of operations making clean the config file after loading it --- limbo/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/limbo/config.py b/limbo/config.py index b9426420..1a43b151 100644 --- a/limbo/config.py +++ b/limbo/config.py @@ -6,19 +6,19 @@ class Config(object): def __init__(self): - self.load_env_config() - self.load_config_file() self.env_config = {} self.file_config = None # type: confparser.ConfigParser + self.load_env_config() + self.load_config_file() def load_config_file(self): - self.file_config = confparser.ConfigParser() config_file = self.env_config.get("config_location", "config.ini") # check if config exists if not os.path.exists(config_file): logger = logging.getLogger(__name__) logger.warning("File for configuration not found") else: + self.file_config = confparser.ConfigParser() self.file_config.read(config_file) def load_env_config(self): From ddb4b32a6655eecbe1f71ba8331b6f8ea1c144ba Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Sun, 23 Sep 2018 22:57:10 +0100 Subject: [PATCH 7/8] Fix importing backports that is missing in python3 --- limbo/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/limbo/config.py b/limbo/config.py index 1a43b151..ca4078a8 100644 --- a/limbo/config.py +++ b/limbo/config.py @@ -1,6 +1,7 @@ import logging import os -from backports import configparser as confparser + +import configparser as confparser class Config(object): From a0702a32c85556a64620ddb36c033c64aebf5159 Mon Sep 17 00:00:00 2001 From: Eduardo Soares Date: Sun, 23 Sep 2018 23:18:09 +0100 Subject: [PATCH 8/8] Add an improved google search --- limbo/plugins/google.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/limbo/plugins/google.py b/limbo/plugins/google.py index a30c79b6..344d48a8 100644 --- a/limbo/plugins/google.py +++ b/limbo/plugins/google.py @@ -7,6 +7,25 @@ from urllib.request import quote, unquote import requests +google_api_key = None +google_cse_id = None + +def on_init(server): + global google_api_key + global google_cse_id + google_api_key = server.config.get("GOOGLE", "API") + google_cse_id = server.config.get("GOOGLE", "CSE") + +def improved_google(q): + # google custom search is more acurate than the old search + # in order to use google custom search configure your account and get your API KEY and CSE ID + # instructions to configure can be found here: https://stackoverflow.com/a/45911123/2999723 + results = requests.get("https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=%s"%(google_api_key, google_cse_id, query)).json() + #pprint.pprint(results) + if not results or "items" not in results.keys(): + return ":crying_cat_face: Sorry, google doesn't have an answer for you :crying_cat_face:" + result = results["items"][0] + return result["title"] + " in: "+ result["link"] def google(q): query = quote(q) @@ -30,8 +49,10 @@ def on_message(msg, server): match = re.findall(r"!(?:google|search) (.*)", text) if not match: return - - return google(match[0]) + if google_api_key and google_cse_id: + return improved_google(match[0]) + else: + return google(match[0]) on_bot_message = on_message