extensions.py 4.93 KB
Newer Older
1
2
import os
import sys
3
import imp
4
5

from flask import current_app
6
7
from collections import defaultdict
from .plugins import SentimentPlugin, EmotionPlugin
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

try:
    from flask import _app_ctx_stack as stack
except ImportError:
    from flask import _request_ctx_stack as stack

from blueprints import nif_blueprint
from git import Repo, InvalidGitRepositoryError

class Senpy(object):

    def __init__(self, app=None, plugin_folder="plugins"):
        self.app = app
        base_folder = os.path.join(os.path.dirname(__file__), "plugins")

23
        self.search_folders = (folder for folder in (base_folder, plugin_folder, '/tmp/plugins')
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
                                if folder and os.path.isdir(folder))

        if app is not None:
            self.init_app(app)

    """

        Note: I'm not particularly fond of adding self.app and app.senpy, but
        I can't think of a better way to do it.
    """
    def init_app(self, app, plugin_folder="plugins"):
        app.senpy = self
        #app.config.setdefault('SQLITE3_DATABASE', ':memory:')
        # Use the newstyle teardown_appcontext if it's available,
        # otherwise fall back to the request context
        if hasattr(app, 'teardown_appcontext'):
            app.teardown_appcontext(self.teardown)
        else:
            app.teardown_request(self.teardown)
        app.register_blueprint(nif_blueprint)

    def analyse(self, **params):
46
47
        algo = None
        print("analysing with params: {}".format(params))
48
49
        if "algorithm" in params:
            algo = params["algorithm"]
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        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
        else:
            return {"status": 500, "message": "No valid algorithm"}

    @property
    def default_plugin(self):
        if self.plugins:
            candidate = self.filter_plugins(enabled=True).keys()[0]
            print("Default: {}".format(candidate))
            return candidate
        else:
            return Exception("No algorithm")
68

69
    def parameters(self, algo):
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        return getattr(self.plugins.get(algo or self.default_plugin), "params", {})

    def enable_plugin(self, plugin):
        self.plugins[plugin].disable()

    def disable_plugin(self, plugin):
        self.plugins[plugin].disable()

    def reload_plugin(self, plugin):
        print("Reloading {}".format(plugin))
        plug = self.plugins[plugin]
        nplug = self._load_plugin(plug.module, plug.path)
        del self.plugins[plugin]
        self.plugins[nplug.name] = nplug
84
85
86

    def _load_plugin(self, plugin, search_folder, enabled=True):
        sys.path.append(search_folder)
87
88
        (fp, pathname, desc) = imp.find_module(plugin)
        tmp = imp.load_module(plugin, fp, pathname, desc).plugin
89
90
91
92
93
94
95
96
97
        sys.path.remove(search_folder)
        tmp.path = search_folder
        try:
            repo_path = os.path.join(search_folder, plugin)
            tmp.repo = Repo(repo_path)
        except InvalidGitRepositoryError:
            tmp.repo = None
        if not hasattr(tmp, "enabled"):
            tmp.enabled = enabled
98
        tmp.module = plugin
99
100
101
102
103
104
105
106
107
108
        return tmp


    def _load_plugins(self):
        plugins = {}
        for search_folder in self.search_folders:
            for item in os.listdir(search_folder):
                if os.path.isdir(os.path.join(search_folder, item)) \
                        and os.path.exists(
                            os.path.join(search_folder, item, "__init__.py")):
109
110
                    plugin = self._load_plugin(item, search_folder)
                    plugins[plugin.name] = plugin
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

        return plugins

    def teardown(self, exception):
        pass

    def enable_all(self):
        for plugin in self.plugins:
            self.enable_plugin(plugin)

    def enable_plugin(self, item):
        self.plugins[item].enabled = True

    def disable_plugin(self, item):
        self.plugins[item].enabled = False

    @property
    def plugins(self):
        ctx = stack.top
        if ctx is not None:
            if not hasattr(self, '_plugins'):
                self._plugins = self._load_plugins()
            return self._plugins

135
136
137
138
139
140
141
142
143
144
145
146
147
148
    def filter_plugins(self, **kwargs):
        def matches(plug):
            res = all(getattr(plug, k, None)==v for (k,v) in kwargs.items())
            print("matching {} with {}: {}".format(plug.name, kwargs, res))
            return res
        if not kwargs:
            return self.plugins
        else:
            return {n:p for n,p in self.plugins.items() if matches(p)}

    def sentiment_plugins(self):
        return (plugin for plugin in self.plugins if
                isinstance(plugin, SentimentPlugin))

149
150
151
152
153
154
155
if __name__ == '__main__':
    from flask import Flask
    app = Flask(__name__)
    sp = Senpy()
    sp.init_app(app)
    with app.app_context():
        sp._load_plugins()