Completed
Push — master ( 5c8ee4...f74340 )
by Felipe A.
50s
created

browsepy.ButtonWidget.__init__()   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 markupsafe import Markup
8
from flask import url_for
9
10
from .__meta__ import __app__
11
12
13
class PluginNotFoundError(ImportError):
14
    pass
15
16
17
class PluginManagerBase(object):
18
19
    @property
20
    def namespaces(self):
21
        return self.app.config['plugin_namespaces']
22
23
    def __init__(self, app=None):
24
        if not app is None:
25
            self.init_app(app)
26
27
    def init_app(self, app):
28
        self.app = app
29
        if not hasattr(app, 'extensions'):
30
            app.extensions = {}
31
        app.extensions['plugin_manager'] = self
32
33
    def import_plugin(self, plugin):
34
        names = [
35
            '%s.%s' % (namespace, plugin) if namespace else plugin
36
            for namespace in self.namespaces
37
            ]
38
        for name in names:
39
            try:
40
                __import__(name)
41
                return sys.modules[name]
42
            except (ImportError, IndexError):
43
                pass
44
        raise PluginNotFoundError('No plugin module %r found, tried %r' % (plugin, names), plugin, names)
45
46
    def load_plugin(self, plugin):
47
        module = self.import_plugin(plugin)
48
        if hasattr(module, 'register_plugin'):
49
            module.register_plugin(self)
50
        return module
51
52
53
class BlueprintPluginManager(PluginManagerBase):
54
    def register_blueprint(self, blueprint):
55
        self.app.register_blueprint(blueprint)
56
57
58
class WidgetBase(object):
59
    place = None
60
    def __init__(self, *args, **kwargs):
61
        self.args = args
62
        self.kwargs = kwargs
63
64
65
class ButtonWidget(WidgetBase):
66
    place = 'button'
67
    def __init__(self, html='', text='', css=""):
68
        self.content = Markup(html) if html else text
69
        self.css = css
70
71
72
class StyleWidget(WidgetBase):
73
    place = 'style'
74
75
    @property
76
    def href(self):
77
        return url_for(*self.args, **self.kwargs)
78
79
class JavascriptWidget(WidgetBase):
80
    place = 'javascript'
81
82
    @property
83
    def src(self):
84
        return url_for(*self.args, **self.kwargs)
85
86
87
class MimetypeActionPluginManager(PluginManagerBase):
88
    action_class = collections.namedtuple('MimetypeAction', ('endpoint', 'widget'))
89
    button_class = ButtonWidget
90
    style_class = StyleWidget
91
    javascript_class = JavascriptWidget
92
93
    def __init__(self, app=None):
94
        self._root = {}
95
        self._widgets = {}
96
        super(MimetypeActionPluginManager, self).__init__(app=app)
97
98
    def get_widgets(self, place):
99
        return self._widgets.get(place, [])
100
101
    def get_actions(self, mimetype):
102
        category, variant = mimetype.split('/')
103
        return [
104
            action
105
            for tree_category in (category, '*')
106
            for tree_variant in (variant, '*')
107
            for action in self._root.get(tree_category, {}).get(tree_variant, ())
108
            ]
109
110
    def register_widget(self, widget):
111
        self._widgets.setdefault(widget.place, []).append(widget)
112
113
    def register_action(self, endpoint, widget, mimetypes=(), **kwargs):
114
        action = self.action_class(endpoint, widget)
115
        for mimetype in mimetypes:
116
            category, variant = mimetype.split('/')
117
            self._root.setdefault(category, {}).setdefault(variant, []).append(action)
118
119
120
class PluginManager(BlueprintPluginManager, MimetypeActionPluginManager):
121
    pass
122