Completed
Push — master ( 890bd3...b13734 )
by Felipe A.
45s
created

browsepy.PluginManagerBase.reload()   A

Complexity

Conditions 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 3
rs 10
1
#!/usr/bin/env python
2
# -*- coding: UTF-8 -*-
3
4
import sys
5
import collections
6
7
from . import mimetype
8
from . import widget
9
from .compat import isnonstriterable
10
11
12
class PluginNotFoundError(ImportError):
13
    pass
14
15
16
class PluginManagerBase(object):
17
18
    @property
19
    def namespaces(self):
20
        return self.app.config['plugin_namespaces']
21
22
    def __init__(self, app=None):
23
        if not app is None:
24
            self.init_app(app)
25
26
    def init_app(self, app):
27
        self.app = app
28
        if not hasattr(app, 'extensions'):
29
            app.extensions = {}
30
        app.extensions['plugin_manager'] = self
31
        self.reload()
32
33
    def reload(self):
34
        for plugin in self.app.config.get('plugin_modules', ()):
35
            self.load_plugin(plugin)
36
37
    def load_plugin(self, plugin):
38
        names = [
39
            '%s.%s' % (namespace, plugin) if namespace else plugin
40
            for namespace in self.namespaces
41
            ]
42
43
        for name in names:
44
            if name in sys.modules:
45
                return sys.modules[name]
46
47
        for name in names:
48
            try:
49
                __import__(name)
50
                return sys.modules[name]
51
            except (ImportError, IndexError):
52
                pass
53
54
        raise PluginNotFoundError('No plugin module %r found, tried %r' % (plugin, names), plugin, names)
55
56
57
class BlueprintPluginManager(PluginManagerBase):
58
    def register_blueprint(self, blueprint):
59
        self.app.register_blueprint(blueprint)
60
61
    def load_plugin(self, plugin):
62
        module = super(BlueprintPluginManager, self).load_plugin(plugin)
63
        if hasattr(module, 'register_plugin'):
64
            module.register_plugin(self)
65
        return module
66
67
68
class MimetypeActionPluginManager(PluginManagerBase):
69
    action_class = collections.namedtuple('MimetypeAction', ('endpoint', 'widget'))
70
    button_class = widget.ButtonWidget
71
    style_class = widget.StyleWidget
72
    javascript_class = widget.JavascriptWidget
73
74
    def __init__(self, app=None):
75
        self._root = {}
76
        self._widgets = {}
77
        self._mimetype_functions = [
78
            mimetype.by_default,
79
            mimetype.by_file,
80
            mimetype.by_python
81
        ]
82
        super(MimetypeActionPluginManager, self).__init__(app=app)
83
84
    def get_mimetype(self, path):
85
        for fnc in reversed(self._mimetype_functions):
86
            mime = fnc(path)
87
            if mime:
88
                return mime
89
        return mimetype.by_default(path)
90
91
    def get_widgets(self, place):
92
        return self._widgets.get(place, [])
93
94
    def get_actions(self, mimetype):
95
        category, variant = mimetype.split('/')
96
        return [
97
            action
98
            for tree_category in (category, '*')
99
            for tree_variant in (variant, '*')
100
            for action in self._root.get(tree_category, {}).get(tree_variant, ())
101
            ]
102
103
    def register_mimetype_function(self, fnc):
104
        self._mimetype_functions.append(fnc)
105
106
    def register_widget(self, widget):
107
        self._widgets.setdefault(widget.place, []).append(widget)
108
109
    def register_action(self, endpoint, widget, mimetypes=(), **kwargs):
110
        mimetypes = mimetypes if isnonstriterable(mimetypes) else (mimetypes,)
111
        action = self.action_class(endpoint, widget)
112
        for mimetype in mimetypes:
113
            category, variant = mimetype.split('/')
114
            self._root.setdefault(category, {}).setdefault(variant, []).append(action)
115
116
117
class PluginManager(BlueprintPluginManager, MimetypeActionPluginManager):
118
    pass
119