From dabf44460732d1df448c87588cb4b91029c5dbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fernando=20S=C3=A1nchez?= Date: Wed, 26 Nov 2014 22:09:02 +0100 Subject: [PATCH] Switched to Yapsy --- app.py | 2 ++ plugins/yapsy_plugin/prueba.py | 45 +++++++++++++++++++++++++ plugins/yapsy_plugin/prueba.senpy | 8 +++++ requirements.txt | 3 +- senpy/blueprints.py | 4 +-- senpy/extensions.py | 56 ++++++++++++++++++++++--------- senpy/plugins.py | 14 +++----- tests/dummy_plugin/__init__.py | 3 -- tests/dummy_plugin/dummy.py | 6 ++++ tests/dummy_plugin/dummy.senpy | 8 +++++ tests/extensions_test/__init__.py | 23 ++++++------- 11 files changed, 129 insertions(+), 43 deletions(-) create mode 100644 plugins/yapsy_plugin/prueba.py create mode 100644 plugins/yapsy_plugin/prueba.senpy delete mode 100644 tests/dummy_plugin/__init__.py create mode 100644 tests/dummy_plugin/dummy.py create mode 100644 tests/dummy_plugin/dummy.senpy diff --git a/app.py b/app.py index a82ef27..d1e48d2 100644 --- a/app.py +++ b/app.py @@ -29,5 +29,7 @@ sp = Senpy() sp.init_app(app) if __name__ == '__main__': + import logging + logging.basicConfig(level=config.DEBUG) app.debug = config.DEBUG app.run(host="0.0.0.0", use_reloader=False) diff --git a/plugins/yapsy_plugin/prueba.py b/plugins/yapsy_plugin/prueba.py new file mode 100644 index 0000000..1cf4407 --- /dev/null +++ b/plugins/yapsy_plugin/prueba.py @@ -0,0 +1,45 @@ +import requests +import json + +from senpy.plugins import SentimentPlugin +from senpy.models import Response, Opinion, Entry + + +class Sentiment140Plugin(SentimentPlugin): + EXTRA_PARAMS = { + "language": {"aliases": ["language", "l"], + "required": False, + "options": ["es", "en", "auto"], + } + } + + def __init__(self, **kwargs): + super(Sentiment140Plugin, self).__init__(name="sentiment140", + version="2.0", + extraparams=self.EXTRA_PARAMS, + **kwargs) + + def analyse(self, **params): + lang = params.get("language", "auto") + res = requests.post("http://www.sentiment140.com/api/bulkClassifyJson", + json.dumps({"language": lang, + "data": [{"text": params["input"]}] + } + ) + ) + + response = Response() + polarity_value = int(res.json()["data"][0]["polarity"]) * 25 + polarity = "marl:Neutral" + if polarity_value > 50: + polarity = "marl:Positive" + elif polarity_value < 50: + polarity = "marl:Negative" + entry = Entry(text=params["input"]) + opinion = Opinion(polarity=polarity, polarity_value=polarity_value) + entry.opinions.append(opinion) + entry.language = lang + response.entries.append(entry) + return response + +plugin = Sentiment140Plugin() diff --git a/plugins/yapsy_plugin/prueba.senpy b/plugins/yapsy_plugin/prueba.senpy new file mode 100644 index 0000000..2745644 --- /dev/null +++ b/plugins/yapsy_plugin/prueba.senpy @@ -0,0 +1,8 @@ +[Core] +Name = Test plugin of Yapsy +Module = prueba +[Documentation] +Description = What my plugin broadly does +Author = My very own name +Version = 0.1 +Website = My very own website diff --git a/requirements.txt b/requirements.txt index 1f91c73..86bf1e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Flask==0.10.1 gunicorn==19.0.0 requests==2.4.1 -GitPython==0.3.2.RC1 \ No newline at end of file +GitPython==0.3.2.RC1 +Yapsy>=1.10.423 \ No newline at end of file diff --git a/senpy/blueprints.py b/senpy/blueprints.py index cafc91d..1bf5b4d 100644 --- a/senpy/blueprints.py +++ b/senpy/blueprints.py @@ -120,10 +120,10 @@ def plugins(plugin=None, action="list"): dic = {plug: plugs[plug].jsonable(with_params) for plug in plugs} return jsonify(dic) if action == "disable": - current_app.senpy.disable_plugin(plugin) + current_app.senpy.deactivate_plugin(plugin) return "Ok" elif action == "enable": - current_app.senpy.enable_plugin(plugin) + current_app.senpy.activate_plugin(plugin) return "Ok" elif action == "reload": current_app.senpy.reload_plugin(plugin) diff --git a/senpy/extensions.py b/senpy/extensions.py index 2ff544d..c0fc7c4 100644 --- a/senpy/extensions.py +++ b/senpy/extensions.py @@ -8,6 +8,8 @@ import logging logger = logging.getLogger(__name__) from .plugins import SentimentPlugin, EmotionPlugin +from yapsy.PluginFileLocator import PluginFileLocator, PluginFileAnalyzerWithInfoFile +from yapsy.PluginManager import PluginManager try: from flask import _app_ctx_stack as stack @@ -50,11 +52,13 @@ class Senpy(object): app.register_blueprint(nif_blueprint) def add_folder(self, folder): + logger.debug("Adding folder: %s", folder) if os.path.isdir(folder): self._search_folders.add(folder) self._outdated = True return True else: + logger.debug("Not a folder: %s", folder) return False def analyse(self, **params): @@ -64,18 +68,25 @@ class Senpy(object): algo = params["algorithm"] elif self.plugins: algo = self.default_plugin - if algo in self.plugins and self.plugins[algo].enabled: - plug = self.plugins[algo] - resp = plug.analyse(**params) - resp.analysis.append(plug.jsonable()) - return resp + if algo in self.plugins: + if self.plugins[algo].is_activated: + plug = self.plugins[algo] + resp = plug.analyse(**params) + resp.analysis.append(plug.jsonable()) + return resp + logger.debug("Plugin not activated: {}".format(algo)) else: + logger.debug("The algorithm '{}' is not valid\nValid algorithms: {}".format(algo, self.plugins.keys())) return {"status": 400, "message": "The algorithm '{}' is not valid".format(algo)} + def activate_all(self): + for plug in self.plugins.values(): + plug.activate() + @property def default_plugin(self): - candidates = self.filter_plugins(enabled=True) - if len(candidates) > 1: + candidates = self.filter_plugins(is_activated=True) + if len(candidates) > 0: candidate = candidates.keys()[0] logger.debug("Default: {}".format(candidate)) return candidate @@ -85,11 +96,11 @@ class Senpy(object): def parameters(self, algo): return getattr(self.plugins.get(algo or self.default_plugin), "params", {}) - def enable_plugin(self, plugin): - self.plugins[plugin].enable() + def activate_plugin(self, plugin): + self.plugins[plugin].activate() - def disable_plugin(self, plugin): - self.plugins[plugin].disable() + def deactivate_plugin(self, plugin): + self.plugins[plugin].deactivate() def reload_plugin(self, plugin): logger.debug("Reloading {}".format(plugin)) @@ -99,7 +110,7 @@ class Senpy(object): self.plugins[nplug.name] = nplug @staticmethod - def _load_plugin(plugin, search_folder, enabled=True): + def _load_plugin(plugin, search_folder, is_activated=True): logger.debug("Loading plugins") sys.path.append(search_folder) (fp, pathname, desc) = imp.find_module(plugin) @@ -112,8 +123,8 @@ class Senpy(object): tmp.repo = Repo(repo_path) except InvalidGitRepositoryError: tmp.repo = None - if not hasattr(tmp, "enabled"): - tmp.enabled = enabled + if not hasattr(tmp, "is_activated"): + tmp.is_activated = is_activated tmp.module = plugin except Exception as ex: tmp = None @@ -140,7 +151,20 @@ class Senpy(object): def enable_all(self): for plugin in self.plugins: - self.enable_plugin(plugin) + self.activate_plugin(plugin) + + @property + def manager(self): + ctx = stack.top + if ctx is not None: + if not hasattr(ctx, 'senpy_manager'): + logger.debug("Loading manager: %s", self._search_folders) + ctx.senpy_manager = PluginManager(plugin_info_ext="senpy") + ctx.senpy_manager.getPluginLocator().setPluginPlaces(self._search_folders) + ctx.senpy_manager.locatePlugins() + ctx.senpy_manager.loadPlugins() + self.activate_all() + return ctx.senpy_manager @property def plugins(self): @@ -148,7 +172,7 @@ class Senpy(object): ctx = stack.top if ctx is not None: if not hasattr(ctx, 'senpy_plugins') or self._outdated: - ctx.senpy_plugins = self._load_plugins() + ctx.senpy_plugins = {p.name:p.plugin_object for p in self.manager.getAllPlugins()} return ctx.senpy_plugins def filter_plugins(self, **kwargs): diff --git a/senpy/plugins.py b/senpy/plugins.py index 31e80e2..4f9b634 100644 --- a/senpy/plugins.py +++ b/senpy/plugins.py @@ -1,4 +1,5 @@ import logging +from yapsy.IPlugin import IPlugin logger = logging.getLogger(__name__) @@ -33,7 +34,7 @@ PARAMS = {"input": {"aliases": ["i", "input"], } -class SenpyPlugin(object): +class SenpyPlugin(IPlugin): def __init__(self, name=None, version=None, extraparams=None, params=None): logger.debug("Initialising {}".format(name)) self.name = name @@ -45,21 +46,16 @@ class SenpyPlugin(object): if extraparams: self.params.update(extraparams) self.extraparams = extraparams or {} - self.enabled = True + self.is_activated = True def analyse(self, *args, **kwargs): + logger.debug("Analysing with: {} {}".format(self.name, self.version)) pass - def enable(self): - self.enabled = True - - def disable(self): - self.enabled = False - def jsonable(self, parameters=False): resp = { "@id": "{}_{}".format(self.name, self.version), - "enabled": self.enabled, + "is_activated": self.is_activated, } if hasattr(self, "repo") and self.repo: resp["repo"] = self.repo.remotes[0].url diff --git a/tests/dummy_plugin/__init__.py b/tests/dummy_plugin/__init__.py deleted file mode 100644 index c9e674c..0000000 --- a/tests/dummy_plugin/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from senpy.plugins import SenpyPlugin - -plugin = SenpyPlugin("dummy") diff --git a/tests/dummy_plugin/dummy.py b/tests/dummy_plugin/dummy.py new file mode 100644 index 0000000..70272d7 --- /dev/null +++ b/tests/dummy_plugin/dummy.py @@ -0,0 +1,6 @@ +from senpy.plugins import SenpyPlugin + +class DummyPlugin(SenpyPlugin): + def __init__(self): + super(DummyPlugin, self).__init__("dummy") + diff --git a/tests/dummy_plugin/dummy.senpy b/tests/dummy_plugin/dummy.senpy new file mode 100644 index 0000000..c694003 --- /dev/null +++ b/tests/dummy_plugin/dummy.senpy @@ -0,0 +1,8 @@ +[Core] +Name = dummy +Module = dummy +[Documentation] +Description = What my plugin broadly does +Author = My very own name +Version = 0.1 +Website = My very own website diff --git a/tests/extensions_test/__init__.py b/tests/extensions_test/__init__.py index 25ed292..006aab2 100644 --- a/tests/extensions_test/__init__.py +++ b/tests/extensions_test/__init__.py @@ -13,10 +13,9 @@ from flask.ext.testing import TestCase class ExtensionsTest(TestCase): def create_app(self): self.app = Flask("test_extensions") - self.senpy = Senpy() - self.senpy.init_app(self.app) self.dir = os.path.join(os.path.dirname(__file__), "..") - self.senpy.add_folder(self.dir) + self.senpy = Senpy(plugin_folder=self.dir) + self.senpy.init_app(self.app) return self.app def test_init(self): @@ -35,14 +34,14 @@ class ExtensionsTest(TestCase): def test_enabling(self): """ Enabling a plugin """ - self.senpy.enable_plugin("dummy") - assert self.senpy.plugins["dummy"].enabled + self.senpy.activate_plugin("dummy") + assert self.senpy.plugins["dummy"].is_activated def test_disabling(self): """ Disabling a plugin """ - self.senpy.enable_plugin("dummy") - self.senpy.disable_plugin("dummy") - assert not self.senpy.plugins["dummy"].enabled + self.senpy.activate_plugin("dummy") + self.senpy.deactivate_plugin("dummy") + assert not self.senpy.plugins["dummy"].is_activated def test_default(self): """ Default plugin should be set """ @@ -57,7 +56,7 @@ class ExtensionsTest(TestCase): mocked.assert_any_call(input="tupni", output="tuptuo", algorithm="dummy") mocked.assert_any_call(input="tupni", output="tuptuo") for plug in self.senpy.plugins: - self.senpy.disable_plugin(plug) + self.senpy.deactivate_plugin(plug) resp = self.senpy.analyse(input="tupni") logging.debug("Response: {}".format(resp)) assert resp["status"] == 400 @@ -66,6 +65,6 @@ class ExtensionsTest(TestCase): """ Filtering plugins """ assert len(self.senpy.filter_plugins(name="dummy")) > 0 assert not len(self.senpy.filter_plugins(name="notdummy")) - assert self.senpy.filter_plugins(name="dummy", enabled=True) - self.senpy.disable_plugin("dummy") - assert not len(self.senpy.filter_plugins(name="dummy", enabled=True)) + assert self.senpy.filter_plugins(name="dummy", is_activated=True) + self.senpy.deactivate_plugin("dummy") + assert not len(self.senpy.filter_plugins(name="dummy", is_activated=True))